update asterisk to new upstream release (v1.2.1)
authornico <nico@3c298f89-4303-0410-b956-a3cf2f4a3e73>
Thu, 15 Dec 2005 08:22:57 +0000 (08:22 +0000)
committernico <nico@3c298f89-4303-0410-b956-a3cf2f4a3e73>
Thu, 15 Dec 2005 08:22:57 +0000 (08:22 +0000)
git-svn-id: svn://svn.openwrt.org/openwrt/trunk@2682 3c298f89-4303-0410-b956-a3cf2f4a3e73

36 files changed:
openwrt/package/asterisk/Config.in
openwrt/package/asterisk/Makefile
openwrt/package/asterisk/files/modules.conf
openwrt/package/asterisk/ipkg/asterisk-sqlite.control [new file with mode: 0644]
openwrt/package/asterisk/ipkg/asterisk.conffiles
openwrt/package/asterisk/patches/asterisk-1.0.7-Makefile-apps.patch [deleted file]
openwrt/package/asterisk/patches/asterisk-1.0.7-Makefile-cdr.patch [deleted file]
openwrt/package/asterisk/patches/asterisk-1.0.7-Makefile-channels-h323.patch [deleted file]
openwrt/package/asterisk/patches/asterisk-1.0.7-Makefile-channels.patch [deleted file]
openwrt/package/asterisk/patches/asterisk-1.0.7-Makefile-codecs-ilbc.patch [deleted file]
openwrt/package/asterisk/patches/asterisk-1.0.7-Makefile-codecs.patch [deleted file]
openwrt/package/asterisk/patches/asterisk-1.0.7-Makefile-res.patch [deleted file]
openwrt/package/asterisk/patches/asterisk-1.0.7-Makefile.patch [deleted file]
openwrt/package/asterisk/patches/asterisk-1.0.7-astdb-in-spool.patch [deleted file]
openwrt/package/asterisk/patches/asterisk-1.0.7-no-crypto.diff [deleted file]
openwrt/package/asterisk/patches/asterisk-1.0.7-no-newt.diff [deleted file]
openwrt/package/asterisk/patches/asterisk-1.0.7-no_gtk.patch [deleted file]
openwrt/package/asterisk/patches/asterisk-1.0.7-pbx_dundi.patch [deleted file]
openwrt/package/asterisk/patches/asterisk-1.0.7-sipura-rtp.patch [deleted file]
openwrt/package/asterisk/patches/asterisk-1.0.9-Makefile-codecs-gsm.patch [deleted file]
openwrt/package/asterisk/patches/asterisk-1.0.9-chan_bluetooth.patch
openwrt/package/asterisk/patches/asterisk-1.2.0-Makefile-apps.patch [new file with mode: 0644]
openwrt/package/asterisk/patches/asterisk-1.2.0-Makefile-cdr.patch [new file with mode: 0644]
openwrt/package/asterisk/patches/asterisk-1.2.0-Makefile-channels.patch [new file with mode: 0644]
openwrt/package/asterisk/patches/asterisk-1.2.0-Makefile-codecs-gsm.patch [new file with mode: 0644]
openwrt/package/asterisk/patches/asterisk-1.2.0-Makefile-codecs.patch [new file with mode: 0644]
openwrt/package/asterisk/patches/asterisk-1.2.0-Makefile-pbx.patch [new file with mode: 0644]
openwrt/package/asterisk/patches/asterisk-1.2.0-Makefile-res.patch [new file with mode: 0644]
openwrt/package/asterisk/patches/asterisk-1.2.0-Makefile.patch [new file with mode: 0644]
openwrt/package/asterisk/patches/asterisk-1.2.0-app_mysql.patch [new file with mode: 0644]
openwrt/package/asterisk/patches/asterisk-1.2.0-cdr_mysql.patch [new file with mode: 0644]
openwrt/package/asterisk/patches/asterisk-1.2.0-chan_bluetooth.patch [new file with mode: 0644]
openwrt/package/asterisk/patches/asterisk-1.2.0-compat-getloadavg.patch [new file with mode: 0644]
openwrt/package/asterisk/patches/asterisk-1.2.0-res_mysql.patch [new file with mode: 0644]
openwrt/package/asterisk/patches/asterisk-1.2.1-Makefile-versionnum.patch [new file with mode: 0644]
openwrt/package/asterisk/patches/mysql+postgres-support.diff [deleted file]

index 127bb15..dad8cf7 100644 (file)
@@ -95,7 +95,16 @@ config BR2_PACKAGE_ASTERISK_PGSQL
        select BR2_PACKAGE_LIBPQ
        help
          PostgreSQL modules for Asterisk
-         
+
+config BR2_PACKAGE_ASTERISK_SQLITE
+       prompt   "asterisk-sqlite................. SQLite modules"
+       tristate
+       default m if CONFIG_DEVEL
+       depends BR2_PACKAGE_ASTERISK
+       select BR2_PACKAGE_LIBSQLITE
+       help
+         SQLite modules for Asterisk
+
 config BR2_PACKAGE_ASTERISK_SOUNDS
        prompt   "asterisk-sounds................. Sound files"
        tristate
@@ -111,7 +120,7 @@ config BR2_PACKAGE_ASTERISK_VOICEMAIL
        depends BR2_PACKAGE_ASTERISK
        help
          Voicemail related modules for Asterisk
-         
+
 config BR2_PACKAGE_ASTERISK_MINI
        prompt "asterisk-mini..................... Minimal open source PBX"
        tristate
@@ -137,6 +146,5 @@ config BR2_PACKAGE_ASTERISK_MINI
            - pbx_config
            - res_features
            - res_musiconhold
-         
 
 endmenu
index e670774..4703154 100644 (file)
@@ -3,9 +3,9 @@
 include $(TOPDIR)/rules.mk
 
 PKG_NAME:=asterisk
-PKG_VERSION:=1.0.10
+PKG_VERSION:=1.2.1
 PKG_RELEASE:=1
-PKG_MD5SUM:=f60f4c4edc36fa61dc55a5385fd82e71
+PKG_MD5SUM:=04657086791e80f319c0d728af705001
 
 PKG_SOURCE_URL:=http://ftp.digium.com/pub/asterisk/ ftp://ftp.digium.com/pub/asterisk/
 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
@@ -19,6 +19,7 @@ $(eval $(call PKG_template,ASTERISK,asterisk,$(PKG_VERSION)-$(PKG_RELEASE),$(ARC
 $(eval $(call PKG_template,ASTERISK_MINI,asterisk-mini,$(PKG_VERSION)-$(PKG_RELEASE),$(ARCH)))
 $(eval $(call PKG_template,ASTERISK_MYSQL,asterisk-mysql,$(PKG_VERSION)-$(PKG_RELEASE),$(ARCH)))
 $(eval $(call PKG_template,ASTERISK_PGSQL,asterisk-pgsql,$(PKG_VERSION)-$(PKG_RELEASE),$(ARCH)))
+$(eval $(call PKG_template,ASTERISK_SQLITE,asterisk-sqlite,$(PKG_VERSION)-$(PKG_RELEASE),$(ARCH)))
 $(eval $(call PKG_template,ASTERISK_VOICEMAIL,asterisk-voicemail,$(PKG_VERSION)-$(PKG_RELEASE),$(ARCH)))
 $(eval $(call PKG_template,ASTERISK_SOUNDS,asterisk-sounds,$(PKG_VERSION)-$(PKG_RELEASE),$(ARCH)))
 $(eval $(call PKG_template,ASTERISK_CHAN_BLUETOOTH,asterisk-chan-bluetooth,$(PKG_VERSION)-$(PKG_RELEASE),$(ARCH)))
@@ -30,47 +31,53 @@ $(eval $(call PKG_template,ASTERISK_CODEC_SPEEX,asterisk-codec-speex,$(PKG_VERSI
 $(eval $(call PKG_template,ASTERISK_PBX_DUNDI,asterisk-pbx-dundi,$(PKG_VERSION)-$(PKG_RELEASE),$(ARCH)))
 $(eval $(call PKG_template,ASTERISK_RES_AGI,asterisk-res-agi,$(PKG_VERSION)-$(PKG_RELEASE),$(ARCH)))
 
-ifneq ($(DEVELOPER),)
-APPS:=app_sql_mysql.so app_sql_postgres.so
-MODS:=cdr_mysql.so cdr_pgsql.so
-SPEEX:=codec_speex.so
-else
-APPS:=
-MODS:=
+EXTRA_CFLAGS := -I$(STAGING_DIR)/usr/include -I$(STAGING_DIR)/include
+EXTRA_LDFLAGS := -L$(STAGING_DIR)/usr/lib -L$(STAGING_DIR)/lib
+
 ifneq ($(BR2_PACKAGE_ASTERISK_MYSQL),)
-APPS += app_sql_mysql.so
-MODS += cdr_mysql.so
+EXTRA_CFLAGS += -I$(STAGING_DIR)/usr/include/mysql
+EXTRA_LDFLAGS += -L$(STAGING_DIR)/usr/lib/mysql
+EXTRA_APP_MODULES += app_sql_mysql.so
+EXTRA_CDR_MODULES += cdr_mysql.so
+EXTRA_RES_MODULES += res_config_mysql.so
 endif
 ifneq ($(BR2_PACKAGE_ASTERISK_PGSQL),)
-APPS += app_sql_postgres.so
-MODS += cdr_pgsql.so
+EXTRA_APP_MODULES += app_sql_postgres.so
+EXTRA_CDR_MODULES += cdr_pgsql.so
 endif
-ifneq ($(BR2_PACKAGE_ASTERISK_CODEC_SPEEX),)
-SPEEX:=codec_speex.so
+ifneq ($(BR2_PACKAGE_ASTERISK_SQLITE),)
+EXTRA_CDR_MODULES += cdr_sqlite.so
 endif
+ifneq ($(BR2_PACKAGE_ASTERISK_CODEC_SPEEX),)
+EXTRA_CFLAGS += -I$(STAGING_DIR)/usr/include/speex
+EXTRA_CODEC_MODULES += codec_speex.so
 endif
 
 $(PKG_BUILD_DIR)/.configured:
        touch $@
 
 $(PKG_BUILD_DIR)/.built:
-       $(MAKE) -C "$(PKG_BUILD_DIR)/channels" \
-               CC="$(HOSTCC)" \
-               gentone 
        $(MAKE) -C "$(PKG_BUILD_DIR)" \
-               CC_FOR_BUILD="$(HOSTCC)" \
+               CROSS_ARCH="Linux" \
+               CROSS_COMPILE="$(TARGET_CROSS)" \
+               CROSS_COMPILE_BIN="/void/" \
+               CROSS_COMPILE_TARGET="/void/" \
                $(TARGET_CONFIGURE_OPTS) \
+               HOST_CC="$(HOSTCC)" \
                OPTIMIZE="$(TARGET_CFLAGS)" \
                PROC="$(ARCH)" \
-               CFLAGS_EXTRA="-I$(STAGING_DIR)/usr/include -I$(STAGING_DIR)/usr/include/speex" \
-               LDFLAGS_EXTRA="-L$(STAGING_DIR)/usr/lib -L$(STAGING_DIR)/usr/lib/mysql" \
-               CRYPTO_LIBS="-L$(STAGING_DIR)/usr/lib -Wl,-Bstatic -lssl -lcrypto -Wl,-Bdynamic" \
-               EXTRA_APPS="$(APPS)" \
-               EXTRA_MODS="$(MODS)" \
-               MODSPEEX="$(SPEEX)"
-       $(MAKE) -C $(PKG_BUILD_DIR) \
+               DEBUG="" \
+               OPTIONS="-DLOW_MEMORY -Dlinux" \
+               NOCRYPTO="yes" \
+               EXTRA_CFLAGS="$(EXTRA_CFLAGS)" \
+               EXTRA_LDFLAGS="$(EXTRA_LDFLAGS)" \
+               EXTRA_APP_MODULES="$(EXTRA_APP_MODULES)" \
+               EXTRA_CDR_MODULES="$(EXTRA_CDR_MODULES)" \
+               EXTRA_CODEC_MODULES="$(EXTRA_CODEC_MODULES)" \
+               EXTRA_RES_MODULES="$(EXTRA_RES_MODULES)" \
                DESTDIR="$(PKG_INSTALL_DIR)" \
-               install samples
+               ASTVARLIBDIR="/usr/lib/asterisk" \
+               all install samples
        rm -f $(PKG_INSTALL_DIR)/etc/asterisk/*.old
        touch $@
 
@@ -164,6 +171,12 @@ $(IPKG_ASTERISK_PGSQL):
        $(RSTRIP) $(IDIR_ASTERISK_PGSQL)
        $(IPKG_BUILD) $(IDIR_ASTERISK_PGSQL) $(PACKAGE_DIR)
 
+$(IPKG_ASTERISK_SQLITE):
+       install -d -m0755 $(IDIR_ASTERISK_SQLITE)/usr/lib/asterisk/modules
+       install -m0755 $(PKG_BUILD_DIR)/cdr/cdr_sqlite.so $(IDIR_ASTERISK_SQLITE)/usr/lib/asterisk/modules/
+       $(RSTRIP) $(IDIR_ASTERISK_SQLITE)
+       $(IPKG_BUILD) $(IDIR_ASTERISK_SQLITE) $(PACKAGE_DIR)
+
 $(IPKG_ASTERISK_SOUNDS):
        install -d -m0755 $(IDIR_ASTERISK_SOUNDS)/usr/lib/asterisk/sounds
        cp -fpR $(PKG_BUILD_DIR)/sounds/* $(IDIR_ASTERISK_SOUNDS)/usr/lib/asterisk/sounds/
index eeda73f..1d6f354 100644 (file)
@@ -7,12 +7,29 @@
 [modules]
 autoload=yes
 ;
+; Any modules that need to be loaded before the Asterisk core has been
+; initialized (just after the logger has been initialized) can be loaded
+; using 'preload'. This will frequently be needed if you wish to map all
+; module configuration files into Realtime storage, since the Realtime
+; driver will need to be loaded before the modules using those configuration
+; files are initialized.
+;
+; An example of loading ODBC support would be:
+;preload => res_odbc.so
+;preload => res_config_odbc.so
+;
+noload => res_config_mysql.so ; 
+;
 ; load => res_features.so ; Call Parking Resource 
 noload => res_indications.so ; Indications Configuration
 noload => res_monitor.so ; Call Monitoring Resource 
 ; load => res_musiconhold.so ; Music On Hold Resource 
 noload => cdr_csv.so ; Comma Separated Values CDR Backend
+noload => cdr_custom.so ; Customizable Comma Separated Values CDR Backend
 noload => cdr_manager.so ; Asterisk Call Manager CDR Backend
+noload => cdr_mysql.so ; MySQL CDR Backend
+noload => cdr_pgsql.so ; PostgreSQL CDR Backend
+noload => cdr_sqlite.so ; SQLite CDR Backend
 noload => chan_agent.so ; Agent Proxy Channel
 ; load => chan_iax2.so ; Inter Asterisk eXchange (Ver 2)
 ; load => chan_local.so ; Local Proxy Channel
@@ -21,8 +38,11 @@ noload => codec_a_mu.so ; A-law and Mulaw direct Coder/Decoder
 noload => codec_adpcm.so ; Adaptive Differential PCM Coder/Decoder
 noload => codec_alaw.so ; A-law Coder/Decoder
 noload => codec_g726.so ; ITU G.726-32kbps G726 Transcoder
-; load => codec_gsm.so ; GSM/PCM16 (signed linear) Codec Translat
+; load => codec_gsm.so ; GSM/PCM16 (signed linear) Codec Translation
 ; load => codec_ulaw.so ; Mu-law Coder/Decoder
+noload => codec_speex.so ; Speex/PCM16 (signed linear) Codec Translator
+noload => format_au.so ; Sun Microsystems AU format (signed linear)
+noload => format_g723.so ; G.723.1 Simple Timestamp File Format
 noload => format_g726.so ; Raw G.726 (16/24/32/40kbps) data
 noload => format_g729.so ; Raw G729 data
 ; load => format_gsm.so ; Raw GSM data
@@ -34,21 +54,26 @@ noload => format_sln.so ; Raw Signed Linear Audio support (SLN)
 noload => format_vox.so ; Dialogic VOX (ADPCM) File Format
 ; load => format_wav.so ; Microsoft WAV format (8000hz Signed Line
 ; load => format_wav_gsm.so ; Microsoft WAV format (Proprietary GSM)
-noload => app_alarmreceiver.so ; Alarm Receiver for Asterisk
+noload => app_alarmreceiver.so ; Alarm Receiver Application
 noload => app_authenticate.so ; Authentication Application
-noload => app_cdr.so ; Make sure asterisk doesn't save CDR for
+noload => app_cdr.so ; Make sure asterisk doesn't save CDR
 noload => app_chanisavail.so ; Check if channel is available
+noload => app_chanspy.so ; Listen in on any channel
 noload => app_controlplayback.so ; Control Playback Application
 noload => app_cut.so ; Cuts up variables
-noload => app_db.so ; Database access functions for Asterisk e
+noload => app_db.so ; Database access functions
 ; load => app_dial.so ; Dialing Application
+noload => app_dictate.so ; Virtual Dictation Machine Application
 noload => app_directory.so ; Extension Directory
-noload => app_disa.so ; DISA (Direct Inward System Access) Appli
+noload => app_directed_pickup.so ; Directed Call Pickup Support
+noload => app_disa.so ; DISA (Direct Inward System Access) Application
+noload => app_dumpchan.so ; Dump channel variables Application
 ; load => app_echo.so ; Simple Echo Application
 noload => app_enumlookup.so ; ENUM Lookup
 noload => app_eval.so ; Reevaluates strings
 noload => app_exec.so ; Executes applications
-noload => app_forkcdr.so ; Fork The CDR into 2 seperate entities.
+noload => app_externalivr.so ; External IVR application interface
+noload => app_forkcdr.so ; Fork The CDR into 2 seperate entities
 noload => app_getcpeid.so ; Get ADSI CPE ID
 noload => app_groupcount.so ; Group Management Routines
 noload => app_ices.so ; Encode and Stream via icecast and ices
@@ -56,14 +81,18 @@ noload => app_image.so ; Image Transmission Application
 noload => app_lookupblacklist.so ; Look up Caller*ID name/number from black
 noload => app_lookupcidname.so ; Look up CallerID Name from local databas
 ; load => app_macro.so ; Extension Macros
-; load => app_milliwatt.so ; Digital Milliwatt (mu-law) Test Applicat
+noload => app_math.so ; A simple math Application
+noload => app_md5.so ; MD5 checksum Application
+; load => app_milliwatt.so ; Digital Milliwatt (mu-law) Test Application
+noload => app_mixmonitor.so ; Record a call and mix the audio during the recording
 noload => app_parkandannounce.so ; Call Parking and Announce Application
 ; load => app_playback.so ; Trivial Playback Application
 noload => app_privacy.so ; Require phone number to be entered, if n
-noload => app_qcall.so ; Call from Queue
 noload => app_queue.so ; True Call Queueing
 noload => app_random.so ; Random goto
 noload => app_read.so ; Read Variable Application
+noload => app_readfile.so ; Read in a file
+noload => app_realtime.so ; Realtime Data Lookup/Rewrite
 noload => app_record.so ; Trivial Record Application
 ; load => app_sayunixtime.so ; Say time
 noload => app_senddtmf.so ; Send DTMF digits Application
@@ -72,10 +101,13 @@ noload => app_setcallerid.so ; Set CallerID Application
 noload => app_setcdruserfield.so ; CDR user field apps
 noload => app_setcidname.so ; Set CallerID Name
 noload => app_setcidnum.so ; Set CallerID Number
+noload => app_setrndis.so ; Set RDNIS Number
+noload => app_settransfercapability.so ; Set ISDN Transfer Capability
 noload => app_sms.so ; SMS/PSTN handler
 noload => app_softhangup.so ; Hangs up the requested channel
-noload => app_striplsd.so ; Strip trailing digits
-noload => app_substring.so ; (Deprecated) Save substring digits in a
+noload => app_sql_mysql.so ; Simple MySQL Interface
+noload => app_sql_postgres.so ; Simple PostgreSQL Interface
+noload => app_stack.so ; Stack Routines
 noload => app_system.so ; Generic System() application
 noload => app_talkdetect.so ; Playback with Talk Detection
 noload => app_test.so ; Interface Test Application
@@ -85,9 +117,18 @@ noload => app_url.so ; Send URL Applications
 noload => app_userevent.so ; Custom User Event Application
 ; load => app_verbose.so ; Send verbose output
 noload => app_waitforring.so ; Waits until first ring after time
+noload => app_waitforsilence.so ; Wait For Silence Application
+noload => app_while.so ; While Loops and Conditional Execution
+noload => pbx_ael.so ; Asterisk Extension Language Compiler
 ; load => pbx_config.so ; Text Extension Configuration
+noload => pbx_functions.so ; Builtin dialplan functions
+noload => pbx_loopback.so ; Loopback Switch
+noload => pbx_realtime.so ; Realtime Switch
 noload => pbx_spool.so ; Outgoing Spool Support
 noload => pbx_wilcalu.so ; Wil Cal U (Auto Dialer) 
+noload => func_callerid.so ; Caller ID related dialplan functions
+noload => func_enum.so ; ENUM Functions
+noload => func_uri.so ; URI encoding / decoding functions
 
 ;
 ; Module names listed in "global" section will have symbols globally
diff --git a/openwrt/package/asterisk/ipkg/asterisk-sqlite.control b/openwrt/package/asterisk/ipkg/asterisk-sqlite.control
new file mode 100644 (file)
index 0000000..e43651d
--- /dev/null
@@ -0,0 +1,5 @@
+Package: asterisk-sqlite
+Priority: optional
+Section: net
+Description: SQLite modules for Asterisk
+Depends: asterisk, libsqlite2
index db04961..5f805de 100644 (file)
@@ -2,6 +2,7 @@
 /etc/asterisk/agents.conf
 /etc/asterisk/alarmreceiver.conf
 /etc/asterisk/cdr_manager.conf
+/etc/asterisk/codecs.conf
 /etc/asterisk/enum.conf
 /etc/asterisk/extconfig.conf
 /etc/asterisk/extensions.conf
diff --git a/openwrt/package/asterisk/patches/asterisk-1.0.7-Makefile-apps.patch b/openwrt/package/asterisk/patches/asterisk-1.0.7-Makefile-apps.patch
deleted file mode 100644 (file)
index 9ac842e..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-diff -ruN asterisk-1.0.7-old/apps/Makefile asterisk-1.0.7-new/apps/Makefile
---- asterisk-1.0.7-old/apps/Makefile   2004-09-24 23:32:56.000000000 +0200
-+++ asterisk-1.0.7-new/apps/Makefile   2005-03-19 17:38:06.000000000 +0100
-@@ -35,13 +35,14 @@
- APPS+=app_intercom.so
- endif
--#APPS+=app_sql_postgres.so
-+# add extra apps
-+APPS+=$(EXTRA_APPS)
- #APPS+=app_sql_odbc.so
- #APPS+=app_rpt.so
--APPS+=$(shell if [ -f /usr/include/linux/zaptel.h ]; then echo "app_zapras.so app_meetme.so app_flash.so app_zapbarge.so app_zapscan.so" ; fi)
--APPS+=$(shell if [ -f /usr/local/include/zaptel.h ]; then echo "app_zapras.so app_meetme.so app_flash.so app_zapbarge.so app_zapscan.so" ; fi)
--APPS+=$(shell if [ -f /usr/include/osp/osp.h ]; then echo "app_osplookup.so" ; fi)
-+#APPS+=$(shell if [ -f /usr/include/linux/zaptel.h ]; then echo "app_zapras.so app_meetme.so app_flash.so app_zapbarge.so app_zapscan.so" ; fi)
-+#APPS+=$(shell if [ -f /usr/local/include/zaptel.h ]; then echo "app_zapras.so app_meetme.so app_flash.so app_zapbarge.so app_zapscan.so" ; fi)
-+#APPS+=$(shell if [ -f /usr/include/osp/osp.h ]; then echo "app_osplookup.so" ; fi)
- CFLAGS+=-fPIC
diff --git a/openwrt/package/asterisk/patches/asterisk-1.0.7-Makefile-cdr.patch b/openwrt/package/asterisk/patches/asterisk-1.0.7-Makefile-cdr.patch
deleted file mode 100644 (file)
index 3484b92..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-diff -ruN asterisk-1.0.7-old/cdr/Makefile asterisk-1.0.7-new/cdr/Makefile
---- asterisk-1.0.7-old/cdr/Makefile    2004-08-31 18:33:00.000000000 +0200
-+++ asterisk-1.0.7-new/cdr/Makefile    2005-03-19 17:38:06.000000000 +0100
-@@ -12,7 +12,7 @@
- #
- #ADD cdr_pgsql.so to MODS= to include PostgreSQL support: REQUIRES PostgreSQL libs
--MODS=cdr_csv.so cdr_manager.so
-+MODS=cdr_csv.so cdr_manager.so $(EXTRA_MODS)
- CFLAGS+=-fPIC
diff --git a/openwrt/package/asterisk/patches/asterisk-1.0.7-Makefile-channels-h323.patch b/openwrt/package/asterisk/patches/asterisk-1.0.7-Makefile-channels-h323.patch
deleted file mode 100644 (file)
index 8d89328..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-diff -ruN asterisk-1.0.7-old/channels/h323/Makefile asterisk-1.0.7-new/channels/h323/Makefile
---- asterisk-1.0.7-old/channels/h323/Makefile  2004-11-15 03:35:35.000000000 +0100
-+++ asterisk-1.0.7-new/channels/h323/Makefile  2005-03-19 17:38:06.000000000 +0100
-@@ -22,9 +22,11 @@
- OSARCH=$(shell uname -s)
- ifneq (${OSARCH},FreeBSD)
- ifneq (${OSARCH},NetBSD)
-+ifneq ($(PROC),mipsel)
- CFLAGS += -march=$(shell uname -m)
- endif
- endif
-+endif
- CFLAGS += -DPBYTE_ORDER=PLITTLE_ENDIAN
- ifeq (${OSARCH},Linux)
-@@ -47,7 +49,7 @@
- # Pre Janus release directives
- CFLAGS += -DNDEBUG -DDO_CRASH -DDEBUG_THREADS
--CFLAGS += -pipe -Wall -fPIC
-+CFLAGS += -pipe -Wall -fPIC $(OPTIMIZE)
- ifeq (${OSARCH},Linux)
- CFLAGS += -DP_LINUX
- LIBS+=-lpthread
-@@ -74,7 +76,7 @@
-  
- libchanh323.a:        ast_h323.o
--      ar cr libchanh323.a ast_h323.o
-+      $(AR) cr libchanh323.a ast_h323.o
- ast_h323.o:   ast_h323.cpp
-       $(CXX) -g -c -fno-rtti -o $@ $(CFLAGS) $<
diff --git a/openwrt/package/asterisk/patches/asterisk-1.0.7-Makefile-channels.patch b/openwrt/package/asterisk/patches/asterisk-1.0.7-Makefile-channels.patch
deleted file mode 100644 (file)
index d139510..0000000
+++ /dev/null
@@ -1,61 +0,0 @@
-diff -ruN asterisk-1.0.7-old/channels/Makefile asterisk-1.0.7-new/channels/Makefile
---- asterisk-1.0.7-old/channels/Makefile       2004-08-31 18:33:00.000000000 +0200
-+++ asterisk-1.0.7-new/channels/Makefile       2005-03-19 17:38:06.000000000 +0100
-@@ -71,25 +71,25 @@
- CHANNEL_LIBS+=chan_oss.so
- endif
--CHANNEL_LIBS+=$(shell [ -f /usr/include/linux/ixjuser.h ] && echo chan_phone.so)
--CHANNEL_LIBS+=$(shell [ -f /usr/local/include/ixjuser.h ] && echo chan_phone.so)
--CHANNEL_LIBS+=$(shell [ -f h323/libchanh323.a ] && echo chan_h323.so)
--
--CFLAGS+=-Wno-missing-prototypes -Wno-missing-declarations
--CFLAGS+=$(shell [ ! -f /usr/include/linux/if_wanpipe.h ] && echo " -DOLD_SANGOMA_API")
--CHANNEL_LIBS+=$(shell [ -f /usr/include/alsa/asoundlib.h ] && echo "chan_alsa.so")
--CFLAGS+=$(shell [ -f /usr/lib/libpri.so.1 ] && echo " -DZAPATA_PRI")
--CFLAGS+=$(shell [ -f /usr/lib/libmfcr2.so.1 ] && echo " -DZAPATA_R2")
--CFLAGS+=$(shell [ -f alsa-monitor.h ] && echo " -DALSA_MONITOR")
--ZAPPRI=$(shell [ -f /usr/lib/libpri.so.1 ] && echo "-lpri")
--ZAPR2=$(shell [ -f /usr/lib/libmfcr2.so.1 ] && echo "-lmfcr2")
--CFLAGS+=$(shell [ -f /usr/include/linux/zaptel.h ] && echo "-DIAX_TRUNKING")
--CFLAGS+=$(shell [ -f /usr/local/include/zaptel.h ] && echo "-DIAX_TRUNKING")
--CHANNEL_LIBS+=$(shell [ -f /usr/include/vpbapi.h ] && echo "chan_vpb.so" )
--CFLAGS+=$(shell [ -f /usr/include/vpbapi.h ] && echo " -DLINUX")
-+#CHANNEL_LIBS+=$(shell [ -f /usr/include/linux/ixjuser.h ] && echo chan_phone.so)
-+#CHANNEL_LIBS+=$(shell [ -f /usr/local/include/ixjuser.h ] && echo chan_phone.so)
-+#CHANNEL_LIBS+=$(shell [ -f h323/libchanh323.a ] && echo chan_h323.so)
-+
-+#CFLAGS+=-Wno-missing-prototypes -Wno-missing-declarations
-+#CFLAGS+=$(shell [ ! -f /usr/include/linux/if_wanpipe.h ] && echo " -DOLD_SANGOMA_API")
-+#CHANNEL_LIBS+=$(shell [ -f /usr/include/alsa/asoundlib.h ] && echo "chan_alsa.so")
-+#CFLAGS+=$(shell [ -f /usr/lib/libpri.so.1 ] && echo " -DZAPATA_PRI")
-+#CFLAGS+=$(shell [ -f /usr/lib/libmfcr2.so.1 ] && echo " -DZAPATA_R2")
-+#CFLAGS+=$(shell [ -f alsa-monitor.h ] && echo " -DALSA_MONITOR")
-+#ZAPPRI=$(shell [ -f /usr/lib/libpri.so.1 ] && echo "-lpri")
-+#ZAPR2=$(shell [ -f /usr/lib/libmfcr2.so.1 ] && echo "-lmfcr2")
-+#CFLAGS+=$(shell [ -f /usr/include/linux/zaptel.h ] && echo "-DIAX_TRUNKING")
-+#CFLAGS+=$(shell [ -f /usr/local/include/zaptel.h ] && echo "-DIAX_TRUNKING")
-+#CHANNEL_LIBS+=$(shell [ -f /usr/include/vpbapi.h ] && echo "chan_vpb.so" )
-+#CFLAGS+=$(shell [ -f /usr/include/vpbapi.h ] && echo " -DLINUX")
--ALSA_SRC=chan_alsa.c
--ALSA_SRC+=$(shell [ -f alsa-monitor.h ] && echo "alsa-monitor.h")
-+#ALSA_SRC=chan_alsa.c
-+#ALSA_SRC+=$(shell [ -f alsa-monitor.h ] && echo "alsa-monitor.h")
- CFLAGS+=-DCRYPTO
- CFLAGS+=-fPIC
-@@ -106,10 +106,10 @@
- ZAPDIR=/usr/lib
--CHANNEL_LIBS+=$(shell [ -f /usr/include/linux/zaptel.h ] && echo "chan_zap.so")
--CHANNEL_LIBS+=$(shell [ -f /usr/local/include/zaptel.h ] && echo "chan_zap.so")
-+#CHANNEL_LIBS+=$(shell [ -f /usr/include/linux/zaptel.h ] && echo "chan_zap.so")
-+#CHANNEL_LIBS+=$(shell [ -f /usr/local/include/zaptel.h ] && echo "chan_zap.so")
--CHANNEL_LIBS+=$(shell [ -f /usr/include/nbs.h ] && echo "chan_nbs.so" )
-+#CHANNEL_LIBS+=$(shell [ -f /usr/include/nbs.h ] && echo "chan_nbs.so" )
- ifndef OPENH323DIR
- OPENH323DIR=$(HOME)/openh323
diff --git a/openwrt/package/asterisk/patches/asterisk-1.0.7-Makefile-codecs-ilbc.patch b/openwrt/package/asterisk/patches/asterisk-1.0.7-Makefile-codecs-ilbc.patch
deleted file mode 100644 (file)
index 2d2fd3d..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-diff -ruN asterisk-1.0.7-old/codecs/ilbc/Makefile asterisk-1.0.7-new/codecs/ilbc/Makefile
---- asterisk-1.0.7-old/codecs/ilbc/Makefile    2004-08-29 19:40:58.000000000 +0200
-+++ asterisk-1.0.7-new/codecs/ilbc/Makefile    2005-03-19 17:38:06.000000000 +0100
-@@ -1,5 +1,5 @@
- ARCH=$(PROC)
--CFLAGS+=-Wall -fPIC -O3 -funroll-loops -fomit-frame-pointer
-+CFLAGS+=-Wall -fPIC $(OPTIMIZE)
- LIB=libilbc.a
- OBJS= anaFilter.o iCBSearch.o packing.o \
-@@ -12,8 +12,8 @@
- $(LIB): $(OBJS)
--      ar cr $(LIB) $(OBJS)
--      ranlib $(LIB)
-+      $(AR) cr $(LIB) $(OBJS)
-+      $(RANLIB) $(LIB)
- clean:
-       rm -f $(LIB) *.o
diff --git a/openwrt/package/asterisk/patches/asterisk-1.0.7-Makefile-codecs.patch b/openwrt/package/asterisk/patches/asterisk-1.0.7-Makefile-codecs.patch
deleted file mode 100644 (file)
index 1a854a0..0000000
+++ /dev/null
@@ -1,69 +0,0 @@
-diff -ruN asterisk-1.0.7-old/codecs/Makefile asterisk-1.0.7-new/codecs/Makefile
---- asterisk-1.0.7-old/codecs/Makefile 2005-03-17 15:43:51.000000000 +0100
-+++ asterisk-1.0.7-new/codecs/Makefile 2005-03-22 23:26:20.000000000 +0100
-@@ -17,21 +17,21 @@
- # g723.1b)
- #
- #MODG723=codec_g723_1.so codec_g723_1b.so
--MODG723=$(shell [ -f g723.1/coder.c ] && echo "codec_g723_1.so")
--MODG723+=$(shell [ -f g723.1b/coder2.c ] && echo "codec_g723_1b.so")
--MODSPEEX=$(shell [ -f /usr/include/speex.h ] || [ -f /usr/include/speex/speex.h ] || [ -f /usr/local/include/speex.h ] || [ -f /usr/local/include/speex/speex.h ] && echo "codec_speex.so")
-+#MODG723=$(shell [ -f g723.1/coder.c ] && echo "codec_g723_1.so")
-+#MODG723+=$(shell [ -f g723.1b/coder2.c ] && echo "codec_g723_1b.so")
-+#MODSPEEX=$(shell [ -f /usr/include/speex.h ] || [ -f /usr/include/speex/speex.h ] || [ -f /usr/local/include/speex.h ] || [ -f /usr/local/include/speex/speex.h ] && echo "codec_speex.so")
- MODILBC=$(shell [ -f ilbc/iLBC_decode.h ] && echo "codec_ilbc.so")
- CFLAGS+=-fPIC
--CFLAGS+=$(shell [ -f /usr/local/include/speex.h ] && echo "-I/usr/local/include")
--CFLAGS+=$(shell [ -f /usr/local/include/speex/speex.h ] && echo "-I/usr/local/include/speex")
--CFLAGS+=$(shell [ -f /usr/include/speex/speex.h ] && echo "-I/usr/include/speex")
-+#CFLAGS+=$(shell [ -f /usr/local/include/speex.h ] && echo "-I/usr/local/include")
-+#CFLAGS+=$(shell [ -f /usr/local/include/speex/speex.h ] && echo "-I/usr/local/include/speex")
-+#CFLAGS+=$(shell [ -f /usr/include/speex/speex.h ] && echo "-I/usr/include/speex")
- LIBG723=g723.1/libg723.a
- LIBG723B=g723.1b/libg723b.a
- LIBGSM=gsm/lib/libgsm.a
- LIBGSMT=gsm/lib/libgsm.a
- LIBLPC10=lpc10/liblpc10.a
--LIBSPEEX=$(shell [ -f /usr/local/lib/libspeex.a ] && echo "-L/usr/local/lib")
-+LIBSPEEX=$(LDFLAGS_EXTRA)
- LIBSPEEX+=-lspeex -lm
- LIBILBC=ilbc/libilbc.a
-@@ -43,26 +43,26 @@
- clean:
-       rm -f *.so *.o .depend
--      ! [ -d g723.1 ] || $(MAKE) -C g723.1 clean
--      ! [ -d g723.1b ] || $(MAKE) -C g723.1b clean
--      $(MAKE) -C gsm clean
--      $(MAKE) -C lpc10 clean
--      $(MAKE) -C ilbc clean
-+      ! [ -d g723.1 ] || $(MAKE) PROC=$(PROC) -C g723.1 clean
-+      ! [ -d g723.1b ] || $(MAKE) PROC=$(PROC) -C g723.1b clean
-+      $(MAKE) PROC=$(PROC) -C gsm clean
-+      $(MAKE) PROC=$(PROC) -C lpc10 clean
-+      $(MAKE) PROC=$(PROC) -C ilbc clean
- $(LIBG723):
--      $(MAKE) -C g723.1 all
-+      $(MAKE) PROC=$(PROC) -C g723.1 all
- gsm/lib/libgsm.a:
--      $(MAKE) -C gsm lib/libgsm.a
-+      $(MAKE) PROC=$(PROC) -C gsm lib/libgsm.a
- $(LIBG723B):
--      $(MAKE) -C g723.1b all
-+      $(MAKE) PROC=$(PROC) -C g723.1b all
- $(LIBLPC10):
--      $(MAKE) -C lpc10 all
-+      $(MAKE) PROC=$(PROC) -C lpc10 all
- $(LIBILBC):
--      $(MAKE) -C ilbc all
-+      $(MAKE) PROC=$(PROC) -C ilbc all
- codec_ilbc.so: codec_ilbc.o $(LIBILBC)
-       $(CC) $(SOLINK) -o $@ $< $(LIBILBC)
diff --git a/openwrt/package/asterisk/patches/asterisk-1.0.7-Makefile-res.patch b/openwrt/package/asterisk/patches/asterisk-1.0.7-Makefile-res.patch
deleted file mode 100644 (file)
index 0cd4580..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-diff -ruN asterisk-1.0.7-old/res/Makefile asterisk-1.0.7-new/res/Makefile
---- asterisk-1.0.7-old/res/Makefile    2004-07-17 22:58:01.000000000 +0200
-+++ asterisk-1.0.7-new/res/Makefile    2005-03-19 17:58:17.000000000 +0100
-@@ -13,9 +13,9 @@
- MODS=res_adsi.so res_features.so res_crypto.so res_musiconhold.so res_indications.so res_monitor.so \
-      res_agi.so
--MODS+=$(shell if [ -f "/usr/include/odbcinst.h" ]; then echo "res_odbc.so res_config_odbc.so"; fi)
--MODS+=$(shell if [ -f "/usr/local/include/odbcinst.h" ]; then echo "res_odbc.so res_config_odbc.so"; fi)
--MODS+=$(shell if [ -f "/usr/include/osp/osp.h" ]; then echo "res_osp.so"; fi)
-+#MODS+=$(shell if [ -f "/usr/include/odbcinst.h" ]; then echo "res_odbc.so res_config_odbc.so"; fi)
-+#MODS+=$(shell if [ -f "/usr/local/include/odbcinst.h" ]; then echo "res_odbc.so res_config_odbc.so"; fi)
-+#MODS+=$(shell if [ -f "/usr/include/osp/osp.h" ]; then echo "res_osp.so"; fi)
- CRYPTO_LIBS=-lssl -lcrypto
diff --git a/openwrt/package/asterisk/patches/asterisk-1.0.7-Makefile.patch b/openwrt/package/asterisk/patches/asterisk-1.0.7-Makefile.patch
deleted file mode 100644 (file)
index 9c557f2..0000000
+++ /dev/null
@@ -1,121 +0,0 @@
-diff -ruN asterisk-1.0.7-old/Makefile asterisk-1.0.7-new/Makefile
---- asterisk-1.0.7-old/Makefile        2005-03-10 09:15:05.000000000 +0100
-+++ asterisk-1.0.7-new/Makefile        2005-03-19 17:38:06.000000000 +0100
-@@ -63,10 +63,10 @@
- #K6OPT  = -DK6OPT
- #Tell gcc to optimize the asterisk's code
--OPTIMIZE+=-O6
-+#OPTIMIZE+=-O6
- #Include debug symbols in the executables (-g) and profiling info (-pg)
--DEBUG=-g #-pg
-+#DEBUG=-g #-pg
- # If you are running a radio application, define RADIO_RELAX so that the DTMF
- # will be received more reliably
-@@ -74,7 +74,7 @@
- # If you don't have a lot of memory (e.g. embedded Asterisk), uncomment the
- # following to reduce the size of certain static buffers
--#OPTIONS += -DLOW_MEMORY
-+OPTIONS += -DLOW_MEMORY
- # Optional debugging parameters
- DEBUG_THREADS = #-DDEBUG_THREADS #-DDO_CRASH 
-@@ -112,7 +112,7 @@
- BUSYDETECT+= #-DBUSYDETECT_COMPARE_TONE_AND_SILENCE
- ASTLIBDIR=$(INSTALL_PREFIX)/usr/lib/asterisk
--ASTVARLIBDIR=$(INSTALL_PREFIX)/var/lib/asterisk
-+ASTVARLIBDIR=$(INSTALL_PREFIX)/usr/lib/asterisk
- ASTETCDIR=$(INSTALL_PREFIX)/etc/asterisk
- ASTSPOOLDIR=$(INSTALL_PREFIX)/var/spool/asterisk
- ASTLOGDIR=$(INSTALL_PREFIX)/var/log/asterisk
-@@ -128,7 +128,7 @@
- INCLUDE=-Iinclude -I../include
- CFLAGS=-pipe  -Wall -Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations $(DEBUG) $(INCLUDE) -D_REENTRANT -D_GNU_SOURCE #-DMAKE_VALGRIND_HAPPY
--CFLAGS+=$(OPTIMIZE)
-+CFLAGS+=$(OPTIMIZE) $(CFLAGS_EXTRA)
- ifneq ($(PROC),ultrasparc)
- CFLAGS+=$(shell if $(CC) -march=$(PROC) -S -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo "-march=$(PROC)"; fi)
-@@ -187,7 +187,7 @@
- CFLAGS+=# -fomit-frame-pointer 
- SUBDIRS=res channels pbx apps codecs formats agi cdr astman stdtime
- ifeq (${OSARCH},Linux)
--LIBS=-ldl -lpthread
-+LIBS=$(LDFLAGS_EXTRA) -ldl -lpthread
- endif
- LIBS+=-lncurses -lm
- ifeq (${OSARCH},Linux)
-@@ -205,7 +205,7 @@
- ifeq (${OSARCH},OpenBSD)
- LIBS=-lcrypto -lpthread -lm -lncurses
- endif
--LIBS+=-lssl
-+LIBS+=-Wl,-Bstatic -lssl -Wl,-Bdynamic
- OBJS=io.o sched.o logger.o frame.o loader.o config.o channel.o \
-       translate.o file.o say.o pbx.o cli.o md5.o term.o \
-       ulaw.o alaw.o callerid.o fskmodem.o image.o app.o \
-@@ -240,12 +240,12 @@
-       cd editline && unset CFLAGS LIBS && ./configure ; \
- editline/libedit.a: FORCE
--      cd editline && unset CFLAGS LIBS && test -f config.h || ./configure
--      $(MAKE) -C editline libedit.a
-+      cd editline && unset CFLAGS LIBS && test -f config.h || CFLAGS="$(OPTIMIZE) $(CFLAGS_EXTRA)" LDFLAGS="$(LDFLAGS_EXTRA)" ./configure
-+      $(MAKE) PROC=$(PROC) CFLAGS="$(OPTIMIZE)" -C editline libedit.a
- db1-ast/libdb1.a: FORCE
-       @if [ -d db1-ast ]; then \
--              $(MAKE) -C db1-ast libdb1.a ; \
-+              $(MAKE) PROC=$(PROC) OORG="$(OPTIMIZE)" -C db1-ast libdb1.a ; \
-       else \
-               echo "You need to do a cvs update -d not just cvs update"; \
-               exit 1; \
-@@ -289,7 +289,7 @@
- stdtime/libtime.a: FORCE
-       @if [ -d stdtime ]; then \
--              $(MAKE) -C stdtime libtime.a ; \
-+              $(MAKE) PROC=$(PROC) -C stdtime libtime.a ; \
-       else \
-               echo "You need to do a cvs update -d not just cvs update"; \
-               exit 1; \
-@@ -381,7 +381,7 @@
-       if [ ! -f $(DESTDIR)$(ASTSBINDIR)/safe_asterisk ]; then \
-               install -m 755 contrib/scripts/safe_asterisk $(DESTDIR)$(ASTSBINDIR)/ ;\
-       fi
--      for x in $(SUBDIRS); do $(MAKE) -C $$x install || exit 1 ; done
-+      for x in $(SUBDIRS); do $(MAKE) PROC=$(PROC) -C $$x install || exit 1 ; done
-       install -d $(DESTDIR)$(ASTHEADERDIR)
-       install -m 644 include/asterisk/*.h $(DESTDIR)$(ASTHEADERDIR)
-       rm -f $(DESTDIR)$(ASTVARLIBDIR)/sounds/vm
-@@ -519,8 +519,8 @@
- __rpm: _version
-       rm -rf /tmp/asterisk ; \
-       mkdir -p /tmp/asterisk/redhat/RPMS/i386 ; \
--      $(MAKE) DESTDIR=/tmp/asterisk install ; \
--      $(MAKE) DESTDIR=/tmp/asterisk samples ; \
-+      $(MAKE) PROC=$(PROC) DESTDIR=/tmp/asterisk install ; \
-+      $(MAKE) PROC=$(PROC) DESTDIR=/tmp/asterisk samples ; \
-       mkdir -p /tmp/asterisk/etc/rc.d/init.d ; \
-       cp -f redhat/asterisk /tmp/asterisk/etc/rc.d/init.d/ ; \
-       sed "s/^Version:.*/Version: $(RPMVERSION)/g" redhat/asterisk.spec > asterisk.spec ; \
-@@ -544,12 +544,12 @@
-       fi 
- dont-optimize:
--      $(MAKE) OPTIMIZE= K6OPT= install
-+      $(MAKE) PROC=$(PROC) OPTIMIZE= K6OPT= install
- valgrind: dont-optimize
- depend: .depend
--      for x in $(SUBDIRS); do $(MAKE) -C $$x depend || exit 1 ; done
-+      for x in $(SUBDIRS); do $(MAKE) PROC=$(PROC) -C $$x depend || exit 1 ; done
- .depend:
-       @if ! which mpg123 &>/dev/null ; then \
diff --git a/openwrt/package/asterisk/patches/asterisk-1.0.7-astdb-in-spool.patch b/openwrt/package/asterisk/patches/asterisk-1.0.7-astdb-in-spool.patch
deleted file mode 100644 (file)
index 13efe3b..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-diff -ruN asterisk-1.0.7-old/asterisk.h asterisk-1.0.7-new/asterisk.h
---- asterisk-1.0.7-old/asterisk.h      2004-09-07 17:02:53.000000000 +0200
-+++ asterisk-1.0.7-new/asterisk.h      2005-05-17 09:56:13.000000000 +0200
-@@ -27,7 +27,7 @@
- #define AST_LOG_DIR   ASTLOGDIR
- #define AST_AGI_DIR   ASTAGIDIR
- #define AST_KEY_DIR   ASTVARLIBDIR "/keys"
--#define AST_DB                ASTVARLIBDIR "/astdb"
-+#define AST_DB                ASTSPOOLDIR "/astdb"
- #define AST_TMP_DIR   ASTSPOOLDIR "/tmp"
- #define AST_CONFIG_FILE ASTCONFPATH
diff --git a/openwrt/package/asterisk/patches/asterisk-1.0.7-no-crypto.diff b/openwrt/package/asterisk/patches/asterisk-1.0.7-no-crypto.diff
deleted file mode 100644 (file)
index 8d17f5a..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-diff -urN asterisk-1.0.7-old/res/Makefile asterisk-1.0.7-new/res/Makefile
---- asterisk-1.0.7-old/res/Makefile    2005-04-25 20:53:11.000000000 +0200
-+++ asterisk-1.0.7-new/res/Makefile    2005-04-25 20:53:26.000000000 +0200
-@@ -11,7 +11,7 @@
- # the GNU General Public License
- #
--MODS=res_adsi.so res_features.so res_crypto.so res_musiconhold.so res_indications.so res_monitor.so \
-+MODS=res_adsi.so res_features.so res_musiconhold.so res_indications.so res_monitor.so \
-      res_agi.so
- #MODS+=$(shell if [ -f "/usr/include/odbcinst.h" ]; then echo "res_odbc.so res_config_odbc.so"; fi)
- #MODS+=$(shell if [ -f "/usr/local/include/odbcinst.h" ]; then echo "res_odbc.so res_config_odbc.so"; fi)
diff --git a/openwrt/package/asterisk/patches/asterisk-1.0.7-no-newt.diff b/openwrt/package/asterisk/patches/asterisk-1.0.7-no-newt.diff
deleted file mode 100644 (file)
index b1638b3..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-diff -urN asterisk-1.0.7-old/astman/Makefile asterisk-1.0.7-new/astman/Makefile
---- asterisk-1.0.7-old/astman/Makefile 2004-06-26 21:25:39.000000000 +0200
-+++ asterisk-1.0.7-new/astman/Makefile 2005-04-29 15:54:53.000000000 +0200
-@@ -8,7 +8,7 @@
- CFLAGS+=-I/usr/local/include -L/usr/local/lib
- endif
--TARGET=$(shell if [ -f /usr/include/newt.h ]; then echo "astman"; else if [ -f /usr/local/include/newt.h ]; then echo "astman"; else echo "none" ; fi ; fi)
-+TARGET=none
- all: depend $(TARGET)
- install:
diff --git a/openwrt/package/asterisk/patches/asterisk-1.0.7-no_gtk.patch b/openwrt/package/asterisk/patches/asterisk-1.0.7-no_gtk.patch
deleted file mode 100644 (file)
index 9b99e8d..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-diff -ruN asterisk-1.0.7-old/pbx/Makefile asterisk-1.0.7-new/pbx/Makefile
---- asterisk-1.0.7-old/pbx/Makefile    2003-10-26 19:50:49.000000000 +0100
-+++ asterisk-1.0.7-new/pbx/Makefile    2005-07-04 15:42:52.000000000 +0200
-@@ -16,13 +16,13 @@
- PBX_LIBS=pbx_config.so pbx_wilcalu.so pbx_spool.so     # pbx_gtkconsole.so pbx_kdeconsole.so
- # Add GTK console if appropriate
--PBX_LIBS+=$(shell gtk-config --cflags >/dev/null 2>/dev/null && echo "pbx_gtkconsole.so")
-+#PBX_LIBS+=$(shell gtk-config --cflags >/dev/null 2>/dev/null && echo "pbx_gtkconsole.so")
- # Add KDE Console if appropriate
- #PBX_LIBS+=$(shell [ "$$QTDIR" != "" ] && echo "pbx_kdeconsole.so")
--GTK_FLAGS=`gtk-config --cflags gthread`
--GTK_LIBS=`gtk-config --libs gthread`
-+#GTK_FLAGS=`gtk-config --cflags gthread`
-+#GTK_LIBS=`gtk-config --libs gthread`
- #CXX=egcs
- MOC=$(QTDIR)/bin/moc
- KDE_FLAGS=-I$(KDEDIR)/include -I$(KDEDIR)/include/kde -I$(QTDIR)/include
diff --git a/openwrt/package/asterisk/patches/asterisk-1.0.7-pbx_dundi.patch b/openwrt/package/asterisk/patches/asterisk-1.0.7-pbx_dundi.patch
deleted file mode 100644 (file)
index f8066ba..0000000
+++ /dev/null
@@ -1,6493 +0,0 @@
-diff -ruN asterisk-1.0.7-orig/channels/chan_iax2.c asterisk-1.0.7-pbx_dundi/channels/chan_iax2.c
---- asterisk-1.0.7-orig/channels/chan_iax2.c   2005-03-18 18:30:05.000000000 +0100
-+++ asterisk-1.0.7-pbx_dundi/channels/chan_iax2.c      2005-06-02 20:21:37.000000000 +0200
-@@ -197,6 +197,7 @@
- struct iax2_user {
-       char name[80];
-       char secret[80];
-+      char dbsecret[80];
-       int authmethods;
-       char accountcode[20];
-       char inkeys[80];                                /* Key(s) this user can use to authenticate to us */
-@@ -219,6 +220,7 @@
-       char name[80];
-       char username[80];              
-       char secret[80];
-+      char dbsecret[80];
-       char outkey[80];                /* What key we use to talk to this peer */
-       char context[AST_MAX_EXTENSION];        /* Default context (for transfer really) */
-       char regexten[AST_MAX_EXTENSION];       /* Extension to register (if regcontext is used) */
-@@ -2194,6 +2196,26 @@
-                               *notransfer=p->notransfer;
-                       if (usejitterbuf)
-                               *usejitterbuf=p->usejitterbuf;
-+                      if (secret) {
-+                              if (!ast_strlen_zero(p->dbsecret)) {
-+                                      char *family, *key=NULL;
-+                                      family = ast_strdupa(p->dbsecret);
-+                                      if (family) {
-+                                              key = strchr(family, '/');
-+                                              if (key) {
-+                                                      *key = '\0';
-+                                                      key++;
-+                                              }
-+                                      }
-+                                      if (!family || !key || ast_db_get(family, key, secret, seclen)) {
-+                                              ast_log(LOG_WARNING, "Unable to retrieve database password for family/key '%s'!\n", p->dbsecret);
-+                                              if (p->temponly)
-+                                                      free(p);
-+                                              p = NULL;
-+                                      }
-+                              } else
-+                                      strncpy(secret, p->secret, seclen); /* safe */
-+                      }
-               } else {
-                       if (p->temponly)
-                               free(p);
-@@ -3624,6 +3646,15 @@
-       return 0;
- }
-+static void free_context(struct iax2_context *con)
-+{
-+      struct iax2_context *conl;
-+      while(con) {
-+              conl = con;
-+              con = con->next;
-+              free(conl);
-+      }
-+}
- static int check_access(int callno, struct sockaddr_in *sin, struct iax_ies *ies)
- {
-@@ -3769,6 +3800,28 @@
-                       strncpy(iaxs[callno]->language, user->language, sizeof(iaxs[callno]->language)-1);
-               iaxs[callno]->notransfer = user->notransfer;
-               iaxs[callno]->usejitterbuf = user->usejitterbuf;
-+              /* Keep this check last */
-+              if (!ast_strlen_zero(user->dbsecret)) {
-+                      char *family, *key=NULL;
-+                      family = ast_strdupa(user->dbsecret);
-+                      if (family) {
-+                              key = strchr(family, '/');
-+                              if (key) {
-+                                      *key = '\0';
-+                                      key++;
-+                              }
-+                      }
-+                      if (!family || !key || ast_db_get(family, key, iaxs[callno]->secret, sizeof(iaxs[callno]->secret))) {
-+                              ast_log(LOG_WARNING, "Unable to retrieve database password for family/key '%s'!\n", user->dbsecret);
-+                              if (user->temponly) {
-+                                      ast_free_ha(user->ha);
-+                                      free_context(user->contexts);
-+                                      free(user);
-+                                      user = NULL;
-+                              }
-+                      }
-+              } else
-+                      strncpy(iaxs[callno]->secret, user->secret, sizeof(iaxs[callno]->secret) - 1);
-               res = 0;
-       }
-       iaxs[callno]->trunk = iax2_getpeertrunk(*sin);
-@@ -3844,15 +3897,23 @@
-       } else if (p->authmethods & IAX_AUTH_MD5) {
-               struct MD5Context md5;
-               unsigned char digest[16];
--              MD5Init(&md5);
--              MD5Update(&md5, p->challenge, strlen(p->challenge));
--              MD5Update(&md5, p->secret, strlen(p->secret));
--              MD5Final(digest, &md5);
--              /* If they support md5, authenticate with it.  */
--              for (x=0;x<16;x++)
--                      sprintf(requeststr + (x << 1), "%2.2x", digest[x]); /* safe */
--              if (!strcasecmp(requeststr, md5secret))
--                      res = 0;
-+              char *tmppw, *stringp;
-+              
-+              tmppw = ast_strdupa(p->secret);
-+              stringp = tmppw;
-+              while((tmppw = strsep(&stringp, ";"))) {
-+                      MD5Init(&md5);
-+                      MD5Update(&md5, p->challenge, strlen(p->challenge));
-+                      MD5Update(&md5, tmppw, strlen(tmppw));
-+                      MD5Final(digest, &md5);
-+                      /* If they support md5, authenticate with it.  */
-+                      for (x=0;x<16;x++)
-+                              sprintf(requeststr + (x << 1), "%2.2x", digest[x]); /* safe */
-+                      if (!strcasecmp(requeststr, md5secret)) {
-+                              res = 0;
-+                              break;
-+                      }
-+              }
-       } else if (p->authmethods & IAX_AUTH_PLAINTEXT) {
-               if (!strcmp(secret, p->secret))
-                       res = 0;
-@@ -6237,16 +6298,6 @@
-       return 0;
- }
--static void free_context(struct iax2_context *con)
--{
--      struct iax2_context *conl;
--      while(con) {
--              conl = con;
--              con = con->next;
--              free(conl);
--      }
--}
--
- static struct ast_channel *iax2_request(char *type, int format, void *data)
- {
-       int callno;
-@@ -6469,6 +6520,8 @@
-                               strncpy(peer->secret, v->value, sizeof(peer->secret)-1);
-                       else if (!strcasecmp(v->name, "mailbox"))
-                               strncpy(peer->mailbox, v->value, sizeof(peer->mailbox) - 1);
-+                      else if (!strcasecmp(v->name, "dbsecret"))
-+                              strncpy(peer->dbsecret, v->value, sizeof(peer->dbsecret)-1);
-                       else if (!strcasecmp(v->name, "mailboxdetail"))
-                               peer->messagedetail = ast_true(v->value);
-                       else if (!strcasecmp(v->name, "trunk")) {
-@@ -6665,6 +6718,8 @@
-                               user->notransfer = ast_true(v->value);
-                       } else if (!strcasecmp(v->name, "jitterbuffer")) {
-                               user->usejitterbuf = ast_true(v->value);
-+                      } else if (!strcasecmp(v->name, "dbsecret")) {
-+                              strncpy(user->dbsecret, v->value, sizeof(user->dbsecret)-1);
-                       } else if (!strcasecmp(v->name, "secret")) {
-                               strncpy(user->secret, v->value, sizeof(user->secret)-1);
-                       } else if (!strcasecmp(v->name, "callerid")) {
-diff -ruN asterisk-1.0.7-orig/configs/dundi.conf.sample asterisk-1.0.7-pbx_dundi/configs/dundi.conf.sample
---- asterisk-1.0.7-orig/configs/dundi.conf.sample      1970-01-01 01:00:00.000000000 +0100
-+++ asterisk-1.0.7-pbx_dundi/configs/dundi.conf.sample 2005-06-02 20:21:37.000000000 +0200
-@@ -0,0 +1,225 @@
-+;
-+; DUNDi configuration file
-+;
-+;
-+[general]
-+;
-+; The "general" section contains general parameters relating
-+; to the operation of the dundi client and server.
-+;
-+; The first part should be your complete contact information
-+; should someone else in your peer group need to contact you.
-+;
-+;department=Your Department
-+;organization=Your Company, Inc.
-+;locality=Your City
-+;stateprov=ST
-+;country=US
-+;email=your@email.com
-+;phone=+12565551212
-+;
-+;
-+; Specify bind address and port number.  Default is
-+; 4520
-+;
-+;bindaddr=0.0.0.0
-+;port=4520
-+;
-+; Our entity identifier (Should generally be the MAC address of the
-+; machine it's running on.  Defaults to the first eth address, but you
-+; can override it here, as long as you set it to the MAC of *something*
-+; you own!)
-+;
-+;entityid=00:07:E9:3B:76:60
-+;
-+; Define the max depth in which to search the DUNDi system (also max # of 
-+; seconds to wait for a reply)
-+;
-+ttl=32
-+;
-+; If we don't get ACK to our DPREQUEST within 2000ms, and autokill is set
-+; to yes, then we cancel the whole thing (that's enough time for one 
-+; retransmission only).  This is used to keep things from stalling for a long
-+; time for a host that is not available, but would be ill advised for bad 
-+; connections.  In addition to 'yes' or 'no' you can also specify a number
-+; of milliseconds.  See 'qualify' for individual peers to turn on for just
-+; a specific peer.
-+;
-+autokill=yes
-+;
-+; pbx_dundi creates a rotating key called "secret", under the family
-+; 'secretpath'.  The default family is dundi (resulting in 
-+; the key being held at dundi/secret).
-+;
-+;secretpath=dundi
-+;
-+; The 'storehistory' option (also changeable at runtime with
-+; 'dundi store history' and 'dundi no store history') will
-+; cause the DUNDi engine to keep track of the last several
-+; queries and the amount of time each query took to execute
-+; for the purpose of tracking slow nodes.  This option is
-+; off by default due to performance impacts.
-+;
-+;storehistory=yes
-+
-+[mappings]
-+;
-+; The "mappings" section maps DUNDi contexts
-+; to contexts on the local asterisk system.  Remember
-+; that numbers that are made available under the e164 
-+; DUNDi context are regulated by the DUNDi General Peering 
-+; Agreement (GPA) if you are a member of the DUNDi E.164
-+; Peering System.
-+;
-+; dundi_context => local_context,weight,tech,dest[,options]]
-+;
-+; dundi_context is the name of the context being requested
-+; within the DUNDi request
-+;
-+; local_context is the name of the context on the local system
-+; in which numbers can be looked up for which responses shall be given.
-+;
-+; tech is the technology to use (IAX, SIP, H323)
-+;
-+; dest is the destination to supply for reaching that number.  The
-+; following variables can be used in the destination string and will
-+; be automatically substituted:
-+; ${NUMBER}: The number being requested
-+; ${IPADDR}: The IP address to connect to
-+; ${SECRET}: The current rotating secret key to be used
-+;
-+; Further options may include:
-+;
-+; nounsolicited:  No unsolicited calls of any type permitted via this 
-+;                 route
-+; nocomunsolicit: No commercial unsolicited calls permitted via 
-+;                 this route
-+; residential:    This number is known to be a residence
-+; commercial:     This number is known to be a business
-+; mobile:         This number is known to be a mobile phone
-+; nocomunsolicit: No commercial unsolicited calls permitted via 
-+;                 this route
-+; nopartial:      Do not search for partial matches
-+;
-+; There *must* exist an entry in mappings for DUNDi to respond
-+; to any request, although it may be empty.
-+;
-+;e164 => dundi-e164-canonical,0,IAX2,dundi:${SECRET}@${IPADDR}/${NUMBER},nounsolicited,nocomunsolicit,nopartial
-+;e164 => dundi-e164-customers,100,IAX2,dundi:${SECRET}@${IPADDR}/${NUMBER},nounsolicited,nocomunsolicit,nopartial
-+;e164 => dundi-e164-via-pstn,400,IAX2,dundi:${SECRET}@${IPADDR}/${NUMBER},nounsolicited,nocomunsolicit,nopartial
-+
-+;digexten => default,0,IAX2,guest@lappy/${NUMBER}
-+;asdf =>
-+
-+
-+;
-+;
-+; The remaining sections represent the peers
-+; that we fundamentally trust.  The section name
-+; represents the name and optionally at a specific
-+; DUNDi context if you want the trust to be established
-+; for only a specific DUNDi context.
-+;
-+; inkey - What key they will be authenticating to us with
-+;
-+; outkey - What key we use to authenticate to them
-+;
-+; host - What their host is
-+;
-+; order - What search order to use.  May be 'primary', 'secondary', 
-+;         'tertiary' or 'quartiary'.  In large systems, it is beneficial
-+;         to only query one up-stream host in order to maximize caching
-+;         value.  Adding one with primary and one with secondary gives you
-+;         redundancy without sacraficing performance.
-+;
-+; include - Includes this peer when searching a particular context
-+;           for lookup (set "all" to perform all lookups with that
-+;           host.  This is also the context in which peers are permitted
-+;           to precache.
-+;
-+; noinclude - Disincludes this peer when searching a particular context
-+;             for lookup (set "all" to perform no lookups with that
-+;             host.
-+;
-+; permit - Permits this peer to search a given DUNDi context on
-+;          the local system.  Set "all" to permit this host to
-+;          lookup all contexts.  This is also a context for which
-+;          we will create/forward PRECACHE commands.
-+;
-+; deny -   Denies this peer to search a given DUNDi context on
-+;          the local system.  Set "all" to deny this host to
-+;          lookup all contexts.
-+;
-+; model - inbound, outbound, or symmetric for whether we receive 
-+;         requests only, transmit requests only, or do both.
-+;
-+; precache - Utilize/Permit precaching with this peer (to pre
-+;            cache means to provide an answer when no request
-+;            was made and is used so that machines with few
-+;            routes can push those routes up a to a higher level).
-+;            outgoing means we send precache routes to this peer,
-+;            incoming means we permit this peer to send us
-+;            precache routes.  symmetric means we do both.
-+;
-+; Note: You cannot mix symmetric/outbound model with symmetric/inbound
-+; precache, nor can you mix symmetric/inbound model with symmetric/outbound
-+; precache.
-+;
-+;
-+; The '*' peer is special and matches an unspecified entity
-+;
-+
-+;
-+; Sample Primary e164 DUNDi peer
-+;
-+[00:50:8B:F3:75:BB]
-+model = symmetric
-+host = 64.215.96.114
-+inkey = digium
-+outkey = misery
-+include = e164
-+permit = e164
-+qualify = yes
-+
-+;
-+; Sample Secondary e164 DUNDi peer
-+;
-+;[00:A0:C9:96:92:84]
-+;model = symmetric
-+;host = misery.digium.com
-+;inkey = misery
-+;outkey = ourkey
-+;include = e164
-+;permit = e164
-+;qualify = yes
-+;order = secondary
-+
-+;
-+; Sample "push mode" downstream host
-+;
-+;[00:0C:76:96:75:28]
-+;model = incoming
-+;host = dynamic
-+;precache = incoming
-+;inkey = littleguy
-+;outkey = ourkey
-+;include = e164       ; In this case used only for precaching
-+;permit = e164      
-+;qualify = yes
-+
-+;
-+; Sample "push mode" upstream host
-+;
-+;[00:07:E9:3B:76:60]
-+;model = outbound
-+;precache = outbound
-+;host = 216.207.245.34
-+;register = yes
-+;inkey = dhcp34
-+;permit = all ; In this case used only for precaching
-+;include = all 
-+;qualify = yes
-+;outkey=foo
-+
-+;[*]
-+;
-diff -ruN asterisk-1.0.7-orig/include/asterisk/dundi.h asterisk-1.0.7-pbx_dundi/include/asterisk/dundi.h
---- asterisk-1.0.7-orig/include/asterisk/dundi.h       1970-01-01 01:00:00.000000000 +0100
-+++ asterisk-1.0.7-pbx_dundi/include/asterisk/dundi.h  2005-06-02 20:21:37.000000000 +0200
-@@ -0,0 +1,212 @@
-+/*
-+ * Distributed Universal Number Discovery (DUNDi)
-+ *
-+ * Copyright (C) 2004, Digium Inc.
-+ *
-+ * Written by Mark Spencer <markster@digium.com>
-+ *
-+ * This program is Free Software distributed under the terms of
-+ * of the GNU General Public License.
-+ */
-+#ifndef _ASTERISK_DUNDI_H 
-+#define _ASTERISK_DUNDI_H
-+
-+#include <asterisk/channel.h>
-+
-+#define DUNDI_PORT 4520
-+
-+/* A DUNDi Entity ID is essentially a MAC address, brief and unique */
-+struct _dundi_eid {
-+      unsigned char eid[6];
-+} __attribute__ ((__packed__));
-+
-+typedef struct _dundi_eid dundi_eid;
-+
-+struct dundi_hdr {
-+      unsigned short strans;                  /* Source transaction */
-+      unsigned short dtrans;                  /* Destination transaction */
-+      unsigned char iseqno;                   /* Next expected incoming sequence number */
-+      unsigned char oseqno;                   /* Outgoing sequence number */
-+      unsigned char cmdresp;                  /* Command / Response */
-+      unsigned char cmdflags;                 /* Command / Response specific flags*/
-+      unsigned char ies[0];
-+} __attribute__ ((__packed__));
-+
-+struct dundi_ie_hdr {
-+      unsigned char ie;
-+      unsigned char len;
-+      unsigned char iedata[0];
-+} __attribute__ ((__packed__));
-+
-+#define DUNDI_FLAG_RETRANS                    (1 << 16)       /* Applies to dtrans */
-+#define DUNDI_FLAG_RESERVED                   (1 << 16)       /* Applies to strans */
-+
-+#define DUNDI_PROTO_NONE                      0       /* No answer yet */
-+#define DUNDI_PROTO_IAX                               1       /* IAX version 2 */
-+#define DUNDI_PROTO_SIP                               2       /* Session Initiation Protocol */
-+#define DUNDI_PROTO_H323                      3       /* ITU H.323 */
-+
-+#define DUNDI_FLAG_NONEXISTANT                (0)                             /* Isn't and can't be a valid number */
-+#define DUNDI_FLAG_EXISTS                     (1 << 0)                /* Is a valid number */
-+#define DUNDI_FLAG_MATCHMORE          (1 << 1)                /* Might be valid if you add more digits */
-+#define DUNDI_FLAG_CANMATCH                   (1 << 2)                /* Might be a match */
-+#define DUNDI_FLAG_IGNOREPAT          (1 << 3)                /* Keep dialtone */
-+#define DUNDI_FLAG_RESIDENTIAL                (1 << 4)                /* Destination known to be residential */
-+#define DUNDI_FLAG_COMMERCIAL         (1 << 5)                /* Destination known to be commercial */
-+#define DUNDI_FLAG_MOBILE                     (1 << 6)                /* Destination known to be cellular/mobile */
-+#define DUNDI_FLAG_NOUNSOLICITED      (1 << 7)                /* No unsolicited calls of any kind through this route */
-+#define DUNDI_FLAG_NOCOMUNSOLICIT     (1 << 8)                /* No commercial unsolicited calls through this route */
-+
-+#define DUNDI_HINT_NONE                               (0)
-+#define DUNDI_HINT_TTL_EXPIRED                (1 << 0)                /* TTL Expired */
-+#define DUNDI_HINT_DONT_ASK                   (1 << 1)                /* Don't ask for anything beginning with data */
-+#define DUNDI_HINT_UNAFFECTED         (1 << 2)                /* Answer not affected by entity list */
-+
-+struct dundi_encblock {                               /* AES-128 encrypted block */
-+      unsigned char iv[16];                   /* Initialization vector of random data */
-+      unsigned char encdata[0];               /* Encrypted / compressed data */
-+} __attribute__ ((__packed__));
-+
-+struct dundi_answer {
-+      dundi_eid eid;                                  /* Original source of answer */
-+      unsigned char protocol;                 /* Protocol (DUNDI_PROTO_*) */
-+      unsigned short flags;                   /* Flags relating to answer */
-+      unsigned short weight;                  /* Weight of answers */
-+      unsigned char data[0];                  /* Protocol specific URI */
-+} __attribute__ ((__packed__));
-+
-+struct dundi_hint {
-+      unsigned short flags;                   /* Flags relating to answer */
-+      unsigned char data[0];                  /* For data for hint */
-+} __attribute__ ((__packed__));
-+
-+#define DUNDI_CAUSE_SUCCESS                   0       /* Success */
-+#define DUNDI_CAUSE_GENERAL                   1       /* General unspecified failure */
-+#define DUNDI_CAUSE_DYNAMIC                   2       /* Requested entity is dynamic */
-+#define DUNDI_CAUSE_NOAUTH                    3       /* No or improper authorization */
-+#define DUNDI_CAUSE_DUPLICATE         4       /* Duplicate request */
-+#define DUNDI_CAUSE_TTL_EXPIRED               5       /* Expired TTL */
-+#define DUNDI_CAUSE_NEEDKEY                   6       /* Need new session key to decode */
-+#define DUNDI_CAUSE_BADENCRYPT                7       /* Badly encrypted data */
-+
-+struct dundi_cause {                  
-+      unsigned char causecode;                /* Numerical cause (DUNDI_CAUSE_*) */
-+      char desc[0];                                   /* Textual description */
-+} __attribute__ ((__packed__));
-+
-+struct dundi_peer_status {
-+      unsigned int flags;
-+      unsigned short netlag;
-+      unsigned short querylag;
-+      dundi_eid peereid;
-+} __attribute__ ((__packed__));
-+
-+#define DUNDI_PEER_PRIMARY                    (1 << 0)
-+#define DUNDI_PEER_SECONDARY          (1 << 1)
-+#define DUNDI_PEER_UNAVAILABLE                (1 << 2)
-+#define DUNDI_PEER_REGISTERED         (1 << 3)
-+#define DUNDI_PEER_MOD_OUTBOUND               (1 << 4)
-+#define DUNDI_PEER_MOD_INBOUND                (1 << 5)
-+#define DUNDI_PEER_PCMOD_OUTBOUND     (1 << 6)
-+#define DUNDI_PEER_PCMOD_INBOUND      (1 << 7)
-+
-+#define DUNDI_COMMAND_FINAL                   (0x80)          /* Or'd with other flags */
-+
-+#define DUNDI_COMMAND_ACK                     (0 | 0x40)      /* Ack a message */
-+#define DUNDI_COMMAND_DPDISCOVER      1                       /* Request discovery */
-+#define DUNDI_COMMAND_DPRESPONSE      (2 | 0x40)      /* Respond to a discovery request */
-+#define DUNDI_COMMAND_EIDQUERY                3                       /* Request information for a peer */
-+#define DUNDI_COMMAND_EIDRESPONSE     (4 | 0x40)      /* Response to a peer query */
-+#define DUNDI_COMMAND_PRECACHERQ      5                       /* Pre-cache Request */
-+#define DUNDI_COMMAND_PRECACHERP      (6 | 0x40)      /* Pre-cache Response */
-+#define DUNDI_COMMAND_INVALID         (7 | 0x40)      /* Invalid dialog state (does not require ack) */
-+#define DUNDI_COMMAND_UNKNOWN         (8 | 0x40)      /* Unknown command */
-+#define DUNDI_COMMAND_NULL                    9                       /* No-op */
-+#define DUNDI_COMMAND_REGREQ          (10)            /* Register Request */
-+#define DUNDI_COMMAND_REGRESPONSE     (11 | 0x40)     /* Register Response */
-+#define DUNDI_COMMAND_CANCEL          (12)            /* Cancel transaction entirely */
-+#define DUNDI_COMMAND_ENCRYPT         (13)            /* Send an encrypted message */
-+#define DUNDI_COMMAND_ENCREJ          (14 | 0x40)     /* Reject an encrypted message */
-+
-+#define DUNDI_COMMAND_STATUS          15                      /* Status command */
-+
-+/*
-+ * Remember that some information elements may occur
-+ * more than one time within a message
-+ */
-+
-+#define DUNDI_IE_EID                          1       /* Entity identifier (dundi_eid) */
-+#define DUNDI_IE_CALLED_CONTEXT               2       /* DUNDi Context (string) */
-+#define DUNDI_IE_CALLED_NUMBER                3       /* Number of equivalent (string) */
-+#define DUNDI_IE_EID_DIRECT                   4       /* Entity identifier (dundi_eid), direct connect */
-+#define DUNDI_IE_ANSWER                               5       /* An answer (struct dundi_answer) */
-+#define DUNDI_IE_TTL                          6       /* Max TTL for this request / Remaining TTL for the response  (short)*/
-+#define DUNDI_IE_VERSION                      10      /* DUNDi version (should be 1) (short) */
-+#define DUNDI_IE_EXPIRATION                   11      /* Recommended expiration (short) */
-+#define DUNDI_IE_UNKNOWN                      12      /* Unknown command (byte) */
-+#define DUNDI_IE_CAUSE                                14      /* Success or cause of failure */
-+#define DUNDI_IE_REQEID                               15      /* EID being requested for EIDQUERY*/
-+#define DUNDI_IE_ENCDATA                      16      /* AES-128 encrypted data */
-+#define DUNDI_IE_SHAREDKEY                    17      /* RSA encrypted AES-128 key */
-+#define DUNDI_IE_SIGNATURE                    18      /* RSA Signature of encrypted shared key */
-+#define DUNDI_IE_KEYCRC32                     19      /* CRC32 of encrypted key (int) */
-+#define DUNDI_IE_HINT                         20      /* Answer hints (struct ast_hint) */
-+
-+#define DUNDI_IE_DEPARTMENT                   21      /* Department, for EIDQUERY (string) */
-+#define DUNDI_IE_ORGANIZATION         22      /* Organization, for EIDQUERY (string) */
-+#define DUNDI_IE_LOCALITY                     23      /* City/Locality, for EIDQUERY (string) */
-+#define DUNDI_IE_STATE_PROV                   24      /* State/Province, for EIDQUERY (string) */
-+#define DUNDI_IE_COUNTRY                      25      /* Country, for EIDQUERY (string) */
-+#define DUNDI_IE_EMAIL                                26      /* E-mail addy, for EIDQUERY (string) */
-+#define DUNDI_IE_PHONE                                27      /* Contact Phone, for EIDQUERY (string) */
-+#define DUNDI_IE_IPADDR                               28      /* IP Address, for EIDQUERY (string) */
-+#define DUNDI_IE_CACHEBYPASS          29      /* Bypass cache (empty) */
-+
-+#define DUNDI_IE_PEERSTATUS                   30      /* Peer/peer status (struct dundi_peer_status) */
-+
-+#define DUNDI_FLUFF_TIME                      2000    /* Amount of time for answer */
-+#define DUNDI_TTL_TIME                                200             /* Incremental average time */
-+
-+#define DUNDI_DEFAULT_RETRANS         5
-+#define DUNDI_DEFAULT_RETRANS_TIMER   1000
-+#define DUNDI_DEFAULT_TTL                     120     /* In seconds/hops like TTL */
-+#define DUNDI_DEFAULT_VERSION         1
-+#define DUNDI_DEFAULT_CACHE_TIME      3600    /* In seconds */
-+#define DUNDI_DEFAULT_KEY_EXPIRE      3600    /* Life of shared key In seconds */
-+#define DUNDI_DEF_EMPTY_CACHE_TIME    60      /* In seconds, cache of empty answer */
-+#define DUNDI_WINDOW                          1       /* Max 1 message in window */
-+
-+#define DEFAULT_MAXMS                         2000
-+
-+struct dundi_result {
-+      int flags;
-+      int weight;
-+      int expiration;
-+      int techint;
-+      dundi_eid eid;
-+      char eid_str[20];
-+      char tech[10];
-+      char dest[256];
-+};
-+
-+struct dundi_entity_info {
-+      char country[80];
-+      char stateprov[80];
-+      char locality[80];
-+      char org[80];
-+      char orgunit[80];
-+      char email[80];
-+      char phone[80]; 
-+      char ipaddr[80];
-+};
-+
-+/* Lookup the given number in the given dundi context (or e164 if unspecified) using the given callerid (if specified) and return up to maxret results in the array specified.
-+   returns the number of results found or -1 on a hangup of teh channel. */
-+int dundi_lookup(struct dundi_result *result, int maxret, struct ast_channel *chan, const char *dcontext, const char *number, int nocache);
-+
-+/* Retrieve information on a specific EID */
-+int dundi_query_eid(struct dundi_entity_info *dei, const char *dcontext, dundi_eid eid);
-+
-+/* Pre-cache to push upstream peers */
-+int dundi_precache(const char *dcontext, const char *number);
-+#endif /* _ASTERISK_DUNDI_H */
-diff -ruN asterisk-1.0.7-orig/pbx/Makefile asterisk-1.0.7-pbx_dundi/pbx/Makefile
---- asterisk-1.0.7-orig/pbx/Makefile   2003-10-26 19:50:49.000000000 +0100
-+++ asterisk-1.0.7-pbx_dundi/pbx/Makefile      2005-06-02 20:21:37.000000000 +0200
-@@ -13,7 +13,7 @@
--PBX_LIBS=pbx_config.so pbx_wilcalu.so pbx_spool.so     # pbx_gtkconsole.so pbx_kdeconsole.so
-+PBX_LIBS=pbx_config.so pbx_wilcalu.so pbx_spool.so pbx_dundi.so # pbx_gtkconsole.so pbx_kdeconsole.so
- # Add GTK console if appropriate
- PBX_LIBS+=$(shell gtk-config --cflags >/dev/null 2>/dev/null && echo "pbx_gtkconsole.so")
-@@ -51,6 +51,9 @@
- pbx_kdeconsole.so: $(KDE_CONSOLE_OBJS)
-       $(CC) $(SOLINK) -o $@ $(KDE_CONSOLE_OBJS) $(KDE_LIBS)
-+pbx_dundi.so: dundi-parser.o pbx_dundi.o
-+      $(CC) $(SOLINK) -o $@ pbx_dundi.o dundi-parser.o $(LDFLAGS_EXTRA) -lz
-+
- %.moc : %.h
-       $(MOC) $< -o $@
-diff -ruN asterisk-1.0.7-orig/pbx/dundi-parser.c asterisk-1.0.7-pbx_dundi/pbx/dundi-parser.c
---- asterisk-1.0.7-orig/pbx/dundi-parser.c     1970-01-01 01:00:00.000000000 +0100
-+++ asterisk-1.0.7-pbx_dundi/pbx/dundi-parser.c        2005-06-02 20:21:37.000000000 +0200
-@@ -0,0 +1,813 @@
-+/*
-+ * Distributed Universal Number Discovery (DUNDi)
-+ *
-+ * Copyright (C) 2004, Digium Inc.
-+ *
-+ * Written by Mark Spencer <markster@digium.com>
-+ *
-+ * This program is Free Software distributed under the terms of
-+ * of the GNU General Public License.
-+ */
-+
-+#include <sys/types.h>
-+#include <sys/socket.h>
-+#include <string.h>
-+#include <netinet/in.h>
-+#include <asterisk/frame.h>
-+#include <asterisk/utils.h>
-+#include <arpa/inet.h>
-+#include <unistd.h>
-+#include <stdlib.h>
-+#include <stdio.h>
-+#include <asterisk/dundi.h>
-+#include "dundi-parser.h"
-+#include <asterisk/dundi.h>
-+
-+static void internaloutput(const char *str)
-+{
-+      fputs(str, stdout);
-+}
-+
-+static void internalerror(const char *str)
-+{
-+      fprintf(stderr, "WARNING: %s", str);
-+}
-+
-+static void (*outputf)(const char *str) = internaloutput;
-+static void (*errorf)(const char *str) = internalerror;
-+
-+char *dundi_eid_to_str(char *s, int maxlen, dundi_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:", eid->eid[x]);
-+                      s += 3;
-+              }
-+              sprintf(s, "%02x", eid->eid[5]);
-+      }
-+      return os;
-+}
-+
-+char *dundi_eid_to_str_short(char *s, int maxlen, dundi_eid *eid)
-+{
-+      int x;
-+      char *os = s;
-+      if (maxlen < 13) {
-+              if (s && (maxlen > 0))
-+                      *s = '\0';
-+      } else {
-+              for (x=0;x<6;x++) {
-+                      sprintf(s, "%02X", eid->eid[x]);
-+                      s += 2;
-+              }
-+      }
-+      return os;
-+}
-+
-+int dundi_str_to_eid(dundi_eid *eid, char *s)
-+{
-+      unsigned int eid_int[6];
-+      int x;
-+      if (sscanf(s, "%x:%x:%x:%x:%x:%x", &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 dundi_str_short_to_eid(dundi_eid *eid, 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 dundi_eid_zero(dundi_eid *eid)
-+{
-+      int x;
-+      for (x=0;x<sizeof(eid->eid) / sizeof(eid->eid[0]);x++)
-+              if (eid->eid[x]) return 0;
-+      return 1;
-+}
-+
-+int dundi_eid_cmp(dundi_eid *eid1, dundi_eid *eid2)
-+{
-+      return memcmp(eid1, eid2, sizeof(dundi_eid));
-+}
-+
-+static void dump_string(char *output, int maxlen, void *value, int len)
-+{
-+      maxlen--;
-+      if (maxlen > len)
-+              maxlen = len;
-+      strncpy(output,value, maxlen);
-+      output[maxlen] = '\0';
-+}
-+
-+static void dump_cbypass(char *output, int maxlen, void *value, int len)
-+{
-+      strncpy(output, "Bypass Caches", maxlen);
-+      output[maxlen] = '\0';
-+}
-+
-+static void dump_eid(char *output, int maxlen, void *value, int len)
-+{
-+      if (len == 6)
-+              dundi_eid_to_str(output, maxlen, (dundi_eid *)value);
-+      else
-+              snprintf(output, maxlen, "Invalid EID len %d", len);
-+}
-+
-+char *dundi_hint2str(char *buf, int bufsiz, int flags)
-+{
-+      strcpy(buf, "");
-+      buf[bufsiz-1] = '\0';
-+      if (flags & DUNDI_HINT_TTL_EXPIRED) {
-+              strncat(buf, "TTLEXPIRED|", bufsiz - strlen(buf) - 1);
-+      }
-+      if (flags & DUNDI_HINT_DONT_ASK) {
-+              strncat(buf, "DONTASK|", bufsiz - strlen(buf) - 1);
-+      }
-+      if (flags & DUNDI_HINT_UNAFFECTED) {
-+              strncat(buf, "UNAFFECTED|", bufsiz - strlen(buf) - 1);
-+      }
-+      /* Get rid of trailing | */
-+      if (ast_strlen_zero(buf))
-+              strcpy(buf, "NONE|");
-+      buf[strlen(buf)-1] = '\0';
-+      return buf;
-+}
-+
-+static void dump_hint(char *output, int maxlen, void *value, int len)
-+{
-+      unsigned short flags;
-+      char tmp[512];
-+      char tmp2[256];
-+      if (len < 2) {
-+              strncpy(output, "<invalid contents>", maxlen);
-+              return;
-+      }
-+      memcpy(&flags, value, sizeof(flags));
-+      flags = ntohs(flags);
-+      memset(tmp, 0, sizeof(tmp));
-+      dundi_hint2str(tmp2, sizeof(tmp2), flags);
-+      snprintf(tmp, sizeof(tmp), "[%s] ", tmp2);
-+      memcpy(tmp + strlen(tmp), value + 2, len - 2);
-+      strncpy(output, tmp, maxlen - 1);
-+}
-+
-+static void dump_cause(char *output, int maxlen, void *value, int len)
-+{
-+      static char *causes[] = {
-+              "SUCCESS",
-+              "GENERAL",
-+              "DYNAMIC",
-+              "NOAUTH" ,
-+              };
-+      char tmp[256];
-+      char tmp2[256];
-+      int mlen;
-+      unsigned char cause;
-+      if (len < 1) {
-+              strncpy(output, "<invalid contents>", maxlen);
-+              return;
-+      }
-+      cause = *((unsigned char *)value);
-+      memset(tmp2, 0, sizeof(tmp2));
-+      mlen = len - 1;
-+      if (mlen > 255)
-+              mlen = 255;
-+      memcpy(tmp2, value + 1, mlen);
-+      if (cause < sizeof(causes) / sizeof(causes[0])) {
-+              if (len > 1)
-+                      snprintf(tmp, sizeof(tmp), "%s: %s", causes[cause], tmp2);
-+              else
-+                      snprintf(tmp, sizeof(tmp), "%s", causes[cause]);
-+      } else {
-+              if (len > 1)
-+                      snprintf(tmp, sizeof(tmp), "%d: %s", cause, tmp2);
-+              else
-+                      snprintf(tmp, sizeof(tmp), "%d", cause);
-+      }
-+      
-+      strncpy(output,tmp, maxlen);
-+      output[maxlen] = '\0';
-+}
-+
-+static void dump_int(char *output, int maxlen, void *value, int len)
-+{
-+      if (len == (int)sizeof(unsigned int))
-+              snprintf(output, maxlen, "%lu", (unsigned long)ntohl(*((unsigned int *)value)));
-+      else
-+              snprintf(output, maxlen, "Invalid INT");
-+}
-+
-+static void dump_short(char *output, int maxlen, void *value, int len)
-+{
-+      if (len == (int)sizeof(unsigned short))
-+              snprintf(output, maxlen, "%d", ntohs(*((unsigned short *)value)));
-+      else
-+              snprintf(output, maxlen, "Invalid SHORT");
-+}
-+
-+static void dump_byte(char *output, int maxlen, void *value, int len)
-+{
-+      if (len == (int)sizeof(unsigned char))
-+              snprintf(output, maxlen, "%d", *((unsigned char *)value));
-+      else
-+              snprintf(output, maxlen, "Invalid BYTE");
-+}
-+
-+static char *proto2str(int proto, char *buf, int bufsiz)
-+{     
-+      switch(proto) {
-+      case DUNDI_PROTO_NONE:
-+              strncpy(buf, "None", bufsiz - 1);
-+              break;
-+      case DUNDI_PROTO_IAX:
-+              strncpy(buf, "IAX", bufsiz - 1);
-+              break;
-+      case DUNDI_PROTO_SIP:
-+              strncpy(buf, "SIP", bufsiz - 1);
-+              break;
-+      case DUNDI_PROTO_H323:
-+              strncpy(buf, "H.323", bufsiz - 1);
-+              break;
-+      default:
-+              snprintf(buf, bufsiz, "Unknown Proto(%d)", proto);
-+      }
-+      buf[bufsiz-1] = '\0';
-+      return buf;
-+}
-+
-+char *dundi_flags2str(char *buf, int bufsiz, int flags)
-+{
-+      strcpy(buf, "");
-+      buf[bufsiz-1] = '\0';
-+      if (flags & DUNDI_FLAG_EXISTS) {
-+              strncat(buf, "EXISTS|", bufsiz - strlen(buf) - 1);
-+      }
-+      if (flags & DUNDI_FLAG_MATCHMORE) {
-+              strncat(buf, "MATCHMORE|", bufsiz - strlen(buf) - 1);
-+      }
-+      if (flags & DUNDI_FLAG_CANMATCH) {
-+              strncat(buf, "CANMATCH|", bufsiz - strlen(buf) - 1);
-+      }
-+      if (flags & DUNDI_FLAG_IGNOREPAT) {
-+              strncat(buf, "IGNOREPAT|", bufsiz - strlen(buf) - 1);
-+      }
-+      if (flags & DUNDI_FLAG_RESIDENTIAL) {
-+              strncat(buf, "RESIDENCE|", bufsiz - strlen(buf) - 1);
-+      }
-+      if (flags & DUNDI_FLAG_COMMERCIAL) {
-+              strncat(buf, "COMMERCIAL|", bufsiz - strlen(buf) - 1);
-+      }
-+      if (flags & DUNDI_FLAG_MOBILE) {
-+              strncat(buf, "MOBILE", bufsiz - strlen(buf) - 1);
-+      }
-+      if (flags & DUNDI_FLAG_NOUNSOLICITED) {
-+              strncat(buf, "NOUNSLCTD|", bufsiz - strlen(buf) - 1);
-+      }
-+      if (flags & DUNDI_FLAG_NOCOMUNSOLICIT) {
-+              strncat(buf, "NOCOMUNSLTD|", bufsiz - strlen(buf) - 1);
-+      }
-+      /* Get rid of trailing | */
-+      if (ast_strlen_zero(buf))
-+              strcpy(buf, "NONE|");
-+      buf[strlen(buf)-1] = '\0';
-+      return buf;
-+}
-+
-+static void dump_answer(char *output, int maxlen, void *value, int len)
-+{
-+      struct dundi_answer *answer;
-+      char proto[40];
-+      char flags[40];
-+      char eid_str[40];
-+      char tmp[512]="";
-+      if (len >= 10) {
-+              answer = (struct dundi_answer *)(value);
-+              memcpy(tmp, answer->data, (len >= 500) ? 500 : len - 10);
-+              dundi_eid_to_str(eid_str, sizeof(eid_str), &answer->eid);
-+              snprintf(output, maxlen, "[%s] %d <%s/%s> from [%s]", 
-+                      dundi_flags2str(flags, sizeof(flags), ntohs(answer->flags)), 
-+                      ntohs(answer->weight),
-+                      proto2str(answer->protocol, proto, sizeof(proto)), 
-+                              tmp, eid_str);
-+      } else
-+              strncpy(output, "Invalid Answer", maxlen - 1);
-+}
-+
-+static void dump_encrypted(char *output, int maxlen, void *value, int len)
-+{
-+      char iv[33];
-+      int x;
-+      if ((len > 16) && !(len % 16)) {
-+              /* Build up IV */
-+              for (x=0;x<16;x++) {
-+                      snprintf(iv + (x << 1), 3, "%02x", ((unsigned char *)value)[x]);
-+              }
-+              snprintf(output, maxlen, "[IV %s] %d encrypted blocks\n", iv, len / 16);
-+      } else
-+              snprintf(output, maxlen, "Invalid Encrypted Datalen %d", len);
-+}
-+
-+static void dump_raw(char *output, int maxlen, void *value, int len)
-+{
-+      int x;
-+      unsigned char *u = value;
-+      output[maxlen - 1] = '\0';
-+      strcpy(output, "[ ");
-+      for (x=0;x<len;x++) {
-+              snprintf(output + strlen(output), maxlen - strlen(output) - 1, "%02x ", u[x]);
-+      }
-+      strncat(output + strlen(output), "]", maxlen - strlen(output) - 1);
-+}
-+
-+static struct dundi_ie {
-+      int ie;
-+      char *name;
-+      void (*dump)(char *output, int maxlen, void *value, int len);
-+} ies[] = {
-+      { DUNDI_IE_EID, "ENTITY IDENT", dump_eid },
-+      { DUNDI_IE_CALLED_CONTEXT, "CALLED CONTEXT", dump_string },
-+      { DUNDI_IE_CALLED_NUMBER, "CALLED NUMBER", dump_string },
-+      { DUNDI_IE_EID_DIRECT, "DIRECT EID", dump_eid },
-+      { DUNDI_IE_ANSWER, "ANSWER", dump_answer },
-+      { DUNDI_IE_TTL, "TTL", dump_short },
-+      { DUNDI_IE_VERSION, "VERSION", dump_short },
-+      { DUNDI_IE_EXPIRATION, "EXPIRATION", dump_short },
-+      { DUNDI_IE_UNKNOWN, "UKWN DUNDI CMD", dump_byte },
-+      { DUNDI_IE_CAUSE, "CAUSE", dump_cause },
-+      { DUNDI_IE_REQEID, "REQUEST EID", dump_eid },
-+      { DUNDI_IE_ENCDATA, "ENCDATA", dump_encrypted },
-+      { DUNDI_IE_SHAREDKEY, "SHAREDKEY", dump_raw },
-+      { DUNDI_IE_SIGNATURE, "SIGNATURE", dump_raw },
-+      { DUNDI_IE_KEYCRC32, "KEYCRC32", dump_int },
-+      { DUNDI_IE_HINT, "HINT", dump_hint },
-+      { DUNDI_IE_DEPARTMENT, "DEPARTMENT", dump_string },
-+      { DUNDI_IE_ORGANIZATION, "ORGANIZTN", dump_string },
-+      { DUNDI_IE_LOCALITY, "LOCALITY", dump_string },
-+      { DUNDI_IE_STATE_PROV, "STATEPROV", dump_string },
-+      { DUNDI_IE_COUNTRY, "COUNTRY", dump_string },
-+      { DUNDI_IE_EMAIL, "EMAIL", dump_string },
-+      { DUNDI_IE_PHONE, "PHONE", dump_string },
-+      { DUNDI_IE_IPADDR, "ADDRESS", dump_string },
-+      { DUNDI_IE_CACHEBYPASS, "CBYPASS", dump_cbypass },
-+};
-+
-+const char *dundi_ie2str(int ie)
-+{
-+      int x;
-+      for (x=0;x<(int)sizeof(ies) / (int)sizeof(ies[0]); x++) {
-+              if (ies[x].ie == ie)
-+                      return ies[x].name;
-+      }
-+      return "Unknown IE";
-+}
-+
-+static void dump_ies(unsigned char *iedata, int spaces, int len)
-+{
-+      int ielen;
-+      int ie;
-+      int x;
-+      int found;
-+      char interp[1024];
-+      char tmp[1024];
-+      if (len < 2)
-+              return;
-+      while(len >= 2) {
-+              ie = iedata[0];
-+              ielen = iedata[1];
-+              /* Encrypted data is the remainder */
-+              if (ie == DUNDI_IE_ENCDATA)
-+                      ielen = len - 2;
-+              if (ielen + 2> len) {
-+                      snprintf(tmp, (int)sizeof(tmp), "Total IE length of %d bytes exceeds remaining frame length of %d bytes\n", ielen + 2, len);
-+                      outputf(tmp);
-+                      return;
-+              }
-+              found = 0;
-+              for (x=0;x<(int)sizeof(ies) / (int)sizeof(ies[0]); x++) {
-+                      if (ies[x].ie == ie) {
-+                              if (ies[x].dump) {
-+                                      ies[x].dump(interp, (int)sizeof(interp), iedata + 2, ielen);
-+                                      snprintf(tmp, (int)sizeof(tmp), "   %s%-15.15s : %s\n", (spaces ? "     " : "" ), ies[x].name, interp);
-+                                      outputf(tmp);
-+                              } else {
-+                                      if (ielen)
-+                                              snprintf(interp, (int)sizeof(interp), "%d bytes", ielen);
-+                                      else
-+                                              strcpy(interp, "Present");
-+                                      snprintf(tmp, (int)sizeof(tmp), "   %s%-15.15s : %s\n", (spaces ? "     " : "" ), ies[x].name, interp);
-+                                      outputf(tmp);
-+                              }
-+                              found++;
-+                      }
-+              }
-+              if (!found) {
-+                      snprintf(tmp, (int)sizeof(tmp), "   %sUnknown IE %03d  : Present\n", (spaces ? "     " : "" ), ie);
-+                      outputf(tmp);
-+              }
-+              iedata += (2 + ielen);
-+              len -= (2 + ielen);
-+      }
-+      outputf("\n");
-+}
-+
-+void dundi_showframe(struct dundi_hdr *fhi, int rx, struct sockaddr_in *sin, int datalen)
-+{
-+      char *pref[] = {
-+              "Tx",
-+              "Rx",
-+              "    ETx",
-+              "    Erx" };
-+      char *commands[] = {
-+              "ACK         ",
-+              "DPDISCOVER  ",
-+              "DPRESPONSE  ",
-+              "EIDQUERY    ",
-+              "EIDRESPONSE ",
-+              "PRECACHERQ  ",
-+              "PRECACHERP  ",
-+              "INVALID     ",
-+              "UNKNOWN CMD ",
-+              "NULL        ",
-+              "REQREQ      ",
-+              "REGRESPONSE ",
-+              "CANCEL      ",
-+              "ENCRYPT     ",
-+              "ENCREJ      " };
-+      char class2[20];
-+      char *class;
-+      char subclass2[20];
-+      char *subclass;
-+      char tmp[256];
-+      char retries[20];
-+      char iabuf[INET_ADDRSTRLEN];
-+      if (ntohs(fhi->dtrans) & DUNDI_FLAG_RETRANS)
-+              strcpy(retries, "Yes");
-+      else
-+              strcpy(retries, "No");
-+      if ((ntohs(fhi->strans) & DUNDI_FLAG_RESERVED)) {
-+              /* Ignore frames with high bit set to 1 */
-+              return;
-+      }
-+      if ((fhi->cmdresp & 0x3f) > (int)sizeof(commands)/(int)sizeof(char *)) {
-+              snprintf(class2, (int)sizeof(class2), "(%d?)", fhi->cmdresp);
-+              class = class2;
-+      } else {
-+              class = commands[(int)(fhi->cmdresp & 0x3f)];
-+      }
-+      snprintf(subclass2, (int)sizeof(subclass2), "%02x", fhi->cmdflags);
-+      subclass = subclass2;
-+      snprintf(tmp, (int)sizeof(tmp), 
-+              "%s-Frame Retry[%s] -- OSeqno: %3.3d ISeqno: %3.3d Type: %s (%s)\n",
-+              pref[rx],
-+              retries, fhi->oseqno, fhi->iseqno, class, fhi->cmdresp & 0x40 ? "Response" : "Command");
-+      outputf(tmp);
-+      snprintf(tmp, (int)sizeof(tmp), 
-+              "%s     Flags: %s STrans: %5.5d  DTrans: %5.5d [%s:%d]%s\n", (rx > 1) ? "     " : "",
-+              subclass, ntohs(fhi->strans) & ~DUNDI_FLAG_RESERVED, ntohs(fhi->dtrans) & ~DUNDI_FLAG_RETRANS,
-+              ast_inet_ntoa(iabuf, sizeof(iabuf), sin->sin_addr), ntohs(sin->sin_port),
-+              fhi->cmdresp & 0x80 ? " (Final)" : "");
-+      outputf(tmp);
-+      dump_ies(fhi->ies, rx > 1, datalen);
-+}
-+
-+int dundi_ie_append_raw(struct dundi_ie_data *ied, unsigned char ie, void *data, int datalen)
-+{
-+      char tmp[256];
-+      if (datalen > ((int)sizeof(ied->buf) - ied->pos)) {
-+              snprintf(tmp, (int)sizeof(tmp), "Out of space for ie '%s' (%d), need %d have %d\n", dundi_ie2str(ie), ie, datalen, (int)sizeof(ied->buf) - ied->pos);
-+              errorf(tmp);
-+              return -1;
-+      }
-+      ied->buf[ied->pos++] = ie;
-+      ied->buf[ied->pos++] = datalen;
-+      memcpy(ied->buf + ied->pos, data, datalen);
-+      ied->pos += datalen;
-+      return 0;
-+}
-+
-+int dundi_ie_append_cause(struct dundi_ie_data *ied, unsigned char ie, unsigned char cause, unsigned char *data)
-+{
-+      char tmp[256];
-+      int datalen = data ? strlen(data) + 1 : 1;
-+      if (datalen > ((int)sizeof(ied->buf) - ied->pos)) {
-+              snprintf(tmp, (int)sizeof(tmp), "Out of space for ie '%s' (%d), need %d have %d\n", dundi_ie2str(ie), ie, datalen, (int)sizeof(ied->buf) - ied->pos);
-+              errorf(tmp);
-+              return -1;
-+      }
-+      ied->buf[ied->pos++] = ie;
-+      ied->buf[ied->pos++] = datalen;
-+      ied->buf[ied->pos++] = cause;
-+      memcpy(ied->buf + ied->pos, data, datalen-1);
-+      ied->pos += datalen-1;
-+      return 0;
-+}
-+
-+int dundi_ie_append_hint(struct dundi_ie_data *ied, unsigned char ie, unsigned short flags, unsigned char *data)
-+{
-+      char tmp[256];
-+      int datalen = data ? strlen(data) + 2 : 2;
-+      if (datalen > ((int)sizeof(ied->buf) - ied->pos)) {
-+              snprintf(tmp, (int)sizeof(tmp), "Out of space for ie '%s' (%d), need %d have %d\n", dundi_ie2str(ie), ie, datalen, (int)sizeof(ied->buf) - ied->pos);
-+              errorf(tmp);
-+              return -1;
-+      }
-+      ied->buf[ied->pos++] = ie;
-+      ied->buf[ied->pos++] = datalen;
-+      flags = htons(flags);
-+      memcpy(ied->buf + ied->pos, &flags, sizeof(flags));
-+      ied->pos += 2;
-+      memcpy(ied->buf + ied->pos, data, datalen-1);
-+      ied->pos += datalen-2;
-+      return 0;
-+}
-+
-+int dundi_ie_append_encdata(struct dundi_ie_data *ied, unsigned char ie, unsigned char *iv, void *data, int datalen)
-+{
-+      char tmp[256];
-+      datalen += 16;
-+      if (datalen > ((int)sizeof(ied->buf) - ied->pos)) {
-+              snprintf(tmp, (int)sizeof(tmp), "Out of space for ie '%s' (%d), need %d have %d\n", dundi_ie2str(ie), ie, datalen, (int)sizeof(ied->buf) - ied->pos);
-+              errorf(tmp);
-+              return -1;
-+      }
-+      ied->buf[ied->pos++] = ie;
-+      ied->buf[ied->pos++] = datalen;
-+      memcpy(ied->buf + ied->pos, iv, 16);
-+      ied->pos += 16;
-+      if (data) {
-+              memcpy(ied->buf + ied->pos, data, datalen-16);
-+              ied->pos += datalen-16;
-+      }
-+      return 0;
-+}
-+
-+int dundi_ie_append_answer(struct dundi_ie_data *ied, unsigned char ie, dundi_eid *eid, unsigned char protocol, unsigned short flags, unsigned short weight, unsigned char *data)
-+{
-+      char tmp[256];
-+      int datalen = data ? strlen(data) + 11 : 11;
-+      int x;
-+      unsigned short myw;
-+      if (datalen > ((int)sizeof(ied->buf) - ied->pos)) {
-+              snprintf(tmp, (int)sizeof(tmp), "Out of space for ie '%s' (%d), need %d have %d\n", dundi_ie2str(ie), ie, datalen, (int)sizeof(ied->buf) - ied->pos);
-+              errorf(tmp);
-+              return -1;
-+      }
-+      ied->buf[ied->pos++] = ie;
-+      ied->buf[ied->pos++] = datalen;
-+      for (x=0;x<6;x++)
-+              ied->buf[ied->pos++] = eid->eid[x];
-+      ied->buf[ied->pos++] = protocol;
-+      myw = htons(flags);
-+      memcpy(ied->buf + ied->pos, &myw, 2);
-+      ied->pos += 2;
-+      myw = htons(weight);
-+      memcpy(ied->buf + ied->pos, &myw, 2);
-+      ied->pos += 2;
-+      memcpy(ied->buf + ied->pos, data, datalen-11);
-+      ied->pos += datalen-11;
-+      return 0;
-+}
-+
-+int dundi_ie_append_addr(struct dundi_ie_data *ied, unsigned char ie, struct sockaddr_in *sin)
-+{
-+      return dundi_ie_append_raw(ied, ie, sin, (int)sizeof(struct sockaddr_in));
-+}
-+
-+int dundi_ie_append_int(struct dundi_ie_data *ied, unsigned char ie, unsigned int value) 
-+{
-+      unsigned int newval;
-+      newval = htonl(value);
-+      return dundi_ie_append_raw(ied, ie, &newval, (int)sizeof(newval));
-+}
-+
-+int dundi_ie_append_short(struct dundi_ie_data *ied, unsigned char ie, unsigned short value) 
-+{
-+      unsigned short newval;
-+      newval = htons(value);
-+      return dundi_ie_append_raw(ied, ie, &newval, (int)sizeof(newval));
-+}
-+
-+int dundi_ie_append_str(struct dundi_ie_data *ied, unsigned char ie, unsigned char *str)
-+{
-+      return dundi_ie_append_raw(ied, ie, str, strlen(str));
-+}
-+
-+int dundi_ie_append_eid(struct dundi_ie_data *ied, unsigned char ie, dundi_eid *eid)
-+{
-+      return dundi_ie_append_raw(ied, ie, (unsigned char *)eid, sizeof(dundi_eid));
-+}
-+
-+int dundi_ie_append_byte(struct dundi_ie_data *ied, unsigned char ie, unsigned char dat)
-+{
-+      return dundi_ie_append_raw(ied, ie, &dat, 1);
-+}
-+
-+int dundi_ie_append(struct dundi_ie_data *ied, unsigned char ie) 
-+{
-+      return dundi_ie_append_raw(ied, ie, NULL, 0);
-+}
-+
-+void dundi_set_output(void (*func)(const char *))
-+{
-+      outputf = func;
-+}
-+
-+void dundi_set_error(void (*func)(const char *))
-+{
-+      errorf = func;
-+}
-+
-+int dundi_parse_ies(struct dundi_ies *ies, unsigned char *data, int datalen)
-+{
-+      /* Parse data into information elements */
-+      int len;
-+      int ie;
-+      char tmp[256];
-+      memset(ies, 0, (int)sizeof(struct dundi_ies));
-+      ies->ttl = -1;
-+      ies->expiration = -1;
-+      ies->unknowncmd = -1;
-+      ies->cause = -1;
-+      while(datalen >= 2) {
-+              ie = data[0];
-+              len = data[1];
-+              if (len > datalen - 2) {
-+                      errorf("Information element length exceeds message size\n");
-+                      return -1;
-+              }
-+              switch(ie) {
-+              case DUNDI_IE_EID:
-+              case DUNDI_IE_EID_DIRECT:
-+                      if (len != (int)sizeof(dundi_eid)) {
-+                              errorf("Improper entity identifer, expecting 6 bytes!\n");
-+                      } else if (ies->eidcount < DUNDI_MAX_STACK) {
-+                              ies->eids[ies->eidcount] = (dundi_eid *)(data + 2);
-+                              ies->eid_direct[ies->eidcount] = (ie == DUNDI_IE_EID_DIRECT);
-+                              ies->eidcount++;
-+                      } else
-+                              errorf("Too many entities in stack!\n");
-+                      break;
-+              case DUNDI_IE_REQEID:
-+                      if (len != (int)sizeof(dundi_eid)) {
-+                              errorf("Improper requested entity identifer, expecting 6 bytes!\n");
-+                      } else
-+                              ies->reqeid = (dundi_eid *)(data + 2);
-+                      break;
-+              case DUNDI_IE_CALLED_CONTEXT:
-+                      ies->called_context = data + 2;
-+                      break;
-+              case DUNDI_IE_CALLED_NUMBER:
-+                      ies->called_number = data + 2;
-+                      break;
-+              case DUNDI_IE_ANSWER:
-+                      if (len < sizeof(struct dundi_answer)) {
-+                              snprintf(tmp, (int)sizeof(tmp), "Answer expected to be >=%d bytes long but was %d\n", (int)sizeof(struct dundi_answer), len);
-+                              errorf(tmp);
-+                      } else {
-+                              if (ies->anscount < DUNDI_MAX_ANSWERS)
-+                                      ies->answers[ies->anscount++]= (struct dundi_answer *)(data + 2);
-+                              else 
-+                                      errorf("Ignoring extra answers!\n");
-+                      }
-+                      break;
-+              case DUNDI_IE_TTL:
-+                      if (len != (int)sizeof(unsigned short)) {
-+                              snprintf(tmp, (int)sizeof(tmp), "Expecting ttl to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
-+                              errorf(tmp);
-+                      } else
-+                              ies->ttl = ntohs(*((unsigned short *)(data + 2)));
-+                      break;
-+              case DUNDI_IE_VERSION:
-+                      if (len != (int)sizeof(unsigned short)) {
-+                              snprintf(tmp, (int)sizeof(tmp),  "Expecting version to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
-+                              errorf(tmp);
-+                      } else
-+                              ies->version = ntohs(*((unsigned short *)(data + 2)));
-+                      break;
-+              case DUNDI_IE_EXPIRATION:
-+                      if (len != (int)sizeof(unsigned short)) {
-+                              snprintf(tmp, (int)sizeof(tmp),  "Expecting expiration to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
-+                              errorf(tmp);
-+                      } else
-+                              ies->expiration = ntohs(*((unsigned short *)(data + 2)));
-+                      break;
-+              case DUNDI_IE_KEYCRC32:
-+                      if (len != (int)sizeof(unsigned int)) {
-+                              snprintf(tmp, (int)sizeof(tmp),  "Expecting expiration to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
-+                              errorf(tmp);
-+                      } else
-+                              ies->keycrc32 = ntohl(*((unsigned int *)(data + 2)));
-+                      break;
-+              case DUNDI_IE_UNKNOWN:
-+                      if (len == 1)
-+                              ies->unknowncmd = data[2];
-+                      else {
-+                              snprintf(tmp, (int)sizeof(tmp), "Expected single byte Unknown command, but was %d long\n", len);
-+                              errorf(tmp);
-+                      }
-+                      break;
-+              case DUNDI_IE_CAUSE:
-+                      if (len >= 1) {
-+                              ies->cause = data[2];
-+                              ies->causestr = data + 3;
-+                      } else {
-+                              snprintf(tmp, (int)sizeof(tmp), "Expected at least one byte cause, but was %d long\n", len);
-+                              errorf(tmp);
-+                      }
-+                      break;
-+              case DUNDI_IE_HINT:
-+                      if (len >= 2) {
-+                              ies->hint = (struct dundi_hint *)(data + 2);
-+                      } else {
-+                              snprintf(tmp, (int)sizeof(tmp), "Expected at least two byte hint, but was %d long\n", len);
-+                              errorf(tmp);
-+                      }
-+                      break;
-+              case DUNDI_IE_DEPARTMENT:
-+                      ies->q_dept = data + 2;
-+                      break;
-+              case DUNDI_IE_ORGANIZATION:
-+                      ies->q_org = data + 2;
-+                      break;
-+              case DUNDI_IE_LOCALITY:
-+                      ies->q_locality = data + 2;
-+                      break;
-+              case DUNDI_IE_STATE_PROV:
-+                      ies->q_stateprov = data + 2;
-+                      break;
-+              case DUNDI_IE_COUNTRY:
-+                      ies->q_country = data + 2;
-+                      break;
-+              case DUNDI_IE_EMAIL:
-+                      ies->q_email = data + 2;
-+                      break;
-+              case DUNDI_IE_PHONE:
-+                      ies->q_phone = data + 2;
-+                      break;
-+              case DUNDI_IE_IPADDR:
-+                      ies->q_ipaddr = data + 2;
-+                      break;
-+              case DUNDI_IE_ENCDATA:
-+                      /* Recalculate len as the remainder of the message, regardless of
-+                         theoretical length */
-+                      len = datalen - 2;
-+                      if ((len > 16) && !(len % 16)) {
-+                              ies->encblock = (struct dundi_encblock *)(data + 2);
-+                              ies->enclen = len - 16;
-+                      } else {
-+                              snprintf(tmp, (int)sizeof(tmp), "Invalid encrypted data length %d\n", len);
-+                              errorf(tmp);
-+                      }
-+                      break;
-+              case DUNDI_IE_SHAREDKEY:
-+                      if (len == 128) {
-+                              ies->encsharedkey = (unsigned char *)(data + 2);
-+                      } else {
-+                              snprintf(tmp, (int)sizeof(tmp), "Invalid encrypted shared key length %d\n", len);
-+                              errorf(tmp);
-+                      }
-+                      break;
-+              case DUNDI_IE_SIGNATURE:
-+                      if (len == 128) {
-+                              ies->encsig = (unsigned char *)(data + 2);
-+                      } else {
-+                              snprintf(tmp, (int)sizeof(tmp), "Invalid encrypted signature length %d\n", len);
-+                              errorf(tmp);
-+                      }
-+                      break;
-+              case DUNDI_IE_CACHEBYPASS:
-+                      ies->cbypass = 1;
-+                      break;
-+              default:
-+                      snprintf(tmp, (int)sizeof(tmp), "Ignoring unknown information element '%s' (%d) of length %d\n", dundi_ie2str(ie), ie, len);
-+                      outputf(tmp);
-+              }
-+              /* Overwrite information element with 0, to null terminate previous portion */
-+              data[0] = 0;
-+              datalen -= (len + 2);
-+              data += (len + 2);
-+      }
-+      /* Null-terminate last field */
-+      *data = '\0';
-+      if (datalen) {
-+              errorf("Invalid information element contents, strange boundary\n");
-+              return -1;
-+      }
-+      return 0;
-+}
-diff -ruN asterisk-1.0.7-orig/pbx/dundi-parser.h asterisk-1.0.7-pbx_dundi/pbx/dundi-parser.h
---- asterisk-1.0.7-orig/pbx/dundi-parser.h     1970-01-01 01:00:00.000000000 +0100
-+++ asterisk-1.0.7-pbx_dundi/pbx/dundi-parser.h        2005-06-02 20:21:37.000000000 +0200
-@@ -0,0 +1,88 @@
-+/*
-+ * Distributed Universal Number Discovery (DUNDi)
-+ *
-+ * Copyright (C) 2004, Digium Inc.
-+ *
-+ * Written by Mark Spencer <markster@digium.com>
-+ *
-+ * This program is Free Software distributed under the terms of
-+ * of the GNU General Public License.
-+ */
-+
-+#ifndef _DUNDI_PARSER_H
-+#define _DUNDI_PARSER_H
-+
-+#include <asterisk/dundi.h>
-+#include <asterisk/aes.h>
-+
-+#define DUNDI_MAX_STACK 512
-+#define DUNDI_MAX_ANSWERS     100
-+
-+struct dundi_ies {
-+      dundi_eid *eids[DUNDI_MAX_STACK + 1];
-+      int eid_direct[DUNDI_MAX_STACK + 1];
-+      dundi_eid *reqeid;
-+      int eidcount;
-+      char *called_context;
-+      char *called_number;
-+      struct dundi_answer *answers[DUNDI_MAX_ANSWERS + 1];
-+      struct dundi_hint *hint;
-+      int anscount;
-+      int ttl;
-+      int version;
-+      int expiration;
-+      int unknowncmd;
-+      unsigned char *pubkey;
-+      int cause;
-+      unsigned char *q_dept;
-+      unsigned char *q_org;
-+      unsigned char *q_locality;
-+      unsigned char *q_stateprov;
-+      unsigned char *q_country;
-+      unsigned char *q_email;
-+      unsigned char *q_phone;
-+      unsigned char *q_ipaddr;
-+      unsigned char *causestr;
-+      unsigned char *encsharedkey;
-+      unsigned char *encsig;
-+      unsigned long keycrc32;
-+      struct dundi_encblock *encblock;
-+      int enclen;
-+      int cbypass;
-+};
-+
-+struct dundi_ie_data {
-+      int pos;
-+      unsigned char buf[8192];
-+};
-+
-+/* Choose a different function for output */
-+extern void dundi_set_output(void (*output)(const char *data));
-+/* Choose a different function for errors */
-+extern void dundi_set_error(void (*output)(const char *data));
-+extern void dundi_showframe(struct dundi_hdr *fhi, int rx, struct sockaddr_in *sin, int datalen);
-+
-+extern const char *dundi_ie2str(int ie);
-+
-+extern int dundi_ie_append_raw(struct dundi_ie_data *ied, unsigned char ie, void *data, int datalen);
-+extern int dundi_ie_append_addr(struct dundi_ie_data *ied, unsigned char ie, struct sockaddr_in *sin);
-+extern int dundi_ie_append_int(struct dundi_ie_data *ied, unsigned char ie, unsigned int value);
-+extern int dundi_ie_append_short(struct dundi_ie_data *ied, unsigned char ie, unsigned short value);
-+extern int dundi_ie_append_str(struct dundi_ie_data *ied, unsigned char ie, unsigned char *str);
-+extern int dundi_ie_append_eid(struct dundi_ie_data *ied, unsigned char ie, dundi_eid *eid);
-+extern int dundi_ie_append_cause(struct dundi_ie_data *ied, unsigned char ie, unsigned char cause, unsigned char *desc);
-+extern int dundi_ie_append_hint(struct dundi_ie_data *ied, unsigned char ie, unsigned short flags, unsigned char *data);
-+extern int dundi_ie_append_answer(struct dundi_ie_data *ied, unsigned char ie, dundi_eid *eid, unsigned char protocol, unsigned short flags, unsigned short weight, unsigned char *desc);
-+extern int dundi_ie_append_encdata(struct dundi_ie_data *ied, unsigned char ie, unsigned char *iv, void *data, int datalen);
-+extern int dundi_ie_append_byte(struct dundi_ie_data *ied, unsigned char ie, unsigned char dat);
-+extern int dundi_ie_append(struct dundi_ie_data *ied, unsigned char ie);
-+extern int dundi_parse_ies(struct dundi_ies *ies, unsigned char *data, int datalen);
-+extern char *dundi_eid_to_str(char *s, int maxlen, dundi_eid *eid);
-+extern char *dundi_eid_to_str_short(char *s, int maxlen, dundi_eid *eid);
-+extern int dundi_str_to_eid(dundi_eid *eid, char *s);
-+extern int dundi_str_short_to_eid(dundi_eid *eid, char *s);
-+extern int dundi_eid_zero(dundi_eid *eid);
-+extern int dundi_eid_cmp(dundi_eid *eid1, dundi_eid *eid2);
-+extern char *dundi_flags2str(char *s, int maxlen, int flags);
-+extern char *dundi_hint2str(char *s, int maxlen, int flags);
-+#endif
-diff -ruN asterisk-1.0.7-orig/pbx/pbx_dundi.c asterisk-1.0.7-pbx_dundi/pbx/pbx_dundi.c
---- asterisk-1.0.7-orig/pbx/pbx_dundi.c        1970-01-01 01:00:00.000000000 +0100
-+++ asterisk-1.0.7-pbx_dundi/pbx/pbx_dundi.c   2005-06-02 20:21:37.000000000 +0200
-@@ -0,0 +1,4881 @@
-+/*
-+ * Distributed Universal Number Discovery (DUNDi)
-+ *
-+ * Copyright (C) 2004, Digium Inc.
-+ *
-+ * Written by Mark Spencer <markster@digium.com>
-+ *
-+ * This program is Free Software distributed under the terms of
-+ * of the GNU General Public License.
-+ */
-+
-+#include <asterisk/file.h>
-+#include <asterisk/logger.h>
-+#include <asterisk/channel.h>
-+#include <asterisk/config.h>
-+#include <asterisk/options.h>
-+#include <asterisk/pbx.h>
-+#include <asterisk/module.h>
-+#include <asterisk/frame.h>
-+#include <asterisk/file.h>
-+#include <asterisk/channel_pvt.h>
-+#include <asterisk/cli.h>
-+#include <asterisk/lock.h>
-+#include <asterisk/md5.h>
-+#include <asterisk/dundi.h>
-+#include <asterisk/sched.h>
-+#include <asterisk/io.h>
-+#include <asterisk/utils.h>
-+#include <asterisk/crypto.h>
-+#include <asterisk/astdb.h>
-+#include <asterisk/acl.h>
-+#include <asterisk/aes.h>
-+
-+#include "dundi-parser.h"
-+#include <stdlib.h>
-+#include <unistd.h>
-+#include <arpa/inet.h>
-+#include <netinet/in.h>
-+#include <sys/socket.h>
-+#include <string.h>
-+#include <errno.h>
-+#if defined(__FreeBSD__) || defined(__NetBSD__)
-+#include <sys/types.h>
-+#include <netinet/in_systm.h>
-+#endif
-+#include <netinet/ip.h>
-+#include <sys/ioctl.h>
-+#include <netinet/in.h>
-+#include <net/if.h>
-+#if defined(__FreeBSD__) || defined(__NetBSD__)
-+#include <net/if_dl.h>
-+#include <ifaddrs.h>
-+#endif
-+#include <zlib.h>
-+
-+#define MAX_RESULTS   64
-+
-+#define MAX_PACKET_SIZE 8192
-+
-+extern char ast_config_AST_KEY_DIR[];
-+
-+static char *tdesc = "Distributed Universal Number Discovery (DUNDi)";
-+
-+static char *app = "DUNDiLookup";
-+static char *synopsis = "Look up a number with DUNDi";
-+static char *descrip = 
-+"DUNDiLookup(number[|context[|options]])\n"
-+"      Looks up a given number in the global context specified or in\n"
-+"the reserved 'e164' context if not specified.  Returns -1 if the channel\n"
-+"is hungup during the lookup or 0 otherwise.  On completion, the variable\n"
-+"${DUNDTECH} and ${DUNDDEST} will contain the technology and destination\n"
-+"of the appropriate technology and destination to access the number. If no\n"
-+"answer was found, and the priority n + 101 exists, execution will continue\n"
-+"at that location.\n";
-+
-+#define DUNDI_MODEL_INBOUND           (1 << 0)
-+#define DUNDI_MODEL_OUTBOUND  (1 << 1)
-+#define DUNDI_MODEL_SYMMETRIC (DUNDI_MODEL_INBOUND | DUNDI_MODEL_OUTBOUND)
-+
-+/* Keep times of last 10 lookups */
-+#define DUNDI_TIMING_HISTORY  10
-+
-+#define FLAG_ISREG            (1 << 0)                /* Transaction is register request */
-+#define FLAG_DEAD             (1 << 1)                /* Transaction is dead */
-+#define FLAG_FINAL            (1 << 2)                /* Transaction has final message sent */
-+#define FLAG_ISQUAL           (1 << 3)                /* Transaction is a qualification */
-+#define FLAG_ENCRYPT  (1 << 4)                /* Transaction is encrypted wiht ECX/DCX */
-+#define FLAG_SENDFULLKEY      (1 << 5)                /* Send full key on transaction */
-+#define FLAG_STOREHIST        (1 << 6)                /* Record historic performance */
-+
-+#define DUNDI_FLAG_INTERNAL_NOPARTIAL (1 << 17)
-+
-+#if 0
-+#define DUNDI_SECRET_TIME 15  /* Testing only */
-+#else
-+#define DUNDI_SECRET_TIME DUNDI_DEFAULT_CACHE_TIME
-+#endif
-+
-+#define KEY_OUT                       0
-+#define KEY_IN                        1
-+
-+static struct io_context *io;
-+static struct sched_context *sched;
-+static int netsocket = -1;
-+static pthread_t netthreadid = AST_PTHREADT_NULL;
-+static pthread_t precachethreadid = AST_PTHREADT_NULL;
-+static int tos = 0;
-+static int dundidebug = 0;
-+static int authdebug = 0;
-+static int dundi_ttl = DUNDI_DEFAULT_TTL;
-+static int dundi_key_ttl = DUNDI_DEFAULT_KEY_EXPIRE;
-+static int global_autokilltimeout = 0;
-+static dundi_eid global_eid;
-+static int default_expiration = 60;
-+static int global_storehistory = 0;
-+static int map_update_interval = 0;
-+static int map_updates_per_pkt = 45;
-+static int map_peering_sid = -1;
-+static int map_contact_sid = -1;
-+static char map_context[80];
-+static struct sockaddr_in map_addr;
-+static char dept[80];
-+static char org[80];
-+static char locality[80];
-+static char stateprov[80];
-+static char country[80];
-+static char email[80];
-+static char phone[80];
-+static char secretpath[80];
-+static char cursecret[80];
-+static char ipaddr[80];
-+static time_t rotatetime;
-+static dundi_eid empty_eid = { { 0, 0, 0, 0, 0, 0 } };
-+struct permission {
-+      struct permission *next;
-+      int allow;
-+      char name[0];
-+};
-+
-+struct dundi_packet {
-+      struct dundi_hdr *h;
-+      struct dundi_packet *next;
-+      int datalen;
-+      struct dundi_transaction *parent;
-+      int retransid;
-+      int retrans;
-+      unsigned char data[0];
-+};
-+
-+struct dundi_hint_metadata {
-+      unsigned short flags;
-+      char exten[AST_MAX_EXTENSION];
-+};
-+
-+struct dundi_precache_queue {
-+      struct dundi_precache_queue *next;
-+      char *context;
-+      time_t expiration;
-+      char number[0];
-+};
-+
-+struct dundi_request;
-+
-+struct dundi_transaction {
-+      struct sockaddr_in addr;        /* Other end of transaction */
-+      struct timeval start;           /* When this transaction was created */
-+      dundi_eid eids[DUNDI_MAX_STACK + 1];
-+      int eidcount;                           /* Number of eids in eids */
-+      dundi_eid us_eid;                       /* Our EID, to them */
-+      dundi_eid them_eid;                     /* Their EID, to us */
-+      aes_encrypt_ctx ecx;            /* AES 128 Encryption context */
-+      aes_decrypt_ctx dcx;            /* AES 128 Decryption context */
-+      int flags;                                      /* Has final packet been sent */
-+      int ttl;                                        /* Remaining TTL for queries on this one */
-+      int thread;                                     /* We have a calling thread */
-+      int retranstimer;                       /* How long to wait before retransmissions */
-+      int autokillid;                         /* ID to kill connection if answer doesn't come back fast enough */
-+      int autokilltimeout;            /* Recommended timeout for autokill */
-+      unsigned short strans;          /* Our transaction identifier */
-+      unsigned short dtrans;          /* Their transaction identifer */
-+      unsigned char iseqno;           /* Next expected received seqno */
-+      unsigned char oiseqno;          /* Last received incoming seqno */
-+      unsigned char oseqno;           /* Next transmitted seqno */
-+      unsigned char aseqno;           /* Last acknowledge seqno */
-+      struct dundi_packet *packets;   /* Packets to be retransmitted */
-+      struct dundi_packet *lasttrans; /* Last transmitted / ACK'd packet */
-+      struct dundi_transaction *next; /* Next with respect to the parent */
-+      struct dundi_request *parent;   /* Parent request (if there is one) */
-+      struct dundi_transaction *allnext; /* Next with respect to all DUNDi transactions */
-+} *alltrans;
-+
-+struct dundi_request {
-+      char dcontext[AST_MAX_EXTENSION];
-+      char number[AST_MAX_EXTENSION];
-+      dundi_eid query_eid;
-+      dundi_eid root_eid;
-+      struct dundi_result *dr;
-+      struct dundi_entity_info *dei;
-+      struct dundi_hint_metadata *hmd;
-+      int maxcount;
-+      int respcount;
-+      int expiration;
-+      int cbypass;
-+      int pfds[2];
-+      unsigned long crc32;                                                    /* CRC-32 of all but root EID's in avoid list */
-+      struct dundi_transaction *trans;        /* Transactions */
-+      struct dundi_request *next;
-+} *requests;
-+
-+static struct dundi_mapping {
-+      char dcontext[AST_MAX_EXTENSION];
-+      char lcontext[AST_MAX_EXTENSION];
-+      int weight;
-+      int options;
-+      int tech;
-+      int dead;
-+      char dest[AST_MAX_EXTENSION];
-+      struct dundi_mapping *next;
-+} *mappings = NULL;
-+
-+static struct dundi_peer {
-+      dundi_eid eid;
-+      struct sockaddr_in addr;        /* Address of DUNDi peer */
-+      struct permission *permit;
-+      struct permission *include;
-+      struct permission *precachesend;
-+      struct permission *precachereceive;
-+      dundi_eid us_eid;
-+      char inkey[80];
-+      char outkey[80];
-+      int dead;
-+      int registerid;
-+      int qualifyid;
-+      int sentfullkey;
-+      int order;
-+      unsigned char txenckey[256]; /* Transmitted encrypted key + sig */
-+      unsigned char rxenckey[256]; /* Cache received encrypted key + sig */
-+      unsigned long us_keycrc32;      /* CRC-32 of our key */
-+      aes_encrypt_ctx us_ecx;         /* Cached AES 128 Encryption context */
-+      aes_decrypt_ctx us_dcx;         /* Cached AES 128 Decryption context */
-+      unsigned long them_keycrc32;/* CRC-32 of our key */
-+      aes_encrypt_ctx them_ecx;       /* Cached AES 128 Encryption context */
-+      aes_decrypt_ctx them_dcx;       /* Cached AES 128 Decryption context */
-+      time_t keyexpire;                       /* When to expire/recreate key */
-+      int registerexpire;
-+      int lookuptimes[DUNDI_TIMING_HISTORY];
-+      char *lookups[DUNDI_TIMING_HISTORY];
-+      int avgms;
-+      struct dundi_transaction *regtrans;     /* Registration transaction */
-+      struct dundi_transaction *qualtrans;    /* Qualify transaction */
-+      struct dundi_transaction *keypending;
-+      int model;                                      /* Pull model */
-+      int pcmodel;                            /* Push/precache model */
-+      int dynamic;                            /* Are we dynamic? */
-+      int lastms;                                     /* Last measured latency */
-+      int maxms;                                      /* Max permissible latency */
-+      struct timeval qualtx;          /* Time of transmit */
-+      struct dundi_peer *next;
-+} *peers;
-+
-+static struct dundi_precache_queue *pcq;
-+
-+AST_MUTEX_DEFINE_STATIC(peerlock);
-+AST_MUTEX_DEFINE_STATIC(pclock);
-+
-+static int dundi_xmit(struct dundi_packet *pack);
-+
-+static void dundi_debug_output(const char *data)
-+{
-+      if (dundidebug)
-+              ast_verbose("%s", data);
-+}
-+
-+static void dundi_error_output(const char *data)
-+{
-+      ast_log(LOG_WARNING, "%s", data);
-+}
-+
-+static int has_permission(struct permission *ps, char *cont)
-+{
-+      int res=0;
-+      while(ps) {
-+              if (!strcasecmp(ps->name, "all") || !strcasecmp(ps->name, cont))
-+                      res = ps->allow;
-+              ps = ps->next;
-+      }
-+      return res;
-+}
-+
-+static char *tech2str(int tech)
-+{
-+      switch(tech) {
-+      case DUNDI_PROTO_NONE:
-+              return "None";
-+      case DUNDI_PROTO_IAX:
-+              return "IAX2";
-+      case DUNDI_PROTO_SIP:
-+              return "SIP";
-+      case DUNDI_PROTO_H323:
-+              return "H323";
-+      default:
-+              return "Unknown";
-+      }
-+}
-+
-+static int str2tech(char *str)
-+{
-+      if (!strcasecmp(str, "IAX") || !strcasecmp(str, "IAX2")) 
-+              return DUNDI_PROTO_IAX;
-+      else if (!strcasecmp(str, "SIP"))
-+              return DUNDI_PROTO_SIP;
-+      else if (!strcasecmp(str, "H323"))
-+              return DUNDI_PROTO_H323;
-+      else
-+              return -1;
-+}
-+
-+static int dundi_lookup_internal(struct dundi_result *result, int maxret, struct ast_channel *chan, const char *dcontext, const char *number, int ttl, int blockempty, struct dundi_hint_metadata *md, int *expiration, int cybpass, int modeselect, dundi_eid *skip, dundi_eid *avoid[], int direct[]);
-+static int dundi_precache_internal(const char *context, const char *number, int ttl, dundi_eid *avoids[]);
-+static struct dundi_transaction *create_transaction(struct dundi_peer *p);
-+static struct dundi_transaction *find_transaction(struct dundi_hdr *hdr, struct sockaddr_in *sin)
-+{
-+      /* Look for an exact match first */
-+      struct dundi_transaction *trans;
-+      trans = alltrans;
-+      while(trans) {
-+              if (!inaddrcmp(&trans->addr, sin) && 
-+                   ((trans->strans == (ntohs(hdr->dtrans) & 32767)) /* Matches our destination */ ||
-+                        ((trans->dtrans == (ntohs(hdr->strans) & 32767)) && (!hdr->dtrans))) /* We match their destination */) {
-+                        if (hdr->strans)
-+                                trans->dtrans = ntohs(hdr->strans) & 32767;
-+                        break;
-+              }
-+              trans = trans->allnext;
-+      }
-+      if (!trans) {
-+              switch(hdr->cmdresp & 0x7f) {
-+              case DUNDI_COMMAND_DPDISCOVER:
-+              case DUNDI_COMMAND_EIDQUERY:
-+              case DUNDI_COMMAND_PRECACHERQ:
-+              case DUNDI_COMMAND_REGREQ:
-+              case DUNDI_COMMAND_NULL:
-+              case DUNDI_COMMAND_ENCRYPT:
-+                      if (hdr->strans) {      
-+                              /* Create new transaction */
-+                              trans = create_transaction(NULL);
-+                              if (trans) {
-+                                      memcpy(&trans->addr, sin, sizeof(trans->addr));
-+                                      trans->dtrans = ntohs(hdr->strans) & 32767;
-+                              } else
-+                                      ast_log(LOG_WARNING, "Out of memory!\n");
-+                      }
-+                      break;
-+              default:
-+                      break;
-+              }
-+      }
-+      return trans;
-+}
-+
-+static int dundi_send(struct dundi_transaction *trans, int cmdresp, int flags, int final, struct dundi_ie_data *ied);
-+
-+static int dundi_ack(struct dundi_transaction *trans, int final)
-+{
-+      return dundi_send(trans, DUNDI_COMMAND_ACK, 0, final, NULL);
-+}
-+static void dundi_reject(struct dundi_hdr *h, struct sockaddr_in *sin)
-+{
-+      struct {
-+              struct dundi_packet pack;
-+              struct dundi_hdr hdr;
-+      } tmp;
-+      struct dundi_transaction trans;
-+      /* Never respond to an INVALID with another INVALID */
-+      if (h->cmdresp == DUNDI_COMMAND_INVALID)
-+              return;
-+      memset(&tmp, 0, sizeof(tmp));
-+      memset(&trans, 0, sizeof(trans));
-+      memcpy(&trans.addr, sin, sizeof(trans.addr));
-+      tmp.hdr.strans = h->dtrans;
-+      tmp.hdr.dtrans = h->strans;
-+      tmp.hdr.iseqno = h->oseqno;
-+      tmp.hdr.oseqno = h->iseqno;
-+      tmp.hdr.cmdresp = DUNDI_COMMAND_INVALID;
-+      tmp.hdr.cmdflags = 0;
-+      tmp.pack.h = (struct dundi_hdr *)tmp.pack.data;
-+      tmp.pack.datalen = sizeof(struct dundi_hdr);
-+      tmp.pack.parent = &trans;
-+      dundi_xmit(&tmp.pack);
-+}
-+
-+static void reset_global_eid(void)
-+{
-+#if defined(SIOCGIFHWADDR)
-+      int x,s;
-+      char eid_str[20];
-+      struct ifreq ifr;
-+
-+      s = socket(AF_INET, SOCK_STREAM, 0);
-+      if (s > 0) {
-+              x = 0;
-+              for(x=0;x<10;x++) {
-+                      memset(&ifr, 0, sizeof(ifr));
-+                      snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "eth%d", x);
-+                      if (!ioctl(s, SIOCGIFHWADDR, &ifr)) {
-+                              memcpy(&global_eid, ((unsigned char *)&ifr.ifr_hwaddr) + 2, sizeof(global_eid));
-+                              ast_log(LOG_DEBUG, "Seeding global EID '%s' from '%s'\n", dundi_eid_to_str(eid_str, sizeof(eid_str), &global_eid), ifr.ifr_name);
-+                              return;
-+                      }
-+        }
-+      }
-+#else
-+#if defined(ifa_broadaddr)
-+      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) {
-+                              struct sockaddr_dl* sdp = (struct sockaddr_dl*) p->ifa_addr;
-+                              memcpy(
-+                                      &(global_eid.eid),
-+                                      sdp->sdl_data + sdp->sdl_nlen, 6);
-+                              ast_log(LOG_DEBUG, "Seeding global EID '%s' from '%s'\n", dundi_eid_to_str(eid_str, sizeof(eid_str), &global_eid), ifap->ifa_name);
-+                              freeifaddrs(ifap);
-+                              return;
-+                      }
-+              }
-+              freeifaddrs(ifap);
-+      }
-+#endif
-+#endif
-+      ast_log(LOG_NOTICE, "No ethernet interface found for seeding global EID  You will have to set it manually.\n");
-+}
-+
-+static int get_trans_id(void)
-+{
-+      struct dundi_transaction *t;
-+      int stid = (rand() % 32766) + 1;
-+      int tid = stid;
-+      do {
-+              t = alltrans;
-+              while(t) {
-+                      if (t->strans == tid) 
-+                              break;
-+                      t = t->allnext;
-+              }
-+              if (!t)
-+                      return tid;
-+              tid = (tid % 32766) + 1;
-+      } while (tid != stid);
-+      return 0;
-+}
-+
-+static int reset_transaction(struct dundi_transaction *trans)
-+{
-+      int tid;
-+      tid = get_trans_id();
-+      if (tid < 1)
-+              return -1;
-+      trans->strans = tid;
-+      trans->dtrans = 0;
-+      trans->iseqno = 0;
-+      trans->oiseqno = 0;
-+      trans->oseqno = 0;
-+      trans->aseqno = 0;
-+      trans->flags &= ~FLAG_FINAL;
-+      return 0;
-+}
-+
-+static struct dundi_peer *find_peer(dundi_eid *eid)
-+{
-+      struct dundi_peer *cur;
-+      if (!eid)
-+              eid = &empty_eid;
-+      cur = peers;
-+      while(cur) {
-+              if (!dundi_eid_cmp(&cur->eid,eid))
-+                      return cur;
-+              cur = cur->next;
-+      }
-+      return NULL;
-+}
-+
-+static void build_iv(unsigned char *iv)
-+{
-+      /* XXX Would be nice to be more random XXX */
-+      unsigned int *fluffy;
-+      int x;
-+      fluffy = (unsigned int *)(iv);
-+      for (x=0;x<4;x++)
-+              fluffy[x] = rand();
-+}
-+
-+struct dundi_query_state {
-+      dundi_eid *eids[DUNDI_MAX_STACK + 1]; 
-+      int directs[DUNDI_MAX_STACK + 1]; 
-+      dundi_eid reqeid;
-+      char called_context[AST_MAX_EXTENSION];
-+      char called_number[AST_MAX_EXTENSION];
-+      struct dundi_mapping *maps;
-+      int nummaps;
-+      int nocache;
-+      struct dundi_transaction *trans;
-+      void *chal;
-+      int challen;
-+      int ttl;
-+      char fluffy[0];
-+};
-+
-+static int dundi_lookup_local(struct dundi_result *dr, struct dundi_mapping *map, char *called_number, dundi_eid *us_eid, int anscnt, struct dundi_hint_metadata *hmd)
-+{
-+      int flags;
-+      int x;
-+      if (!ast_strlen_zero(map->lcontext)) {
-+              flags = 0;
-+              if (ast_exists_extension(NULL, map->lcontext, called_number, 1, NULL))
-+                      flags |= DUNDI_FLAG_EXISTS;
-+              if (ast_canmatch_extension(NULL, map->lcontext, called_number, 1, NULL))
-+                      flags |= DUNDI_FLAG_CANMATCH;
-+              if (ast_matchmore_extension(NULL, map->lcontext, called_number, 1, NULL))
-+                      flags |= DUNDI_FLAG_MATCHMORE;
-+              if (ast_ignore_pattern(map->lcontext, called_number))
-+                      flags |= DUNDI_FLAG_IGNOREPAT;
-+
-+              /* Clearly we can't say 'don't ask' anymore if we found anything... */
-+              if (flags) 
-+                      hmd->flags &= ~DUNDI_HINT_DONT_ASK;
-+
-+              if (map->options & DUNDI_FLAG_INTERNAL_NOPARTIAL) {
-+                      /* Skip partial answers */
-+                      flags &= ~(DUNDI_FLAG_MATCHMORE|DUNDI_FLAG_CANMATCH);
-+              }
-+              if (flags) {
-+                      struct varshead headp;
-+                      struct ast_var_t *newvariable;
-+                      flags |= map->options & 0xffff;
-+                      dr[anscnt].flags = flags;
-+                      dr[anscnt].techint = map->tech;
-+                      dr[anscnt].weight = map->weight;
-+                      dr[anscnt].expiration = DUNDI_DEFAULT_CACHE_TIME;
-+                      strncpy(dr[anscnt].tech, tech2str(map->tech), sizeof(dr[anscnt].tech));
-+                      dr[anscnt].eid = *us_eid;
-+                      dundi_eid_to_str(dr[anscnt].eid_str, sizeof(dr[anscnt].eid_str), &dr[anscnt].eid);
-+                      if (flags & DUNDI_FLAG_EXISTS) {
-+                              AST_LIST_HEAD_INIT(&headp);
-+                              newvariable = ast_var_assign("NUMBER", called_number);
-+                              AST_LIST_INSERT_HEAD(&headp, newvariable, entries);
-+                              newvariable = ast_var_assign("EID", dr[anscnt].eid_str);
-+                              AST_LIST_INSERT_HEAD(&headp, newvariable, entries);
-+                              newvariable = ast_var_assign("SECRET", cursecret);
-+                              AST_LIST_INSERT_HEAD(&headp, newvariable, entries);
-+                              newvariable = ast_var_assign("IPADDR", ipaddr);
-+                              AST_LIST_INSERT_HEAD(&headp, newvariable, entries);
-+                              pbx_substitute_variables_varshead(&headp, map->dest, dr[anscnt].dest, sizeof(dr[anscnt].dest));
-+                              while (!AST_LIST_EMPTY(&headp)) {           /* List Deletion. */
-+                                      newvariable = AST_LIST_FIRST(&headp);
-+                                      AST_LIST_REMOVE_HEAD(&headp, entries);
-+                                      ast_var_delete(newvariable);
-+                              }
-+                      } else
-+                              dr[anscnt].dest[0] = '\0';
-+                      anscnt++;
-+              } else {
-+                      /* No answers...  Find the fewest number of digits from the
-+                         number for which we have no answer. */
-+                      char tmp[AST_MAX_EXTENSION]="";
-+                      for (x=0;x<AST_MAX_EXTENSION;x++) {
-+                              tmp[x] = called_number[x];
-+                              if (!tmp[x])
-+                                      break;
-+                              if (!ast_canmatch_extension(NULL, map->lcontext, tmp, 1, NULL)) {
-+                                      /* Oops found something we can't match.  If this is longer
-+                                         than the running hint, we have to consider it */
-+                                      if (strlen(tmp) > strlen(hmd->exten)) {
-+                                              strncpy(hmd->exten, tmp, sizeof(hmd->exten) - 1);
-+                                      }
-+                                      break;
-+                              }
-+                      }
-+              }
-+      }
-+      return anscnt;
-+}
-+
-+static void destroy_trans(struct dundi_transaction *trans, int fromtimeout);
-+
-+static void *dundi_lookup_thread(void *data)
-+{
-+      struct dundi_query_state *st = data;
-+      struct dundi_result dr[MAX_RESULTS];
-+      struct dundi_ie_data ied;
-+      struct dundi_hint_metadata hmd;
-+      char eid_str[20];
-+      int res, x;
-+      int ouranswers=0;
-+      int max = 999999;
-+      int expiration = DUNDI_DEFAULT_CACHE_TIME;
-+
-+      ast_log(LOG_DEBUG, "Whee, looking up '%s@%s' for '%s'\n", st->called_number, st->called_context, 
-+              st->eids[0] ? dundi_eid_to_str(eid_str, sizeof(eid_str), st->eids[0]) :  "ourselves");
-+      memset(&ied, 0, sizeof(ied));
-+      memset(&dr, 0, sizeof(dr));
-+      memset(&hmd, 0, sizeof(hmd));
-+      /* Assume 'don't ask for anything' and 'unaffected', no TTL expired */
-+      hmd.flags = DUNDI_HINT_DONT_ASK | DUNDI_HINT_UNAFFECTED;
-+      for (x=0;x<st->nummaps;x++)
-+              ouranswers = dundi_lookup_local(dr, st->maps + x, st->called_number, &st->trans->us_eid, ouranswers, &hmd);
-+      if (ouranswers < 0)
-+              ouranswers = 0;
-+      for (x=0;x<ouranswers;x++) {
-+              if (dr[x].weight < max)
-+                      max = dr[x].weight;
-+      }
-+              
-+      if (max) {
-+              /* If we do not have a canonical result, keep looking */
-+              res = dundi_lookup_internal(dr + ouranswers, MAX_RESULTS - ouranswers, NULL, st->called_context, st->called_number, st->ttl, 1, &hmd, &expiration, st->nocache, 0, NULL, st->eids, st->directs);
-+              if (res > 0) {
-+                      /* Append answer in result */
-+                      ouranswers += res;
-+              } else {
-+                      if ((res < -1) && (!ouranswers))
-+                              dundi_ie_append_cause(&ied, DUNDI_IE_CAUSE, DUNDI_CAUSE_DUPLICATE, "Duplicate Request Pending");
-+              }
-+      }
-+      ast_mutex_lock(&peerlock);
-+      /* Truncate if "don't ask" isn't present */
-+      if (!(hmd.flags & DUNDI_HINT_DONT_ASK))
-+              hmd.exten[0] = '\0';
-+      if (st->trans->flags & FLAG_DEAD) {
-+              ast_log(LOG_DEBUG, "Our transaction went away!\n");
-+              st->trans->thread = 0;
-+              destroy_trans(st->trans, 0);
-+      } else {
-+              for (x=0;x<ouranswers;x++) {
-+                      /* Add answers */
-+                      if (dr[x].expiration && (expiration > dr[x].expiration))
-+                              expiration = dr[x].expiration;
-+                      dundi_ie_append_answer(&ied, DUNDI_IE_ANSWER, &dr[x].eid, dr[x].techint, dr[x].flags, dr[x].weight, dr[x].dest);
-+              }
-+              dundi_ie_append_hint(&ied, DUNDI_IE_HINT, hmd.flags, hmd.exten);
-+              dundi_ie_append_short(&ied, DUNDI_IE_EXPIRATION, expiration);
-+              dundi_send(st->trans, DUNDI_COMMAND_DPRESPONSE, 0, 1, &ied);
-+              st->trans->thread = 0;
-+      }
-+      ast_mutex_unlock(&peerlock);
-+      free(st);
-+      return NULL;    
-+}
-+
-+static void *dundi_precache_thread(void *data)
-+{
-+      struct dundi_query_state *st = data;
-+      struct dundi_ie_data ied;
-+      struct dundi_hint_metadata hmd;
-+      char eid_str[20];
-+
-+      ast_log(LOG_DEBUG, "Whee, precaching '%s@%s' for '%s'\n", st->called_number, st->called_context, 
-+              st->eids[0] ? dundi_eid_to_str(eid_str, sizeof(eid_str), st->eids[0]) :  "ourselves");
-+      memset(&ied, 0, sizeof(ied));
-+
-+      /* Now produce precache */
-+      dundi_precache_internal(st->called_context, st->called_number, st->ttl, st->eids);
-+
-+      ast_mutex_lock(&peerlock);
-+      /* Truncate if "don't ask" isn't present */
-+      if (!(hmd.flags & DUNDI_HINT_DONT_ASK))
-+              hmd.exten[0] = '\0';
-+      if (st->trans->flags & FLAG_DEAD) {
-+              ast_log(LOG_DEBUG, "Our transaction went away!\n");
-+              st->trans->thread = 0;
-+              destroy_trans(st->trans, 0);
-+      } else {
-+              dundi_send(st->trans, DUNDI_COMMAND_PRECACHERP, 0, 1, &ied);
-+              st->trans->thread = 0;
-+      }
-+      ast_mutex_unlock(&peerlock);
-+      free(st);
-+      return NULL;    
-+}
-+
-+static inline int calc_ms(struct timeval *start)
-+{
-+      struct timeval tv;
-+      gettimeofday(&tv, NULL);
-+      return ((tv.tv_sec - start->tv_sec) * 1000 + (tv.tv_usec - start->tv_usec) / 1000);
-+}
-+
-+static int dundi_query_eid_internal(struct dundi_entity_info *dei, const char *dcontext, dundi_eid *eid, struct dundi_hint_metadata *hmd, int ttl, int blockempty, dundi_eid *avoid[]);
-+
-+static void *dundi_query_thread(void *data)
-+{
-+      struct dundi_query_state *st = data;
-+      struct dundi_entity_info dei;
-+      struct dundi_ie_data ied;
-+      struct dundi_hint_metadata hmd;
-+      char eid_str[20];
-+      int res;
-+      ast_log(LOG_DEBUG, "Whee, looking up '%s@%s' for '%s'\n", st->called_number, st->called_context, 
-+              st->eids[0] ? dundi_eid_to_str(eid_str, sizeof(eid_str), st->eids[0]) :  "ourselves");
-+      memset(&ied, 0, sizeof(ied));
-+      memset(&dei, 0, sizeof(dei));
-+      memset(&hmd, 0, sizeof(hmd));
-+      if (!dundi_eid_cmp(&st->trans->us_eid, &st->reqeid)) {
-+              /* Ooh, it's us! */
-+              ast_log(LOG_DEBUG, "Neat, someone look for us!\n");
-+              strncpy(dei.orgunit, dept, sizeof(dei.orgunit));
-+              strncpy(dei.org, org, sizeof(dei.org));
-+              strncpy(dei.locality, locality, sizeof(dei.locality));
-+              strncpy(dei.stateprov, stateprov, sizeof(dei.stateprov));
-+              strncpy(dei.country, country, sizeof(dei.country));
-+              strncpy(dei.email, email, sizeof(dei.email));
-+              strncpy(dei.phone, phone, sizeof(dei.phone));
-+              res = 1;
-+      } else {
-+              /* If we do not have a canonical result, keep looking */
-+              res = dundi_query_eid_internal(&dei, st->called_context, &st->reqeid, &hmd, st->ttl, 1, st->eids);
-+      }
-+      ast_mutex_lock(&peerlock);
-+      if (st->trans->flags & FLAG_DEAD) {
-+              ast_log(LOG_DEBUG, "Our transaction went away!\n");
-+              st->trans->thread = 0;
-+              destroy_trans(st->trans, 0);
-+      } else {
-+              if (res) {
-+                      dundi_ie_append_str(&ied, DUNDI_IE_DEPARTMENT, dei.orgunit);
-+                      dundi_ie_append_str(&ied, DUNDI_IE_ORGANIZATION, dei.org);
-+                      dundi_ie_append_str(&ied, DUNDI_IE_LOCALITY, dei.locality);
-+                      dundi_ie_append_str(&ied, DUNDI_IE_STATE_PROV, dei.stateprov);
-+                      dundi_ie_append_str(&ied, DUNDI_IE_COUNTRY, dei.country);
-+                      dundi_ie_append_str(&ied, DUNDI_IE_EMAIL, dei.email);
-+                      dundi_ie_append_str(&ied, DUNDI_IE_PHONE, dei.phone);
-+                      if (!ast_strlen_zero(dei.ipaddr))
-+                              dundi_ie_append_str(&ied, DUNDI_IE_IPADDR, dei.ipaddr);
-+              }
-+              dundi_ie_append_hint(&ied, DUNDI_IE_HINT, hmd.flags, hmd.exten);
-+              dundi_send(st->trans, DUNDI_COMMAND_EIDRESPONSE, 0, 1, &ied);
-+              st->trans->thread = 0;
-+      }
-+      ast_mutex_unlock(&peerlock);
-+      free(st);
-+      return NULL;    
-+}
-+
-+static int dundi_answer_entity(struct dundi_transaction *trans, struct dundi_ies *ies, char *ccontext)
-+{
-+      struct dundi_query_state *st;
-+      int totallen;
-+      int x;
-+      int skipfirst=0;
-+      struct dundi_ie_data ied;
-+      char eid_str[20];
-+      char *s;
-+      pthread_t lookupthread;
-+      pthread_attr_t attr;
-+      if (ies->eidcount > 1) {
-+              /* Since it is a requirement that the first EID is the authenticating host
-+                 and the last EID is the root, it is permissible that the first and last EID
-+                 could be the same.  In that case, we should go ahead copy only the "root" section
-+                 since we will not need it for authentication. */
-+              if (!dundi_eid_cmp(ies->eids[0], ies->eids[ies->eidcount - 1]))
-+                      skipfirst = 1;
-+      }
-+      totallen = sizeof(struct dundi_query_state);
-+      totallen += (ies->eidcount - skipfirst) * sizeof(dundi_eid);
-+      st = malloc(totallen);
-+      if (st) {
-+              memset(st, 0, totallen);
-+              strncpy(st->called_context, ies->called_context, sizeof(st->called_context) - 1);
-+              memcpy(&st->reqeid, ies->reqeid, sizeof(st->reqeid));
-+              st->trans = trans;
-+              st->ttl = ies->ttl - 1;
-+              if (st->ttl < 0)
-+                      st->ttl = 0;
-+              s = st->fluffy;
-+              for (x=skipfirst;ies->eids[x];x++) {
-+                      st->eids[x-skipfirst] = (dundi_eid *)s;
-+                      *st->eids[x-skipfirst] = *ies->eids[x];
-+                      s += sizeof(dundi_eid);
-+              }
-+              ast_log(LOG_DEBUG, "Answering EID query for '%s@%s'!\n", dundi_eid_to_str(eid_str, sizeof(eid_str), ies->reqeid), ies->called_context);
-+              pthread_attr_init(&attr);
-+              pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
-+              trans->thread = 1;
-+              if (ast_pthread_create(&lookupthread, &attr, dundi_query_thread, st)) {
-+                      trans->thread = 0;
-+                      ast_log(LOG_WARNING, "Unable to create thread!\n");
-+                      free(st);
-+                      memset(&ied, 0, sizeof(ied));
-+                      dundi_ie_append_cause(&ied, DUNDI_IE_CAUSE, DUNDI_CAUSE_GENERAL, "Out of threads");
-+                      dundi_send(trans, DUNDI_COMMAND_EIDRESPONSE, 0, 1, &ied);
-+                      return -1;
-+              }
-+      } else {
-+              ast_log(LOG_WARNING, "Out of memory!\n");
-+              memset(&ied, 0, sizeof(ied));
-+              dundi_ie_append_cause(&ied, DUNDI_IE_CAUSE, DUNDI_CAUSE_GENERAL, "Out of memory");
-+              dundi_send(trans, DUNDI_COMMAND_EIDRESPONSE, 0, 1, &ied);
-+              return -1;
-+      }
-+      return 0;
-+}
-+
-+static int cache_save_hint(dundi_eid *eidpeer, struct dundi_request *req, struct dundi_hint *hint, int expiration)
-+{
-+      int unaffected;
-+      char key1[256];
-+      char key2[256];
-+      char eidpeer_str[20];
-+      char eidroot_str[20];
-+      char data[80]="";
-+      time_t timeout;
-+
-+      if (expiration < 0)
-+              expiration = DUNDI_DEFAULT_CACHE_TIME;
-+
-+      /* Only cache hint if "don't ask" is there... */
-+      if (!(ntohs(hint->flags)& DUNDI_HINT_DONT_ASK))
-+              return 0;
-+
-+      unaffected = ntohs(hint->flags) & DUNDI_HINT_UNAFFECTED;
-+
-+      dundi_eid_to_str_short(eidpeer_str, sizeof(eidpeer_str), eidpeer);
-+      dundi_eid_to_str_short(eidroot_str, sizeof(eidroot_str), &req->root_eid);
-+      snprintf(key1, sizeof(key1), "hint/%s/%s/%s/e%08lx", eidpeer_str, hint->data, req->dcontext, unaffected ? 0 : req->crc32);
-+      snprintf(key2, sizeof(key2), "hint/%s/%s/%s/r%s", eidpeer_str, hint->data, req->dcontext, eidroot_str);
-+
-+      time(&timeout);
-+      timeout += expiration;
-+      snprintf(data, sizeof(data), "%ld|", (long)(timeout));
-+      
-+      ast_db_put("dundi/cache", key1, data);
-+      ast_log(LOG_DEBUG, "Caching hint at '%s'\n", key1);
-+      ast_db_put("dundi/cache", key2, data);
-+      ast_log(LOG_DEBUG, "Caching hint at '%s'\n", key2);
-+      return 0;
-+}
-+
-+static int cache_save(dundi_eid *eidpeer, struct dundi_request *req, int start, int unaffected, int expiration, int push)
-+{
-+      int x;
-+      char key1[256];
-+      char key2[256];
-+      char data[1024]="";
-+      char eidpeer_str[20];
-+      char eidroot_str[20];
-+      time_t timeout;
-+
-+      if (expiration < 1)     
-+              expiration = DUNDI_DEFAULT_CACHE_TIME;
-+
-+      /* Keep pushes a little longer, cut pulls a little short */
-+      if (push)
-+              expiration += 10;
-+      else
-+              expiration -= 10;
-+      if (expiration < 1)
-+              expiration = 1;
-+      dundi_eid_to_str_short(eidpeer_str, sizeof(eidpeer_str), eidpeer);
-+      dundi_eid_to_str_short(eidroot_str, sizeof(eidroot_str), &req->root_eid);
-+      snprintf(key1, sizeof(key1), "%s/%s/%s/e%08lx", eidpeer_str, req->number, req->dcontext, unaffected ? 0 : req->crc32);
-+      snprintf(key2, sizeof(key2), "%s/%s/%s/r%s", eidpeer_str, req->number, req->dcontext, eidroot_str);
-+      /* Build request string */
-+      time(&timeout);
-+      timeout += expiration;
-+      snprintf(data, sizeof(data), "%ld|", (long)(timeout));
-+      for (x=start;x<req->respcount;x++) {
-+              /* Skip anything with an illegal pipe in it */
-+              if (strchr(req->dr[x].dest, '|'))
-+                      continue;
-+              snprintf(data + strlen(data), sizeof(data) - strlen(data), "%d/%d/%d/%s/%s|", 
-+                      req->dr[x].flags, req->dr[x].weight, req->dr[x].techint, req->dr[x].dest, 
-+                      dundi_eid_to_str_short(eidpeer_str, sizeof(eidpeer_str), &req->dr[x].eid));
-+      }
-+      ast_db_put("dundi/cache", key1, data);
-+      ast_db_put("dundi/cache", key2, data);
-+      return 0;
-+}
-+
-+static int dundi_prop_precache(struct dundi_transaction *trans, struct dundi_ies *ies, char *ccontext)
-+{
-+      struct dundi_query_state *st;
-+      int totallen;
-+      int x,z;
-+      struct dundi_ie_data ied;
-+      char *s;
-+      struct dundi_result dr2[MAX_RESULTS];
-+      struct dundi_request dr;
-+      struct dundi_hint_metadata hmd;
-+
-+      struct dundi_mapping *cur;
-+      int mapcount;
-+      int skipfirst = 0;
-+      
-+      pthread_t lookupthread;
-+      pthread_attr_t attr;
-+
-+      memset(&dr2, 0, sizeof(dr2));
-+      memset(&dr, 0, sizeof(dr));
-+      memset(&hmd, 0, sizeof(hmd));
-+      
-+      /* Forge request structure to hold answers for cache */
-+      hmd.flags = DUNDI_HINT_DONT_ASK | DUNDI_HINT_UNAFFECTED;
-+      dr.dr = dr2;
-+      dr.maxcount = MAX_RESULTS;
-+      dr.expiration = DUNDI_DEFAULT_CACHE_TIME;
-+      dr.hmd = &hmd;
-+      dr.pfds[0] = dr.pfds[1] = -1;
-+      trans->parent = &dr;
-+      strncpy(dr.dcontext, ies->called_context ? ies->called_context : "e164", sizeof(dr.dcontext));
-+      strncpy(dr.number, ies->called_number, sizeof(dr.number) - 1);
-+      
-+      for (x=0;x<ies->anscount;x++) {
-+              if (trans->parent->respcount < trans->parent->maxcount) {
-+                      /* Make sure it's not already there */
-+                      for (z=0;z<trans->parent->respcount;z++) {
-+                              if ((trans->parent->dr[z].techint == ies->answers[x]->protocol) &&
-+                                  !strcmp(trans->parent->dr[z].dest, ies->answers[x]->data)) 
-+                                              break;
-+                      }
-+                      if (z == trans->parent->respcount) {
-+                              /* Copy into parent responses */
-+                              trans->parent->dr[trans->parent->respcount].flags = ntohs(ies->answers[x]->flags);
-+                              trans->parent->dr[trans->parent->respcount].techint = ies->answers[x]->protocol;
-+                              trans->parent->dr[trans->parent->respcount].weight = ntohs(ies->answers[x]->weight);
-+                              trans->parent->dr[trans->parent->respcount].eid = ies->answers[x]->eid;
-+                              if (ies->expiration > 0)
-+                                      trans->parent->dr[trans->parent->respcount].expiration = ies->expiration;
-+                              else
-+                                      trans->parent->dr[trans->parent->respcount].expiration = DUNDI_DEFAULT_CACHE_TIME;
-+                              dundi_eid_to_str(trans->parent->dr[trans->parent->respcount].eid_str, 
-+                                      sizeof(trans->parent->dr[trans->parent->respcount].eid_str),
-+                                      &ies->answers[x]->eid);
-+                              strncpy(trans->parent->dr[trans->parent->respcount].dest, ies->answers[x]->data,
-+                                      sizeof(trans->parent->dr[trans->parent->respcount].dest));
-+                                      strncpy(trans->parent->dr[trans->parent->respcount].tech, tech2str(ies->answers[x]->protocol),
-+                                      sizeof(trans->parent->dr[trans->parent->respcount].tech));
-+                              trans->parent->respcount++;
-+                              trans->parent->hmd->flags &= ~DUNDI_HINT_DONT_ASK;
-+                      } else if (trans->parent->dr[z].weight > ies->answers[x]->weight) {
-+                              /* Update weight if appropriate */
-+                              trans->parent->dr[z].weight = ies->answers[x]->weight;
-+                      }
-+              } else
-+                      ast_log(LOG_NOTICE, "Dropping excessive answers in precache for %s@%s\n",
-+                              trans->parent->number, trans->parent->dcontext);
-+
-+      }
-+      /* Save all the results (if any) we had.  Even if no results, still cache lookup. */
-+      cache_save(&trans->them_eid, trans->parent, 0, 0, ies->expiration, 1);
-+      if (ies->hint)
-+              cache_save_hint(&trans->them_eid, trans->parent, ies->hint, ies->expiration);
-+
-+      totallen = sizeof(struct dundi_query_state);
-+      /* Count matching map entries */
-+      mapcount = 0;
-+      cur = mappings;
-+      while(cur) {
-+              if (!strcasecmp(cur->dcontext, ccontext))
-+                      mapcount++;
-+              cur = cur->next;
-+      }
-+      
-+      /* If no maps, return -1 immediately */
-+      if (!mapcount)
-+              return -1;
-+
-+      if (ies->eidcount > 1) {
-+              /* Since it is a requirement that the first EID is the authenticating host
-+                 and the last EID is the root, it is permissible that the first and last EID
-+                 could be the same.  In that case, we should go ahead copy only the "root" section
-+                 since we will not need it for authentication. */
-+              if (!dundi_eid_cmp(ies->eids[0], ies->eids[ies->eidcount - 1]))
-+                      skipfirst = 1;
-+      }
-+
-+      /* Prepare to run a query and then propagate that as necessary */
-+      totallen += mapcount * sizeof(struct dundi_mapping);
-+      totallen += (ies->eidcount - skipfirst) * sizeof(dundi_eid);
-+      st = malloc(totallen);
-+      if (st) {
-+              memset(st, 0, totallen);
-+              strncpy(st->called_context, ies->called_context, sizeof(st->called_context) - 1);
-+              strncpy(st->called_number, ies->called_number, sizeof(st->called_number) - 1);
-+              st->trans = trans;
-+              st->ttl = ies->ttl - 1;
-+              st->nocache = ies->cbypass;
-+              if (st->ttl < 0)
-+                      st->ttl = 0;
-+              s = st->fluffy;
-+              for (x=skipfirst;ies->eids[x];x++) {
-+                      st->eids[x-skipfirst] = (dundi_eid *)s;
-+                      *st->eids[x-skipfirst] = *ies->eids[x];
-+                      st->directs[x-skipfirst] = ies->eid_direct[x];
-+                      s += sizeof(dundi_eid);
-+              }
-+              /* Append mappings */
-+              x = 0;
-+              st->maps = (struct dundi_mapping *)s;
-+              cur = mappings;
-+              while(cur) {
-+                      if (!strcasecmp(cur->dcontext, ccontext)) {
-+                              if (x < mapcount) {
-+                                      st->maps[x] = *cur;
-+                                      st->maps[x].next = NULL;
-+                                      x++;
-+                              }
-+                      }
-+                      cur = cur->next;
-+              }
-+              st->nummaps = mapcount;
-+              ast_log(LOG_DEBUG, "Forwarding precache for '%s@%s'!\n", ies->called_number, ies->called_context);
-+              pthread_attr_init(&attr);
-+              pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
-+              trans->thread = 1;
-+              if (ast_pthread_create(&lookupthread, &attr, dundi_precache_thread, st)) {
-+                      trans->thread = 0;
-+                      ast_log(LOG_WARNING, "Unable to create thread!\n");
-+                      free(st);
-+                      memset(&ied, 0, sizeof(ied));
-+                      dundi_ie_append_cause(&ied, DUNDI_IE_CAUSE, DUNDI_CAUSE_GENERAL, "Out of threads");
-+                      dundi_send(trans, DUNDI_COMMAND_PRECACHERP, 0, 1, &ied);
-+                      return -1;
-+              }
-+      } else {
-+              ast_log(LOG_WARNING, "Out of memory!\n");
-+              memset(&ied, 0, sizeof(ied));
-+              dundi_ie_append_cause(&ied, DUNDI_IE_CAUSE, DUNDI_CAUSE_GENERAL, "Out of memory");
-+              dundi_send(trans, DUNDI_COMMAND_PRECACHERP, 0, 1, &ied);
-+              return -1;
-+      }
-+      return 0;
-+}
-+
-+static int dundi_answer_query(struct dundi_transaction *trans, struct dundi_ies *ies, char *ccontext)
-+{
-+      struct dundi_query_state *st;
-+      int totallen;
-+      int x;
-+      struct dundi_ie_data ied;
-+      char *s;
-+      struct dundi_mapping *cur;
-+      int mapcount;
-+      int skipfirst = 0;
-+      
-+      pthread_t lookupthread;
-+      pthread_attr_t attr;
-+      totallen = sizeof(struct dundi_query_state);
-+      /* Count matching map entries */
-+      mapcount = 0;
-+      cur = mappings;
-+      while(cur) {
-+              if (!strcasecmp(cur->dcontext, ccontext))
-+                      mapcount++;
-+              cur = cur->next;
-+      }
-+      /* If no maps, return -1 immediately */
-+      if (!mapcount)
-+              return -1;
-+
-+      if (ies->eidcount > 1) {
-+              /* Since it is a requirement that the first EID is the authenticating host
-+                 and the last EID is the root, it is permissible that the first and last EID
-+                 could be the same.  In that case, we should go ahead copy only the "root" section
-+                 since we will not need it for authentication. */
-+              if (!dundi_eid_cmp(ies->eids[0], ies->eids[ies->eidcount - 1]))
-+                      skipfirst = 1;
-+      }
-+
-+      totallen += mapcount * sizeof(struct dundi_mapping);
-+      totallen += (ies->eidcount - skipfirst) * sizeof(dundi_eid);
-+      st = malloc(totallen);
-+      if (st) {
-+              memset(st, 0, totallen);
-+              strncpy(st->called_context, ies->called_context, sizeof(st->called_context) - 1);
-+              strncpy(st->called_number, ies->called_number, sizeof(st->called_number) - 1);
-+              st->trans = trans;
-+              st->ttl = ies->ttl - 1;
-+              st->nocache = ies->cbypass;
-+              if (st->ttl < 0)
-+                      st->ttl = 0;
-+              s = st->fluffy;
-+              for (x=skipfirst;ies->eids[x];x++) {
-+                      st->eids[x-skipfirst] = (dundi_eid *)s;
-+                      *st->eids[x-skipfirst] = *ies->eids[x];
-+                      st->directs[x-skipfirst] = ies->eid_direct[x];
-+                      s += sizeof(dundi_eid);
-+              }
-+              /* Append mappings */
-+              x = 0;
-+              st->maps = (struct dundi_mapping *)s;
-+              cur = mappings;
-+              while(cur) {
-+                      if (!strcasecmp(cur->dcontext, ccontext)) {
-+                              if (x < mapcount) {
-+                                      st->maps[x] = *cur;
-+                                      st->maps[x].next = NULL;
-+                                      x++;
-+                              }
-+                      }
-+                      cur = cur->next;
-+              }
-+              st->nummaps = mapcount;
-+              ast_log(LOG_DEBUG, "Answering query for '%s@%s'!\n", ies->called_number, ies->called_context);
-+              pthread_attr_init(&attr);
-+              pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
-+              trans->thread = 1;
-+              if (ast_pthread_create(&lookupthread, &attr, dundi_lookup_thread, st)) {
-+                      trans->thread = 0;
-+                      ast_log(LOG_WARNING, "Unable to create thread!\n");
-+                      free(st);
-+                      memset(&ied, 0, sizeof(ied));
-+                      dundi_ie_append_cause(&ied, DUNDI_IE_CAUSE, DUNDI_CAUSE_GENERAL, "Out of threads");
-+                      dundi_send(trans, DUNDI_COMMAND_DPRESPONSE, 0, 1, &ied);
-+                      return -1;
-+              }
-+      } else {
-+              ast_log(LOG_WARNING, "Out of memory!\n");
-+              memset(&ied, 0, sizeof(ied));
-+              dundi_ie_append_cause(&ied, DUNDI_IE_CAUSE, DUNDI_CAUSE_GENERAL, "Out of memory");
-+              dundi_send(trans, DUNDI_COMMAND_DPRESPONSE, 0, 1, &ied);
-+              return -1;
-+      }
-+      return 0;
-+}
-+
-+static int cache_lookup_internal(time_t now, struct dundi_request *req, char *key, char *eid_str_full, int *lowexpiration)
-+{
-+      char data[1024]="";
-+      char *ptr, *term, *src;
-+      int tech;
-+      int flags;
-+      int weight;
-+      int length;
-+      int z;
-+      int expiration;
-+      char fs[256];
-+      time_t timeout;
-+      /* Build request string */
-+      if (!ast_db_get("dundi/cache", key, data, sizeof(data))) {
-+              ptr = data;
-+              if (sscanf(ptr, "%ld|%n", &timeout, &length) == 1) {
-+                      expiration = timeout - now;
-+                      if (expiration > 0) {
-+                              ast_log(LOG_DEBUG, "Found cache expiring in %d seconds!\n", (int)(timeout - now));
-+                              ptr += length;
-+                              while((sscanf(ptr, "%d/%d/%d/%n", &flags, &weight, &tech, &length) == 3)) {
-+                                      ptr += length;
-+                                      term = strchr(ptr, '|');
-+                                      if (term) {
-+                                              *term = '\0';
-+                                              src = strrchr(ptr, '/');
-+                                              if (src) {
-+                                                      *src = '\0';
-+                                                      src++;
-+                                              } else
-+                                                      src = "";
-+                                              ast_log(LOG_DEBUG, "Found cached answer '%s/%s' originally from '%s' with flags '%s' on behalf of '%s'\n", 
-+                                                      tech2str(tech), ptr, src, dundi_flags2str(fs, sizeof(fs), flags), eid_str_full);
-+                                              /* Make sure it's not already there */
-+                                              for (z=0;z<req->respcount;z++) {
-+                                                      if ((req->dr[z].techint == tech) &&
-+                                                          !strcmp(req->dr[z].dest, ptr)) 
-+                                                                      break;
-+                                              }
-+                                              if (z == req->respcount) {
-+                                                      /* Copy into parent responses */
-+                                                      req->dr[req->respcount].flags = flags;
-+                                                      req->dr[req->respcount].weight = weight;
-+                                                      req->dr[req->respcount].techint = tech;
-+                                                      req->dr[req->respcount].expiration = expiration;
-+                                                      dundi_str_short_to_eid(&req->dr[req->respcount].eid, src);
-+                                                      dundi_eid_to_str(req->dr[req->respcount].eid_str, 
-+                                                              sizeof(req->dr[req->respcount].eid_str), &req->dr[req->respcount].eid);
-+                                                      strncpy(req->dr[req->respcount].dest, ptr,
-+                                                              sizeof(req->dr[req->respcount].dest));
-+                                                      strncpy(req->dr[req->respcount].tech, tech2str(tech),
-+                                                              sizeof(req->dr[req->respcount].tech));
-+                                                      req->respcount++;
-+                                                      req->hmd->flags &= ~DUNDI_HINT_DONT_ASK;
-+                                              } else if (req->dr[z].weight > weight)
-+                                                      req->dr[z].weight = weight;
-+                                              ptr = term + 1;
-+                                      }
-+                              }
-+                              /* We found *something* cached */
-+                              if (expiration < *lowexpiration)
-+                                      *lowexpiration = expiration;
-+                              return 1;
-+                      } else 
-+                              ast_db_del("dundi/cache", key);
-+              } else 
-+                      ast_db_del("dundi/cache", key);
-+      }
-+              
-+      return 0;
-+}
-+
-+static int cache_lookup(struct dundi_request *req, dundi_eid *peer_eid, unsigned long crc32, int *lowexpiration)
-+{
-+      char key[256];
-+      char eid_str[20];
-+      char eidroot_str[20];
-+      time_t now;
-+      int res=0;
-+      int res2=0;
-+      char eid_str_full[20];
-+      char tmp[256]="";
-+      int x;
-+
-+      time(&now);
-+      dundi_eid_to_str_short(eid_str, sizeof(eid_str), peer_eid);
-+      dundi_eid_to_str_short(eidroot_str, sizeof(eidroot_str), &req->root_eid);
-+      dundi_eid_to_str(eid_str_full, sizeof(eid_str_full), peer_eid);
-+      snprintf(key, sizeof(key), "%s/%s/%s/e%08lx", eid_str, req->number, req->dcontext, crc32);
-+      res |= cache_lookup_internal(now, req, key, eid_str_full, lowexpiration);
-+      snprintf(key, sizeof(key), "%s/%s/%s/e%08lx", eid_str, req->number, req->dcontext, 0L);
-+      res |= cache_lookup_internal(now, req, key, eid_str_full, lowexpiration);
-+      snprintf(key, sizeof(key), "%s/%s/%s/r%s", eid_str, req->number, req->dcontext, eidroot_str);
-+      res |= cache_lookup_internal(now, req, key, eid_str_full, lowexpiration);
-+      x = 0;
-+      if (!req->respcount) {
-+              while(!res2) {
-+                      /* Look and see if we have a hint that would preclude us from looking at this
-+                         peer for this number. */
-+                      if (!(tmp[x] = req->number[x])) 
-+                              break;
-+                      x++;
-+                      /* Check for hints */
-+                      snprintf(key, sizeof(key), "hint/%s/%s/%s/e%08lx", eid_str, tmp, req->dcontext, crc32);
-+                      res2 |= cache_lookup_internal(now, req, key, eid_str_full, lowexpiration);
-+                      snprintf(key, sizeof(key), "hint/%s/%s/%s/e%08lx", eid_str, tmp, req->dcontext, 0L);
-+                      res2 |= cache_lookup_internal(now, req, key, eid_str_full, lowexpiration);
-+                      snprintf(key, sizeof(key), "hint/%s/%s/%s/r%s", eid_str, tmp, req->dcontext, eidroot_str);
-+                      res2 |= cache_lookup_internal(now, req, key, eid_str_full, lowexpiration);
-+                      if (res2) {
-+                              if (strlen(tmp) > strlen(req->hmd->exten)) {
-+                                      /* Update meta data if appropriate */
-+                                      strncpy(req->hmd->exten, tmp, sizeof(req->hmd->exten) - 1);
-+                              }
-+                      }
-+              }
-+              res |= res2;
-+      }
-+
-+      return res;
-+}
-+
-+static void qualify_peer(struct dundi_peer *peer, int schedonly);
-+
-+static void apply_peer(struct dundi_transaction *trans, struct dundi_peer *p)
-+{
-+      if (!trans->addr.sin_addr.s_addr)
-+              memcpy(&trans->addr, &p->addr, sizeof(trans->addr));
-+      trans->us_eid = p->us_eid;
-+      trans->them_eid = p->eid;
-+      /* Enable encryption if appropriate */
-+      if (!ast_strlen_zero(p->inkey))
-+              trans->flags |= FLAG_ENCRYPT;
-+      if (p->maxms) {
-+              trans->autokilltimeout = p->maxms;
-+              trans->retranstimer = DUNDI_DEFAULT_RETRANS_TIMER;
-+              if (p->lastms > 1) {
-+                      trans->retranstimer = p->lastms * 2;
-+                      /* Keep it from being silly */
-+                      if (trans->retranstimer < 150)
-+                              trans->retranstimer = 150;
-+              }
-+              if (trans->retranstimer > DUNDI_DEFAULT_RETRANS_TIMER)
-+                      trans->retranstimer = DUNDI_DEFAULT_RETRANS_TIMER;
-+      } else
-+              trans->autokilltimeout = global_autokilltimeout;
-+}
-+
-+static int do_register_expire(void *data)
-+{
-+      struct dundi_peer *peer = data;
-+      char eid_str[20];
-+      /* Called with peerlock already held */
-+      ast_log(LOG_DEBUG, "Register expired for '%s'\n", dundi_eid_to_str(eid_str, sizeof(eid_str), &peer->eid));
-+      peer->registerexpire = -1;
-+      peer->lastms = 0;
-+      memset(&peer->addr, 0, sizeof(peer->addr));
-+      return 0;
-+}
-+
-+static int update_key(struct dundi_peer *peer)
-+{
-+      unsigned char key[16];
-+      struct ast_key *ekey, *skey;
-+      char eid_str[20];
-+      int res;
-+      if (!peer->keyexpire || (peer->keyexpire < time(NULL))) {
-+              build_iv(key);
-+              aes_encrypt_key128(key, &peer->us_ecx);
-+              aes_decrypt_key128(key, &peer->us_dcx);
-+              ekey = ast_key_get(peer->inkey, AST_KEY_PUBLIC);
-+              if (!ekey) {
-+                      ast_log(LOG_NOTICE, "No such key '%s' for creating RSA encrypted shared key for '%s'!\n",
-+                              peer->inkey, dundi_eid_to_str(eid_str, sizeof(eid_str), &peer->eid));
-+                      return -1;
-+              }
-+              skey = ast_key_get(peer->outkey, AST_KEY_PRIVATE);
-+              if (!skey) {
-+                      ast_log(LOG_NOTICE, "No such key '%s' for signing RSA encrypted shared key for '%s'!\n",
-+                              peer->outkey, dundi_eid_to_str(eid_str, sizeof(eid_str), &peer->eid));
-+                      return -1;
-+              }
-+              if ((res = ast_encrypt_bin(peer->txenckey, key, sizeof(key), ekey)) != 128) {
-+                      ast_log(LOG_NOTICE, "Whoa, got a weird encrypt size (%d != %d)!\n", res, 128);
-+                      return -1;
-+              }
-+              if ((res = ast_sign_bin(skey, peer->txenckey, 128, peer->txenckey + 128))) {
-+                      ast_log(LOG_NOTICE, "Failed to sign key (%d)!\n", res);
-+                      return -1;
-+              }
-+              peer->us_keycrc32 = crc32(0L, peer->txenckey, 128);
-+              peer->sentfullkey = 0;
-+              /* Looks good */
-+              time(&peer->keyexpire);
-+              peer->keyexpire += dundi_key_ttl;
-+      }
-+      return 0;
-+}
-+
-+static int encrypt_memcpy(unsigned char *dst, unsigned char *src, int len, unsigned char *iv, aes_encrypt_ctx *ecx) 
-+{
-+      unsigned char curblock[16];
-+      int x;
-+      memcpy(curblock, iv, sizeof(curblock));
-+      while(len > 0) {
-+              for (x=0;x<16;x++)
-+                      curblock[x] ^= src[x];
-+              aes_encrypt(curblock, dst, ecx);
-+              memcpy(curblock, dst, sizeof(curblock)); 
-+              dst += 16;
-+              src += 16;
-+              len -= 16;
-+      }
-+      return 0;
-+}
-+static int decrypt_memcpy(unsigned char *dst, unsigned char *src, int len, unsigned char *iv, aes_decrypt_ctx *dcx) 
-+{
-+      unsigned char lastblock[16];
-+      int x;
-+      memcpy(lastblock, iv, sizeof(lastblock));
-+      while(len > 0) {
-+              aes_decrypt(src, dst, dcx);
-+              for (x=0;x<16;x++)
-+                      dst[x] ^= lastblock[x];
-+              memcpy(lastblock, src, sizeof(lastblock));
-+              dst += 16;
-+              src += 16;
-+              len -= 16;
-+      }
-+      return 0;
-+}
-+
-+static struct dundi_hdr *dundi_decrypt(struct dundi_transaction *trans, unsigned char *dst, int *dstlen, struct dundi_hdr *ohdr, struct dundi_encblock *src, int srclen)
-+{
-+      int space = *dstlen;
-+      unsigned long bytes;
-+      struct dundi_hdr *h;
-+      unsigned char *decrypt_space;
-+      decrypt_space = alloca(srclen);
-+      if (!decrypt_space)
-+              return NULL;
-+      decrypt_memcpy(decrypt_space, src->encdata, srclen, src->iv, &trans->dcx);
-+      /* Setup header */
-+      h = (struct dundi_hdr *)dst;
-+      *h = *ohdr;
-+      bytes = space - 6;
-+      if (uncompress(dst + 6, &bytes, decrypt_space, srclen) != Z_OK) {
-+              ast_log(LOG_DEBUG, "Ouch, uncompress failed :(\n");
-+              return NULL;
-+      }
-+      /* Update length */
-+      *dstlen = bytes + 6;
-+      /* Return new header */
-+      return h;
-+}
-+
-+static int dundi_encrypt(struct dundi_transaction *trans, struct dundi_packet *pack)
-+{
-+      unsigned char *compress_space;
-+      int len;
-+      int res;
-+      unsigned long bytes;
-+      struct dundi_ie_data ied;
-+      struct dundi_peer *peer;
-+      unsigned char iv[16];
-+      len = pack->datalen + pack->datalen / 100 + 42;
-+      compress_space = alloca(len);
-+      if (compress_space) {
-+              memset(compress_space, 0, len);
-+              /* We care about everthing save the first 6 bytes of header */
-+              bytes = len;
-+              res = compress(compress_space, &bytes, pack->data + 6, pack->datalen - 6);
-+              if (res != Z_OK) {
-+                      ast_log(LOG_DEBUG, "Ouch, compression failed!\n");
-+                      return -1;
-+              }
-+              memset(&ied, 0, sizeof(ied));
-+              /* Say who we are */
-+              if (!pack->h->iseqno && !pack->h->oseqno) {
-+                      /* Need the key in the first copy */
-+                      if (!(peer = find_peer(&trans->them_eid))) 
-+                              return -1;
-+                      if (update_key(peer))
-+                              return -1;
-+                      if (!peer->sentfullkey)
-+                              trans->flags |= FLAG_SENDFULLKEY;
-+                      /* Append key data */
-+                      dundi_ie_append_eid(&ied, DUNDI_IE_EID, &trans->us_eid);
-+                      if (trans->flags & FLAG_SENDFULLKEY) {
-+                              dundi_ie_append_raw(&ied, DUNDI_IE_SHAREDKEY, peer->txenckey, 128);
-+                              dundi_ie_append_raw(&ied, DUNDI_IE_SIGNATURE, peer->txenckey + 128, 128);
-+                      } else {
-+                              dundi_ie_append_int(&ied, DUNDI_IE_KEYCRC32, peer->us_keycrc32);
-+                      }
-+                      /* Setup contexts */
-+                      trans->ecx = peer->us_ecx;
-+                      trans->dcx = peer->us_dcx;
-+
-+                      /* We've sent the full key */
-+                      peer->sentfullkey = 1;
-+              }
-+              /* Build initialization vector */
-+              build_iv(iv);
-+              /* Add the field, rounded up to 16 bytes */
-+              dundi_ie_append_encdata(&ied, DUNDI_IE_ENCDATA, iv, NULL, ((bytes + 15) / 16) * 16);
-+              /* Copy the data */
-+              if ((ied.pos + bytes) >= sizeof(ied.buf)) {
-+                      ast_log(LOG_NOTICE, "Final packet too large!\n");
-+                      return -1;
-+              }
-+              encrypt_memcpy(ied.buf + ied.pos, compress_space, bytes, iv, &trans->ecx);
-+              ied.pos += ((bytes + 15) / 16) * 16;
-+              /* Reconstruct header */
-+              pack->datalen = sizeof(struct dundi_hdr);
-+              pack->h->cmdresp = DUNDI_COMMAND_ENCRYPT;
-+              pack->h->cmdflags = 0;
-+              memcpy(pack->h->ies, ied.buf, ied.pos);
-+              pack->datalen += ied.pos;
-+              return 0;
-+      }
-+      return -1;
-+}
-+
-+static int check_key(struct dundi_peer *peer, unsigned char *newkey, unsigned char *newsig, unsigned long keycrc32)
-+{
-+      unsigned char dst[128];
-+      int res;
-+      struct ast_key *key, *skey;
-+      char eid_str[20];
-+      if (option_debug)
-+              ast_log(LOG_DEBUG, "Expected '%08lx' got '%08lx'\n", peer->them_keycrc32, keycrc32);
-+      if (peer->them_keycrc32 && (peer->them_keycrc32 == keycrc32)) {
-+              /* A match */
-+              return 1;
-+      } else if (!newkey || !newsig)
-+              return 0;
-+      if (!memcmp(peer->rxenckey, newkey, 128) &&
-+          !memcmp(peer->rxenckey + 128, newsig, 128)) {
-+              /* By definition, a match */
-+              return 1;
-+      }
-+      /* Decrypt key */
-+      key = ast_key_get(peer->outkey, AST_KEY_PRIVATE);
-+      if (!key) {
-+              ast_log(LOG_NOTICE, "Unable to find key '%s' to decode shared key from '%s'\n",
-+                      peer->outkey, dundi_eid_to_str(eid_str, sizeof(eid_str), &peer->eid));
-+              return -1;
-+      }
-+
-+      skey = ast_key_get(peer->inkey, AST_KEY_PUBLIC);
-+      if (!skey) {
-+              ast_log(LOG_NOTICE, "Unable to find key '%s' to verify shared key from '%s'\n",
-+                      peer->inkey, dundi_eid_to_str(eid_str, sizeof(eid_str), &peer->eid));
-+              return -1;
-+      }
-+
-+      /* First check signature */
-+      res = ast_check_signature_bin(skey, newkey, 128, newsig);
-+      if (res) 
-+              return 0;
-+
-+      res = ast_decrypt_bin(dst, newkey, sizeof(dst), key);
-+      if (res != 16) {
-+              if (res >= 0)
-+                      ast_log(LOG_NOTICE, "Weird, key decoded to the wrong size (%d)\n", res);
-+              return 0;
-+      }
-+      /* Decrypted, passes signature */
-+      ast_log(LOG_DEBUG, "Wow, new key combo passed signature and decrypt!\n");
-+      memcpy(peer->rxenckey, newkey, 128);
-+      memcpy(peer->rxenckey + 128, newsig, 128);
-+      peer->them_keycrc32 = crc32(0L, peer->rxenckey, 128);
-+      aes_decrypt_key128(dst, &peer->them_dcx);
-+      aes_encrypt_key128(dst, &peer->them_ecx);
-+      return 1;
-+}
-+
-+static int handle_command_response(struct dundi_transaction *trans, struct dundi_hdr *hdr, int datalen, int encrypted)
-+{
-+      /* Handle canonical command / response */
-+      int final = hdr->cmdresp & 0x80;
-+      int cmd = hdr->cmdresp & 0x7f;
-+      int x,y,z;
-+      int resp;
-+      int res;
-+      int authpass=0;
-+      unsigned char *bufcpy;
-+      struct dundi_ie_data ied;
-+      struct dundi_ies ies;
-+      struct dundi_peer *peer;
-+      char eid_str[20];
-+      char eid_str2[20];
-+      memset(&ied, 0, sizeof(ied));
-+      memset(&ies, 0, sizeof(ies));
-+      if (datalen) {
-+              bufcpy = alloca(datalen);
-+              if (!bufcpy)
-+                      return -1;
-+              /* Make a copy for parsing */
-+              memcpy(bufcpy, hdr->ies, datalen);
-+              ast_log(LOG_DEBUG, "Got canonical message %d (%d), %d bytes data%s\n", cmd, hdr->oseqno, datalen, final ? " (Final)" : "");
-+              if (dundi_parse_ies(&ies, bufcpy, datalen) < 0) {
-+                      ast_log(LOG_WARNING, "Failed to parse DUNDI information elements!\n");
-+                      return -1;
-+              }
-+      }
-+      switch(cmd) {
-+      case DUNDI_COMMAND_DPDISCOVER:
-+      case DUNDI_COMMAND_EIDQUERY:
-+      case DUNDI_COMMAND_PRECACHERQ:
-+              if (cmd == DUNDI_COMMAND_EIDQUERY)
-+                      resp = DUNDI_COMMAND_EIDRESPONSE;
-+              else if (cmd == DUNDI_COMMAND_PRECACHERQ)
-+                      resp = DUNDI_COMMAND_PRECACHERP;
-+              else
-+                      resp = DUNDI_COMMAND_DPRESPONSE;
-+              /* A dialplan or entity discover -- qualify by highest level entity */
-+              peer = find_peer(ies.eids[0]);
-+              if (!peer) {
-+                      dundi_ie_append_cause(&ied, DUNDI_IE_CAUSE, DUNDI_CAUSE_NOAUTH, NULL);
-+                      dundi_send(trans, resp, 0, 1, &ied);
-+              } else {
-+                      int hasauth = 0;
-+                      trans->us_eid = peer->us_eid;
-+                      if (strlen(peer->inkey)) {
-+                              hasauth = encrypted;
-+                      } else 
-+                              hasauth = 1;
-+                      if (hasauth) {
-+                              /* Okay we're authentiated and all, now we check if they're authorized */
-+                              if (!ies.called_context)
-+                                      ies.called_context = "e164";
-+                              if (cmd == DUNDI_COMMAND_EIDQUERY) {
-+                                      res = dundi_answer_entity(trans, &ies, ies.called_context);
-+                              } else {
-+                                      if (!ies.called_number || ast_strlen_zero(ies.called_number)) {
-+                                              /* They're not permitted to access that context */
-+                                              dundi_ie_append_cause(&ied, DUNDI_IE_CAUSE, DUNDI_CAUSE_GENERAL, "Invalid or missing number/entity");
-+                                              dundi_send(trans, resp, 0, 1, &ied);
-+                                      } else if ((cmd == DUNDI_COMMAND_DPDISCOVER) && 
-+                                                 (peer->model & DUNDI_MODEL_INBOUND) && 
-+                                                         has_permission(peer->permit, ies.called_context)) {
-+                                              res = dundi_answer_query(trans, &ies, ies.called_context);
-+                                              if (res < 0) {
-+                                                      /* There is no such dundi context */
-+                                                      dundi_ie_append_cause(&ied, DUNDI_IE_CAUSE, DUNDI_CAUSE_NOAUTH, "Unsupported DUNDI Context");
-+                                                      dundi_send(trans, resp, 0, 1, &ied);
-+                                              }
-+                                      } else if ((cmd = DUNDI_COMMAND_PRECACHERQ) && 
-+                                                 (peer->pcmodel & DUNDI_MODEL_INBOUND) && 
-+                                                         has_permission(peer->include, ies.called_context)) {
-+                                              res = dundi_prop_precache(trans, &ies, ies.called_context);
-+                                              if (res < 0) {
-+                                                      /* There is no such dundi context */
-+                                                      dundi_ie_append_cause(&ied, DUNDI_IE_CAUSE, DUNDI_CAUSE_NOAUTH, "Unsupported DUNDI Context");
-+                                                      dundi_send(trans, resp, 0, 1, &ied);
-+                                              }
-+                                      } else {
-+                                              /* They're not permitted to access that context */
-+                                              dundi_ie_append_cause(&ied, DUNDI_IE_CAUSE, DUNDI_CAUSE_NOAUTH, "Permission to context denied");
-+                                              dundi_send(trans, resp, 0, 1, &ied);
-+                                      }
-+                              }
-+                      } else {
-+                              /* They're not permitted to access that context */
-+                              dundi_ie_append_cause(&ied, DUNDI_IE_CAUSE, DUNDI_CAUSE_NOAUTH, "Unencrypted responses not permitted");
-+                              dundi_send(trans, resp, 0, 1, &ied);
-+                      }
-+              }
-+              break;
-+      case DUNDI_COMMAND_REGREQ:
-+              /* A register request -- should only have one entity */
-+              peer = find_peer(ies.eids[0]);
-+              if (!peer || !peer->dynamic) {
-+                      dundi_ie_append_cause(&ied, DUNDI_IE_CAUSE, DUNDI_CAUSE_NOAUTH, NULL);
-+                      dundi_send(trans, DUNDI_COMMAND_REGRESPONSE, 0, 1, &ied);
-+              } else {
-+                      int hasauth = 0;
-+                      trans->us_eid = peer->us_eid;
-+                      if (!ast_strlen_zero(peer->inkey)) {
-+                              hasauth = encrypted;
-+                      } else
-+                              hasauth = 1;
-+                      if (hasauth) {
-+                              int expire = default_expiration;
-+                              char iabuf[INET_ADDRSTRLEN];
-+                              char data[256];
-+                              int needqual = 0;
-+                              if (peer->registerexpire > -1)
-+                                      ast_sched_del(sched, peer->registerexpire);
-+                              peer->registerexpire = ast_sched_add(sched, (expire + 10) * 1000, do_register_expire, peer);
-+                              ast_inet_ntoa(iabuf, sizeof(iabuf), trans->addr.sin_addr);
-+                              snprintf(data, sizeof(data), "%s:%d:%d", iabuf, ntohs(trans->addr.sin_port), expire);
-+                              ast_db_put("dundi/dpeers", dundi_eid_to_str_short(eid_str, sizeof(eid_str), &peer->eid), data);
-+                              if (inaddrcmp(&peer->addr, &trans->addr)) {
-+                                      if (option_verbose > 2)
-+                                              ast_verbose(VERBOSE_PREFIX_3 "Registered DUNDi peer '%s' at '%s:%d'\n", dundi_eid_to_str(eid_str, sizeof(eid_str), &peer->eid), iabuf, ntohs(trans->addr.sin_port));
-+                                      needqual = 1;
-+                              }
-+                                      
-+                              memcpy(&peer->addr, &trans->addr, sizeof(peer->addr));
-+                              dundi_ie_append_short(&ied, DUNDI_IE_EXPIRATION, default_expiration);
-+                              dundi_send(trans, DUNDI_COMMAND_REGRESPONSE, 0, 1, &ied);
-+                              if (needqual)
-+                                      qualify_peer(peer, 1);
-+                      }
-+              }
-+              break;
-+      case DUNDI_COMMAND_DPRESPONSE:
-+              /* A dialplan response, lets see what we got... */
-+              if (ies.cause < 1) {
-+                      /* Success of some sort */
-+                      ast_log(LOG_DEBUG, "Looks like success of some sort (%d), %d answers\n", ies.cause, ies.anscount);
-+                      if (trans->flags & FLAG_ENCRYPT) {
-+                              authpass = encrypted;
-+                      } else 
-+                              authpass = 1;
-+                      if (authpass) {
-+                              /* Pass back up answers */
-+                              if (trans->parent && trans->parent->dr) {
-+                                      y = trans->parent->respcount;
-+                                      for (x=0;x<ies.anscount;x++) {
-+                                              if (trans->parent->respcount < trans->parent->maxcount) {
-+                                                      /* Make sure it's not already there */
-+                                                      for (z=0;z<trans->parent->respcount;z++) {
-+                                                              if ((trans->parent->dr[z].techint == ies.answers[x]->protocol) &&
-+                                                                  !strcmp(trans->parent->dr[z].dest, ies.answers[x]->data)) 
-+                                                                              break;
-+                                                      }
-+                                                      if (z == trans->parent->respcount) {
-+                                                              /* Copy into parent responses */
-+                                                              trans->parent->dr[trans->parent->respcount].flags = ntohs(ies.answers[x]->flags);
-+                                                              trans->parent->dr[trans->parent->respcount].techint = ies.answers[x]->protocol;
-+                                                              trans->parent->dr[trans->parent->respcount].weight = ntohs(ies.answers[x]->weight);
-+                                                              trans->parent->dr[trans->parent->respcount].eid = ies.answers[x]->eid;
-+                                                              if (ies.expiration > 0)
-+                                                                      trans->parent->dr[trans->parent->respcount].expiration = ies.expiration;
-+                                                              else
-+                                                                      trans->parent->dr[trans->parent->respcount].expiration = DUNDI_DEFAULT_CACHE_TIME;
-+                                                              dundi_eid_to_str(trans->parent->dr[trans->parent->respcount].eid_str, 
-+                                                                      sizeof(trans->parent->dr[trans->parent->respcount].eid_str),
-+                                                                      &ies.answers[x]->eid);
-+                                                              strncpy(trans->parent->dr[trans->parent->respcount].dest, ies.answers[x]->data,
-+                                                                      sizeof(trans->parent->dr[trans->parent->respcount].dest));
-+                                                              strncpy(trans->parent->dr[trans->parent->respcount].tech, tech2str(ies.answers[x]->protocol),
-+                                                                      sizeof(trans->parent->dr[trans->parent->respcount].tech));
-+                                                              trans->parent->respcount++;
-+                                                              trans->parent->hmd->flags &= ~DUNDI_HINT_DONT_ASK;
-+                                                      } else if (trans->parent->dr[z].weight > ies.answers[x]->weight) {
-+                                                              /* Update weight if appropriate */
-+                                                              trans->parent->dr[z].weight = ies.answers[x]->weight;
-+                                                      }
-+                                              } else
-+                                                      ast_log(LOG_NOTICE, "Dropping excessive answers to request for %s@%s\n",
-+                                                              trans->parent->number, trans->parent->dcontext);
-+                                      }
-+                                      /* Save all the results (if any) we had.  Even if no results, still cache lookup.  Let
-+                                         the cache know if this request was unaffected by our entity list. */
-+                                      cache_save(&trans->them_eid, trans->parent, y, 
-+                                                      ies.hint ? ntohs(ies.hint->flags) & DUNDI_HINT_UNAFFECTED : 0, ies.expiration, 0);
-+                                      if (ies.hint) {
-+                                              cache_save_hint(&trans->them_eid, trans->parent, ies.hint, ies.expiration);
-+                                              if (ntohs(ies.hint->flags) & DUNDI_HINT_TTL_EXPIRED)
-+                                                      trans->parent->hmd->flags |= DUNDI_HINT_TTL_EXPIRED;
-+                                              if (ntohs(ies.hint->flags) & DUNDI_HINT_DONT_ASK) { 
-+                                                      if (strlen(ies.hint->data) > strlen(trans->parent->hmd->exten)) {
-+                                                              strncpy(trans->parent->hmd->exten, ies.hint->data, 
-+                                                                      sizeof(trans->parent->hmd->exten) - 1);
-+                                                      }
-+                                              } else {
-+                                                      trans->parent->hmd->flags &= ~DUNDI_HINT_DONT_ASK;
-+                                              }
-+                                      }
-+                                      if (ies.expiration > 0) {
-+                                              if (trans->parent->expiration > ies.expiration) {
-+                                                      trans->parent->expiration = ies.expiration;
-+                                              }
-+                                      }
-+                              }
-+                              /* Close connection if not final */
-+                              if (!final) 
-+                                      dundi_send(trans, DUNDI_COMMAND_CANCEL, 0, 1, NULL);
-+                      }
-+                      
-+              } else {
-+                      /* Auth failure, check for data */
-+                      if (!final) {
-+                              /* Cancel if they didn't already */
-+                              dundi_send(trans, DUNDI_COMMAND_CANCEL, 0, 1, NULL);
-+                      }
-+              }
-+              break;
-+      case DUNDI_COMMAND_EIDRESPONSE:
-+              /* A dialplan response, lets see what we got... */
-+              if (ies.cause < 1) {
-+                      /* Success of some sort */
-+                      ast_log(LOG_DEBUG, "Looks like success of some sort (%d)\n", ies.cause);
-+                      if (trans->flags & FLAG_ENCRYPT) {
-+                              authpass = encrypted;
-+                      } else 
-+                              authpass = 1;
-+                      if (authpass) {
-+                              /* Pass back up answers */
-+                              if (trans->parent && trans->parent->dei && ies.q_org) {
-+                                      if (!trans->parent->respcount) {
-+                                              trans->parent->respcount++;
-+                                              if (ies.q_dept)
-+                                                      strncpy(trans->parent->dei->orgunit, ies.q_dept, sizeof(trans->parent->dei->orgunit) - 1);
-+                                              if (ies.q_org)
-+                                                      strncpy(trans->parent->dei->org, ies.q_org, sizeof(trans->parent->dei->org) - 1);
-+                                              if (ies.q_locality)
-+                                                      strncpy(trans->parent->dei->locality, ies.q_locality, sizeof(trans->parent->dei->locality) - 1);
-+                                              if (ies.q_stateprov)
-+                                                      strncpy(trans->parent->dei->stateprov, ies.q_stateprov, sizeof(trans->parent->dei->stateprov) - 1);
-+                                              if (ies.q_country)
-+                                                      strncpy(trans->parent->dei->country, ies.q_country, sizeof(trans->parent->dei->country) - 1);
-+                                              if (ies.q_email)
-+                                                      strncpy(trans->parent->dei->email, ies.q_email, sizeof(trans->parent->dei->email) - 1);
-+                                              if (ies.q_phone)
-+                                                      strncpy(trans->parent->dei->phone, ies.q_phone, sizeof(trans->parent->dei->phone) - 1);
-+                                              if (ies.q_ipaddr)
-+                                                      strncpy(trans->parent->dei->ipaddr, ies.q_ipaddr, sizeof(trans->parent->dei->ipaddr) - 1);
-+                                              if (!dundi_eid_cmp(&trans->them_eid, &trans->parent->query_eid)) {
-+                                                      /* If it's them, update our address */
-+                                                      ast_inet_ntoa(trans->parent->dei->ipaddr, sizeof(trans->parent->dei->ipaddr),
-+                                                              trans->addr.sin_addr);
-+                                              }
-+                                      }
-+                                      if (ies.hint) {
-+                                              if (ntohs(ies.hint->flags) & DUNDI_HINT_TTL_EXPIRED)
-+                                                      trans->parent->hmd->flags |= DUNDI_HINT_TTL_EXPIRED;
-+                                      }
-+                              }
-+                              /* Close connection if not final */
-+                              if (!final) 
-+                                      dundi_send(trans, DUNDI_COMMAND_CANCEL, 0, 1, NULL);
-+                      }
-+                      
-+              } else {
-+                      /* Auth failure, check for data */
-+                      if (!final) {
-+                              /* Cancel if they didn't already */
-+                              dundi_send(trans, DUNDI_COMMAND_CANCEL, 0, 1, NULL);
-+                      }
-+              }
-+              break;
-+      case DUNDI_COMMAND_REGRESPONSE:
-+              /* A dialplan response, lets see what we got... */
-+              if (ies.cause < 1) {
-+                      int hasauth;
-+                      /* Success of some sort */
-+                      if (trans->flags & FLAG_ENCRYPT) {
-+                              hasauth = encrypted;
-+                      } else 
-+                              hasauth = 1;
-+                      
-+                      if (!hasauth) {
-+                              ast_log(LOG_NOTICE, "Reponse to register not authorized!\n");
-+                              if (!final) {
-+                                      dundi_ie_append_cause(&ied, DUNDI_IE_CAUSE, DUNDI_CAUSE_NOAUTH, "Improper signature in answer");
-+                                      dundi_send(trans, DUNDI_COMMAND_CANCEL, 0, 1, &ied);
-+                              }
-+                      } else {
-+                              ast_log(LOG_DEBUG, "Yay, we've registered as '%s' to '%s'\n", dundi_eid_to_str(eid_str, sizeof(eid_str), &trans->us_eid),
-+                                                      dundi_eid_to_str(eid_str2, sizeof(eid_str2), &trans->them_eid));
-+                              /* Close connection if not final */
-+                              if (!final) 
-+                                      dundi_send(trans, DUNDI_COMMAND_CANCEL, 0, 1, NULL);
-+                      }
-+              } else {
-+                      /* Auth failure, cancel if they didn't for some reason */
-+                      if (!final) {
-+                              dundi_send(trans, DUNDI_COMMAND_CANCEL, 0, 1, NULL);
-+                      }
-+              }
-+              break;
-+      case DUNDI_COMMAND_INVALID:
-+      case DUNDI_COMMAND_NULL:
-+      case DUNDI_COMMAND_PRECACHERP:
-+              /* Do nothing special */
-+              if (!final) 
-+                      dundi_send(trans, DUNDI_COMMAND_CANCEL, 0, 1, NULL);
-+              break;
-+      case DUNDI_COMMAND_ENCREJ:
-+              if ((trans->flags & FLAG_SENDFULLKEY) || !trans->lasttrans || !(peer = find_peer(&trans->them_eid))) {
-+                      /* No really, it's over at this point */
-+                      if (!final) 
-+                              dundi_send(trans, DUNDI_COMMAND_CANCEL, 0, 1, NULL);
-+              } else {
-+                      /* Send with full key */
-+                      trans->flags |= FLAG_SENDFULLKEY;
-+                      if (final) {
-+                              /* Ooops, we got a final message, start by sending ACK... */
-+                              dundi_ack(trans, hdr->cmdresp & 0x80);
-+                              trans->aseqno = trans->iseqno;
-+                              /* Now, we gotta create a new transaction */
-+                              if (!reset_transaction(trans)) {
-+                                      /* Make sure handle_frame doesn't destroy us */
-+                                      hdr->cmdresp &= 0x7f;
-+                                      /* Parse the message we transmitted */
-+                                      memset(&ies, 0, sizeof(ies));
-+                                      dundi_parse_ies(&ies, trans->lasttrans->h->ies, trans->lasttrans->datalen - sizeof(struct dundi_hdr));
-+                                      /* Reconstruct outgoing encrypted packet */
-+                                      memset(&ied, 0, sizeof(ied));
-+                                      dundi_ie_append_eid(&ied, DUNDI_IE_EID, &trans->us_eid);
-+                                      dundi_ie_append_raw(&ied, DUNDI_IE_SHAREDKEY, peer->txenckey, 128);
-+                                      dundi_ie_append_raw(&ied, DUNDI_IE_SIGNATURE, peer->txenckey + 128, 128);
-+                                      if (ies.encblock) 
-+                                              dundi_ie_append_encdata(&ied, DUNDI_IE_ENCDATA, ies.encblock->iv, ies.encblock->encdata, ies.enclen);
-+                                      dundi_send(trans, DUNDI_COMMAND_ENCRYPT, 0, trans->lasttrans->h->cmdresp & 0x80, &ied);
-+                                      peer->sentfullkey = 1;
-+                              }
-+                      }
-+              }
-+              break;
-+      case DUNDI_COMMAND_ENCRYPT:
-+              if (!encrypted) {
-+                      /* No nested encryption! */
-+                      if ((trans->iseqno == 1) && !trans->oseqno) {
-+                              if (!ies.eids[0] || !(peer = find_peer(ies.eids[0])) || 
-+                                      ((!ies.encsharedkey || !ies.encsig) && !ies.keycrc32) || 
-+                                      (check_key(peer, ies.encsharedkey, ies.encsig, ies.keycrc32) < 1)) {
-+                                      if (!final) {
-+                                              dundi_send(trans, DUNDI_COMMAND_ENCREJ, 0, 1, NULL);
-+                                      }
-+                                      break;
-+                              }
-+                              apply_peer(trans, peer);
-+                              /* Key passed, use new contexts for this session */
-+                              trans->ecx = peer->them_ecx;
-+                              trans->dcx = peer->them_dcx;
-+                      }
-+                      if ((trans->flags & FLAG_ENCRYPT) && ies.encblock && ies.enclen) {
-+                              struct dundi_hdr *dhdr;
-+                              unsigned char decoded[MAX_PACKET_SIZE];
-+                              int ddatalen;
-+                              ddatalen = sizeof(decoded);
-+                              dhdr = dundi_decrypt(trans, decoded, &ddatalen, hdr, ies.encblock, ies.enclen);
-+                              if (dhdr) {
-+                                      /* Handle decrypted response */
-+                                      if (dundidebug)
-+                                              dundi_showframe(dhdr, 3, &trans->addr, ddatalen - sizeof(struct dundi_hdr));
-+                                      handle_command_response(trans, dhdr, ddatalen - sizeof(struct dundi_hdr), 1);
-+                                      /* Carry back final flag */
-+                                      hdr->cmdresp |= dhdr->cmdresp & 0x80;
-+                                      break;
-+                              } else
-+                                      ast_log(LOG_DEBUG, "Ouch, decrypt failed :(\n");
-+                      }
-+              }
-+              if (!final) {
-+                      /* Turn off encryption */
-+                      trans->flags &= ~FLAG_ENCRYPT;
-+                      dundi_send(trans, DUNDI_COMMAND_ENCREJ, 0, 1, NULL);
-+              }
-+              break;
-+      default:
-+              /* Send unknown command if we don't know it, with final flag IFF it's the
-+                 first command in the dialog and only if we haven't recieved final notification */
-+              if (!final) {
-+                      dundi_ie_append_byte(&ied, DUNDI_IE_UNKNOWN, cmd);
-+                      dundi_send(trans, DUNDI_COMMAND_UNKNOWN, 0, !hdr->oseqno, &ied);
-+              }
-+      }
-+      return 0;
-+}
-+
-+static void destroy_packet(struct dundi_packet *pack, int needfree);
-+static void destroy_packets(struct dundi_packet *p)
-+{
-+      struct dundi_packet *prev;
-+      while(p) {
-+              prev = p;
-+              p = p->next;
-+              if (prev->retransid > -1)
-+                      ast_sched_del(sched, prev->retransid);
-+              free(prev);
-+      }
-+}
-+
-+
-+static int ack_trans(struct dundi_transaction *trans, int iseqno)
-+{
-+      /* Ack transmitted packet corresponding to iseqno */
-+      struct dundi_packet *pack;
-+      pack = trans->packets;
-+      while(pack) {
-+              if ((pack->h->oseqno + 1) % 255 == iseqno) {
-+                      destroy_packet(pack, 0);
-+                      if (trans->lasttrans) {
-+                              ast_log(LOG_WARNING, "Whoa, there was still a last trans?\n");
-+                              destroy_packets(trans->lasttrans);
-+                      }
-+                      trans->lasttrans = pack;
-+                      if (trans->autokillid > -1)
-+                              ast_sched_del(sched, trans->autokillid);
-+                      trans->autokillid = -1;
-+                      return 1;
-+              }
-+              pack = pack->next;
-+      }
-+      return 0;
-+}
-+
-+static int handle_frame(struct dundi_hdr *h, struct sockaddr_in *sin, int datalen)
-+{
-+      struct dundi_transaction *trans;
-+      trans = find_transaction(h, sin);
-+      if (!trans) {
-+              dundi_reject(h, sin);
-+              return 0;
-+      }
-+      /* Got a transaction, see where this header fits in */
-+      if (h->oseqno == trans->iseqno) {
-+              /* Just what we were looking for...  Anything but ack increments iseqno */
-+              if (ack_trans(trans, h->iseqno) && (trans->flags & FLAG_FINAL)) {
-+                      /* If final, we're done */
-+                      destroy_trans(trans, 0);
-+                      return 0;
-+              }
-+              if (h->cmdresp != DUNDI_COMMAND_ACK) {
-+                      trans->oiseqno = trans->iseqno;
-+                      trans->iseqno++;
-+                      handle_command_response(trans, h, datalen, 0);
-+              }
-+              if (trans->aseqno != trans->iseqno) {
-+                      dundi_ack(trans, h->cmdresp & 0x80);
-+                      trans->aseqno = trans->iseqno;
-+              }
-+              /* Delete any saved last transmissions */
-+              destroy_packets(trans->lasttrans);
-+              trans->lasttrans = NULL;
-+              if (h->cmdresp & 0x80) {
-+                      /* Final -- destroy now */
-+                      destroy_trans(trans, 0);
-+              }
-+      } else if (h->oseqno == trans->oiseqno) {
-+              /* Last incoming sequence number -- send ACK without processing */
-+              dundi_ack(trans, 0);
-+      } else {
-+              /* Out of window -- simply drop */
-+              ast_log(LOG_DEBUG, "Dropping packet out of window!\n");
-+      }
-+      return 0;
-+}
-+
-+static int socket_read(int *id, int fd, short events, void *cbdata)
-+{
-+      struct sockaddr_in sin;
-+      int res;
-+      struct dundi_hdr *h;
-+      unsigned char buf[MAX_PACKET_SIZE];
-+      int len;
-+      len = sizeof(sin);
-+      res = recvfrom(netsocket, buf, sizeof(buf) - 1, 0,(struct sockaddr *) &sin, &len);
-+      if (res < 0) {
-+              if (errno != ECONNREFUSED)
-+                      ast_log(LOG_WARNING, "Error: %s\n", strerror(errno));
-+              return 1;
-+      }
-+      if (res < sizeof(struct dundi_hdr)) {
-+              ast_log(LOG_WARNING, "midget packet received (%d of %d min)\n", res, (int)sizeof(struct dundi_hdr));
-+              return 1;
-+      }
-+      buf[res] = '\0';
-+      h = (struct dundi_hdr *)buf;
-+      if (dundidebug)
-+              dundi_showframe(h, 1, &sin, res - sizeof(struct dundi_hdr));
-+      ast_mutex_lock(&peerlock);
-+      handle_frame(h, &sin, res - sizeof(struct dundi_hdr));
-+      ast_mutex_unlock(&peerlock);
-+      return 1;
-+}
-+
-+static void build_secret(char *secret, int seclen)
-+{
-+      char tmp[16];
-+      char *s;
-+      build_iv(tmp);
-+      secret[0] = '\0';
-+      ast_base64encode(secret ,tmp, sizeof(tmp), seclen);
-+      /* Eliminate potential bad characters */
-+      while((s = strchr(secret, ';'))) *s = '+';
-+      while((s = strchr(secret, '/'))) *s = '+';
-+      while((s = strchr(secret, ':'))) *s = '+';
-+      while((s = strchr(secret, '@'))) *s = '+';
-+}
-+
-+
-+static void save_secret(const char *newkey, const char *oldkey)
-+{
-+      char tmp[256];
-+      if (oldkey)
-+              snprintf(tmp, sizeof(tmp), "%s;%s", oldkey, newkey);
-+      else
-+              snprintf(tmp, sizeof(tmp), "%s", newkey);
-+      rotatetime = time(NULL) + DUNDI_SECRET_TIME;
-+      ast_db_put(secretpath, "secret", tmp);
-+      snprintf(tmp, sizeof(tmp), "%ld", rotatetime);
-+      ast_db_put(secretpath, "secretexpiry", tmp);
-+}
-+
-+static void load_password(void)
-+{
-+      char *current=NULL;
-+      char *last=NULL;
-+      char tmp[256];
-+      time_t expired;
-+      
-+      ast_db_get(secretpath, "secretexpiry", tmp, sizeof(tmp));
-+      if (sscanf(tmp, "%ld", &expired) == 1) {
-+              ast_db_get(secretpath, "secret", tmp, sizeof(tmp));
-+              current = strchr(tmp, ';');
-+              if (!current)
-+                      current = tmp;
-+              else {
-+                      *current = '\0';
-+                      current++;
-+              };
-+              if ((time(NULL) - expired) < 0) {
-+                      if ((expired - time(NULL)) > DUNDI_SECRET_TIME)
-+                              expired = time(NULL) + DUNDI_SECRET_TIME;
-+              } else if ((time(NULL) - (expired + DUNDI_SECRET_TIME)) < 0) {
-+                      last = current;
-+                      current = NULL;
-+              } else {
-+                      last = NULL;
-+                      current = NULL;
-+              }
-+      }
-+      if (current) {
-+              /* Current key is still valid, just setup rotatation properly */
-+              strncpy(cursecret, current, sizeof(cursecret) - 1);
-+              rotatetime = expired;
-+      } else {
-+              /* Current key is out of date, rotate or eliminate all together */
-+              build_secret(cursecret, sizeof(cursecret));
-+              save_secret(cursecret, last);
-+      }
-+}
-+
-+static void check_password(void)
-+{
-+      char oldsecret[80];
-+      time_t now;
-+      
-+      time(&now);     
-+#if 0
-+      printf("%ld/%ld\n", now, rotatetime);
-+#endif
-+      if ((now - rotatetime) >= 0) {
-+              /* Time to rotate keys */
-+              strncpy(oldsecret, cursecret, sizeof(oldsecret) - 1);
-+              build_secret(cursecret, sizeof(cursecret));
-+              save_secret(cursecret, oldsecret);
-+      }
-+}
-+
-+static void *network_thread(void *ignore)
-+{
-+      /* Our job is simple: Send queued messages, retrying if necessary.  Read frames 
-+         from the network, and queue them for delivery to the channels */
-+      int res;
-+      /* Establish I/O callback for socket read */
-+      ast_io_add(io, netsocket, socket_read, AST_IO_IN, NULL);
-+      for(;;) {
-+              res = ast_sched_wait(sched);
-+              if ((res > 1000) || (res < 0))
-+                      res = 1000;
-+              res = ast_io_wait(io, res);
-+              if (res >= 0) {
-+                      ast_mutex_lock(&peerlock);
-+                      ast_sched_runq(sched);
-+                      ast_mutex_unlock(&peerlock);
-+              }
-+              check_password();
-+      }
-+      return NULL;
-+}
-+
-+static void *process_precache(void *ign)
-+{
-+      struct dundi_precache_queue *qe;
-+      time_t now;
-+      char context[256]="";
-+      char number[256]="";
-+      int run;
-+      for (;;) {
-+              time(&now);
-+              run = 0;
-+              ast_mutex_lock(&pclock);
-+              if (pcq) {
-+                      if (!pcq->expiration) {
-+                              /* Gone...  Remove... */
-+                              qe = pcq;
-+                              pcq = pcq->next;
-+                              free(qe);
-+                      } else if (pcq->expiration < now) {
-+                              /* Process this entry */
-+                              pcq->expiration = 0;
-+                              strncpy(context, pcq->context, sizeof(context) - 1);
-+                              strncpy(number, pcq->number, sizeof(number) - 1);
-+                              run = 1;
-+                      }
-+              }
-+              ast_mutex_unlock(&pclock);
-+              if (run) {
-+                      dundi_precache(context, number);
-+              } else
-+                      sleep(1);
-+      }
-+      return NULL;
-+}
-+
-+static int start_network_thread(void)
-+{
-+      ast_pthread_create(&netthreadid, NULL, network_thread, NULL);
-+      ast_pthread_create(&precachethreadid, NULL, process_precache, NULL);
-+      return 0;
-+}
-+
-+static int dundi_do_debug(int fd, int argc, char *argv[])
-+{
-+      if (argc != 2)
-+              return RESULT_SHOWUSAGE;
-+      dundidebug = 1;
-+      ast_cli(fd, "DUNDi Debugging Enabled\n");
-+      return RESULT_SUCCESS;
-+}
-+
-+static int dundi_do_store_history(int fd, int argc, char *argv[])
-+{
-+      if (argc != 3)
-+              return RESULT_SHOWUSAGE;
-+      global_storehistory = 1;
-+      ast_cli(fd, "DUNDi History Storage Enabled\n");
-+      return RESULT_SUCCESS;
-+}
-+
-+static int dundi_flush(int fd, int argc, char *argv[])
-+{
-+      int stats=0;
-+      if ((argc < 2) || (argc > 3))
-+              return RESULT_SHOWUSAGE;
-+      if (argc > 2) {
-+              if (!strcasecmp(argv[2], "stats"))
-+                      stats = 1;
-+              else
-+                      return RESULT_SHOWUSAGE;
-+      }
-+      if (stats) {
-+              /* Flush statistics */
-+              struct dundi_peer *p;
-+              int x;
-+              ast_mutex_lock(&peerlock);
-+              p = peers;
-+              while(p) {
-+                      for (x=0;x<DUNDI_TIMING_HISTORY;x++) {
-+                              if (p->lookups[x])
-+                                      free(p->lookups[x]);
-+                              p->lookups[x] = NULL;
-+                              p->lookuptimes[x] = 0;
-+                      }
-+                      p->avgms = 0;
-+                      p = p->next;
-+              }
-+              ast_mutex_unlock(&peerlock);
-+      } else {
-+              ast_db_deltree("dundi/cache", NULL);
-+              ast_cli(fd, "DUNDi Cache Flushed\n");
-+      }
-+      return RESULT_SUCCESS;
-+}
-+
-+static int dundi_no_debug(int fd, int argc, char *argv[])
-+{
-+      if (argc != 3)
-+              return RESULT_SHOWUSAGE;
-+      dundidebug = 0;
-+      ast_cli(fd, "DUNDi Debugging Disabled\n");
-+      return RESULT_SUCCESS;
-+}
-+
-+static int dundi_no_store_history(int fd, int argc, char *argv[])
-+{
-+      if (argc != 4)
-+              return RESULT_SHOWUSAGE;
-+      global_storehistory = 0;
-+      ast_cli(fd, "DUNDi History Storage Disabled\n");
-+      return RESULT_SUCCESS;
-+}
-+
-+static char *model2str(int model)
-+{
-+      switch(model) {
-+      case DUNDI_MODEL_INBOUND:
-+              return "Inbound";
-+      case DUNDI_MODEL_OUTBOUND:
-+              return "Outbound";
-+      case DUNDI_MODEL_SYMMETRIC:
-+              return "Symmetric";
-+      default:
-+              return "Unknown";
-+      }
-+}
-+
-+static char *complete_peer_helper(char *line, char *word, int pos, int state, int rpos)
-+{
-+      int which=0;
-+      char *ret;
-+      struct dundi_peer *p;
-+      char eid_str[20];
-+      if (pos != rpos)
-+              return NULL;
-+      ast_mutex_lock(&peerlock);
-+      p = peers;
-+      while(p) {
-+              if (!strncasecmp(word, dundi_eid_to_str(eid_str, sizeof(eid_str), &p->eid), strlen(word))) {
-+                      if (++which > state)
-+                              break;
-+              }
-+              p = p->next;
-+      }
-+      if (p) {
-+              ret = strdup(dundi_eid_to_str(eid_str, sizeof(eid_str), &p->eid));
-+      } else
-+              ret = NULL;
-+      ast_mutex_unlock(&peerlock);
-+      return ret;
-+}
-+
-+static char *complete_peer_4(char *line, char *word, int pos, int state)
-+{
-+      return complete_peer_helper(line, word, pos, state, 3);
-+}
-+
-+static int rescomp(const void *a, const void *b)
-+{
-+      const struct dundi_result *resa, *resb;
-+      resa = a;
-+      resb = b;
-+      if (resa->weight < resb->weight)
-+              return -1;
-+      if (resa->weight > resb->weight)
-+              return 1;
-+      return 0;
-+}
-+
-+static void sort_results(struct dundi_result *results, int count)
-+{
-+      qsort(results, count, sizeof(results[0]), rescomp);
-+}
-+
-+static int dundi_do_lookup(int fd, int argc, char *argv[])
-+{
-+      int res;
-+      char tmp[256] = "";
-+      char fs[80] = "";
-+      char *context;
-+      int x;
-+      int bypass = 0;
-+      struct dundi_result dr[MAX_RESULTS];
-+      struct timeval start;
-+      if ((argc < 3) || (argc > 4))
-+              return RESULT_SHOWUSAGE;
-+      if (argc > 3) {
-+              if (!strcasecmp(argv[3], "bypass"))
-+                      bypass=1;
-+              else
-+                      return RESULT_SHOWUSAGE;
-+      }
-+      strncpy(tmp, argv[2], sizeof(tmp) - 1);
-+      context = strchr(tmp, '@');
-+      if (context) {
-+              *context = '\0';
-+              context++;
-+      }
-+      gettimeofday(&start, NULL);
-+      res = dundi_lookup(dr, MAX_RESULTS, NULL, context, tmp, bypass);
-+      
-+      if (res < 0) 
-+              ast_cli(fd, "DUNDi lookup returned error.\n");
-+      else if (!res) 
-+              ast_cli(fd, "DUNDi lookup returned no results.\n");
-+      else
-+              sort_results(dr, res);
-+      for (x=0;x<res;x++) {
-+              ast_cli(fd, "%3d. %5d %s/%s (%s)\n", x + 1, dr[x].weight, dr[x].tech, dr[x].dest, dundi_flags2str(fs, sizeof(fs), dr[x].flags));
-+              ast_cli(fd, "     from %s, expires in %d s\n", dr[x].eid_str, dr[x].expiration);
-+      }
-+      ast_cli(fd, "DUNDi lookup completed in %d ms\n", calc_ms(&start));
-+      return RESULT_SUCCESS;
-+}
-+
-+static int dundi_do_precache(int fd, int argc, char *argv[])
-+{
-+      int res;
-+      char tmp[256] = "";
-+      char *context;
-+      struct timeval start;
-+      if ((argc < 3) || (argc > 3))
-+              return RESULT_SHOWUSAGE;
-+      strncpy(tmp, argv[2], sizeof(tmp) - 1);
-+      context = strchr(tmp, '@');
-+      if (context) {
-+              *context = '\0';
-+              context++;
-+      }
-+      gettimeofday(&start, NULL);
-+      res = dundi_precache(context, tmp);
-+      
-+      if (res < 0) 
-+              ast_cli(fd, "DUNDi precache returned error.\n");
-+      else if (!res) 
-+              ast_cli(fd, "DUNDi precache returned no error.\n");
-+      ast_cli(fd, "DUNDi lookup completed in %d ms\n", calc_ms(&start));
-+      return RESULT_SUCCESS;
-+}
-+
-+static int dundi_do_query(int fd, int argc, char *argv[])
-+{
-+      int res;
-+      char tmp[256] = "";
-+      char *context;
-+      dundi_eid eid;
-+      struct dundi_entity_info dei;
-+      if ((argc < 3) || (argc > 3))
-+              return RESULT_SHOWUSAGE;
-+      if (dundi_str_to_eid(&eid, argv[2])) {
-+              ast_cli(fd, "'%s' is not a valid EID!\n", argv[2]);
-+              return RESULT_SHOWUSAGE;
-+      }
-+      strncpy(tmp, argv[2], sizeof(tmp) - 1);
-+      context = strchr(tmp, '@');
-+      if (context) {
-+              *context = '\0';
-+              context++;
-+      }
-+      res = dundi_query_eid(&dei, context, eid);
-+      if (res < 0) 
-+              ast_cli(fd, "DUNDi Query EID returned error.\n");
-+      else if (!res) 
-+              ast_cli(fd, "DUNDi Query EID returned no results.\n");
-+      else {
-+              ast_cli(fd, "DUNDi Query EID succeeded:\n");
-+              ast_cli(fd, "Department:      %s\n", dei.orgunit);
-+              ast_cli(fd, "Organization:    %s\n", dei.org);
-+              ast_cli(fd, "City/Locality:   %s\n", dei.locality);
-+              ast_cli(fd, "State/Province:  %s\n", dei.stateprov);
-+              ast_cli(fd, "Country:         %s\n", dei.country);
-+              ast_cli(fd, "E-mail:          %s\n", dei.email);
-+              ast_cli(fd, "Phone:           %s\n", dei.phone);
-+              ast_cli(fd, "IP Address:      %s\n", dei.ipaddr);
-+      }
-+      return RESULT_SUCCESS;
-+}
-+
-+static int dundi_show_peer(int fd, int argc, char *argv[])
-+{
-+      struct dundi_peer *peer;
-+      struct permission *p;
-+      char *order;
-+      char iabuf[INET_ADDRSTRLEN];
-+      char eid_str[20];
-+      int x, cnt;
-+      
-+      if (argc != 4)
-+              return RESULT_SHOWUSAGE;
-+      ast_mutex_lock(&peerlock);
-+      peer = peers;
-+      while(peer) {
-+              if (!strcasecmp(dundi_eid_to_str(eid_str, sizeof(eid_str), &peer->eid), argv[3]))
-+                      break;
-+              peer = peer->next;
-+      }
-+      if (peer) {
-+              switch(peer->order) {
-+              case 0:
-+                      order = "Primary";
-+                      break;
-+              case 1:
-+                      order = "Secondary";
-+                      break;
-+              case 2:
-+                      order = "Tertiary";
-+                      break;
-+              case 3:
-+                      order = "Quartiary";
-+                      break;
-+              default:
-+                      order = "Unknown";
-+              }
-+              ast_cli(fd, "Peer:    %s\n", dundi_eid_to_str(eid_str, sizeof(eid_str), &peer->eid));
-+              ast_cli(fd, "Model:   %s\n", model2str(peer->model));
-+              ast_cli(fd, "Order:   %s\n", order);
-+              ast_cli(fd, "Host:    %s\n", peer->addr.sin_addr.s_addr ? ast_inet_ntoa(iabuf, sizeof(iabuf), peer->addr.sin_addr) : "<Unspecified>");
-+              ast_cli(fd, "Dynamic: %s\n", peer->dynamic ? "yes" : "no");
-+              ast_cli(fd, "KeyPend: %s\n", peer->keypending ? "yes" : "no");
-+              ast_cli(fd, "Reg:     %s\n", peer->registerid < 0 ? "No" : "Yes");
-+              ast_cli(fd, "In Key:  %s\n", ast_strlen_zero(peer->inkey) ? "<None>" : peer->inkey);
-+              ast_cli(fd, "Out Key: %s\n", ast_strlen_zero(peer->outkey) ? "<None>" : peer->outkey);
-+              if (peer->include) {
-+                      ast_cli(fd, "Include logic%s:\n", peer->model & DUNDI_MODEL_OUTBOUND ? "" : " (IGNORED)");
-+              }
-+              p = peer->include;
-+              while(p) {
-+                      ast_cli(fd, "-- %s %s\n", p->allow ? "include" : "do not include", p->name);
-+                      p = p->next;
-+              }
-+              if (peer->permit) {
-+                      ast_cli(fd, "Query logic%s:\n", peer->model & DUNDI_MODEL_INBOUND ? "" : " (IGNORED)");
-+              }
-+              p = peer->permit;
-+              while(p) {
-+                      ast_cli(fd, "-- %s %s\n", p->allow ? "permit" : "deny", p->name);
-+                      p = p->next;
-+              }
-+              cnt = 0;
-+              for (x=0;x<DUNDI_TIMING_HISTORY;x++) {
-+                      if (peer->lookups[x]) {
-+                              if (!cnt)
-+                                      ast_cli(fd, "Last few query times:\n");
-+                              ast_cli(fd, "-- %d. %s (%d ms)\n", x + 1, peer->lookups[x], peer->lookuptimes[x]);
-+                              cnt++;
-+                      }
-+              }
-+              if (cnt)
-+                      ast_cli(fd, "Average query time: %d ms\n", peer->avgms);
-+      } else
-+              ast_cli(fd, "No such peer '%s'\n", argv[3]);
-+      ast_mutex_unlock(&peerlock);
-+      return RESULT_SUCCESS;
-+}
-+
-+static int dundi_show_peers(int fd, int argc, char *argv[])
-+{
-+#define FORMAT2 "%-20.20s %-15.15s     %-10.10s %-10.10s %-8.8s %-15.15s\n"
-+#define FORMAT "%-20.20s %-15.15s %s %-10.10s %-10.10s %-8.8s %-15.15s\n"
-+      struct dundi_peer *peer;
-+      char iabuf[INET_ADDRSTRLEN];
-+      int registeredonly=0;
-+      char avgms[20];
-+      char eid_str[20];
-+      char *order = NULL;
-+
-+      if ((argc != 3) && (argc != 4) && (argc != 5))
-+              return RESULT_SHOWUSAGE;
-+      if ((argc == 4)) {
-+              if (!strcasecmp(argv[3], "registered")) {
-+                      registeredonly = 1;
-+              } else
-+                      return RESULT_SHOWUSAGE;
-+      }
-+      ast_mutex_lock(&peerlock);
-+      ast_cli(fd, FORMAT2, "EID", "Host", "Model", "Order", "AvgTime", "Status");
-+      for (peer = peers;peer;peer = peer->next) {
-+              char status[20] = "";
-+        int print_line = -1;
-+              char srch[2000] = "";
-+              if (registeredonly && !peer->addr.sin_addr.s_addr)
-+                      continue;
-+              if (peer->maxms) {
-+                      if (peer->lastms < 0)
-+                              strncpy(status, "UNREACHABLE", sizeof(status) - 1);
-+                      else if (peer->lastms > peer->maxms) 
-+                              snprintf(status, sizeof(status), "LAGGED (%d ms)", peer->lastms);
-+                      else if (peer->lastms) 
-+                              snprintf(status, sizeof(status), "OK (%d ms)", peer->lastms);
-+                      else 
-+                              strncpy(status, "UNKNOWN", sizeof(status) - 1);
-+              } else 
-+                      strncpy(status, "Unmonitored", sizeof(status) - 1);
-+              if (peer->avgms) 
-+                      snprintf(avgms, sizeof(avgms), "%d ms", peer->avgms);
-+              else
-+                      strcpy(avgms, "Unavail");
-+              switch(peer->order) {
-+              case 0:
-+                      order = "Primary";
-+                      break;
-+              case 1:
-+                      order = "Secondary";
-+                      break;
-+              case 2:
-+                      order = "Tertiary";
-+                      break;
-+              case 3:
-+                      order = "Quartiary";
-+                      break;
-+              default:
-+                      order = "Unknown";
-+              }
-+              snprintf(srch, sizeof(srch), FORMAT, dundi_eid_to_str(eid_str, sizeof(eid_str), &peer->eid), 
-+                                      peer->addr.sin_addr.s_addr ? ast_inet_ntoa(iabuf, sizeof(iabuf), peer->addr.sin_addr) : "(Unspecified)",
-+                                      peer->dynamic ? "(D)" : "(S)", model2str(peer->model), order, avgms, status);
-+
-+                if (argc == 5) {
-+                  if (!strcasecmp(argv[3],"include") && strstr(srch,argv[4])) {
-+                        print_line = -1;
-+                   } else if (!strcasecmp(argv[3],"exclude") && !strstr(srch,argv[4])) {
-+                        print_line = 1;
-+                   } else if (!strcasecmp(argv[3],"begin") && !strncasecmp(srch,argv[4],strlen(argv[4]))) {
-+                        print_line = -1;
-+                   } else {
-+                        print_line = 0;
-+                  }
-+                }
-+              
-+        if (print_line) {
-+                      ast_cli(fd, FORMAT, dundi_eid_to_str(eid_str, sizeof(eid_str), &peer->eid), 
-+                                      peer->addr.sin_addr.s_addr ? ast_inet_ntoa(iabuf, sizeof(iabuf), peer->addr.sin_addr) : "(Unspecified)",
-+                                      peer->dynamic ? "(D)" : "(S)", model2str(peer->model), order, avgms, status);
-+              }
-+      }
-+      ast_mutex_unlock(&peerlock);
-+      return RESULT_SUCCESS;
-+#undef FORMAT
-+#undef FORMAT2
-+}
-+
-+static int dundi_show_trans(int fd, int argc, char *argv[])
-+{
-+#define FORMAT2 "%-22.22s %-5.5s %-5.5s %-3.3s %-3.3s %-3.3s\n"
-+#define FORMAT "%-16.16s:%5d %-5.5d %-5.5d %-3.3d %-3.3d %-3.3d\n"
-+      struct dundi_transaction *trans;
-+      char iabuf[INET_ADDRSTRLEN];
-+      if (argc != 3)
-+              return RESULT_SHOWUSAGE;
-+      ast_mutex_lock(&peerlock);
-+      ast_cli(fd, FORMAT2, "Remote", "Src", "Dst", "Tx", "Rx", "Ack");
-+      for (trans = alltrans;trans;trans = trans->allnext) {
-+                      ast_cli(fd, FORMAT, ast_inet_ntoa(iabuf, sizeof(iabuf), trans->addr.sin_addr), 
-+                                      ntohs(trans->addr.sin_port), trans->strans, trans->dtrans, trans->oseqno, trans->iseqno, trans->aseqno);
-+      }
-+      ast_mutex_unlock(&peerlock);
-+      return RESULT_SUCCESS;
-+#undef FORMAT
-+#undef FORMAT2
-+}
-+
-+static int dundi_show_entityid(int fd, int argc, char *argv[])
-+{
-+      char eid_str[20];
-+      if (argc != 3)
-+              return RESULT_SHOWUSAGE;
-+      ast_mutex_lock(&peerlock);
-+      dundi_eid_to_str(eid_str, sizeof(eid_str), &global_eid);
-+      ast_mutex_unlock(&peerlock);
-+      ast_cli(fd, "Global EID for this system is '%s'\n", eid_str);
-+      return RESULT_SUCCESS;
-+}
-+
-+static int dundi_show_requests(int fd, int argc, char *argv[])
-+{
-+#define FORMAT2 "%-15s %-15s %-15s %-3.3s %-3.3s\n"
-+#define FORMAT "%-15s %-15s %-15s %-3.3d %-3.3d\n"
-+      struct dundi_request *req;
-+      char eidstr[20];
-+      if (argc != 3)
-+              return RESULT_SHOWUSAGE;
-+      ast_mutex_lock(&peerlock);
-+      ast_cli(fd, FORMAT2, "Number", "Context", "Root", "Max", "Rsp");
-+      for (req = requests;req;req = req->next) {
-+                      ast_cli(fd, FORMAT, req->number, req->dcontext,
-+                                              dundi_eid_zero(&req->root_eid) ? "<unspecified>" : dundi_eid_to_str(eidstr, sizeof(eidstr), &req->root_eid), req->maxcount, req->respcount);
-+      }
-+      ast_mutex_unlock(&peerlock);
-+      return RESULT_SUCCESS;
-+#undef FORMAT
-+#undef FORMAT2
-+}
-+
-+/* Grok-a-dial DUNDi */
-+
-+static int dundi_show_mappings(int fd, int argc, char *argv[])
-+{
-+#define FORMAT2 "%-12.12s %-7.7s %-12.12s %-10.10s %-5.5s %-25.25s\n"
-+#define FORMAT "%-12.12s %-7d %-12.12s %-10.10s %-5.5s %-25.25s\n"
-+      struct dundi_mapping *map;
-+      char fs[256];
-+      if (argc != 3)
-+              return RESULT_SHOWUSAGE;
-+      ast_mutex_lock(&peerlock);
-+      ast_cli(fd, FORMAT2, "DUNDi Cntxt", "Weight", "Local Cntxt", "Options", "Tech", "Destination");
-+      for (map = mappings;map;map = map->next) {
-+                      ast_cli(fd, FORMAT, map->dcontext, map->weight, 
-+                                          ast_strlen_zero(map->lcontext) ? "<none>" : map->lcontext, 
-+                                                              dundi_flags2str(fs, sizeof(fs), map->options), tech2str(map->tech), map->dest);
-+      }
-+      ast_mutex_unlock(&peerlock);
-+      return RESULT_SUCCESS;
-+#undef FORMAT
-+#undef FORMAT2
-+}
-+
-+static int dundi_show_precache(int fd, int argc, char *argv[])
-+{
-+#define FORMAT2 "%-12.12s %-12.12s %-10.10s\n"
-+#define FORMAT "%-12.12s %-12.12s %02d:%02d:%02d\n"
-+      struct dundi_precache_queue *qe;
-+      int h,m,s;
-+      time_t now;
-+      
-+      if (argc != 3)
-+              return RESULT_SHOWUSAGE;
-+      time(&now);
-+      ast_mutex_lock(&pclock);
-+      ast_cli(fd, FORMAT2, "Number", "Context", "Expiration");
-+      for (qe = pcq;qe;qe = qe->next) {
-+              s = qe->expiration - now;
-+              h = s / 3600;
-+              s = s % 3600;
-+              m = s / 60;
-+              s = s % 60;
-+              ast_cli(fd, FORMAT, qe->number, qe->context, h,m,s);
-+      }
-+      ast_mutex_unlock(&pclock);
-+      return RESULT_SUCCESS;
-+#undef FORMAT
-+#undef FORMAT2
-+}
-+
-+static char debug_usage[] = 
-+"Usage: dundi debug\n"
-+"       Enables dumping of DUNDi packets for debugging purposes\n";
-+
-+static char no_debug_usage[] = 
-+"Usage: dundi no debug\n"
-+"       Disables dumping of DUNDi packets for debugging purposes\n";
-+
-+static char store_history_usage[] = 
-+"Usage: dundi store history\n"
-+"       Enables storing of DUNDi requests and times for debugging\n"
-+"purposes\n";
-+
-+static char no_store_history_usage[] = 
-+"Usage: dundi no store history\n"
-+"       Disables storing of DUNDi requests and times for debugging\n"
-+"purposes\n";
-+
-+static char show_peers_usage[] = 
-+"Usage: dundi show peers\n"
-+"       Lists all known DUNDi peers.\n";
-+
-+static char show_trans_usage[] = 
-+"Usage: dundi show trans\n"
-+"       Lists all known DUNDi transactions.\n";
-+
-+static char show_mappings_usage[] = 
-+"Usage: dundi show mappings\n"
-+"       Lists all known DUNDi mappings.\n";
-+
-+static char show_precache_usage[] = 
-+"Usage: dundi show precache\n"
-+"       Lists all known DUNDi scheduled precache updates.\n";
-+
-+static char show_entityid_usage[] = 
-+"Usage: dundi show entityid\n"
-+"       Displays the global entityid for this host.\n";
-+
-+static char show_peer_usage[] = 
-+"Usage: dundi show peer [peer]\n"
-+"       Provide a detailed description of a specifid DUNDi peer.\n";
-+
-+static char show_requests_usage[] = 
-+"Usage: dundi show requests\n"
-+"       Lists all known pending DUNDi requests.\n";
-+
-+static char lookup_usage[] =
-+"Usage: dundi lookup <number>[@context] [bypass]\n"
-+"       Lookup the given number within the given DUNDi context\n"
-+"(or e164 if none is specified).  Bypasses cache if 'bypass'\n"
-+"keyword is specified.\n";
-+
-+static char precache_usage[] =
-+"Usage: dundi precache <number>[@context]\n"
-+"       Lookup the given number within the given DUNDi context\n"
-+"(or e164 if none is specified) and precaches the results to any\n"
-+"upstream DUNDi push servers.\n";
-+
-+static char query_usage[] =
-+"Usage: dundi query <entity>[@context]\n"
-+"       Attempts to retrieve contact information for a specific\n"
-+"DUNDi entity identifier (EID) within a given DUNDi context (or\n"
-+"e164 if none is specified).\n";
-+
-+static char flush_usage[] =
-+"Usage: dundi flush [stats]\n"
-+"       Flushes DUNDi answer cache, used primarily for debug.  If\n"
-+"'stats' is present, clears timer statistics instead of normal\n"
-+"operation.\n";
-+
-+static struct ast_cli_entry  cli_debug =
-+      { { "dundi", "debug", NULL }, dundi_do_debug, "Enable DUNDi debugging", debug_usage };
-+
-+static struct ast_cli_entry  cli_store_history =
-+      { { "dundi", "store", "history", NULL }, dundi_do_store_history, "Enable DUNDi historic records", store_history_usage };
-+
-+static struct ast_cli_entry  cli_no_store_history =
-+      { { "dundi", "no", "store", "history", NULL }, dundi_no_store_history, "Disable DUNDi historic records", no_store_history_usage };
-+
-+static struct ast_cli_entry  cli_flush =
-+      { { "dundi", "flush", NULL }, dundi_flush, "Flush DUNDi cache", flush_usage };
-+
-+static struct ast_cli_entry  cli_no_debug =
-+      { { "dundi", "no", "debug", NULL }, dundi_no_debug, "Disable DUNDi debugging", no_debug_usage };
-+
-+static struct ast_cli_entry  cli_show_peers =
-+      { { "dundi", "show", "peers", NULL }, dundi_show_peers, "Show defined DUNDi peers", show_peers_usage };
-+
-+static struct ast_cli_entry  cli_show_trans =
-+      { { "dundi", "show", "trans", NULL }, dundi_show_trans, "Show active DUNDi transactions", show_trans_usage };
-+
-+static struct ast_cli_entry  cli_show_entityid =
-+      { { "dundi", "show", "entityid", NULL }, dundi_show_entityid, "Display Global Entity ID", show_entityid_usage };
-+
-+static struct ast_cli_entry  cli_show_mappings =
-+      { { "dundi", "show", "mappings", NULL }, dundi_show_mappings, "Show DUNDi mappings", show_mappings_usage };
-+
-+static struct ast_cli_entry  cli_show_precache =
-+      { { "dundi", "show", "precache", NULL }, dundi_show_precache, "Show DUNDi precache", show_precache_usage };
-+
-+static struct ast_cli_entry  cli_show_requests =
-+      { { "dundi", "show", "requests", NULL }, dundi_show_requests, "Show DUNDi requests", show_requests_usage };
-+
-+static struct ast_cli_entry  cli_show_peer =
-+      { { "dundi", "show", "peer", NULL }, dundi_show_peer, "Show info on a specific DUNDi peer", show_peer_usage, complete_peer_4 };
-+
-+static struct ast_cli_entry  cli_lookup =
-+      { { "dundi", "lookup", NULL }, dundi_do_lookup, "Lookup a number in DUNDi", lookup_usage };
-+
-+static struct ast_cli_entry  cli_precache =
-+      { { "dundi", "precache", NULL }, dundi_do_precache, "Precache a number in DUNDi", precache_usage };
-+
-+static struct ast_cli_entry  cli_queryeid =
-+      { { "dundi", "query", NULL }, dundi_do_query, "Query a DUNDi EID", query_usage };
-+
-+STANDARD_LOCAL_USER;
-+
-+LOCAL_USER_DECL;
-+
-+static struct dundi_transaction *create_transaction(struct dundi_peer *p)
-+{
-+      struct dundi_transaction *trans;
-+      int tid;
-+      
-+      /* Don't allow creation of transactions to non-registered peers */
-+      if (p && !p->addr.sin_addr.s_addr)
-+              return NULL;
-+      tid = get_trans_id();
-+      if (tid < 1)
-+              return NULL;
-+      trans = malloc(sizeof(struct dundi_transaction));
-+      if (trans) {
-+              memset(trans, 0, sizeof(struct dundi_transaction));
-+              if (global_storehistory) {
-+                      gettimeofday(&trans->start, NULL);
-+                      trans->flags |= FLAG_STOREHIST;
-+              }
-+              trans->retranstimer = DUNDI_DEFAULT_RETRANS_TIMER;
-+              trans->autokillid = -1;
-+              if (p) {
-+                      apply_peer(trans, p);
-+                      if (!p->sentfullkey)
-+                              trans->flags |= FLAG_SENDFULLKEY;
-+              }
-+              trans->strans = tid;
-+              trans->allnext = alltrans;
-+              alltrans = trans;
-+      }
-+      return trans;
-+}
-+
-+static int dundi_xmit(struct dundi_packet *pack)
-+{
-+      int res;
-+      char iabuf[INET_ADDRSTRLEN];
-+      if (dundidebug)
-+              dundi_showframe(pack->h, 0, &pack->parent->addr, pack->datalen - sizeof(struct dundi_hdr));
-+      res = sendto(netsocket, pack->data, pack->datalen, 0, (struct sockaddr *)&pack->parent->addr, sizeof(pack->parent->addr));
-+      if (res < 0) {
-+              ast_log(LOG_WARNING, "Failed to transmit to '%s:%d': %s\n", 
-+                      ast_inet_ntoa(iabuf, sizeof(iabuf), pack->parent->addr.sin_addr),
-+                      ntohs(pack->parent->addr.sin_port), strerror(errno));
-+      }
-+      if (res > 0)
-+              res = 0;
-+      return res;
-+}
-+
-+static inline char *dstatus_append_long(char *buf, long val) {
-+      val = htonl(val);
-+      memcpy(buf, &val, sizeof(long));
-+      return (buf + sizeof(long));
-+}
-+
-+static inline char *dstatus_append_short(char *buf, short val) {
-+      val = htons(val);
-+      memcpy(buf, &val, sizeof(short));
-+      return (buf + sizeof(short));
-+}
-+
-+static inline char *dstatus_append_string(char *buf, char *str) {
-+      unsigned short len = (unsigned short)strlen(str);
-+      buf = dstatus_append_short(buf, len);
-+      memcpy(buf, str, len);
-+      return (buf + len);
-+}
-+
-+/* Create a packet for the DUNDi Status Updates */
-+static char *dstatus_v2_pkt_header(char *buf, char pkt_type, time_t ts, short seq, short totseq) {
-+      *buf++ = '\003';
-+      *buf++ = pkt_type;
-+
-+      /* Timestamp this sequence */
-+      buf = dstatus_append_long(buf, ts);
-+
-+      /* Setup sequence headers */
-+      buf = dstatus_append_short(buf, seq);
-+      buf = dstatus_append_short(buf, totseq);
-+
-+      /* Append our global EID */
-+      memcpy(buf, &global_eid, sizeof(global_eid));
-+      buf += sizeof(global_eid);
-+
-+      buf = dstatus_append_string(buf, map_context);
-+
-+      return buf;
-+}
-+
-+static int dundi_xmit_peering(void *data)
-+{
-+      char buf[1500];
-+      char *ptr = buf;
-+      short seq = 1, totseq = 0;
-+      int need_send = 0, peer_count = 0;
-+      struct dundi_peer *peer;
-+      time_t send_t = time(NULL);
-+
-+      /* If we have no where to send, don't bother */
-+      if(!map_addr.sin_addr.s_addr) {
-+              if(option_verbose)
-+                      ast_verbose(VERBOSE_PREFIX_1 "No server to send mapping update to...\n");
-+              map_peering_sid = ast_sched_add(sched, map_update_interval, dundi_xmit_peering, 0);
-+              return 0;
-+      }
-+   
-+      /* Provide a sequence number for the packet and totals */
-+      ast_mutex_lock(&peerlock);
-+      for (peer = peers;peer;peer = peer->next) {
-+              if(has_permission(peer->include, map_context) || has_permission(peer->permit, map_context)) {
-+                      peer_count++;
-+                      need_send = 1;
-+                      if(peer_count == map_updates_per_pkt) {
-+                              peer_count = 0;
-+                              need_send = 0;
-+                              totseq++;
-+                      }
-+              }
-+      }
-+      totseq += need_send;
-+
-+      /* Initialize the packet header */
-+      ptr = dstatus_v2_pkt_header(buf, 1, send_t, seq, totseq);
-+
-+      /* Include our update interval, in seconds */
-+      ptr = dstatus_append_short(ptr, map_update_interval/1000);
-+
-+      /* Include peers/packet configured */
-+      *ptr++ = (unsigned char)map_updates_per_pkt;
-+
-+      peer_count = 0;
-+      need_send = 0;
-+      for (peer = peers;peer;peer = peer->next) {
-+              if(!has_permission(peer->include, map_context) && !has_permission(peer->permit, map_context))
-+                      continue;
-+
-+              peer_count++;
-+              need_send = 1;
-+
-+              /* Copy the peers EID */
-+              memcpy(ptr, &peer->eid, sizeof(peer->eid));
-+              ptr += sizeof(peer->eid);
-+
-+              /* This is the remote peer */
-+              *ptr++ = (peer->dynamic?0:1);
-+              memcpy(ptr, &peer->addr.sin_addr.s_addr, sizeof(peer->addr.sin_addr.s_addr));
-+              ptr += sizeof(peer->addr.sin_addr.s_addr);
-+
-+              /* Append the model and order */
-+              *ptr++ = peer->model;
-+              *ptr++ = peer->order;
-+
-+              /* Do some long encoding of the timings */
-+              ptr = dstatus_append_long(ptr, peer->maxms);
-+              ptr = dstatus_append_long(ptr, peer->lastms);
-+              ptr = dstatus_append_long(ptr, peer->avgms);
-+
-+              if(peer_count == map_updates_per_pkt) { /* Okay, it's actually arbitrary */
-+                      peer_count = 0;
-+                      need_send = 0;
-+                      sendto(netsocket, buf, ptr - buf, 0, (struct sockaddr *)&map_addr, sizeof(map_addr));
-+                      seq++; /* We sent one, so move on */
-+
-+                      ptr = dstatus_v2_pkt_header(buf, 1, send_t, seq, totseq);
-+                      /* Include our update interval, in seconds */
-+                      ptr = dstatus_append_short(ptr, map_update_interval/1000);
-+
-+                      /* Include peers/packet configured */
-+                      *ptr++ = (unsigned char)map_updates_per_pkt;
-+              }
-+      }
-+
-+      /* If we get here, and haven't sent the packet, send it now */
-+      if(need_send) 
-+              sendto(netsocket, buf, ptr - buf, 0, (struct sockaddr *)&map_addr, sizeof(map_addr));
-+   
-+      /* Unlock */
-+      ast_mutex_unlock(&peerlock);
-+
-+      /* Reschedule yourselves */
-+      map_peering_sid = ast_sched_add(sched, map_update_interval, dundi_xmit_peering, 0);
-+      return RESULT_SUCCESS;   
-+}
-+
-+static int dundi_xmit_contact(void *data) {
-+      char buf[1500];
-+      char *ptr = buf;
-+
-+      /* Packet type 2, sent now, 1/1 packets */
-+      ptr = dstatus_v2_pkt_header(buf, 2, time(NULL), 1, 1);
-+      
-+      ptr = dstatus_append_string(ptr, dept);
-+      ptr = dstatus_append_string(ptr, org);
-+      ptr = dstatus_append_string(ptr, locality);
-+      ptr = dstatus_append_string(ptr, stateprov);
-+      ptr = dstatus_append_string(ptr, country);
-+      ptr = dstatus_append_string(ptr, email);
-+      ptr = dstatus_append_string(ptr, phone);
-+
-+      sendto(netsocket, buf, ptr - buf, 0, (struct sockaddr *)&map_addr, sizeof(map_addr));
-+
-+      map_contact_sid = ast_sched_add(sched, map_update_interval * 5, dundi_xmit_contact, 0);
-+      return RESULT_SUCCESS;
-+}
-+
-+static void destroy_packet(struct dundi_packet *pack, int needfree)
-+{
-+      struct dundi_packet *prev, *cur;
-+      if (pack->parent) {
-+              prev = NULL;
-+              cur = pack->parent->packets;
-+              while(cur) {
-+                      if (cur == pack) {
-+                              if (prev)
-+                                      prev->next = cur->next;
-+                              else
-+                                      pack->parent->packets = cur->next;
-+                              break;
-+                      }
-+                      prev = cur;
-+                      cur = cur->next;
-+              }
-+      }
-+      if (pack->retransid > -1)
-+              ast_sched_del(sched, pack->retransid);
-+      if (needfree)
-+              free(pack);
-+      else {
-+              pack->retransid = -1;
-+              pack->next = NULL;
-+      }
-+}
-+
-+static void destroy_trans(struct dundi_transaction *trans, int fromtimeout)
-+{
-+      struct dundi_transaction *cur, *prev;
-+      struct dundi_peer *peer;
-+      struct timeval tv;
-+      int ms;
-+      int x;
-+      int cnt;
-+      char eid_str[20];
-+      if (trans->flags & (FLAG_ISREG | FLAG_ISQUAL | FLAG_STOREHIST)) {
-+              peer = peers;
-+              while (peer) {
-+                      if (peer->regtrans == trans)
-+                              peer->regtrans = NULL;
-+                      if (peer->keypending == trans)
-+                              peer->keypending = NULL;
-+                      if (peer->qualtrans == trans) {
-+                              if (fromtimeout) {
-+                                      if (peer->lastms > -1)
-+                                              ast_log(LOG_NOTICE, "Peer '%s' has become UNREACHABLE!\n", dundi_eid_to_str(eid_str, sizeof(eid_str), &peer->eid));
-+                                      peer->lastms = -1;
-+                              } else {
-+                                      gettimeofday(&tv, NULL);
-+                                      ms = (tv.tv_sec - peer->qualtx.tv_sec) * 1000 + 
-+                                                      (tv.tv_usec - peer->qualtx.tv_usec) / 1000;
-+                                      if (ms < 1)
-+                                              ms = 1;
-+                                      if (ms < peer->maxms) {
-+                                              if ((peer->lastms >= peer->maxms) || (peer->lastms < 0))
-+                                                      ast_log(LOG_NOTICE, "Peer '%s' has become REACHABLE!\n", dundi_eid_to_str(eid_str, sizeof(eid_str), &peer->eid));
-+                                      } else if (peer->lastms < peer->maxms) {
-+                                              ast_log(LOG_NOTICE, "Peer '%s' has become TOO LAGGED (%d ms)\n", dundi_eid_to_str(eid_str, sizeof(eid_str), &peer->eid), ms);
-+                                      }
-+                                      peer->lastms = ms;
-+                              }
-+                              peer->qualtrans = NULL;
-+                      }
-+                      if (trans->flags & FLAG_STOREHIST) {
-+                              if (trans->parent && !ast_strlen_zero(trans->parent->number)) {
-+                                      if (!dundi_eid_cmp(&trans->them_eid, &peer->eid)) {
-+                                              peer->avgms = 0;
-+                                              cnt = 0;
-+                                              if (peer->lookups[DUNDI_TIMING_HISTORY-1])
-+                                                      free(peer->lookups[DUNDI_TIMING_HISTORY-1]);
-+                                              for (x=DUNDI_TIMING_HISTORY-1;x>0;x--) {
-+                                                      peer->lookuptimes[x] = peer->lookuptimes[x-1];
-+                                                      peer->lookups[x] = peer->lookups[x-1];
-+                                                      if (peer->lookups[x]) {
-+                                                              peer->avgms += peer->lookuptimes[x];
-+                                                              cnt++;
-+                                                      }
-+                                              }
-+                                              peer->lookuptimes[0] = calc_ms(&trans->start);
-+                                              peer->lookups[0] = malloc(strlen(trans->parent->number) + strlen(trans->parent->dcontext) + 2);
-+                                              if (peer->lookups[0]) {
-+                                                      sprintf(peer->lookups[0], "%s@%s", trans->parent->number, trans->parent->dcontext);
-+                                                      peer->avgms += peer->lookuptimes[0];
-+                                                      cnt++;
-+                                              }
-+                                              if (cnt)
-+                                                      peer->avgms /= cnt;
-+                                      }
-+                              }
-+                      }
-+                      peer = peer->next;
-+              }
-+      }
-+      if (trans->parent) {
-+              /* Unlink from parent if appropriate */
-+              prev = NULL;
-+              cur = trans->parent->trans;
-+              while(cur) {
-+                      if (cur == trans) {
-+                              if (prev)
-+                                      prev->next = trans->next;
-+                              else
-+                                      trans->parent->trans = trans->next;
-+                              break;
-+                      }
-+                      prev = cur;
-+                      cur = cur->next;
-+              }
-+              if (!trans->parent->trans) {
-+                      /* Wake up sleeper */
-+                      if (trans->parent->pfds[1] > -1) {
-+                              write(trans->parent->pfds[1], "killa!", 6);
-+                      }
-+              }
-+      }
-+      /* Unlink from all trans */
-+      prev = NULL;
-+      cur = alltrans;
-+      while(cur) {
-+              if (cur == trans) {
-+                      if (prev)
-+                              prev->allnext = trans->allnext;
-+                      else
-+                              alltrans = trans->allnext;
-+                      break;
-+              }
-+              prev = cur;
-+              cur = cur->allnext;
-+      }
-+      destroy_packets(trans->packets);
-+      destroy_packets(trans->lasttrans);
-+      trans->packets = NULL;
-+      if (trans->autokillid > -1)
-+              ast_sched_del(sched, trans->autokillid);
-+      trans->autokillid = -1;
-+      if (trans->thread) {
-+              /* If used by a thread, mark as dead and be done */
-+              trans->flags |= FLAG_DEAD;
-+      } else
-+              free(trans);
-+}
-+
-+static int dundi_rexmit(void *data)
-+{
-+      struct dundi_packet *pack;
-+      char iabuf[INET_ADDRSTRLEN];
-+      int res;
-+      ast_mutex_lock(&peerlock);
-+      pack = data;
-+      if (pack->retrans < 1) {
-+              pack->retransid = -1;
-+              if (!(pack->parent->flags & FLAG_ISQUAL))
-+                      ast_log(LOG_NOTICE, "Max retries exceeded to host '%s:%d' msg %d on call %d\n", 
-+                              ast_inet_ntoa(iabuf, sizeof(iabuf), pack->parent->addr.sin_addr), 
-+                              ntohs(pack->parent->addr.sin_port), pack->h->oseqno, ntohs(pack->h->strans));
-+              destroy_trans(pack->parent, 1);
-+              res = 0;
-+      } else {
-+              /* Decrement retransmission, try again */
-+              pack->retrans--;
-+              dundi_xmit(pack);
-+              res = 1;
-+      }
-+      ast_mutex_unlock(&peerlock);
-+      return res;
-+}
-+
-+static int dundi_send(struct dundi_transaction *trans, int cmdresp, int flags, int final, struct dundi_ie_data *ied)
-+{
-+      struct dundi_packet *pack;
-+      int res;
-+      int len;
-+      char eid_str[20];
-+      len = sizeof(struct dundi_packet) + sizeof(struct dundi_hdr) + (ied ? ied->pos : 0);
-+      /* Reserve enough space for encryption */
-+      if (trans->flags & FLAG_ENCRYPT)
-+              len += 384;
-+      pack = malloc(len);
-+      if (pack) {
-+              memset(pack, 0, len);
-+              pack->h = (struct dundi_hdr *)(pack->data);
-+              if (cmdresp != DUNDI_COMMAND_ACK) {
-+                      pack->retransid = ast_sched_add(sched, trans->retranstimer, dundi_rexmit, pack);
-+                      pack->retrans = DUNDI_DEFAULT_RETRANS - 1;
-+                      pack->next = trans->packets;
-+                      trans->packets = pack;
-+              }
-+              pack->parent = trans;
-+              pack->h->strans = htons(trans->strans);
-+              pack->h->dtrans = htons(trans->dtrans);
-+              pack->h->iseqno = trans->iseqno;
-+              pack->h->oseqno = trans->oseqno;
-+              pack->h->cmdresp = cmdresp;
-+              pack->datalen = sizeof(struct dundi_hdr);
-+              if (ied) {
-+                      memcpy(pack->h->ies, ied->buf, ied->pos);
-+                      pack->datalen += ied->pos;
-+              } 
-+              if (final) {
-+                      pack->h->cmdresp |= DUNDI_COMMAND_FINAL;
-+                      trans->flags |= FLAG_FINAL;
-+              }
-+              pack->h->cmdflags = flags;
-+              if (cmdresp != DUNDI_COMMAND_ACK) {
-+                      trans->oseqno++;
-+                      trans->oseqno = trans->oseqno % 256;
-+              }
-+              trans->aseqno = trans->iseqno;
-+              /* If we have their public key, encrypt */
-+              if (trans->flags & FLAG_ENCRYPT) {
-+                      switch(cmdresp) {
-+                      case DUNDI_COMMAND_REGREQ:
-+                      case DUNDI_COMMAND_REGRESPONSE:
-+                      case DUNDI_COMMAND_DPDISCOVER:
-+                      case DUNDI_COMMAND_DPRESPONSE:
-+                      case DUNDI_COMMAND_EIDQUERY:
-+                      case DUNDI_COMMAND_EIDRESPONSE:
-+                      case DUNDI_COMMAND_PRECACHERQ:
-+                      case DUNDI_COMMAND_PRECACHERP:
-+                              if (dundidebug)
-+                                      dundi_showframe(pack->h, 2, &trans->addr, pack->datalen - sizeof(struct dundi_hdr));
-+                              res = dundi_encrypt(trans, pack);
-+                              break;
-+                      default:
-+                              res = 0;
-+                      }
-+              } else 
-+                      res = 0;
-+              if (!res) 
-+                      res = dundi_xmit(pack);
-+              if (res)
-+                      ast_log(LOG_NOTICE, "Failed to send packet to '%s'\n", dundi_eid_to_str(eid_str, sizeof(eid_str), &trans->them_eid));
-+                              
-+              if (cmdresp == DUNDI_COMMAND_ACK)
-+                      free(pack);
-+              return res;
-+      }
-+      return -1;
-+}
-+
-+static int do_autokill(void *data)
-+{
-+      struct dundi_transaction *trans = data;
-+      char eid_str[20];
-+      ast_log(LOG_NOTICE, "Transaction to '%s' took too long to ACK, destroying\n", 
-+              dundi_eid_to_str(eid_str, sizeof(eid_str), &trans->them_eid));
-+      trans->autokillid = -1;
-+      destroy_trans(trans, 0); /* We could actually set it to 1 instead of 0, but we won't ;-) */
-+      return 0;
-+}
-+
-+static void dundi_ie_append_eid_appropriately(struct dundi_ie_data *ied, char *context, dundi_eid *eid, dundi_eid *us)
-+{
-+      struct dundi_peer *p;
-+      if (!dundi_eid_cmp(eid, us)) {
-+              dundi_ie_append_eid(ied, DUNDI_IE_EID_DIRECT, eid);
-+              return;
-+      }
-+      ast_mutex_lock(&peerlock);
-+      p = peers;
-+      while(p) {
-+              if (!dundi_eid_cmp(&p->eid, eid)) {
-+                      if (has_permission(p->include, context))
-+                              dundi_ie_append_eid(ied, DUNDI_IE_EID_DIRECT, eid);
-+                      else
-+                              dundi_ie_append_eid(ied, DUNDI_IE_EID, eid);
-+                      break;
-+              }
-+              p = p->next;
-+      }
-+      if (!p)
-+              dundi_ie_append_eid(ied, DUNDI_IE_EID, eid);
-+      ast_mutex_unlock(&peerlock);
-+}
-+
-+static int dundi_discover(struct dundi_transaction *trans)
-+{
-+      struct dundi_ie_data ied;
-+      int x;
-+      if (!trans->parent) {
-+              ast_log(LOG_WARNING, "Tried to discover a transaction with no parent?!?\n");
-+              return -1;
-+      }
-+      memset(&ied, 0, sizeof(ied));
-+      dundi_ie_append_short(&ied, DUNDI_IE_VERSION, DUNDI_DEFAULT_VERSION);
-+      if (!dundi_eid_zero(&trans->us_eid))
-+              dundi_ie_append_eid(&ied, DUNDI_IE_EID_DIRECT, &trans->us_eid);
-+      for (x=0;x<trans->eidcount;x++)
-+              dundi_ie_append_eid_appropriately(&ied, trans->parent->dcontext, &trans->eids[x], &trans->us_eid);
-+      dundi_ie_append_str(&ied, DUNDI_IE_CALLED_NUMBER, trans->parent->number);
-+      dundi_ie_append_str(&ied, DUNDI_IE_CALLED_CONTEXT, trans->parent->dcontext);
-+      dundi_ie_append_short(&ied, DUNDI_IE_TTL, trans->ttl);
-+      if (trans->parent->cbypass)
-+              dundi_ie_append(&ied, DUNDI_IE_CACHEBYPASS);
-+      if (trans->autokilltimeout)
-+              trans->autokillid = ast_sched_add(sched, trans->autokilltimeout, do_autokill, trans);
-+      return dundi_send(trans, DUNDI_COMMAND_DPDISCOVER, 0, 0, &ied);
-+}
-+
-+static int precache_trans(struct dundi_transaction *trans, struct dundi_mapping *maps, int mapcount, int *minexp, int *foundanswers)
-+{
-+      struct dundi_ie_data ied;
-+      int x, res;
-+      int max = 999999;
-+      int expiration = DUNDI_DEFAULT_CACHE_TIME;
-+      int ouranswers=0;
-+      dundi_eid *avoid[1] = { NULL, };
-+      int direct[1] = { 0, };
-+      struct dundi_result dr[MAX_RESULTS];
-+      struct dundi_hint_metadata hmd;
-+      if (!trans->parent) {
-+              ast_log(LOG_WARNING, "Tried to discover a transaction with no parent?!?\n");
-+              return -1;
-+      }
-+      memset(&hmd, 0, sizeof(hmd));
-+      memset(&dr, 0, sizeof(dr));
-+      /* Look up the answers we're going to include */
-+      for (x=0;x<mapcount;x++)
-+              ouranswers = dundi_lookup_local(dr, maps + x, trans->parent->number, &trans->us_eid, ouranswers, &hmd);
-+      if (ouranswers < 0)
-+              ouranswers = 0;
-+      for (x=0;x<ouranswers;x++) {
-+              if (dr[x].weight < max)
-+                      max = dr[x].weight;
-+      }
-+      if (max) {
-+              /* If we do not have a canonical result, keep looking */
-+              res = dundi_lookup_internal(dr + ouranswers, MAX_RESULTS - ouranswers, NULL, trans->parent->dcontext, trans->parent->number, trans->ttl, 1, &hmd, &expiration, 0, 1, &trans->them_eid, avoid, direct);
-+              if (res > 0) {
-+                      /* Append answer in result */
-+                      ouranswers += res;
-+              }
-+      }
-+      
-+      if (ouranswers > 0) {
-+              *foundanswers += ouranswers;
-+              memset(&ied, 0, sizeof(ied));
-+              dundi_ie_append_short(&ied, DUNDI_IE_VERSION, DUNDI_DEFAULT_VERSION);
-+              if (!dundi_eid_zero(&trans->us_eid))
-+                      dundi_ie_append_eid(&ied, DUNDI_IE_EID, &trans->us_eid);
-+              for (x=0;x<trans->eidcount;x++)
-+                      dundi_ie_append_eid(&ied, DUNDI_IE_EID, &trans->eids[x]);
-+              dundi_ie_append_str(&ied, DUNDI_IE_CALLED_NUMBER, trans->parent->number);
-+              dundi_ie_append_str(&ied, DUNDI_IE_CALLED_CONTEXT, trans->parent->dcontext);
-+              dundi_ie_append_short(&ied, DUNDI_IE_TTL, trans->ttl);
-+              for (x=0;x<ouranswers;x++) {
-+                      /* Add answers */
-+                      if (dr[x].expiration && (expiration > dr[x].expiration))
-+                              expiration = dr[x].expiration;
-+                      dundi_ie_append_answer(&ied, DUNDI_IE_ANSWER, &dr[x].eid, dr[x].techint, dr[x].flags, dr[x].weight, dr[x].dest);
-+              }
-+              dundi_ie_append_hint(&ied, DUNDI_IE_HINT, hmd.flags, hmd.exten);
-+              dundi_ie_append_short(&ied, DUNDI_IE_EXPIRATION, expiration);
-+              if (trans->autokilltimeout)
-+                      trans->autokillid = ast_sched_add(sched, trans->autokilltimeout, do_autokill, trans);
-+              if (expiration < *minexp)
-+                      *minexp = expiration;
-+              return dundi_send(trans, DUNDI_COMMAND_PRECACHERQ, 0, 0, &ied);
-+      } else {
-+              /* Oops, nothing to send... */
-+              destroy_trans(trans, 0);
-+              return 0;
-+      }
-+}
-+
-+static int dundi_query(struct dundi_transaction *trans)
-+{
-+      struct dundi_ie_data ied;
-+      int x;
-+      if (!trans->parent) {
-+              ast_log(LOG_WARNING, "Tried to query a transaction with no parent?!?\n");
-+              return -1;
-+      }
-+      memset(&ied, 0, sizeof(ied));
-+      dundi_ie_append_short(&ied, DUNDI_IE_VERSION, DUNDI_DEFAULT_VERSION);
-+      if (!dundi_eid_zero(&trans->us_eid))
-+              dundi_ie_append_eid(&ied, DUNDI_IE_EID, &trans->us_eid);
-+      for (x=0;x<trans->eidcount;x++)
-+              dundi_ie_append_eid(&ied, DUNDI_IE_EID, &trans->eids[x]);
-+      dundi_ie_append_eid(&ied, DUNDI_IE_REQEID, &trans->parent->query_eid);
-+      dundi_ie_append_str(&ied, DUNDI_IE_CALLED_CONTEXT, trans->parent->dcontext);
-+      dundi_ie_append_short(&ied, DUNDI_IE_TTL, trans->ttl);
-+      if (trans->autokilltimeout)
-+              trans->autokillid = ast_sched_add(sched, trans->autokilltimeout, do_autokill, trans);
-+      return dundi_send(trans, DUNDI_COMMAND_EIDQUERY, 0, 0, &ied);
-+}
-+
-+static int discover_transactions(struct dundi_request *dr)
-+{
-+      struct dundi_transaction *trans;
-+      trans = dr->trans;
-+      while(trans) {
-+              dundi_discover(trans);
-+              trans = trans->next;
-+      }
-+      return 0;
-+}
-+
-+static int precache_transactions(struct dundi_request *dr, struct dundi_mapping *maps, int mapcount, int *expiration, int *foundanswers)
-+{
-+      struct dundi_transaction *trans;
-+      trans = dr->trans;
-+      while(trans) {
-+              precache_trans(trans, maps, mapcount, expiration, foundanswers);
-+              trans = trans->next;
-+      }
-+      return 0;
-+}
-+
-+static int query_transactions(struct dundi_request *dr)
-+{
-+      struct dundi_transaction *trans;
-+      ast_mutex_lock(&peerlock);
-+      trans = dr->trans;
-+      while(trans) {
-+              dundi_query(trans);
-+              trans = trans->next;
-+      }
-+      ast_mutex_unlock(&peerlock);
-+      return 0;
-+}
-+
-+static int optimize_transactions(struct dundi_request *dr, int order)
-+{
-+      /* Minimize the message propagation through DUNDi by
-+         alerting the network to hops which should be not be considered */
-+      struct dundi_transaction *trans;
-+      struct dundi_peer *peer;
-+      dundi_eid tmp;
-+      int x;
-+      int needpush;
-+      ast_mutex_lock(&peerlock);
-+      trans = dr->trans;
-+      while(trans) {
-+              /* Pop off the true root */
-+              if (trans->eidcount) {
-+                      tmp = trans->eids[--trans->eidcount];
-+                      needpush = 1;
-+              } else {
-+                      tmp = trans->us_eid;
-+                      needpush = 0;
-+              }
-+
-+              peer = peers;
-+              while(peer) {
-+                      if (has_permission(peer->include, dr->dcontext) && 
-+                          dundi_eid_cmp(&peer->eid, &trans->them_eid) &&
-+                              (peer->order <= order)) {
-+                              /* For each other transaction, make sure we don't
-+                                 ask this EID about the others if they're not
-+                                 already in the list */
-+                              if (!dundi_eid_cmp(&tmp, &peer->eid)) 
-+                                      x = -1;
-+                              else {
-+                                      for (x=0;x<trans->eidcount;x++) {
-+                                              if (!dundi_eid_cmp(&trans->eids[x], &peer->eid))
-+                                                      break;
-+                                      }
-+                              }
-+                              if (x == trans->eidcount) {
-+                                      /* Nope not in the list, if needed, add us at the end since we're the source */
-+                                      if (trans->eidcount < DUNDI_MAX_STACK - needpush) {
-+                                              trans->eids[trans->eidcount++] = peer->eid;
-+                                              /* Need to insert the real root (or us) at the bottom now as
-+                                                 a requirement now.  */
-+                                              needpush = 1;
-+                                      }
-+                              }
-+                      }
-+                      peer = peer->next;
-+              }
-+              /* If necessary, push the true root back on the end */
-+              if (needpush)
-+                      trans->eids[trans->eidcount++] = tmp;
-+              trans = trans->next;
-+      }
-+      ast_mutex_unlock(&peerlock);
-+      return 0;
-+}
-+
-+static int append_transaction(struct dundi_request *dr, struct dundi_peer *p, int ttl, dundi_eid *avoid[])
-+{
-+      struct dundi_transaction *trans;
-+      int x;
-+      char eid_str[20];
-+      char eid_str2[20];
-+      /* Ignore if not registered */
-+      if (!p->addr.sin_addr.s_addr)
-+              return 0;
-+      if (p->maxms && ((p->lastms < 0) || (p->lastms >= p->maxms)))
-+              return 0;
-+      if (ast_strlen_zero(dr->number))
-+              ast_log(LOG_DEBUG, "Will query peer '%s' for '%s' (context '%s')\n", dundi_eid_to_str(eid_str, sizeof(eid_str), &p->eid), dundi_eid_to_str(eid_str2, sizeof(eid_str2), &dr->query_eid), dr->dcontext);
-+      else
-+              ast_log(LOG_DEBUG, "Will query peer '%s' for '%s@%s'\n", dundi_eid_to_str(eid_str, sizeof(eid_str), &p->eid), dr->number, dr->dcontext);
-+      trans = create_transaction(p);
-+      if (!trans)
-+              return -1;
-+      trans->next = dr->trans;
-+      trans->parent = dr;
-+      trans->ttl = ttl;
-+      for (x=0;avoid[x] && (x <DUNDI_MAX_STACK);x++)
-+              trans->eids[x] = *avoid[x];
-+      trans->eidcount = x;
-+      dr->trans = trans;
-+      return 0;
-+}
-+
-+static void cancel_request(struct dundi_request *dr)
-+{
-+      struct dundi_transaction *trans, *next;
-+
-+      ast_mutex_lock(&peerlock);
-+      trans = dr->trans;
-+      
-+      while(trans) {
-+              next = trans->next;
-+              /* Orphan transaction from request */
-+              trans->parent = NULL;
-+              trans->next = NULL;
-+              /* Send final cancel */
-+              dundi_send(trans, DUNDI_COMMAND_CANCEL, 0, 1, NULL);
-+              trans = next;
-+      }
-+      ast_mutex_unlock(&peerlock);
-+}
-+
-+static void abort_request(struct dundi_request *dr)
-+{
-+      ast_mutex_lock(&peerlock);
-+      while(dr->trans) 
-+              destroy_trans(dr->trans, 0);
-+      ast_mutex_unlock(&peerlock);
-+}
-+
-+static void build_transactions(struct dundi_request *dr, int ttl, int order, int *foundcache, int *skipped, int blockempty, int nocache, int modeselect, dundi_eid *skip, dundi_eid *avoid[], int directs[])
-+{
-+      struct dundi_peer *p;
-+      int x;
-+      int res;
-+      int pass;
-+      int allowconnect;
-+      char eid_str[20];
-+      ast_mutex_lock(&peerlock);
-+      p = peers;
-+      while(p) {
-+              if (modeselect == 1) {
-+                      /* Send the precache to push upstreams only! */
-+                      pass = has_permission(p->permit, dr->dcontext) && (p->pcmodel & DUNDI_MODEL_OUTBOUND);
-+                      allowconnect = 1;
-+              } else {
-+                      /* Normal lookup / EID query */
-+                      pass = has_permission(p->include, dr->dcontext);
-+                      allowconnect = p->model & DUNDI_MODEL_OUTBOUND;
-+              }
-+              if (skip) {
-+                      if (!dundi_eid_cmp(skip, &p->eid))
-+                              pass = 0;
-+              }
-+              if (pass) {
-+                      if (p->order <= order) {
-+                              /* Check order first, then check cache, regardless of
-+                                 omissions, this gets us more likely to not have an
-+                                 affected answer. */
-+                              if((nocache || !(res = cache_lookup(dr, &p->eid, dr->crc32, &dr->expiration)))) {
-+                                      res = 0;
-+                                      /* Make sure we haven't already seen it and that it won't
-+                                         affect our answer */
-+                                      for (x=0;avoid[x];x++) {
-+                                              if (!dundi_eid_cmp(avoid[x], &p->eid) || !dundi_eid_cmp(avoid[x], &p->us_eid)) {
-+                                                      /* If not a direct connection, it affects our answer */
-+                                                      if (directs && !directs[x]) 
-+                                                              dr->hmd->flags &= ~DUNDI_HINT_UNAFFECTED;
-+                                                      break;
-+                                              }
-+                                      }
-+                                      /* Make sure we can ask */
-+                                      if (allowconnect) {
-+                                              if (!avoid[x] && (!blockempty || !dundi_eid_zero(&p->us_eid))) {
-+                                                      /* Check for a matching or 0 cache entry */
-+                                                      append_transaction(dr, p, ttl, avoid);
-+                                              } else
-+                                                      ast_log(LOG_DEBUG, "Avoiding '%s' in transaction\n", dundi_eid_to_str(eid_str, sizeof(eid_str), avoid[x]));
-+                                      }
-+                              }
-+                              *foundcache |= res;
-+                      } else if (!*skipped || (p->order < *skipped))
-+                              *skipped = p->order;
-+              }
-+              p = p->next;
-+      }
-+      ast_mutex_unlock(&peerlock);
-+}
-+
-+static int register_request(struct dundi_request *dr, struct dundi_request **pending)
-+{
-+      struct dundi_request *cur;
-+      int res=0;
-+      char eid_str[20];
-+      ast_mutex_lock(&peerlock);
-+      cur = requests;
-+      while(cur) {
-+              if (option_debug)
-+                      ast_log(LOG_DEBUG, "Checking '%s@%s' vs '%s@%s'\n", cur->dcontext, cur->number,
-+                              dr->dcontext, dr->number);
-+              if (!strcasecmp(cur->dcontext, dr->dcontext) &&
-+                  !strcasecmp(cur->number, dr->number) &&
-+                      (!dundi_eid_cmp(&cur->root_eid, &dr->root_eid) || (cur->crc32 == dr->crc32))) {
-+                              ast_log(LOG_DEBUG, "Found existing query for '%s@%s' for '%s' crc '%08lx'\n", 
-+                                      cur->dcontext, cur->number, dundi_eid_to_str(eid_str, sizeof(eid_str), &cur->root_eid), cur->crc32);
-+                              *pending = cur;
-+                      res = 1;
-+                      break;
-+              }
-+              cur = cur->next;
-+      }
-+      if (!res) {
-+              ast_log(LOG_DEBUG, "Registering request for '%s@%s' on behalf of '%s' crc '%08lx'\n", 
-+                              dr->number, dr->dcontext, dundi_eid_to_str(eid_str, sizeof(eid_str), &dr->root_eid), dr->crc32);
-+              /* Go ahead and link us in since nobody else is searching for this */
-+              dr->next = requests;
-+              requests = dr;
-+              *pending = NULL;
-+      }
-+      ast_mutex_unlock(&peerlock);
-+      return res;
-+}
-+
-+static void unregister_request(struct dundi_request *dr)
-+{
-+      struct dundi_request *cur, *prev;
-+      ast_mutex_lock(&peerlock);
-+      prev = NULL;
-+      cur = requests;
-+      while(cur) {
-+              if (cur == dr) {
-+                      if (prev)
-+                              prev->next = cur->next;
-+                      else
-+                              requests = cur->next;
-+                      break;
-+              }
-+              prev = cur;
-+              cur = cur->next;
-+      }
-+      ast_mutex_unlock(&peerlock);
-+}
-+
-+static int check_request(struct dundi_request *dr)
-+{
-+      struct dundi_request *cur;
-+      int res = 0;
-+      ast_mutex_lock(&peerlock);
-+      cur = requests;
-+      while(cur) {
-+              if (cur == dr) {
-+                      res = 1;
-+                      break;
-+              }
-+              cur = cur->next;
-+      }
-+      ast_mutex_unlock(&peerlock);
-+      return res;
-+}
-+
-+static unsigned long avoid_crc32(dundi_eid *avoid[])
-+{
-+      /* Idea is that we're calculating a checksum which is independent of
-+         the order that the EID's are listed in */
-+      unsigned long acrc32 = 0;
-+      int x;
-+      for (x=0;avoid[x];x++) {
-+              /* Order doesn't matter */
-+              if (avoid[x+1]) {
-+                      acrc32 ^= crc32(0L, (unsigned char *)avoid[x], sizeof(dundi_eid));
-+              }
-+      }
-+      return acrc32;
-+}
-+
-+static int dundi_lookup_internal(struct dundi_result *result, int maxret, struct ast_channel *chan, const char *dcontext, const char *number, int ttl, int blockempty, struct dundi_hint_metadata *hmd, int *expiration, int cbypass, int modeselect, dundi_eid *skip, dundi_eid *avoid[], int direct[])
-+{
-+      int res;
-+      struct dundi_request dr, *pending;
-+      dundi_eid *rooteid=NULL;
-+      int x;
-+      int ttlms;
-+      int ms;
-+      int foundcache;
-+      int skipped=0;
-+      int order=0;
-+      char eid_str[20];
-+      struct timeval start;
-+      
-+      /* Don't do anthing for a hungup channel */
-+      if (chan && chan->_softhangup)
-+              return 0;
-+
-+      ttlms = DUNDI_FLUFF_TIME + ttl * DUNDI_TTL_TIME;
-+
-+      for (x=0;avoid[x];x++)
-+              rooteid = avoid[x];
-+      /* Now perform real check */
-+      memset(&dr, 0, sizeof(dr));
-+      if (pipe(dr.pfds)) {
-+              ast_log(LOG_WARNING, "pipe failed: %s\n" , strerror(errno));
-+              return -1;
-+      }
-+      dr.dr = result;
-+      dr.hmd = hmd;
-+      dr.maxcount = maxret;
-+      dr.expiration = *expiration;
-+      dr.cbypass = cbypass;
-+      dr.crc32 = avoid_crc32(avoid);
-+      strncpy(dr.dcontext, dcontext ? dcontext : "e164", sizeof(dr.dcontext) - 1);
-+      strncpy(dr.number, number, sizeof(dr.number) - 1);
-+      if (rooteid)
-+              dr.root_eid = *rooteid;
-+      res = register_request(&dr, &pending);
-+      if (res) {
-+              /* Already a request */
-+              if (rooteid && !dundi_eid_cmp(&dr.root_eid, &pending->root_eid)) {
-+                      /* This is on behalf of someone else.  Go ahead and close this out since
-+                         they'll get their answer anyway. */
-+                      ast_log(LOG_DEBUG, "Oooh, duplicate request for '%s@%s' for '%s'\n",
-+                              dr.number,dr.dcontext,dundi_eid_to_str(eid_str, sizeof(eid_str), &dr.root_eid));
-+                      close(dr.pfds[0]);
-+                      close(dr.pfds[1]);
-+                      return -2;
-+              } else {
-+                      /* Wait for the cache to populate */
-+                      ast_log(LOG_DEBUG, "Waiting for similar request for '%s@%s' for '%s'\n",
-+                              dr.number,dr.dcontext,dundi_eid_to_str(eid_str, sizeof(eid_str), &pending->root_eid));
-+                      gettimeofday(&start, NULL);
-+                      while(check_request(pending) && (calc_ms(&start) < ttlms) && (!chan || !chan->_softhangup)) {
-+                              /* XXX Would be nice to have a way to poll/select here XXX */
-+                              usleep(1);
-+                      }
-+                      /* Continue on as normal, our cache should kick in */
-+              }
-+      }
-+      /* Create transactions */
-+      do {
-+              order = skipped;
-+              skipped = 0;
-+              foundcache = 0;
-+              build_transactions(&dr, ttl, order, &foundcache, &skipped, blockempty, cbypass, modeselect, skip, avoid, direct);
-+      } while (skipped && !foundcache && !dr.trans);
-+      /* If no TTL, abort and return 0 now after setting TTL expired hint.  Couldn't
-+         do this earlier because we didn't know if we were going to have transactions
-+         or not. */
-+      if (!ttl) {
-+              hmd->flags |= DUNDI_HINT_TTL_EXPIRED;
-+              abort_request(&dr);
-+              unregister_request(&dr);
-+              close(dr.pfds[0]);
-+              close(dr.pfds[1]);
-+              return 0;
-+      }
-+              
-+      /* Optimize transactions */
-+      optimize_transactions(&dr, order);
-+      /* Actually perform transactions */
-+      discover_transactions(&dr);
-+      /* Wait for transaction to come back */
-+      gettimeofday(&start, NULL);
-+      while(dr.trans && (calc_ms(&start) < ttlms) && (!chan || !chan->_softhangup)) {
-+              ms = 100;
-+              ast_waitfor_n_fd(dr.pfds, 1, &ms, NULL);
-+      }
-+      if (chan && chan->_softhangup)
-+              ast_log(LOG_DEBUG, "Hrm, '%s' hungup before their query for %s@%s finished\n", chan->name, dr.number, dr.dcontext);
-+      cancel_request(&dr);
-+      unregister_request(&dr);
-+      res = dr.respcount;
-+      *expiration = dr.expiration;
-+      close(dr.pfds[0]);
-+      close(dr.pfds[1]);
-+      return res;
-+}
-+
-+int dundi_lookup(struct dundi_result *result, int maxret, struct ast_channel *chan, const char *dcontext, const char *number, int cbypass)
-+{
-+      struct dundi_hint_metadata hmd;
-+      dundi_eid *avoid[1] = { NULL, };
-+      int direct[1] = { 0, };
-+      int expiration = DUNDI_DEFAULT_CACHE_TIME;
-+      memset(&hmd, 0, sizeof(hmd));
-+      hmd.flags = DUNDI_HINT_DONT_ASK | DUNDI_HINT_UNAFFECTED;
-+      return dundi_lookup_internal(result, maxret, chan, dcontext, number, dundi_ttl, 0, &hmd, &expiration, cbypass, 0, NULL, avoid, direct);
-+}
-+
-+static void reschedule_precache(const char *number, const char *context, int expiration)
-+{
-+      int len;
-+      struct dundi_precache_queue *qe, *prev=NULL;
-+      ast_mutex_lock(&pclock);
-+      qe = pcq;
-+      while(qe) {
-+              if (!strcmp(number, qe->number) && !strcasecmp(context, qe->context)) {
-+                      if (prev)
-+                              prev->next = qe->next;
-+                      else
-+                              pcq = qe->next;
-+                      qe->next = NULL;
-+                      break;
-+              }
-+              prev = qe;
-+              qe = qe->next;
-+      };
-+      if (!qe) {
-+              len = sizeof(struct dundi_precache_queue);
-+              len += strlen(number) + 1;
-+              len += strlen(context) + 1;
-+              qe = malloc(len);
-+              if (qe) {
-+                      memset(qe, 0, len);
-+                      strcpy(qe->number, number);
-+                      qe->context = qe->number + strlen(number) + 1;
-+                      strcpy(qe->context, context);
-+              }
-+      }
-+      time(&qe->expiration);
-+      qe->expiration += expiration;
-+      prev = pcq;
-+      if (prev) {
-+              while(prev->next && (prev->next->expiration <= qe->expiration))
-+                      prev = prev->next;
-+              qe->next = prev->next;
-+              prev->next = qe;
-+      } else
-+              pcq = qe;
-+      ast_mutex_unlock(&pclock);
-+      
-+}
-+
-+static void dundi_precache_full(void)
-+{
-+      struct dundi_mapping *cur;
-+      struct ast_context *con;
-+      struct ast_exten *e;
-+      cur = mappings;
-+      while(cur) {
-+              ast_log(LOG_NOTICE, "Should precache context '%s'\n", cur->dcontext);
-+              ast_lock_contexts();
-+              con = ast_walk_contexts(NULL);
-+              while(con) {
-+                      if (!strcasecmp(cur->lcontext, ast_get_context_name(con))) {
-+                              /* Found the match, now queue them all up */
-+                              ast_lock_context(con);
-+                              e = ast_walk_context_extensions(con, NULL);
-+                              while(e) {
-+                                      reschedule_precache(ast_get_extension_name(e), cur->dcontext, 0);
-+                                      e = ast_walk_context_extensions(con, e);
-+                              }
-+                              ast_unlock_context(con);
-+                      }
-+                      con = ast_walk_contexts(con);
-+              }
-+              ast_unlock_contexts();
-+              cur = cur->next;
-+      }
-+}
-+
-+static int dundi_precache_internal(const char *context, const char *number, int ttl, dundi_eid *avoids[])
-+{
-+      struct dundi_request dr;
-+      struct dundi_hint_metadata hmd;
-+      struct dundi_result dr2[MAX_RESULTS];
-+      struct timeval start;
-+      struct dundi_mapping *maps=NULL, *cur;
-+      int nummaps;
-+      int foundanswers;
-+      int foundcache, skipped, ttlms, ms;
-+      if (!context)
-+              context = "e164";
-+      ast_log(LOG_DEBUG, "Precache internal (%s@%s)!\n", number, context);
-+
-+      ast_mutex_lock(&peerlock);
-+      nummaps = 0;
-+      cur = mappings;
-+      while(cur) {
-+              if (!strcasecmp(cur->dcontext, context))
-+                      nummaps++;
-+              cur = cur->next;
-+      }
-+      if (nummaps) {
-+              maps = alloca(nummaps * sizeof(struct dundi_mapping));
-+              nummaps = 0;
-+              if (maps) {
-+                      cur = mappings;
-+                      while(cur) {
-+                              if (!strcasecmp(cur->dcontext, context))
-+                                      maps[nummaps++] = *cur;
-+                              cur = cur->next;
-+                      }
-+              }
-+      }
-+      ast_mutex_unlock(&peerlock);
-+      if (!nummaps || !maps)
-+              return -1;
-+      ttlms = DUNDI_FLUFF_TIME + ttl * DUNDI_TTL_TIME;
-+      memset(&dr2, 0, sizeof(dr2));
-+      memset(&dr, 0, sizeof(dr));
-+      memset(&hmd, 0, sizeof(hmd));
-+      dr.dr = dr2;
-+      strncpy(dr.number, number, sizeof(dr.number) - 1);
-+      strncpy(dr.dcontext, context ? context : "e164", sizeof(dr.dcontext) - 1);
-+      dr.maxcount = MAX_RESULTS;
-+      dr.expiration = DUNDI_DEFAULT_CACHE_TIME;
-+      dr.hmd = &hmd;
-+      pipe(dr.pfds);
-+      dr.pfds[0] = dr.pfds[1] = -1;
-+      build_transactions(&dr, ttl, 0, &foundcache, &skipped, 0, 1, 1, NULL, avoids, NULL);
-+      optimize_transactions(&dr, 0);
-+      foundanswers = 0;
-+      precache_transactions(&dr, maps, nummaps, &dr.expiration, &foundanswers);
-+      if (foundanswers) {
-+              if (dr.expiration > 0) 
-+                      reschedule_precache(dr.number, dr.dcontext, dr.expiration);
-+              else
-+                      ast_log(LOG_NOTICE, "Weird, expiration = %d, but need to precache for %s@%s?!\n", dr.expiration, dr.number, dr.dcontext);
-+      }
-+      gettimeofday(&start, NULL);
-+      while(dr.trans && (calc_ms(&start) < ttlms)) {
-+              if (dr.pfds[0] > -1) {
-+                      ms = 100;
-+                      ast_waitfor_n_fd(dr.pfds, 1, &ms, NULL);
-+              } else
-+                      usleep(1);
-+      }
-+      cancel_request(&dr);
-+      if (dr.pfds[0] > -1) {
-+              close(dr.pfds[0]);
-+              close(dr.pfds[1]);
-+      }
-+      return 0;
-+}
-+
-+int dundi_precache(const char *context, const char *number)
-+{
-+      dundi_eid *avoid[1] = { NULL, };
-+      return dundi_precache_internal(context, number, dundi_ttl, avoid);
-+}
-+
-+static int dundi_query_eid_internal(struct dundi_entity_info *dei, const char *dcontext, dundi_eid *eid, struct dundi_hint_metadata *hmd, int ttl, int blockempty, dundi_eid *avoid[])
-+{
-+      int res;
-+      struct dundi_request dr;
-+      dundi_eid *rooteid=NULL;
-+      int x;
-+      int ttlms;
-+      int skipped=0;
-+      int foundcache=0;
-+      struct timeval start;
-+      
-+      ttlms = DUNDI_FLUFF_TIME + ttl * DUNDI_TTL_TIME;
-+
-+      for (x=0;avoid[x];x++)
-+              rooteid = avoid[x];
-+      /* Now perform real check */
-+      memset(&dr, 0, sizeof(dr));
-+      dr.hmd = hmd;
-+      dr.dei = dei;
-+      strncpy(dr.dcontext, dcontext ? dcontext : "e164", sizeof(dr.dcontext) - 1);
-+      memcpy(&dr.query_eid, eid, sizeof(dr.query_eid));
-+      if (rooteid)
-+              dr.root_eid = *rooteid;
-+      /* Create transactions */
-+      build_transactions(&dr, ttl, 9999, &foundcache, &skipped, blockempty, 0, 0, NULL, avoid, NULL);
-+
-+      /* If no TTL, abort and return 0 now after setting TTL expired hint.  Couldn't
-+         do this earlier because we didn't know if we were going to have transactions
-+         or not. */
-+      if (!ttl) {
-+              hmd->flags |= DUNDI_HINT_TTL_EXPIRED;
-+              return 0;
-+      }
-+              
-+      /* Optimize transactions */
-+      optimize_transactions(&dr, 9999);
-+      /* Actually perform transactions */
-+      query_transactions(&dr);
-+      /* Wait for transaction to come back */
-+      gettimeofday(&start, NULL);
-+      while(dr.trans && (calc_ms(&start) < ttlms))
-+              usleep(1);
-+      res = dr.respcount;
-+      return res;
-+}
-+
-+int dundi_query_eid(struct dundi_entity_info *dei, const char *dcontext, dundi_eid eid)
-+{
-+      dundi_eid *avoid[1] = { NULL, };
-+      struct dundi_hint_metadata hmd;
-+      memset(&hmd, 0, sizeof(hmd));
-+      return dundi_query_eid_internal(dei, dcontext, &eid, &hmd, dundi_ttl, 0, avoid);
-+}
-+
-+static int dundi_lookup_exec(struct ast_channel *chan, void *data)
-+{
-+      char *tmp;
-+      char *context;
-+      char *opts;
-+      int res = -1;
-+      struct localuser *u;
-+
-+      if (!data || !strlen(data)) {
-+              ast_log(LOG_WARNING, "DUNDiLookup requires an argument (number)\n");
-+              return 0;
-+      }
-+      LOCAL_USER_ADD(u);
-+      tmp = ast_strdupa(data);
-+      if (tmp) {
-+              context = strchr(tmp, '|');
-+              if (context) {
-+                      *context = '\0';
-+                      context++;
-+                      opts = strchr(context, '|');
-+                      if (opts) {
-+                              *opts = '\0';
-+                              opts++;
-+                      }
-+              } else
-+                      opts = NULL;
-+              if (!context || !strlen(context))
-+                      context = "e164";
-+              if (!opts)
-+                      opts = "";
-+              
-+      }
-+      LOCAL_USER_REMOVE(u);
-+      return res;
-+}
-+
-+
-+static void mark_peers(void)
-+{
-+      struct dundi_peer *peer;
-+      ast_mutex_lock(&peerlock);
-+      peer = peers;
-+      while(peer) {
-+              peer->dead = 1;
-+              peer = peer->next;
-+      }
-+      ast_mutex_unlock(&peerlock);
-+}
-+
-+static void mark_mappings(void)
-+{
-+      struct dundi_mapping *map;
-+      ast_mutex_lock(&peerlock);
-+      map = mappings;
-+      while(map) {
-+              map->dead = 1;
-+              map = map->next;
-+      }
-+      ast_mutex_unlock(&peerlock);
-+}
-+
-+static void destroy_permissions(struct permission *p)
-+{
-+      struct permission *prev;
-+      while(p) {
-+              prev = p;
-+              p = p->next;
-+              free(prev);
-+      }
-+}
-+
-+static void destroy_peer(struct dundi_peer *peer)
-+{
-+      if (peer->registerid > -1)
-+              ast_sched_del(sched, peer->registerid);
-+      if (peer->regtrans)
-+              destroy_trans(peer->regtrans, 0);
-+      if (peer->keypending)
-+              destroy_trans(peer->keypending, 0);
-+      if (peer->qualifyid > -1)
-+              ast_sched_del(sched, peer->qualifyid);
-+      destroy_permissions(peer->permit);
-+      destroy_permissions(peer->include);
-+      free(peer);
-+}
-+
-+static void destroy_map(struct dundi_mapping *map)
-+{
-+      free(map);
-+}
-+
-+static void prune_peers(void)
-+{
-+      struct dundi_peer *peer, *prev, *next;
-+      ast_mutex_lock(&peerlock);
-+      peer = peers;
-+      prev = NULL;
-+      while(peer) {
-+              next = peer->next;
-+              if (peer->dead) {
-+                      if (prev)
-+                              prev->next = peer->next;
-+                      else
-+                              peers = peer->next;
-+                      destroy_peer(peer);
-+              } else
-+                      prev = peer;
-+              peer = next;
-+      }
-+      ast_mutex_unlock(&peerlock);
-+}
-+
-+static void prune_mappings(void)
-+{
-+      struct dundi_mapping *map, *prev, *next;
-+      ast_mutex_lock(&peerlock);
-+      map = mappings;
-+      prev = NULL;
-+      while(map) {
-+              next = map->next;
-+              if (map->dead) {
-+                      if (prev)
-+                              prev->next = map->next;
-+                      else
-+                              mappings = map->next;
-+                      destroy_map(map);
-+              } else
-+                      prev = map;
-+              map = next;
-+      }
-+      ast_mutex_unlock(&peerlock);
-+}
-+
-+static struct permission *append_permission(struct permission *p, char *s, int allow)
-+{
-+      struct permission *start;
-+      start = p;
-+      if (p) {
-+              while(p->next)
-+                      p = p->next;
-+      }
-+      if (p) {
-+              p->next = malloc(sizeof(struct permission) + strlen(s) + 1);
-+              p = p->next;
-+      } else {
-+              p = malloc(sizeof(struct permission) + strlen(s) + 1);
-+      }
-+      if (p) {
-+              memset(p, 0, sizeof(struct permission));
-+              memcpy(p->name, s, strlen(s) + 1);
-+              p->allow = allow;
-+      }
-+      return start ? start : p;
-+}
-+
-+#define MAX_OPTS 128
-+
-+static void build_mapping(char *name, char *value)
-+{
-+      char *t, *fields[MAX_OPTS];
-+      struct dundi_mapping *map;
-+      int x;
-+      int y;
-+      t = ast_strdupa(value);
-+      if (t) {
-+              map = mappings;
-+              while(map) {
-+                      /* Find a double match */
-+                      if (!strcasecmp(map->dcontext, name) && 
-+                              (!strncasecmp(map->lcontext, value, strlen(map->lcontext)) && 
-+                                (!value[strlen(map->lcontext)] || 
-+                                 (value[strlen(map->lcontext)] == ','))))
-+                              break;
-+                      map = map->next;
-+              }
-+              if (!map) {
-+                      map = malloc(sizeof(struct dundi_mapping));
-+                      if (map) {
-+                              memset(map, 0, sizeof(struct dundi_mapping));
-+                              map->next = mappings;
-+                              mappings = map;
-+                              map->dead = 1;
-+                      }
-+              }
-+              if (map) {
-+                      map->options = 0;
-+                      memset(fields, 0, sizeof(fields));
-+                      x = 0;
-+                      while(t && x < MAX_OPTS) {
-+                              fields[x++] = t;
-+                              t = strchr(t, ',');
-+                              if (t) {
-+                                      *t = '\0';
-+                                      t++;
-+                              }
-+                      } /* Russell was here, arrrr! */
-+                      if ((x == 1) && ast_strlen_zero(fields[0])) {
-+                              /* Placeholder mapping */
-+                              strncpy(map->dcontext, name, sizeof(map->dcontext) - 1);
-+                              map->dead = 0;
-+                      } else if (x >= 4) {
-+                              strncpy(map->dcontext, name, sizeof(map->dcontext) - 1);
-+                              strncpy(map->lcontext, fields[0], sizeof(map->lcontext) - 1);
-+                              if ((sscanf(fields[1], "%i", &map->weight) == 1) && (map->weight >= 0) && (map->weight < 60000)) {
-+                                      strncpy(map->dest, fields[3], sizeof(map->dest) - 1);
-+                                      if ((map->tech = str2tech(fields[2]))) {
-+                                              map->dead = 0;
-+                                      }
-+                              } else {
-+                                      ast_log(LOG_WARNING, "Invalid weight '%s' specified, deleting entry '%s/%s'\n", fields[1], map->dcontext, map->lcontext);
-+                              }
-+                              for (y=4;y<x;y++) {
-+                                      if (!strcasecmp(fields[y], "nounsolicited"))
-+                                              map->options |= DUNDI_FLAG_NOUNSOLICITED;
-+                                      else if (!strcasecmp(fields[y], "nocomunsolicit"))
-+                                              map->options |= DUNDI_FLAG_NOCOMUNSOLICIT;
-+                                      else if (!strcasecmp(fields[y], "residential"))
-+                                              map->options |= DUNDI_FLAG_RESIDENTIAL;
-+                                      else if (!strcasecmp(fields[y], "commercial"))
-+                                              map->options |= DUNDI_FLAG_COMMERCIAL;
-+                                      else if (!strcasecmp(fields[y], "mobile"))
-+                                              map->options |= DUNDI_FLAG_MOBILE;
-+                                      else if (!strcasecmp(fields[y], "nopartial"))
-+                                              map->options |= DUNDI_FLAG_INTERNAL_NOPARTIAL;
-+                                      else
-+                                              ast_log(LOG_WARNING, "Don't know anything about option '%s'\n", fields[y]);
-+                              }
-+                      } else 
-+                              ast_log(LOG_WARNING, "Expected at least %d arguments in map, but got only %d\n", 4, x);
-+              }
-+      }
-+}
-+
-+static int do_register(void *data)
-+{
-+      struct dundi_ie_data ied;
-+      struct dundi_peer *peer = data;
-+      char eid_str[20];
-+      char eid_str2[20];
-+      /* Called with peerlock already held */
-+      ast_log(LOG_DEBUG, "Register us as '%s' to '%s'\n", dundi_eid_to_str(eid_str, sizeof(eid_str), &peer->us_eid), dundi_eid_to_str(eid_str2, sizeof(eid_str2), &peer->eid));
-+      peer->registerid = ast_sched_add(sched, default_expiration * 1000, do_register, data);
-+      /* Destroy old transaction if there is one */
-+      if (peer->regtrans)
-+              destroy_trans(peer->regtrans, 0);
-+      peer->regtrans = create_transaction(peer);
-+      if (peer->regtrans) {
-+              peer->regtrans->flags |= FLAG_ISREG;
-+              memset(&ied, 0, sizeof(ied));
-+              dundi_ie_append_short(&ied, DUNDI_IE_VERSION, DUNDI_DEFAULT_VERSION);
-+              dundi_ie_append_eid(&ied, DUNDI_IE_EID, &peer->regtrans->us_eid);
-+              dundi_ie_append_short(&ied, DUNDI_IE_EXPIRATION, default_expiration);
-+              dundi_send(peer->regtrans, DUNDI_COMMAND_REGREQ, 0, 0, &ied);
-+              
-+      } else
-+              ast_log(LOG_NOTICE, "Unable to create new transaction for registering to '%s'!\n", dundi_eid_to_str(eid_str, sizeof(eid_str), &peer->eid));
-+
-+      return 0;
-+}
-+
-+static int do_qualify(void *data)
-+{
-+      struct dundi_peer *peer;
-+      peer = data;
-+      peer->qualifyid = -1;
-+      qualify_peer(peer, 0);
-+      return 0;
-+}
-+
-+static void qualify_peer(struct dundi_peer *peer, int schedonly)
-+{
-+      int when;
-+      if (peer->qualifyid > -1)
-+              ast_sched_del(sched, peer->qualifyid);
-+      peer->qualifyid = -1;
-+      if (peer->qualtrans)
-+              destroy_trans(peer->qualtrans, 0);
-+      peer->qualtrans = NULL;
-+      if (peer->maxms > 0) {
-+              when = 60000;
-+              if (peer->lastms < 0)
-+                      when = 10000;
-+              if (schedonly)
-+                      when = 5000;
-+              peer->qualifyid = ast_sched_add(sched, when, do_qualify, peer);
-+              if (!schedonly)
-+                      peer->qualtrans = create_transaction(peer);
-+              if (peer->qualtrans) {
-+                      gettimeofday(&peer->qualtx, NULL);
-+                      peer->qualtrans->flags |= FLAG_ISQUAL;
-+                      dundi_send(peer->qualtrans, DUNDI_COMMAND_NULL, 0, 1, NULL);
-+              }
-+      }
-+}
-+static void populate_addr(struct dundi_peer *peer, dundi_eid *eid)
-+{
-+      char data[256];
-+      char *c;
-+      int port, expire;
-+      char eid_str[20];
-+      dundi_eid_to_str(eid_str, sizeof(eid_str), eid);
-+      if (!ast_db_get("dundi/dpeers", eid_str, data, sizeof(data))) {
-+              c = strchr(data, ':');
-+              if (c) {
-+                      *c = '\0';
-+                      c++;
-+                      if (sscanf(c, "%d:%d", &port, &expire) == 2) {
-+                              /* Got it! */
-+                              inet_aton(data, &peer->addr.sin_addr);
-+                              peer->addr.sin_family = AF_INET;
-+                              peer->addr.sin_port = htons(port);
-+                              peer->registerexpire = ast_sched_add(sched, (expire + 10) * 1000, do_register_expire, peer);
-+                      }
-+              }
-+      }
-+}
-+
-+
-+static void build_peer(dundi_eid *eid, struct ast_variable *v, int *globalpcmode)
-+{
-+      struct dundi_peer *peer;
-+      struct ast_hostent he;
-+      struct hostent *hp;
-+      dundi_eid testeid;
-+      int needregister=0;
-+      char eid_str[20];
-+
-+      ast_mutex_lock(&peerlock);
-+      peer = peers;
-+      while(peer) {
-+              if (!dundi_eid_cmp(&peer->eid, eid)) {  
-+                      break;
-+              }
-+              peer = peer->next;
-+      }
-+      if (!peer) {
-+              /* Add us into the list */
-+              peer = malloc(sizeof(struct dundi_peer));
-+              if (peer) {
-+                      memset(peer, 0, sizeof(struct dundi_peer));
-+                      peer->registerid = -1;
-+                      peer->registerexpire = -1;
-+                      peer->qualifyid = -1;
-+                      peer->addr.sin_family = AF_INET;
-+                      peer->addr.sin_port = htons(DUNDI_PORT);
-+                      populate_addr(peer, eid);
-+                      peer->next = peers;
-+                      peers = peer;
-+              }
-+      }
-+      if (peer) {
-+              peer->dead = 0;
-+              peer->eid = *eid;
-+              peer->us_eid = global_eid;
-+              destroy_permissions(peer->permit);
-+              destroy_permissions(peer->include);
-+              peer->permit = NULL;
-+              peer->include = NULL;
-+              if (peer->registerid > -1)
-+                      ast_sched_del(sched, peer->registerid);
-+              peer->registerid = -1;
-+              while(v) {
-+                      if (!strcasecmp(v->name, "inkey")) {
-+                              strncpy(peer->inkey, v->value, sizeof(peer->inkey) - 1);
-+                      } else if (!strcasecmp(v->name, "outkey")) {
-+                              strncpy(peer->outkey, v->value, sizeof(peer->outkey) - 1);
-+                      } else if (!strcasecmp(v->name, "host")) {
-+                              if (!strcasecmp(v->value, "dynamic")) {
-+                                      peer->dynamic = 1;
-+                              } else {
-+                                      hp = ast_gethostbyname(v->value, &he);
-+                                      if (hp) {
-+                                              memcpy(&peer->addr.sin_addr, hp->h_addr, sizeof(peer->addr.sin_addr));
-+                                              peer->dynamic = 0;
-+                                      } else {
-+                                              ast_log(LOG_WARNING, "Unable to find host '%s' at line %d\n", v->value, v->lineno);
-+                                              peer->dead = 1;
-+                                      }
-+                              }
-+                      } else if (!strcasecmp(v->name, "ustothem")) {
-+                              if (!dundi_str_to_eid(&testeid, v->value))
-+                                      peer->us_eid = testeid;
-+                              else
-+                                      ast_log(LOG_WARNING, "'%s' is not a valid DUNDi Entity Identifier at line %d\n", v->value, v->lineno);
-+                      } else if (!strcasecmp(v->name, "include")) {
-+                              peer->include = append_permission(peer->include, v->value, 1);
-+                      } else if (!strcasecmp(v->name, "permit")) {
-+                              peer->permit = append_permission(peer->permit, v->value, 1);
-+                      } else if (!strcasecmp(v->name, "noinclude")) {
-+                              peer->include = append_permission(peer->include, v->value, 0);
-+                      } else if (!strcasecmp(v->name, "deny")) {
-+                              peer->permit = append_permission(peer->permit, v->value, 0);
-+                      } else if (!strcasecmp(v->name, "register")) {
-+                              needregister = ast_true(v->value);
-+                      } else if (!strcasecmp(v->name, "order")) {
-+                              if (!strcasecmp(v->value, "primary"))
-+                                      peer->order = 0;
-+                              else if (!strcasecmp(v->value, "secondary"))
-+                                      peer->order = 1;
-+                              else if (!strcasecmp(v->value, "tertiary"))
-+                                      peer->order = 2;
-+                              else if (!strcasecmp(v->value, "quartiary"))
-+                                      peer->order = 3;
-+                              else {
-+                                      ast_log(LOG_WARNING, "'%s' is not a valid order, should be primary, secondary, tertiary or quartiary at line %d\n", v->value, v->lineno);
-+                              }
-+                      } else if (!strcasecmp(v->name, "qualify")) {
-+                              if (!strcasecmp(v->value, "no")) {
-+                                      peer->maxms = 0;
-+                              } else if (!strcasecmp(v->value, "yes")) {
-+                                      peer->maxms = DEFAULT_MAXMS;
-+                              } else if (sscanf(v->value, "%d", &peer->maxms) != 1) {
-+                                      ast_log(LOG_WARNING, "Qualification of peer '%s' should be 'yes', 'no', or a number of milliseconds at line %d of dundi.conf\n", 
-+                                              dundi_eid_to_str(eid_str, sizeof(eid_str), &peer->eid), v->lineno);
-+                                      peer->maxms = 0;
-+                              }
-+                      } else if (!strcasecmp(v->name, "model")) {
-+                              if (!strcasecmp(v->value, "inbound"))
-+                                      peer->model = DUNDI_MODEL_INBOUND;
-+                              else if (!strcasecmp(v->value, "outbound")) 
-+                                      peer->model = DUNDI_MODEL_OUTBOUND;
-+                              else if (!strcasecmp(v->value, "symmetric"))
-+                                      peer->model = DUNDI_MODEL_SYMMETRIC;
-+                              else if (!strcasecmp(v->value, "none"))
-+                                      peer->model = 0;
-+                              else {
-+                                      ast_log(LOG_WARNING, "Unknown model '%s', should be 'none', 'outbound', 'inbound', or 'symmetric' at line %d\n", 
-+                                              v->value, v->lineno);
-+                              }
-+                      } else if (!strcasecmp(v->name, "precache")) {
-+                              if (!strcasecmp(v->value, "inbound"))
-+                                      peer->pcmodel = DUNDI_MODEL_INBOUND;
-+                              else if (!strcasecmp(v->value, "outbound")) 
-+                                      peer->pcmodel = DUNDI_MODEL_OUTBOUND;
-+                              else if (!strcasecmp(v->value, "symmetric"))
-+                                      peer->pcmodel = DUNDI_MODEL_SYMMETRIC;
-+                              else if (!strcasecmp(v->value, "none"))
-+                                      peer->pcmodel = 0;
-+                              else {
-+                                      ast_log(LOG_WARNING, "Unknown pcmodel '%s', should be 'none', 'outbound', 'inbound', or 'symmetric' at line %d\n", 
-+                                              v->value, v->lineno);
-+                              }
-+                      }
-+                      v = v->next;
-+              }
-+              (*globalpcmode) |= peer->pcmodel;
-+              if (!peer->model && !peer->pcmodel) {
-+                      ast_log(LOG_WARNING, "Peer '%s' lacks a model or pcmodel, discarding!\n", 
-+                              dundi_eid_to_str(eid_str, sizeof(eid_str), &peer->eid));
-+                      peer->dead = 1;
-+              } else if ((peer->model & DUNDI_MODEL_INBOUND) && (peer->pcmodel & DUNDI_MODEL_OUTBOUND)) {
-+                      ast_log(LOG_WARNING, "Peer '%s' may not be both inbound/symmetric model and outbound/symmetric precache model, discarding!\n", 
-+                              dundi_eid_to_str(eid_str, sizeof(eid_str), &peer->eid));
-+                      peer->dead = 1;
-+              } else if ((peer->model & DUNDI_MODEL_OUTBOUND) && (peer->pcmodel & DUNDI_MODEL_INBOUND)) {
-+                      ast_log(LOG_WARNING, "Peer '%s' may not be both outbound/symmetric model and inbound/symmetric precache model, discarding!\n", 
-+                              dundi_eid_to_str(eid_str, sizeof(eid_str), &peer->eid));
-+                      peer->dead = 1;
-+              } else if (peer->include && !(peer->model & DUNDI_MODEL_OUTBOUND) && !(peer->pcmodel & DUNDI_MODEL_INBOUND)) {
-+                      ast_log(LOG_WARNING, "Peer '%s' is supposed to be included in outbound searches but isn't an outbound peer or inbound precache!\n", 
-+                              dundi_eid_to_str(eid_str, sizeof(eid_str), &peer->eid));
-+              } else if (peer->permit && !(peer->model & DUNDI_MODEL_INBOUND) && !(peer->pcmodel & DUNDI_MODEL_OUTBOUND)) {
-+                      ast_log(LOG_WARNING, "Peer '%s' is supposed to have permission for some inbound searches but isn't an inbound peer or outbound precache!\n", 
-+                              dundi_eid_to_str(eid_str, sizeof(eid_str), &peer->eid));
-+              } else { 
-+                      if (needregister) {
-+                              peer->registerid = ast_sched_add(sched, 2000, do_register, peer);
-+                      }
-+                      qualify_peer(peer, 1);
-+              }
-+      }
-+      ast_mutex_unlock(&peerlock);
-+}
-+
-+static int dundi_helper(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *data, int flag)
-+{
-+      struct dundi_result results[MAX_RESULTS];
-+      int res;
-+      int x;
-+      int found = 0;
-+      if (!strncasecmp(context, "macro-", 6)) {
-+              if (!chan) {    
-+                      ast_log(LOG_NOTICE, "Can't use macro mode without a channel!\n");
-+                      return -1;
-+              }
-+              /* If done as a macro, use macro extension */
-+              if (!strcasecmp(exten, "s")) {
-+                      exten = pbx_builtin_getvar_helper(chan, "ARG1");
-+                      if (!exten || ast_strlen_zero(exten))
-+                              exten = chan->macroexten;
-+                      if (!exten || ast_strlen_zero(exten))
-+                              exten = chan->exten;
-+                      if (!exten || ast_strlen_zero(exten)) { 
-+                              ast_log(LOG_WARNING, "Called in Macro mode with no ARG1 or MACRO_EXTEN?\n");
-+                              return -1;
-+                      }
-+              }
-+              if (!data || ast_strlen_zero(data))
-+                      data = "e164";
-+      } else {
-+              if (!data || ast_strlen_zero(data))
-+                      data = context;
-+      }
-+      res = dundi_lookup(results, MAX_RESULTS, chan, data, exten, 0);
-+      for (x=0;x<res;x++) {
-+              if (results[x].flags & flag)
-+                      found++;
-+      }
-+      if (found >= priority)
-+              return 1;
-+      return 0;
-+}
-+
-+static int dundi_exists(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data)
-+{
-+      return dundi_helper(chan, context, exten, priority, data, DUNDI_FLAG_EXISTS);
-+}
-+
-+static int dundi_canmatch(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data)
-+{
-+      return dundi_helper(chan, context, exten, priority, data, DUNDI_FLAG_CANMATCH);
-+}
-+
-+static int dundi_exec(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, int newstack, const char *data)
-+{
-+      struct dundi_result results[MAX_RESULTS];
-+      int res;
-+      int x=0;
-+      char req[1024];
-+      struct ast_app *dial;
-+      
-+      if (!strncasecmp(context, "macro-", 6)) {
-+              if (!chan) {    
-+                      ast_log(LOG_NOTICE, "Can't use macro mode without a channel!\n");
-+                      return -1;
-+              }
-+              /* If done as a macro, use macro extension */
-+              if (!strcasecmp(exten, "s")) {
-+                      exten = pbx_builtin_getvar_helper(chan, "ARG1");
-+                      if (!exten || ast_strlen_zero(exten))
-+                              exten = chan->macroexten;
-+                      if (!exten || ast_strlen_zero(exten))
-+                              exten = chan->exten;
-+                      if (!exten || ast_strlen_zero(exten)) { 
-+                              ast_log(LOG_WARNING, "Called in Macro mode with no ARG1 or MACRO_EXTEN?\n");
-+                              return -1;
-+                      }
-+              }
-+              if (!data || ast_strlen_zero(data))
-+                      data = "e164";
-+      } else {
-+              if (!data || ast_strlen_zero(data))
-+                      data = context;
-+      }
-+      res = dundi_lookup(results, MAX_RESULTS, chan, data, exten, 0);
-+      if (res > 0) {
-+              sort_results(results, res);
-+              for (x=0;x<res;x++) {
-+                      if (results[x].flags & DUNDI_FLAG_EXISTS) {
-+                              if (!--priority)
-+                                      break;
-+                      }
-+              }
-+      }
-+      if (x < res) {
-+              /* Got a hit! */
-+              snprintf(req, sizeof(req), "%s/%s", results[x].tech, results[x].dest);
-+              dial = pbx_findapp("Dial");
-+              if (dial)
-+                      res = pbx_exec(chan, dial, req, newstack);
-+      } else
-+              res = -1;
-+      return res;
-+}
-+
-+static int dundi_matchmore(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data)
-+{
-+      return dundi_helper(chan, context, exten, priority, data, DUNDI_FLAG_MATCHMORE);
-+}
-+
-+static struct ast_switch dundi_switch =
-+{
-+        name:                   "DUNDi",
-+        description:                  "DUNDi Discovered Dialplan Switch",
-+        exists:                 dundi_exists,
-+        canmatch:               dundi_canmatch,
-+        exec:                   dundi_exec,
-+        matchmore:              dundi_matchmore,
-+};
-+
-+static int set_config(char *config_file, struct sockaddr_in* sin)
-+{
-+      struct ast_config *cfg;
-+      struct ast_variable *v;
-+      char *cat;
-+      int format;
-+      int x;
-+      char hn[256];
-+      struct ast_hostent he;
-+      struct hostent *hp;
-+      struct sockaddr_in sin2;
-+      static int last_port = 0;
-+      int globalpcmodel = 0;
-+      dundi_eid testeid;
-+
-+      dundi_ttl = DUNDI_DEFAULT_TTL;
-+      cfg = ast_load(config_file);
-+      
-+      
-+      if (!cfg) {
-+              ast_log(LOG_ERROR, "Unable to load config %s\n", config_file);
-+              return -1;
-+      }
-+      ipaddr[0] = '\0';
-+      if (!gethostname(hn, sizeof(hn))) {
-+              hp = ast_gethostbyname(hn, &he);
-+              if (hp) {
-+                      memcpy(&sin2.sin_addr, hp->h_addr, sizeof(sin2.sin_addr));
-+                      ast_inet_ntoa(ipaddr, sizeof(ipaddr), sin2.sin_addr);
-+              } else
-+                      ast_log(LOG_WARNING, "Unable to look up host '%s'\n", hn);
-+      } else
-+              ast_log(LOG_WARNING, "Unable to get host name!\n");
-+      ast_mutex_lock(&peerlock);
-+      reset_global_eid();
-+      global_storehistory = 0;
-+      strncpy(secretpath, "dundi", sizeof(secretpath) - 1);
-+      v = ast_variable_browse(cfg, "general");
-+      while(v) {
-+              if (!strcasecmp(v->name, "port")){ 
-+                      sin->sin_port = ntohs(atoi(v->value));
-+                      if(last_port==0){
-+                              last_port=sin->sin_port;
-+                      } else if(sin->sin_port != last_port)
-+                              ast_log(LOG_WARNING, "change to port ignored until next asterisk re-start\n");
-+              } else if (!strcasecmp(v->name, "bindaddr")) {
-+                      struct hostent *hp;
-+                      struct ast_hostent he;
-+                      hp = ast_gethostbyname(v->value, &he);
-+                      if (hp) {
-+                              memcpy(&sin->sin_addr, hp->h_addr, sizeof(sin->sin_addr));
-+                      } else
-+                              ast_log(LOG_WARNING, "Invalid host/IP '%s'\n", v->value);
-+              } else if (!strcasecmp(v->name, "authdebug")) {
-+                      authdebug = ast_true(v->value);
-+              } else if (!strcasecmp(v->name, "ttl")) {
-+                      if ((sscanf(v->value, "%i", &x) == 1) && (x > 0) && (x < DUNDI_DEFAULT_TTL)) {
-+                              dundi_ttl = x;
-+                      } else {
-+                              ast_log(LOG_WARNING, "'%s' is not a valid TTL at line %d, must be number from 1 to %d\n",
-+                                      v->value, v->lineno, DUNDI_DEFAULT_TTL);
-+                      }
-+              } else if (!strcasecmp(v->name, "autokill")) {
-+                      if (sscanf(v->value, "%i", &x) == 1) {
-+                              if (x >= 0)
-+                                      global_autokilltimeout = x;
-+                              else
-+                                      ast_log(LOG_NOTICE, "Nice try, but autokill has to be >0 or 'yes' or 'no' at line %d\n", v->lineno);
-+                      } else if (ast_true(v->value)) {
-+                              global_autokilltimeout = DEFAULT_MAXMS;
-+                      } else {
-+                              global_autokilltimeout = 0;
-+                      }
-+              } else if (!strcasecmp(v->name, "entityid")) {
-+                      if (!dundi_str_to_eid(&testeid, v->value))
-+                              global_eid = testeid;
-+                      else
-+                              ast_log(LOG_WARNING, "Invalid global endpoint identifier '%s' at line %d\n", v->value, v->lineno);
-+              } else if (!strcasecmp(v->name, "tos")) {
-+                      if (sscanf(v->value, "%i", &format) == 1)
-+                              tos = format & 0xff;
-+                      else if (!strcasecmp(v->value, "lowdelay"))
-+                              tos = IPTOS_LOWDELAY;
-+                      else if (!strcasecmp(v->value, "throughput"))
-+                              tos = IPTOS_THROUGHPUT;
-+                      else if (!strcasecmp(v->value, "reliability"))
-+                              tos = IPTOS_RELIABILITY;
-+#if !defined(__NetBSD__)
-+                      else if (!strcasecmp(v->value, "mincost"))
-+                              tos = IPTOS_MINCOST;
-+#endif
-+                      else if (!strcasecmp(v->value, "none"))
-+                              tos = 0;
-+                      else
-+#if defined(__NetBSD__)
-+                              ast_log(LOG_WARNING, "Invalid tos value at line %d, should be 'lowdelay', 'throughput', 'reliability', 'mincost', or 'none'\n", v->lineno);
-+#else
-+                              ast_log(LOG_WARNING, "Invalid tos value at line %d, should be 'lowdelay', 'throughput', 'reliability', or 'none'\n", v->lineno);
-+#endif
-+              } else if (!strcasecmp(v->name, "department")) {
-+                      strncpy(dept, v->value, sizeof(dept) - 1);
-+              } else if (!strcasecmp(v->name, "organization")) {
-+                      strncpy(org, v->value, sizeof(org) - 1);
-+              } else if (!strcasecmp(v->name, "locality")) {
-+                      strncpy(locality, v->value, sizeof(locality) - 1);
-+              } else if (!strcasecmp(v->name, "stateprov")) {
-+                      strncpy(stateprov, v->value, sizeof(stateprov) - 1);
-+              } else if (!strcasecmp(v->name, "country")) {
-+                      strncpy(country, v->value, sizeof(country) - 1);
-+              } else if (!strcasecmp(v->name, "email")) {
-+                      strncpy(email, v->value, sizeof(email) - 1);
-+              } else if (!strcasecmp(v->name, "phone")) {
-+                      strncpy(phone, v->value, sizeof(phone) - 1);
-+              } else if (!strcasecmp(v->name, "storehistory")) {
-+                      global_storehistory = ast_true(v->value);
-+              } else if (!strcasecmp(v->name, "mapserver")) {
-+                      hp = ast_gethostbyname(v->value, &he);
-+                      if (hp) {
-+                              memcpy(&map_addr.sin_addr, hp->h_addr, sizeof(map_addr.sin_addr));
-+                              if (option_verbose > 1)
-+                                      ast_verbose(VERBOSE_PREFIX_2 "Using mapping server at %s\n", v->value);
-+                      } else {
-+                              memset(&map_addr.sin_addr, 0, sizeof(map_addr.sin_addr));
-+                              ast_log(LOG_WARNING, "Could not find host '%s' for mapping host\n", v->value);
-+                      }
-+              } else if (!strcasecmp(v->name, "mappeers_per_pkt")) {
-+                      map_updates_per_pkt = atoi(v->value);
-+                      if(map_updates_per_pkt < 1 || map_updates_per_pkt > 45) {
-+                              ast_log(LOG_WARNING, "Map updates must be between 1 and 45 inclusive. Setting to 45.\n");
-+                              map_updates_per_pkt = 45;
-+                      }
-+              } else if (!strcasecmp(v->name, "mapport")) {
-+                      if (option_verbose > 1)
-+                              ast_verbose(VERBOSE_PREFIX_2 "Using mapping server at port %d\n", atoi(v->value));
-+                      map_addr.sin_port = htons(atoi(v->value));
-+              } else if (!strcasecmp(v->name, "mapinterval")) {
-+                      map_update_interval = atoi(v->value) * 1000;
-+                      if(map_update_interval < 5000 && map_update_interval != 0)
-+                              map_update_interval = 5000;
-+                      if (option_verbose > 1)
-+                              ast_verbose(VERBOSE_PREFIX_2 "Using mapping update interval of %d ms\n", map_update_interval);
-+              } else if(!strcasecmp(v->name, "mapcontext")) {
-+                      strncpy(map_context, v->value, sizeof(map_context) - 1);
-+              }
-+              v = v->next;
-+      }
-+      ast_mutex_unlock(&peerlock);
-+      mark_mappings();
-+      v = ast_variable_browse(cfg, "mappings");
-+      while(v) {
-+              build_mapping(v->name, v->value);
-+              v = v->next;
-+      }
-+      prune_mappings();
-+      mark_peers();
-+      cat = ast_category_browse(cfg, NULL);
-+      while(cat) {
-+              if (strcasecmp(cat, "general") && strcasecmp(cat, "mappings")) {
-+                      /* Entries */
-+                      if (!dundi_str_to_eid(&testeid, cat))
-+                              build_peer(&testeid, ast_variable_browse(cfg, cat), &globalpcmodel);
-+                      else
-+                              ast_log(LOG_NOTICE, "Ignoring invalid EID entry '%s'\n", cat);
-+              }
-+              cat = ast_category_browse(cfg, cat);
-+      }
-+      prune_peers();
-+      ast_destroy(cfg);
-+      load_password();
-+   
-+      /* Schedule updates */
-+      if(map_peering_sid > -1)
-+              ast_sched_del(sched, map_peering_sid);
-+      if(map_contact_sid > -1)
-+              ast_sched_del(sched, map_contact_sid);
-+      if(map_update_interval) {
-+              map_peering_sid = ast_sched_add(sched, 1000, dundi_xmit_peering, 0);
-+              map_contact_sid = ast_sched_add(sched, 1000, dundi_xmit_contact, 0);
-+      }
-+
-+      if (globalpcmodel & DUNDI_MODEL_OUTBOUND)
-+              dundi_precache_full();
-+
-+      return 0;
-+}
-+
-+int unload_module(void)
-+{
-+      int res;
-+      STANDARD_HANGUP_LOCALUSERS;
-+      ast_cli_unregister(&cli_debug);
-+      ast_cli_unregister(&cli_store_history);
-+      ast_cli_unregister(&cli_flush);
-+      ast_cli_unregister(&cli_no_debug);
-+      ast_cli_unregister(&cli_no_store_history);
-+      ast_cli_unregister(&cli_show_peers);
-+      ast_cli_unregister(&cli_show_entityid);
-+      ast_cli_unregister(&cli_show_trans);
-+      ast_cli_unregister(&cli_show_requests);
-+      ast_cli_unregister(&cli_show_mappings);
-+      ast_cli_unregister(&cli_show_precache);
-+      ast_cli_unregister(&cli_show_peer);
-+      ast_cli_unregister(&cli_lookup);
-+      ast_cli_unregister(&cli_precache);
-+      ast_cli_unregister(&cli_queryeid);
-+      ast_unregister_switch(&dundi_switch);
-+      res = ast_unregister_application(app);
-+      return res;
-+}
-+
-+int reload(void)
-+{
-+      struct sockaddr_in sin;
-+      set_config("dundi.conf",&sin);
-+      return 0;
-+}
-+
-+int load_module(void)
-+{
-+      int res=0;
-+      struct sockaddr_in sin;
-+      char iabuf[INET_ADDRSTRLEN];
-+      
-+      dundi_set_output(dundi_debug_output);
-+      dundi_set_error(dundi_error_output);
-+      
-+      /* Seed random number generator */
-+      srand(time(NULL));
-+      
-+      sin.sin_family = AF_INET;
-+      sin.sin_port = ntohs(DUNDI_PORT);
-+      sin.sin_addr.s_addr = INADDR_ANY;
-+
-+      /* INADDR_ANY should be 0.0.0.0 */
-+      map_addr.sin_family = AF_INET;
-+      map_addr.sin_port = ntohs(4525);
-+      map_addr.sin_addr.s_addr = INADDR_ANY;
-+      strncpy(map_context, "open-e164", sizeof(map_context) - 1);
-+
-+      /* Make a UDP socket */
-+      io = io_context_create();
-+      sched = sched_context_create();
-+      
-+      if (!io || !sched) {
-+              ast_log(LOG_ERROR, "Out of memory\n");
-+              return -1;
-+      }
-+
-+      ast_cli_register(&cli_debug);
-+      ast_cli_register(&cli_store_history);
-+      ast_cli_register(&cli_flush);
-+      ast_cli_register(&cli_no_debug);
-+      ast_cli_register(&cli_no_store_history);
-+      ast_cli_register(&cli_show_peers);
-+      ast_cli_register(&cli_show_entityid);
-+      ast_cli_register(&cli_show_trans);
-+      ast_cli_register(&cli_show_requests);
-+      ast_cli_register(&cli_show_mappings);
-+      ast_cli_register(&cli_show_precache);
-+      ast_cli_register(&cli_show_peer);
-+      ast_cli_register(&cli_lookup);
-+      ast_cli_register(&cli_precache);
-+      ast_cli_register(&cli_queryeid);
-+      if (ast_register_switch(&dundi_switch))
-+              ast_log(LOG_ERROR, "Unable to register DUNDi switch\n");
-+
-+      set_config("dundi.conf",&sin);
-+
-+      netsocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
-+      
-+      if (netsocket < 0) {
-+              ast_log(LOG_ERROR, "Unable to create network socket: %s\n", strerror(errno));
-+              return -1;
-+      }
-+      if (bind(netsocket,(struct sockaddr *)&sin, sizeof(sin))) {
-+              ast_log(LOG_ERROR, "Unable to bind to %s port %d: %s\n", ast_inet_ntoa(iabuf, sizeof(iabuf), sin.sin_addr), ntohs(sin.sin_port), strerror(errno));
-+              return -1;
-+      }
-+
-+      if (option_verbose > 1)
-+              ast_verbose(VERBOSE_PREFIX_2 "Using TOS bits %d\n", tos);
-+
-+      if (setsockopt(netsocket, IPPROTO_IP, IP_TOS, &tos, sizeof(tos))) 
-+              ast_log(LOG_WARNING, "Unable to set TOS to %d\n", tos);
-+      
-+      if (!res) {
-+              res = start_network_thread();
-+              if (option_verbose > 1) 
-+                      ast_verbose(VERBOSE_PREFIX_2 "DUNDi Ready and Listening on %s port %d\n", ast_inet_ntoa(iabuf, sizeof(iabuf), sin.sin_addr), ntohs(sin.sin_port));
-+      } else {
-+              ast_log(LOG_ERROR, "Unable to start network thread\n");
-+              close(netsocket);
-+      }
-+      res = ast_register_application(app, dundi_lookup_exec, synopsis, descrip);
-+
-+      return 0;
-+}
-+
-+char *description(void)
-+{
-+      return tdesc;
-+}
-+
-+int usecount(void)
-+{
-+      int res;
-+      /* XXX DUNDi cannot be unloaded XXX */
-+      return 1;
-+      STANDARD_USECOUNT(res);
-+      return res;
-+}
-+
-+char *key()
-+{
-+      return ASTERISK_GPL_KEY;
-+}
-diff -ruN asterisk-1.0.7-orig/pbx.c asterisk-1.0.7-pbx_dundi/pbx.c
---- asterisk-1.0.7-orig/pbx.c  2005-02-19 01:27:52.000000000 +0100
-+++ asterisk-1.0.7-pbx_dundi/pbx.c     2005-06-02 20:21:37.000000000 +0200
-@@ -820,7 +820,7 @@
- /*--- pbx_retrieve_variable: Support for Asterisk built-in variables and
-       functions in the dialplan
-   ---*/
--static void pbx_substitute_variables_temp(struct ast_channel *c, const char *var, char **ret, char *workspace, int workspacelen)
-+static void pbx_substitute_variables_temp(struct ast_channel *c, const char *var, char **ret, char *workspace, int workspacelen, struct varshead *headp)
- {
-       char *first,*second;
-       char tmpvar[80] = "";
-@@ -829,7 +829,6 @@
-       int offset,offset2;
-       struct ast_var_t *variables;
-       char *name, *num; /* for callerid name + num variables */
--      struct varshead *headp=NULL;
-       if (c) 
-               headp=&c->varshead;
-@@ -854,7 +853,7 @@
-               if (!first)
-                       first = tmpvar + strlen(tmpvar);
-               *first='\0';
--              pbx_substitute_variables_temp(c,tmpvar,ret,workspace,workspacelen - 1);
-+              pbx_substitute_variables_temp(c,tmpvar,ret,workspace,workspacelen - 1, headp);
-               if (!(*ret)) 
-                       return;
-               offset=atoi(first+1);   /* The number of characters, 
-@@ -993,7 +992,7 @@
-               strncpy(workspace, c->language, workspacelen - 1);
-               *ret = workspace;
-       } else {
--              if (c) {
-+              if (headp) {
-                       AST_LIST_TRAVERSE(headp,variables,entries) {
- #if 0
-                               ast_log(LOG_WARNING,"Comparing variable '%s' with '%s'\n",var,ast_var_name(variables));
-@@ -1040,7 +1039,7 @@
-       }
- }
--void pbx_substitute_variables_helper(struct ast_channel *c, const char *cp1, char *cp2, int count)
-+static void pbx_substitute_variables_helper_full(struct ast_channel *c, const char *cp1, char *cp2, int count, struct varshead *headp)
- {
-       char *cp4;
-       const char *tmp, *whereweare;
-@@ -1131,7 +1130,7 @@
-                       
-                       /* Retrieve variable value */
-                       workspace[0] = '\0';
--                      pbx_substitute_variables_temp(c,vars,&cp4, workspace, sizeof(workspace));
-+                      pbx_substitute_variables_temp(c,vars,&cp4, workspace, sizeof(workspace), headp);
-                       if (cp4) {
-                               length = strlen(cp4);
-                               if (length > count)
-@@ -1206,6 +1205,16 @@
-       }
- }
-+void pbx_substitute_variables_helper(struct ast_channel *c, const char *cp1, char *cp2, int count)
-+{
-+      pbx_substitute_variables_helper_full(c, cp1, cp2, count, NULL);
-+}
-+
-+void pbx_substitute_variables_varshead(struct varshead *headp, const char *cp1, char *cp2, int count)
-+{
-+      pbx_substitute_variables_helper_full(NULL, cp1, cp2, count, headp);
-+}
-+
- static void pbx_substitute_variables(char *passdata, int datalen, struct ast_channel *c, struct ast_exten *e) {
-         
-       memset(passdata, 0, datalen);
diff --git a/openwrt/package/asterisk/patches/asterisk-1.0.7-sipura-rtp.patch b/openwrt/package/asterisk/patches/asterisk-1.0.7-sipura-rtp.patch
deleted file mode 100644 (file)
index 58a2e6b..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-diff -ruN asterisk-1.0.7-old/rtp.c asterisk-1.0.7-new/rtp.c
---- asterisk-1.0.7-old/rtp.c   2005-01-19 03:33:54.000000000 +0100
-+++ asterisk-1.0.7-new/rtp.c   2005-05-16 19:40:02.000000000 +0200
-@@ -1048,6 +1048,7 @@
-                       rtpheader[3] |= htonl((800));
-                       /* Set the End bit for the last 3 */
-                       rtpheader[3] |= htonl((1 << 23));
-+                      rtpheader[1] = htonl(++(rtp->lastts)); /* added for Sipura SPA-3000 compat. */
-               } else if ( x < 5) {
-                       rtpheader[0] = htonl((2 << 30) | (payload << 16) | (rtp->seqno++));
-               }
diff --git a/openwrt/package/asterisk/patches/asterisk-1.0.9-Makefile-codecs-gsm.patch b/openwrt/package/asterisk/patches/asterisk-1.0.9-Makefile-codecs-gsm.patch
deleted file mode 100644 (file)
index 3030e78..0000000
+++ /dev/null
@@ -1,80 +0,0 @@
-diff -ruN asterisk-1.0.9-old/codecs/gsm/Makefile asterisk-1.0.9-new/codecs/gsm/Makefile
---- asterisk-1.0.9-old/codecs/gsm/Makefile     2005-06-21 16:27:28.000000000 +0200
-+++ asterisk-1.0.9-new/codecs/gsm/Makefile     2005-07-11 13:36:12.000000000 +0200
-@@ -40,12 +40,12 @@
- ifneq (${OSARCH},Darwin)
- ifneq (${PROC},x86_64)
- ifneq (${PROC},ultrasparc)
--ifneq ($(shell uname -m),ppc)
--ifneq ($(shell uname -m),alpha)
--ifneq ($(shell uname -m),armv4l)
-+ifneq (${PROC},alpha)
-+ifneq (${PROC},armv4l)
- ifneq (${PROC},sparc64)
- ifneq (${PROC},ppc)
- ifneq (${PROC},ppc64)
-+ifneq (${PROC},mipsel)
- OPTIMIZE+=-march=$(PROC)
- endif
- endif
-@@ -84,7 +84,7 @@
- # CCFLAGS     = -c -O
- CC            ?= gcc
--CCFLAGS       += -c -DNeedFunctionPrototypes=1 -funroll-loops -fPIC $(OPTIMIZE) -fomit-frame-pointer
-+CCFLAGS       += -c -DNeedFunctionPrototypes=1 -fPIC $(OPTIMIZE)
- LD            = $(CC)
-@@ -219,11 +219,12 @@
-               $(SRC)/short_term.c     \
-               $(SRC)/table.c
- ifeq (${OSARCH},Linux)
--ifneq ($(shell uname -m),x86_64)
--ifneq ($(shell uname -m),ppc)
--ifneq ($(shell uname -m),alpha)
--ifneq ($(shell uname -m),armv4l)
--ifneq ($(shell uname -m),sparc64)
-+ifneq (${PROC},x86_64)
-+ifneq (${PROC},ppc)
-+ifneq (${PROC},alpha)
-+ifneq (${PROC},armv4l)
-+ifneq (${PROC},sparc64)
-+ifneq ($(PROC),mipsel)
- GSM_SOURCES+= $(SRC)/k6opt.s
- endif
- endif
-@@ -231,6 +232,7 @@
- endif
- endif
- endif
-+endif
- TOAST_SOURCES = $(SRC)/toast.c                \
-               $(SRC)/toast_lin.c      \
-@@ -277,11 +279,12 @@
-               $(SRC)/table.o
- ifeq (${OSARCH},Linux)
--ifneq ($(shell uname -m), x86_64)
--ifneq ($(shell uname -m), ppc)
--ifneq ($(shell uname -m), alpha)
--ifneq ($(shell uname -m), armv4l)
--ifneq ($(shell uname -m), sparc64)
-+ifneq (${PROC}, x86_64)
-+ifneq (${PROC}, ppc)
-+ifneq (${PROC}, alpha)
-+ifneq (${PROC}, armv4l)
-+ifneq (${PROC}, sparc64)
-+ifneq ($(PROC), mipsel)
- GSM_OBJECTS+= $(SRC)/k6opt.o
- endif
- endif
-@@ -289,6 +292,7 @@
- endif
- endif
- endif
-+endif
- TOAST_OBJECTS =       $(SRC)/toast.o          \
-               $(SRC)/toast_lin.o      \
index f6a4cc4..7c278a7 100644 (file)
@@ -19,7 +19,7 @@ diff -ruN asterisk-1.0.9-old/channels/Makefile asterisk-1.0.9-new/channels/Makef
        $(CC) $(SOLINK) -o $@ $< h323/libchanh323.a $(CHANH323LIB) -L$(PWLIBDIR)/lib $(PTLIB) -L$(OPENH323DIR)/lib $(H323LIB) -L/usr/lib -lcrypto -lssl -lexpat
  
 +chan_bluetooth.so: chan_bluetooth.o
-+      $(CC) $(SOLINK) -o $@ $< $(LDFLAGS_EXTRA) -lbluetooth
++      $(CC) $(SOLINK) -o $@ $< $(EXTRA_LDFLAGS) -lbluetooth
 +
  
  #chan_modem.so : chan_modem.o
@@ -164,7 +164,7 @@ diff -ruN asterisk-1.0.9-old/channels/chan_bluetooth.c asterisk-1.0.9-new/channe
 +#define BLT_CONFIG_FILE     "bluetooth.conf"
 +#define BLT_RDBUFF_MAX      1024
 +#define BLT_DEFAULT_HCI_DEV 0
-+#define BLT_SVN_REVISION    "$Rev: 38 $"
++#define BLT_SVN_REVISION    "$Rev$"
 +
 +/* ---------------------------------- */
 +
diff --git a/openwrt/package/asterisk/patches/asterisk-1.2.0-Makefile-apps.patch b/openwrt/package/asterisk/patches/asterisk-1.2.0-Makefile-apps.patch
new file mode 100644 (file)
index 0000000..7df38f7
--- /dev/null
@@ -0,0 +1,34 @@
+diff -ruN asterisk-1.2.0-old/apps/Makefile asterisk-1.2.0-new/apps/Makefile
+--- asterisk-1.2.0-old/apps/Makefile   2005-11-11 01:32:45.000000000 +0100
++++ asterisk-1.2.0-new/apps/Makefile   2005-12-04 19:26:20.000000000 +0100
+@@ -83,6 +83,9 @@
+ #CFLAGS+=-DEXTENDED_ODBC_STORAGE
+ # See doc/README.odbcstorage for more information
++CFLAGS += $(EXTRA_CFLAGS)
++APPS += $(EXTRA_APP_MODULES)
++
+ all: $(APPS)
+ clean:
+@@ -102,14 +105,17 @@
+ app_curl.so: app_curl.o
+       $(CC) $(SOLINK) -o $@ ${CYGSOLINK} $< ${CYGSOLIB} $(CURLLIBS)
++app_sql_mysql.so: app_sql_mysql.o
++      $(CC) $(SOLINK) -o $@ ${CYGSOLINK} $< ${CYGSOLIB} $(EXTRA_LDFLAGS) -lmysqlclient
++
+ app_sql_postgres.o: app_sql_postgres.c
+-      $(CC) -pipe -I/usr/local/pgsql/include $(CFLAGS) -c -o app_sql_postgres.o app_sql_postgres.c
++      $(CC) -pipe $(CFLAGS) -c -o app_sql_postgres.o app_sql_postgres.c
+ app_sql_postgres.so: app_sql_postgres.o
+-      $(CC) $(SOLINK) -o $@ ${CYGSOLINK} $< ${CYGSOLIB} -L/usr/local/pgsql/lib -lpq
++      $(CC) $(SOLINK) -o $@ ${CYGSOLINK} $< ${CYGSOLIB} $(EXTRA_LDFLAGS) -lpq
+ app_sql_odbc.so: app_sql_odbc.o
+-      $(CC) $(SOLINK) -o $@ ${CYGSOLINK} $< ${CYGSOLIB} -lodbc
++      $(CC) $(SOLINK) -o $@ ${CYGSOLINK} $< ${CYGSOLIB} $(EXTRA_LDFLAGS) -lodbc
+ look: look.c
+       $(CC) -pipe -O6 -g look.c -o look -lncurses
diff --git a/openwrt/package/asterisk/patches/asterisk-1.2.0-Makefile-cdr.patch b/openwrt/package/asterisk/patches/asterisk-1.2.0-Makefile-cdr.patch
new file mode 100644 (file)
index 0000000..7fc623e
--- /dev/null
@@ -0,0 +1,37 @@
+diff -ruN asterisk-1.2.0-old/cdr/Makefile asterisk-1.2.0-new/cdr/Makefile
+--- asterisk-1.2.0-old/cdr/Makefile    2005-11-14 01:45:07.000000000 +0100
++++ asterisk-1.2.0-new/cdr/Makefile    2005-12-04 22:22:43.000000000 +0100
+@@ -107,6 +107,9 @@
+   MODS+=cdr_sqlite.so
+ endif
++CFLAGS += $(EXTRA_CFLAGS)
++MODS += $(EXTRA_CDR_MODULES)
++
+ all: depend $(MODS)
+ install: all
+@@ -123,16 +126,19 @@
+ endif
+ cdr_odbc.so: cdr_odbc.o
+-      $(CC) $(SOLINK) -o $@ ${CYGSOLINK} $< ${CYGSOLIB} -lodbc $(MLFLAGS)
++      $(CC) $(SOLINK) -o $@ ${CYGSOLINK} $< ${CYGSOLIB} $(EXTRA_LDFLAGS) -lodbc $(MLFLAGS)
+ cdr_tds.so: cdr_tds.o
+-      $(CC) $(SOLINK) -o $@ ${CYGSOLINK} $< ${CYGSOLIB} -ltds $(MLFLAGS)
++      $(CC) $(SOLINK) -o $@ ${CYGSOLINK} $< ${CYGSOLIB} $(EXTRA_LDFLAGS) -ltds $(MLFLAGS)
++
++cdr_mysql.so: cdr_pgsql.o
++      $(CC) $(SOLINK) -o $@ ${CYGSOLINK} $< ${CYGSOLIB} $(EXTRA_LDFLAGS) -lmysqlclient -lz $(MLFLAGS)
+ cdr_pgsql.so: cdr_pgsql.o
+-      $(CC) $(SOLINK) -o $@ ${CYGSOLINK} $< ${CYGSOLIB} -lpq -lz $(MLFLAGS)
++      $(CC) $(SOLINK) -o $@ ${CYGSOLINK} $< ${CYGSOLIB} $(EXTRA_LDFLAGS) -lpq -lz $(MLFLAGS)
+ cdr_sqlite.so: cdr_sqlite.o
+-      $(CC) $(SOLINK) -o $@ ${CYGSOLINK} $< ${CYGSOLIB} -lsqlite $(MLFLAGS)
++      $(CC) $(SOLINK) -o $@ ${CYGSOLINK} $< ${CYGSOLIB} $(EXTRA_LDFLAGS) -lsqlite $(MLFLAGS)
+ depend: .depend
diff --git a/openwrt/package/asterisk/patches/asterisk-1.2.0-Makefile-channels.patch b/openwrt/package/asterisk/patches/asterisk-1.2.0-Makefile-channels.patch
new file mode 100644 (file)
index 0000000..d5ac6ad
--- /dev/null
@@ -0,0 +1,22 @@
+diff -ruN asterisk-1.2.0-old/channels/Makefile asterisk-1.2.0-new/channels/Makefile
+--- asterisk-1.2.0-old/channels/Makefile       2005-12-04 04:48:40.000000000 +0100
++++ asterisk-1.2.0-new/channels/Makefile       2005-12-04 23:30:19.000000000 +0100
+@@ -155,6 +155,9 @@
+ #CFLAGS+=$(shell [ -f $(ZAPDIR)/libzap.a ] && echo "-I$(ZAPDIR)")
++CFLAGS += $(EXTRA_CFLAGS)
++CHANNEL_LIBS += $(EXTRA_CHAN_MODULES)
++
+ all: depend $(CHANNEL_LIBS) 
+ clean:
+@@ -162,7 +165,7 @@
+       rm -f busy.h ringtone.h gentone gentone-ulaw
+ %.so : %.o
+-      $(CC) $(SOLINK) -o $@ ${CYGSOLINK} $< ${CYGSOLIB} ${LIBS}
++      $(CC) $(SOLINK) -o $@ ${CYGSOLINK} $< ${CYGSOLIB}
+ ifneq ($(wildcard .depend),)
+   include .depend
diff --git a/openwrt/package/asterisk/patches/asterisk-1.2.0-Makefile-codecs-gsm.patch b/openwrt/package/asterisk/patches/asterisk-1.2.0-Makefile-codecs-gsm.patch
new file mode 100644 (file)
index 0000000..ec49daf
--- /dev/null
@@ -0,0 +1,35 @@
+diff -ruN asterisk-1.2.0-old/codecs/gsm/Makefile asterisk-1.2.0-new/codecs/gsm/Makefile
+--- asterisk-1.2.0-old/codecs/gsm/Makefile     2005-11-08 04:31:45.000000000 +0100
++++ asterisk-1.2.0-new/codecs/gsm/Makefile     2005-12-04 13:31:50.000000000 +0100
+@@ -236,6 +236,7 @@
+ ifneq ($(shell uname -m),armv4l)
+ ifneq ($(shell uname -m),sparc64)
+ ifneq (${PROC},arm)
++ifneq (${PROC},mipsel)
+ GSM_SOURCES+= $(SRC)/k6opt.s
+ endif
+ endif
+@@ -245,6 +246,7 @@
+ endif
+ endif
+ endif
++endif
+ TOAST_SOURCES = $(SRC)/toast.c                \
+               $(SRC)/toast_lin.c      \
+@@ -297,6 +299,7 @@
+ ifneq ($(shell uname -m), alpha)
+ ifneq ($(shell uname -m), sparc64)
+ ifneq ($(shell uname -m), armv4l)
++ifneq (${PROC}, mipsel)
+ GSM_OBJECTS+= $(SRC)/k6opt.o
+ endif
+ endif
+@@ -305,6 +308,7 @@
+ endif
+ endif
+ endif
++endif
+ TOAST_OBJECTS =       $(SRC)/toast.o          \
+               $(SRC)/toast_lin.o      \
diff --git a/openwrt/package/asterisk/patches/asterisk-1.2.0-Makefile-codecs.patch b/openwrt/package/asterisk/patches/asterisk-1.2.0-Makefile-codecs.patch
new file mode 100644 (file)
index 0000000..f59c24c
--- /dev/null
@@ -0,0 +1,13 @@
+diff -ruN asterisk-1.2.0-old/codecs/Makefile asterisk-1.2.0-new/codecs/Makefile
+--- asterisk-1.2.0-old/codecs/Makefile 2005-11-08 05:13:18.000000000 +0100
++++ asterisk-1.2.0-new/codecs/Makefile 2005-12-04 19:24:53.000000000 +0100
+@@ -72,6 +72,9 @@
+         codec_adpcm.so codec_ulaw.so codec_alaw.so codec_a_mu.so \
+       codec_g726.so
++CFLAGS += $(EXTRA_CFLAGS)
++CODECS += $(EXTRA_CODEC_MODULES)
++
+ all: depend $(CODECS)
+ clean:
diff --git a/openwrt/package/asterisk/patches/asterisk-1.2.0-Makefile-pbx.patch b/openwrt/package/asterisk/patches/asterisk-1.2.0-Makefile-pbx.patch
new file mode 100644 (file)
index 0000000..f1d2a63
--- /dev/null
@@ -0,0 +1,22 @@
+diff -ruN asterisk-1.2.0-old/pbx/Makefile asterisk-1.2.0-new/pbx/Makefile
+--- asterisk-1.2.0-old/pbx/Makefile    2005-11-01 22:53:30.000000000 +0100
++++ asterisk-1.2.0-new/pbx/Makefile    2005-12-04 19:23:48.000000000 +0100
+@@ -38,6 +38,9 @@
+ KDE_CONSOLE_OBJS=pbx_kdeconsole_main.o pbx_kdeconsole.o 
++CFLAGS += $(EXTRA_CFLAGS)
++PBX_LIBS += $(EXTRA_PBX_MODULES)
++
+ all: depend $(PBX_LIBS)
+ clean:
+@@ -59,7 +62,7 @@
+       $(CC) $(SOLINK) -o $@ $(KDE_CONSOLE_OBJS) $(KDE_LIBS)
+ pbx_dundi.so: dundi-parser.o pbx_dundi.o
+-      $(CC) $(SOLINK) -o $@ ${CYGSOLINK} pbx_dundi.o dundi-parser.o -lz ${CYGSOLIB}
++      $(CC) $(SOLINK) -o $@ ${CYGSOLINK} pbx_dundi.o dundi-parser.o $(EXTRA_LDFLAGS) -lz ${CYGSOLIB}
+ %.moc : %.h
+       $(MOC) $< -o $@
diff --git a/openwrt/package/asterisk/patches/asterisk-1.2.0-Makefile-res.patch b/openwrt/package/asterisk/patches/asterisk-1.2.0-Makefile-res.patch
new file mode 100644 (file)
index 0000000..2f782cb
--- /dev/null
@@ -0,0 +1,26 @@
+diff -ruN asterisk-1.2.0-old/res/Makefile asterisk-1.2.0-new/res/Makefile
+--- asterisk-1.2.0-old/res/Makefile    2005-11-16 21:49:44.000000000 +0100
++++ asterisk-1.2.0-new/res/Makefile    2005-12-04 19:18:15.000000000 +0100
+@@ -69,6 +69,9 @@
+ CFLAGS+=-DOPENSSL_NO_KRB5 -fPIC
+ endif
++CFLAGS += $(EXTRA_CFLAGS)
++MODS += $(EXTRA_RES_MODULES)
++
+ all: depend $(MODS)
+ install: all
+@@ -112,6 +112,12 @@
+ res_config_odbc.so: res_config_odbc.o
+        $(CC) $(SOLINK) -o $@ ${CYGSOLINK} $< ${CYGSOLIB} ${CYG_RES_CONFIG_ODBC_LIB}
+
++res_config_mysql.so: res_config_mysql.o
++      $(CC) $(SOLINK) -o $@ ${CYGSOLINK} $< ${CYGSOLIB} $(EXTRA_LDFLAGS) -lmysqlclient -lz
++
++res_sqlite.so: res_sqlite.o
++      $(CC) $(SOLINK) -o $@ ${CYGSOLINK} $< ${CYGSOLIB} $(EXTRA_LDFLAGS) -lsqlite
++
+ ifneq ($(wildcard .depend),)
+   include .depend
+ endif
diff --git a/openwrt/package/asterisk/patches/asterisk-1.2.0-Makefile.patch b/openwrt/package/asterisk/patches/asterisk-1.2.0-Makefile.patch
new file mode 100644 (file)
index 0000000..2b4afa2
--- /dev/null
@@ -0,0 +1,54 @@
+diff -ruN asterisk-1.2.0-old/Makefile asterisk-1.2.0-new/Makefile
+--- asterisk-1.2.0-old/Makefile        2005-11-16 21:23:53.000000000 +0100
++++ asterisk-1.2.0-new/Makefile        2005-12-04 23:01:16.000000000 +0100
+@@ -341,16 +339,6 @@
+       netsock.o slinfactory.o ast_expr2.o ast_expr2f.o \
+       cryptostub.o
+-ifeq ($(wildcard $(CROSS_COMPILE_TARGET)/usr/include/sys/poll.h),)
+-  OBJS+= poll.o
+-  ASTCFLAGS+=-DPOLLCOMPAT
+-endif
+-
+-ifeq ($(wildcard $(CROSS_COMPILE_TARGET)/usr/include/dlfcn.h),)
+-  OBJS+= dlfcn.o
+-  ASTCFLAGS+=-DDLFCNCOMPAT
+-endif
+-
+ ifeq ($(OSARCH),Linux)
+   LIBS+=-ldl -lpthread -lncurses -lm -lresolv  #-lnjamd
+ else
+@@ -401,7 +389,9 @@
+   HAVEDOT=no
+ endif
++ifneq ($(NOCRYPTO),yes)
+ LIBS+=-lssl
++endif
+ INSTALL=install
+@@ -430,12 +420,12 @@
+       cd editline && unset CFLAGS LIBS && ./configure ; \
+ editline/libedit.a: FORCE
+-      cd editline && unset CFLAGS LIBS && test -f config.h || ./configure
++      cd editline && unset CFLAGS LIBS && test -f config.h || CFLAGS="$(OPTIMIZE) $(EXTRA_CFLAGS)" LDFLAGS="$(EXTRA_LDFLAGS)" ./configure
+       $(MAKE) -C editline libedit.a
+ db1-ast/libdb1.a: FORCE
+       @if [ -d db1-ast ]; then \
+-              $(MAKE) -C db1-ast libdb1.a ; \
++              $(MAKE) OORG="$(OPTIMIZE)" -C db1-ast libdb1.a ; \
+       else \
+               echo "You need to do a cvs update -d not just cvs update"; \
+               exit 1; \
+@@ -513,7 +503,7 @@
+       fi
+       rm -f include/asterisk/build.h.tmp
+       $(CC) -c -o buildinfo.o $(CFLAGS) buildinfo.c
+-      $(CC) $(DEBUG) $(ASTOBJ) $(ASTLINK) $(OBJS) buildinfo.o $(LIBEDIT) db1-ast/libdb1.a stdtime/libtime.a $(LIBS)
++      $(CC) $(DEBUG) $(ASTOBJ) $(ASTLINK) $(OBJS) buildinfo.o $(LIBEDIT) db1-ast/libdb1.a stdtime/libtime.a $(EXTRA_LDFLAGS) $(LIBS)
+ muted: muted.o
+       $(CC) $(AUDIO_LIBS) -o muted muted.o
diff --git a/openwrt/package/asterisk/patches/asterisk-1.2.0-app_mysql.patch b/openwrt/package/asterisk/patches/asterisk-1.2.0-app_mysql.patch
new file mode 100644 (file)
index 0000000..6f02e75
--- /dev/null
@@ -0,0 +1,449 @@
+diff -ruN asterisk-1.2.0-old/apps/app_sql_mysql.c asterisk-1.2.0-new/apps/app_sql_mysql.c
+--- asterisk-1.2.0-old/apps/app_sql_mysql.c    1970-01-01 01:00:00.000000000 +0100
++++ asterisk-1.2.0-new/apps/app_sql_mysql.c    2005-06-07 18:36:28.000000000 +0200
+@@ -0,0 +1,445 @@
++/*
++ * Asterisk -- A telephony toolkit for Linux.
++ *
++ * Connect to MySQL
++ * 
++ * Copyright (C) 2004, Constantine Filin and Christos Ricudis
++ *
++ * Christos Ricudis <ricudis@itc.auth.gr>
++ * Constantine Filin <cf@intermedia.net>
++ *
++ * This program is free software, distributed under the terms of
++ * the GNU General Public License
++ */
++
++#include <stdlib.h>
++#include <unistd.h>
++#include <string.h>
++#include <stdlib.h>
++#include <sys/types.h>
++#include <stdio.h>
++#include <unistd.h>
++
++#include <mysql.h>
++
++#include <asterisk/file.h>
++#include <asterisk/logger.h>
++#include <asterisk/channel.h>
++#include <asterisk/pbx.h>
++#include <asterisk/module.h>
++#include <asterisk/linkedlists.h>
++#include <asterisk/chanvars.h>
++#include <asterisk/lock.h>
++
++#define EXTRA_LOG 0
++
++static char *tdesc = "Simple Mysql Interface";
++
++static char *app = "MYSQL";
++
++static char *synopsis = "Do several mySQLy things";
++
++static char *descrip = 
++"MYSQL():  Do several mySQLy things\n"
++"Syntax:\n"
++"  MYSQL(Connect connid dhhost dbuser dbpass dbname)\n"
++"    Connects to a database.  Arguments contain standard MySQL parameters\n"
++"    passed to function mysql_real_connect.  Connection identifer returned\n"
++"    in ${var}\n"
++"  MYSQL(Query resultid ${connid} query-string)\n"
++"    Executes standard MySQL query contained in query-string using established\n"
++"    connection identified by ${connection_identifier}. Result of query is\n"
++"    is stored in ${var}.\n"
++"  MYSQL(Fetch fetchid ${resultid} var1 var2 ... varN)\n"
++"    Fetches a single row from a result set contained in ${result_identifier}.\n"
++"    Assigns returned fields to ${var1} ... ${varn}.  ${fetchid} is set TRUE\n"
++"    if additional rows exist in result set.\n"
++"  MYSQL(Clear ${resultid})\n"
++"    Frees memory and datastructures associated with result set.\n" 
++"  MYSQL(Disconnect ${connid})\n"
++"    Disconnects from named connection to MySQL.\n"
++"  On exit, always returns 0. Sets MYSQL_STATUS to 0 on success and -1 on error.\n";
++
++/*    
++EXAMPLES OF USE : 
++
++exten => s,2,MYSQL(Connect connid localhost asterisk mypass credit)
++exten => s,3,MYSQL(Query resultid ${connid} SELECT username,credit FROM credit WHERE callerid=${CALLERIDNUM})
++exten => s,4,MYSQL(Fetch fetchid ${resultid} datavar1 datavar2)
++exten => s,5,GotoIf(${fetchid}?6:8)
++exten => s,6,Festival("User ${datavar1} currently has credit balance of ${datavar2} dollars.")        
++exten => s,7,Goto(s,4)
++exten => s,8,MYSQL(Clear ${resultid})
++exten => s,9,MYSQL(Disconnect ${connid})
++*/
++
++STANDARD_LOCAL_USER;
++LOCAL_USER_DECL;
++
++AST_MUTEX_DEFINE_STATIC(_mysql_mutex);
++
++#define AST_MYSQL_ID_DUMMY   0
++#define AST_MYSQL_ID_CONNID  1
++#define AST_MYSQL_ID_RESID   2
++#define AST_MYSQL_ID_FETCHID 3
++
++struct ast_MYSQL_id {
++      int identifier_type; /* 0=dummy, 1=connid, 2=resultid */
++      int identifier;
++      void *data;
++      AST_LIST_ENTRY(ast_MYSQL_id) entries;
++} *ast_MYSQL_id;
++
++AST_LIST_HEAD(MYSQLidshead,ast_MYSQL_id) _mysql_ids_head;
++
++/* helpful procs */
++static void *find_identifier(int identifier,int identifier_type) {
++      struct MYSQLidshead *headp;
++      struct ast_MYSQL_id *i;
++      void *res=NULL;
++      int found=0;
++      
++      headp=&_mysql_ids_head;
++      
++      if (AST_LIST_LOCK(headp)) {
++              ast_log(LOG_WARNING,"Unable to lock identifiers list\n");
++      } else {
++              AST_LIST_TRAVERSE(headp,i,entries) {
++                      if ((i->identifier==identifier) && (i->identifier_type==identifier_type)) {
++                              found=1;
++                              res=i->data;
++                              break;
++                      }
++              }
++              if (!found) {
++                      ast_log(LOG_WARNING,"Identifier %d, identifier_type %d not found in identifier list\n",identifier,identifier_type);
++              }
++              AST_LIST_UNLOCK(headp);
++      }
++      
++      return res;
++}
++
++static int add_identifier(int identifier_type,void *data) {
++      struct ast_MYSQL_id *i,*j;
++      struct MYSQLidshead *headp;
++      int maxidentifier=0;
++      
++      headp=&_mysql_ids_head;
++      i=NULL;
++      j=NULL;
++      
++      if (AST_LIST_LOCK(headp)) {
++              ast_log(LOG_WARNING,"Unable to lock identifiers list\n");
++              return(-1);
++      } else {
++              i=malloc(sizeof(struct ast_MYSQL_id));
++              AST_LIST_TRAVERSE(headp,j,entries) {
++                      if (j->identifier>maxidentifier) {
++                              maxidentifier=j->identifier;
++                      }
++              }
++              i->identifier=maxidentifier+1;
++              i->identifier_type=identifier_type;
++              i->data=data;
++              AST_LIST_INSERT_HEAD(headp,i,entries);
++              AST_LIST_UNLOCK(headp);
++      }
++      return i->identifier;
++}
++
++static int del_identifier(int identifier,int identifier_type) {
++      struct ast_MYSQL_id *i;
++      struct MYSQLidshead *headp;
++      int found=0;
++      
++        headp=&_mysql_ids_head;
++        
++        if (AST_LIST_LOCK(headp)) {
++              ast_log(LOG_WARNING,"Unable to lock identifiers list\n");
++      } else {
++              AST_LIST_TRAVERSE(headp,i,entries) {
++                      if ((i->identifier==identifier) && 
++                          (i->identifier_type==identifier_type)) {
++                              AST_LIST_REMOVE(headp,i,entries);
++                              free(i);
++                              found=1;
++                              break;
++                      }
++              }
++              AST_LIST_UNLOCK(headp);
++      }
++                      
++      if (found==0) {
++              ast_log(LOG_WARNING,"Could not find identifier %d, identifier_type %d in list to delete\n",identifier,identifier_type);
++              return(-1);
++      } else {
++              return(0);
++      }
++}
++
++static int set_asterisk_int(struct ast_channel *chan, char *varname, int id) {
++      if( id>=0 ) {
++              char s[100] = "";
++              snprintf(s, sizeof(s)-1, "%d", id);
++#if EXTRA_LOG
++              ast_log(LOG_WARNING,"MYSQL: setting var '%s' to value '%s'\n",varname,s);
++#endif
++              pbx_builtin_setvar_helper(chan,varname,s);
++      }
++      return id;
++}
++
++static int add_identifier_and_set_asterisk_int(struct ast_channel *chan, char *varname, int identifier_type, void *data) {
++      return set_asterisk_int(chan,varname,add_identifier(identifier_type,data));
++}
++
++static int safe_scan_int( char** data, char* delim, int def ) {
++      char* end;
++      int res = def;
++      char* s = strsep(data,delim);
++      if( s ) {
++              res = strtol(s,&end,10);
++              if (*end) res = def;  /* not an integer */
++      }
++      return res;
++}
++
++/* MYSQL operations */
++static int aMYSQL_connect(struct ast_channel *chan, char *data) {
++      
++      MYSQL *mysql;
++
++      char *connid_var;
++      char *dbhost;
++      char *dbuser;
++      char *dbpass;
++      char *dbname;
++       
++      strsep(&data," "); // eat the first token, we already know it :P 
++
++      connid_var=strsep(&data," ");
++      dbhost=strsep(&data," ");
++      dbuser=strsep(&data," ");
++      dbpass=strsep(&data," ");
++      dbname=strsep(&data,"\n");
++      
++      if( connid_var && dbhost && dbuser && dbpass && dbname ) {
++              mysql = mysql_init(NULL);
++              if (mysql) {
++                      if (mysql_real_connect(mysql,dbhost,dbuser,dbpass,dbname,0,NULL,0)) {
++                              add_identifier_and_set_asterisk_int(chan,connid_var,AST_MYSQL_ID_CONNID,mysql);
++                              return 0;
++                      }
++                      else {
++                              ast_log(LOG_WARNING,"mysql_real_connect(mysql,%s,%s,dbpass,%s,...) failed\n",dbhost,dbuser,dbname);
++                      }
++              }
++              else {
++                      ast_log(LOG_WARNING,"myslq_init returned NULL\n");
++              }
++      }
++      else {
++              ast_log(LOG_WARNING,"MYSQL(connect is missing some arguments\n");
++      }
++
++      return -1;
++}
++
++static int aMYSQL_query(struct ast_channel *chan, char *data) {
++      
++      MYSQL       *mysql;
++      MYSQL_RES   *mysqlres;
++
++      char *resultid_var;
++      int connid;
++      char *querystring;
++
++      strsep(&data," "); // eat the first token, we already know it :P 
++
++      resultid_var = strsep(&data," ");
++      connid       = safe_scan_int(&data," ",-1);
++      querystring  = strsep(&data,"\n");
++
++      if (resultid_var && (connid>=0) && querystring) {
++              if ((mysql=find_identifier(connid,AST_MYSQL_ID_CONNID))!=NULL) {
++                      mysql_query(mysql,querystring);
++                      if ((mysqlres=mysql_use_result(mysql))!=NULL) {
++                              add_identifier_and_set_asterisk_int(chan,resultid_var,AST_MYSQL_ID_RESID,mysqlres);
++                              return 0;
++                      }
++                      else if( mysql_field_count(mysql)==0 ) {
++                              return 0;  // See http://dev.mysql.com/doc/mysql/en/mysql_field_count.html
++                      }
++                      else {
++                              ast_log(LOG_WARNING,"aMYSQL_query: mysql_store_result() failed on query %s\n",querystring);
++                      }
++              }
++              else {
++                      ast_log(LOG_WARNING,"aMYSQL_query: Invalid connection identifier %d passed in aMYSQL_query\n",connid);
++              }
++      }
++      else {
++              ast_log(LOG_WARNING,"aMYSQL_query: missing some arguments\n");
++      }
++      
++      return -1;
++}
++
++
++static int aMYSQL_fetch(struct ast_channel *chan, char *data) {
++      
++      MYSQL_RES *mysqlres;
++      MYSQL_ROW mysqlrow;
++
++      char *fetchid_var,*s5,*s6;
++      int resultid,numFields,j;
++      
++      strsep(&data," "); // eat the first token, we already know it :P 
++
++      fetchid_var = strsep(&data," ");
++      resultid    = safe_scan_int(&data," ",-1);
++
++      if (fetchid_var && (resultid>=0) ) {
++              if ((mysqlres=find_identifier(resultid,AST_MYSQL_ID_RESID))!=NULL) {
++                      /* Grab the next row */
++                      if ((mysqlrow=mysql_fetch_row(mysqlres))!=NULL) {
++                              numFields=mysql_num_fields(mysqlres);
++                              for (j=0;j<numFields;j++) {
++                                      s5=strsep(&data," ");
++                                      if (s5==NULL) {
++                                              ast_log(LOG_WARNING,"ast_MYSQL_fetch: More fields (%d) than variables (%d)\n",numFields,j);
++                                              break;
++                                      }
++                                      s6=mysqlrow[j];
++                                      pbx_builtin_setvar_helper(chan,s5, s6 ? s6 : "NULL");
++                              }
++#ifdef EXTRA_LOG
++                              ast_log(LOG_WARNING,"ast_MYSQL_fetch: numFields=%d\n",numFields);
++#endif
++                              set_asterisk_int(chan,fetchid_var,1); // try more rows
++                      } else {
++#if EXTRA_LOG
++                              ast_log(LOG_WARNING,"ast_MYSQL_fetch : EOF\n");
++#endif
++                              set_asterisk_int(chan,fetchid_var,0); // no more rows
++                      }
++                      return 0;
++              }
++              else {
++                      ast_log(LOG_WARNING,"aMYSQL_fetch: Invalid result identifier %d passed\n",resultid);
++              }
++      }
++      else {
++              ast_log(LOG_WARNING,"aMYSQL_fetch: missing some arguments\n");
++      }
++
++      return -1;
++}
++
++static int aMYSQL_clear(struct ast_channel *chan, char *data) {
++
++      MYSQL_RES *mysqlres;
++
++      int id;
++      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 {
++              mysql_free_result(mysqlres);
++              del_identifier(id,AST_MYSQL_ID_RESID);
++      }
++
++      return 0;
++}
++
++static int aMYSQL_disconnect(struct ast_channel *chan, char *data) {
++      
++      MYSQL *mysql;
++      int id;
++      strsep(&data," "); // eat the first token, we already know it :P 
++
++      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 {
++              mysql_close(mysql);
++              del_identifier(id,AST_MYSQL_ID_CONNID);
++      } 
++
++      return 0;
++}
++
++static int MYSQL_exec(struct ast_channel *chan, void *data)
++{
++      struct localuser *u;
++      int result;
++      char sresult[10];
++
++#if EXTRA_LOG
++      fprintf(stderr,"MYSQL_exec: data=%s\n",(char*)data);
++#endif
++
++      if (!data) {
++              ast_log(LOG_WARNING, "APP_MYSQL requires an argument (see manual)\n");
++              return -1;
++      }
++
++      LOCAL_USER_ADD(u);
++      result=0;
++
++      ast_mutex_lock(&_mysql_mutex);
++
++      if (strncasecmp("connect",data,strlen("connect"))==0) {
++              result=aMYSQL_connect(chan,ast_strdupa(data));
++      } else  if (strncasecmp("query",data,strlen("query"))==0) {
++              result=aMYSQL_query(chan,ast_strdupa(data));
++      } else  if (strncasecmp("fetch",data,strlen("fetch"))==0) {
++              result=aMYSQL_fetch(chan,ast_strdupa(data));
++      } else  if (strncasecmp("clear",data,strlen("clear"))==0) {
++              result=aMYSQL_clear(chan,ast_strdupa(data));
++      } else  if (strncasecmp("disconnect",data,strlen("disconnect"))==0) {
++              result=aMYSQL_disconnect(chan,ast_strdupa(data));
++      } else {
++              ast_log(LOG_WARNING, "Unknown argument to MYSQL application : %s\n",(char *)data);
++              result=-1;      
++      }
++              
++      ast_mutex_unlock(&_mysql_mutex);
++
++      LOCAL_USER_REMOVE(u);                                                                                
++      snprintf(sresult, sizeof(sresult), "%d", result);
++      pbx_builtin_setvar_helper(chan, "MYSQL_STATUS", sresult);
++      return 0;
++}
++
++int unload_module(void)
++{
++      STANDARD_HANGUP_LOCALUSERS;
++      return ast_unregister_application(app);
++}
++
++int load_module(void)
++{
++      struct MYSQLidshead *headp = &_mysql_ids_head;
++      AST_LIST_HEAD_INIT(headp);
++      return ast_register_application(app, MYSQL_exec, synopsis, descrip);
++}
++
++char *description(void)
++{
++      return tdesc;
++}
++
++int usecount(void)
++{
++      int res;
++      STANDARD_USECOUNT(res);
++      return res;
++}
++
++char *key()
++{
++      return ASTERISK_GPL_KEY;
++}
diff --git a/openwrt/package/asterisk/patches/asterisk-1.2.0-cdr_mysql.patch b/openwrt/package/asterisk/patches/asterisk-1.2.0-cdr_mysql.patch
new file mode 100644 (file)
index 0000000..f4dc29f
--- /dev/null
@@ -0,0 +1,522 @@
+diff -ruN asterisk-1.2.0-old/configs/cdr_mysql.conf.sample asterisk-1.2.0-new/configs/cdr_mysql.conf.sample
+--- asterisk-1.2.0-old/configs/cdr_mysql.conf.sample   1970-01-01 01:00:00.000000000 +0100
++++ asterisk-1.2.0-new/configs/cdr_mysql.conf.sample   2005-01-21 02:43:20.000000000 +0100
+@@ -0,0 +1,21 @@
++;
++; Note - if the database server is hosted on the same machine as the
++; asterisk server, you can achieve a local Unix socket connection by
++; setting hostname=localhost
++;
++; port and sock are both optional parameters.  If hostname is specified
++; and is not "localhost", then cdr_mysql will attempt to connect to the
++; port specified or use the default port.  If hostname is not specified
++; or if hostname is "localhost", then cdr_mysql will attempt to connect
++; to the socket file specified by sock or otherwise use the default socket
++; file.
++;
++;[global]
++;hostname=database.host.name
++;dbname=asteriskcdrdb
++;table=cdr
++;password=password 
++;user=asteriskcdruser
++;port=3306
++;sock=/tmp/mysql.sock
++;userfield=1
+diff -ruN asterisk-1.2.0-old/cdr/cdr_mysql.c asterisk-1.2.0-new/cdr/cdr_mysql.c
+--- asterisk-1.2.0-old/cdr/cdr_mysql.c 1970-01-01 01:00:00.000000000 +0100
++++ asterisk-1.2.0-new/cdr/cdr_mysql.c 2005-12-04 20:10:59.000000000 +0100
+@@ -0,0 +1,493 @@
++/*
++ * Asterisk -- A telephony toolkit for Linux.
++ *
++ * MySQL CDR logger 
++ * 
++ * James Sharp <jsharp@psychoses.org>
++ *
++ * Modified August 2003
++ * Tilghman Lesher <asterisk__cdr__cdr_mysql__200308@the-tilghman.com>
++ *
++ * Modified August 6, 2005
++ * Joseph Benden <joe@thrallingpenguin.com>
++ * Added mysql connection timeout parameter
++ * Added an automatic reconnect as to not lose a cdr record
++ * Cleaned up the original code to match the coding guidelines
++ *
++ * This program is free software, distributed under the terms of
++ * the GNU General Public License.
++ *
++ */
++
++#include <sys/types.h>
++
++#include <stdio.h>
++#include <string.h>
++
++#include <stdlib.h>
++#include <unistd.h>
++#include <time.h>
++
++#include <mysql.h>
++#include <errmsg.h>
++
++#include <sys/stat.h>
++#include <sys/types.h>
++#include <errno.h>
++
++#include <asterisk/config.h>
++#include <asterisk/options.h>
++#include <asterisk/channel.h>
++#include <asterisk/cdr.h>
++#include <asterisk/module.h>
++#include <asterisk/logger.h>
++#include <asterisk/cli.h>
++
++#define DATE_FORMAT "%Y-%m-%d %T"
++
++static char *desc = "MySQL CDR Backend";
++static char *name = "mysql";
++static char *config = "cdr_mysql.conf";
++static char *hostname = NULL, *dbname = NULL, *dbuser = NULL, *password = NULL, *dbsock = NULL, *dbtable = NULL;
++static int hostname_alloc = 0, dbname_alloc = 0, dbuser_alloc = 0, password_alloc = 0, dbsock_alloc = 0, dbtable_alloc = 0;
++static int dbport = 0;
++static int connected = 0;
++static time_t connect_time = 0;
++static int records = 0;
++static int totalrecords = 0;
++static int userfield = 0;
++static unsigned int timeout = 0;
++
++AST_MUTEX_DEFINE_STATIC(mysql_lock);
++
++static MYSQL mysql;
++
++static char cdr_mysql_status_help[] =
++"Usage: cdr mysql status\n"
++"       Shows current connection status for cdr_mysql\n";
++
++static int handle_cdr_mysql_status(int fd, int argc, char *argv[])
++{
++      if (connected) {
++              char status[256], status2[100] = "";
++              int ctime = time(NULL) - connect_time;
++              if (dbport)
++                      snprintf(status, 255, "Connected to %s@%s, port %d", dbname, hostname, dbport);
++              else if (dbsock)
++                      snprintf(status, 255, "Connected to %s on socket file %s", dbname, dbsock);
++              else
++                      snprintf(status, 255, "Connected to %s@%s", dbname, hostname);
++
++              if (dbuser && *dbuser)
++                      snprintf(status2, 99, " with username %s", dbuser);
++              if (dbtable && *dbtable)
++                      snprintf(status2, 99, " using table %s", dbtable);
++              if (ctime > 31536000) {
++                      ast_cli(fd, "%s%s for %d years, %d days, %d hours, %d minutes, %d seconds.\n", status, status2, ctime / 31536000, (ctime % 31536000) / 86400, (ctime % 86400) / 3600, (ctime % 3600) / 60, ctime % 60);
++              } else if (ctime > 86400) {
++                      ast_cli(fd, "%s%s for %d days, %d hours, %d minutes, %d seconds.\n", status, status2, ctime / 86400, (ctime % 86400) / 3600, (ctime % 3600) / 60, ctime % 60);
++              } else if (ctime > 3600) {
++                      ast_cli(fd, "%s%s for %d hours, %d minutes, %d seconds.\n", status, status2, ctime / 3600, (ctime % 3600) / 60, ctime % 60);
++              } else if (ctime > 60) {
++                      ast_cli(fd, "%s%s for %d minutes, %d seconds.\n", status, status2, ctime / 60, ctime % 60);
++              } else {
++                      ast_cli(fd, "%s%s for %d seconds.\n", status, status2, ctime);
++              }
++              if (records == totalrecords)
++                      ast_cli(fd, "  Wrote %d records since last restart.\n", totalrecords);
++              else
++                      ast_cli(fd, "  Wrote %d records since last restart and %d records since last reconnect.\n", totalrecords, records);
++              return RESULT_SUCCESS;
++      } else {
++              ast_cli(fd, "Not currently connected to a MySQL server.\n");
++              return RESULT_FAILURE;
++      }
++}
++
++static struct ast_cli_entry cdr_mysql_status_cli =
++      { { "cdr", "mysql", "status", NULL },
++      handle_cdr_mysql_status, "Show connection status of cdr_mysql",
++      cdr_mysql_status_help, NULL };
++
++static int mysql_log(struct ast_cdr *cdr)
++{
++      struct tm tm;
++      struct timeval tv;
++      struct localuser *u;
++      char *userfielddata = NULL;
++      char sqlcmd[2048], timestr[128];
++      char *clid=NULL, *dcontext=NULL, *channel=NULL, *dstchannel=NULL, *lastapp=NULL, *lastdata=NULL;
++      int retries = 5;
++#ifdef MYSQL_LOGUNIQUEID
++      char *uniqueid = NULL;
++#endif
++
++      ast_mutex_lock(&mysql_lock);
++
++      memset(sqlcmd, 0, 2048);
++
++      localtime_r(&cdr->start.tv_sec, &tm);
++      strftime(timestr, 128, DATE_FORMAT, &tm);
++
++db_reconnect:
++      if ((!connected) && (hostname || dbsock) && dbuser && password && dbname && dbtable ) {
++              /* Attempt to connect */
++              mysql_init(&mysql);
++              /* Add option to quickly timeout the connection */
++              if (timeout && mysql_options(&mysql, MYSQL_OPT_CONNECT_TIMEOUT, (char *)&timeout)!=0) {
++                      ast_log(LOG_ERROR, "cdr_mysql: mysql_options returned (%d) %s\n", mysql_errno(&mysql), mysql_error(&mysql));
++              }
++              if (mysql_real_connect(&mysql, hostname, dbuser, password, dbname, dbport, dbsock, 0)) {
++                      connected = 1;
++                      connect_time = time(NULL);
++                      records = 0;
++              } else {
++                      ast_log(LOG_ERROR, "cdr_mysql: cannot connect to database server %s.\n", hostname);
++                      connected = 0;
++              }
++      } else {
++              /* Long connection - ping the server */
++              int error;
++              if ((error = mysql_ping(&mysql))) {
++                      connected = 0;
++                      records = 0;
++                      switch (error) {
++                              case CR_SERVER_GONE_ERROR:
++                              case CR_SERVER_LOST:
++                                      ast_log(LOG_ERROR, "cdr_mysql: Server has gone away. Attempting to reconnect.\n");
++                                      break;
++                              default:
++                                      ast_log(LOG_ERROR, "cdr_mysql: Unknown connection error: (%d) %s\n", mysql_errno(&mysql), mysql_error(&mysql));
++                      }
++                      retries--;
++                      if (retries)
++                              goto db_reconnect;
++                      else
++                              ast_log(LOG_ERROR, "cdr_mysql: Retried to connect fives times, giving up.\n");
++              }
++      }
++
++      /* Maximum space needed would be if all characters needed to be escaped, plus a trailing NULL */
++      /* WARNING: This code previously used mysql_real_escape_string, but the use of said function
++         requires an active connection to a database.  If we are not connected, then this function
++          cannot be used.  This is a problem since we need to store off the SQL statement into our
++         spool file for later restoration.
++         So the question is, what's the best way to handle this?  This works for now.
++      */
++      if ((clid = alloca(strlen(cdr->clid) * 2 + 1)) != NULL)
++              mysql_escape_string(clid, cdr->clid, strlen(cdr->clid));
++      if ((dcontext = alloca(strlen(cdr->dcontext) * 2 + 1)) != NULL)
++              mysql_escape_string(dcontext, cdr->dcontext, strlen(cdr->dcontext));
++      if ((channel = alloca(strlen(cdr->channel) * 2 + 1)) != NULL)
++              mysql_escape_string(channel, cdr->channel, strlen(cdr->channel));
++      if ((dstchannel = alloca(strlen(cdr->dstchannel) * 2 + 1)) != NULL)
++              mysql_escape_string(dstchannel, cdr->dstchannel, strlen(cdr->dstchannel));
++      if ((lastapp = alloca(strlen(cdr->lastapp) * 2 + 1)) != NULL)
++              mysql_escape_string(lastapp, cdr->lastapp, strlen(cdr->lastapp));
++      if ((lastdata = alloca(strlen(cdr->lastdata) * 2 + 1)) != NULL)
++              mysql_escape_string(lastdata, cdr->lastdata, strlen(cdr->lastdata));
++#ifdef MYSQL_LOGUNIQUEID
++      if ((uniqueid = alloca(strlen(cdr->uniqueid) * 2 + 1)) != NULL)
++              mysql_escape_string(uniqueid, cdr->uniqueid, strlen(cdr->uniqueid));
++#endif
++      if (userfield && ((userfielddata = alloca(strlen(cdr->userfield) * 2 + 1)) != NULL))
++              mysql_escape_string(userfielddata, cdr->userfield, strlen(cdr->userfield));
++
++      /* Check for all alloca failures above at once */
++#ifdef MYSQL_LOGUNIQUEID
++      if ((!clid) || (!dcontext) || (!channel) || (!dstchannel) || (!lastapp) || (!lastdata) || (!uniqueid)) {
++#else
++      if ((!clid) || (!dcontext) || (!channel) || (!dstchannel) || (!lastapp) || (!lastdata)) {
++#endif
++              ast_log(LOG_ERROR, "cdr_mysql:  Out of memory error (insert fails)\n");
++              ast_mutex_unlock(&mysql_lock);
++              return -1;
++      }
++
++      ast_log(LOG_DEBUG, "cdr_mysql: inserting a CDR record.\n");
++
++      if (userfield && userfielddata) {
++#ifdef MYSQL_LOGUNIQUEID
++              sprintf(sqlcmd, "INSERT INTO %s (calldate,clid,src,dst,dcontext,channel,dstchannel,lastapp,lastdata,duration,billsec,disposition,amaflags,accountcode,uniqueid,userfield) VALUES ('%s','%s','%s','%s','%s', '%s','%s','%s','%s',%i,%i,'%s',%i,'%s','%s','%s')", dbtable, timestr, clid, cdr->src, cdr->dst, dcontext, channel, dstchannel, lastapp, lastdata, cdr->duration, cdr->billsec, ast_cdr_disp2str(cdr->disposition), cdr->amaflags, cdr->accountcode, uniqueid, userfielddata);
++#else
++              sprintf(sqlcmd, "INSERT INTO %s (calldate,clid,src,dst,dcontext,channel,dstchannel,lastapp,lastdata,duration,billsec,disposition,amaflags,accountcode,userfield) VALUES ('%s','%s','%s','%s','%s', '%s','%s','%s','%s',%i,%i,'%s',%i,'%s','%s')", dbtable, timestr, clid, cdr->src, cdr->dst, dcontext,channel, dstchannel, lastapp, lastdata, cdr->duration, cdr->billsec, ast_cdr_disp2str(cdr->disposition), cdr->amaflags, cdr->accountcode, userfielddata);
++#endif
++      } else {
++#ifdef MYSQL_LOGUNIQUEID
++              sprintf(sqlcmd, "INSERT INTO %s (calldate,clid,src,dst,dcontext,channel,dstchannel,lastapp,lastdata,duration,billsec,disposition,amaflags,accountcode,uniqueid) VALUES ('%s','%s','%s','%s','%s', '%s','%s','%s','%s',%i,%i,'%s',%i,'%s','%s')", dbtable, timestr, clid, cdr->src, cdr->dst, dcontext,channel, dstchannel, lastapp, lastdata, cdr->duration, cdr->billsec, ast_cdr_disp2str(cdr->disposition), cdr->amaflags, cdr->accountcode, uniqueid);
++#else
++              sprintf(sqlcmd, "INSERT INTO %s (calldate,clid,src,dst,dcontext,channel,dstchannel,lastapp,lastdata,duration,billsec,disposition,amaflags,accountcode) VALUES ('%s','%s','%s','%s','%s', '%s','%s','%s','%s',%i,%i,'%s',%i,'%s')", dbtable, timestr, clid, cdr->src, cdr->dst, dcontext, channel, dstchannel, lastapp, lastdata, cdr->duration, cdr->billsec, ast_cdr_disp2str(cdr->disposition), cdr->amaflags, cdr->accountcode);
++#endif
++      }
++      
++      ast_log(LOG_DEBUG, "cdr_mysql: SQL command as follows: %s\n", sqlcmd);
++      
++      if (connected) {
++              if (mysql_real_query(&mysql, sqlcmd, strlen(sqlcmd))) {
++                      ast_log(LOG_ERROR, "mysql_cdr: Failed to insert into database: (%d) %s", mysql_errno(&mysql), mysql_error(&mysql));
++                      connected = 0;
++              } else {
++                      records++;
++                      totalrecords++;
++              }
++      }
++      ast_mutex_unlock(&mysql_lock);
++      return 0;
++}
++
++char *description(void)
++{
++      return desc;
++}
++
++static int my_unload_module(void)
++{ 
++      ast_cli_unregister(&cdr_mysql_status_cli);
++      if (connected) {
++              mysql_close(&mysql);
++              connected = 0;
++              records = 0;
++      }
++      if (hostname && hostname_alloc) {
++              free(hostname);
++              hostname = NULL;
++              hostname_alloc = 0;
++      }
++      if (dbname && dbname_alloc) {
++              free(dbname);
++              dbname = NULL;
++              dbname_alloc = 0;
++      }
++      if (dbuser && dbuser_alloc) {
++              free(dbuser);
++              dbuser = NULL;
++              dbuser_alloc = 0;
++      }
++      if (dbsock && dbsock_alloc) {
++              free(dbsock);
++              dbsock = NULL;
++              dbsock_alloc = 0;
++      }
++      if (dbtable && dbtable_alloc) {
++              free(dbtable);
++              dbtable = NULL;
++              dbtable_alloc = 0;
++      }
++      if (password && password_alloc) {
++              free(password);
++              password = NULL;
++              password_alloc = 0;
++      }
++      dbport = 0;
++      ast_cdr_unregister(name);
++      return 0;
++}
++
++static int my_load_module(void)
++{
++      int res;
++      struct ast_config *cfg;
++      struct ast_variable *var;
++      char *tmp;
++
++      cfg = ast_config_load(config);
++      if (!cfg) {
++              ast_log(LOG_WARNING, "Unable to load config for mysql CDR's: %s\n", config);
++              return 0;
++      }
++      
++      var = ast_variable_browse(cfg, "global");
++      if (!var) {
++              /* nothing configured */
++              return 0;
++      }
++
++      tmp = ast_variable_retrieve(cfg, "global", "hostname");
++      if (tmp) {
++              hostname = malloc(strlen(tmp) + 1);
++              if (hostname != NULL) {
++                      hostname_alloc = 1;
++                      strcpy(hostname, tmp);
++              } else {
++                      ast_log(LOG_ERROR, "Out of memory error.\n");
++                      return -1;
++              }
++      } else {
++              ast_log(LOG_WARNING, "MySQL server hostname not specified.  Assuming localhost\n");
++              hostname = "localhost";
++      }
++
++      tmp = ast_variable_retrieve(cfg, "global", "dbname");
++      if (tmp) {
++              dbname = malloc(strlen(tmp) + 1);
++              if (dbname != NULL) {
++                      dbname_alloc = 1;
++                      strcpy(dbname, tmp);
++              } else {
++                      ast_log(LOG_ERROR, "Out of memory error.\n");
++                      return -1;
++              }
++      } else {
++              ast_log(LOG_WARNING, "MySQL database not specified.  Assuming asteriskcdrdb\n");
++              dbname = "asteriskcdrdb";
++      }
++
++      tmp = ast_variable_retrieve(cfg, "global", "user");
++      if (tmp) {
++              dbuser = malloc(strlen(tmp) + 1);
++              if (dbuser != NULL) {
++                      dbuser_alloc = 1;
++                      strcpy(dbuser, tmp);
++              } else {
++                      ast_log(LOG_ERROR, "Out of memory error.\n");
++                      return -1;
++              }
++      } else {
++              ast_log(LOG_WARNING, "MySQL database user not specified.  Assuming root\n");
++              dbuser = "root";
++      }
++
++      tmp = ast_variable_retrieve(cfg, "global", "sock");
++      if (tmp) {
++              dbsock = malloc(strlen(tmp) + 1);
++              if (dbsock != NULL) {
++                      dbsock_alloc = 1;
++                      strcpy(dbsock, tmp);
++              } else {
++                      ast_log(LOG_ERROR, "Out of memory error.\n");
++                      return -1;
++              }
++      } else {
++              ast_log(LOG_WARNING, "MySQL database sock file not specified.  Using default\n");
++              dbsock = NULL;
++      }
++
++      tmp = ast_variable_retrieve(cfg, "global", "table");
++      if (tmp) {
++              dbtable = malloc(strlen(tmp) + 1);
++              if (dbtable != NULL) {
++                      dbtable_alloc = 1;
++                      strcpy(dbtable, tmp);
++              } else {
++                      ast_log(LOG_ERROR, "Out of memory error.\n");
++                      return -1;
++              }
++      } else {
++              ast_log(LOG_NOTICE, "MySQL database table not specified.  Assuming \"cdr\"\n");
++              dbtable = "cdr";
++      }
++
++      tmp = ast_variable_retrieve(cfg, "global", "password");
++      if (tmp) {
++              password = malloc(strlen(tmp) + 1);
++              if (password != NULL) {
++                      password_alloc = 1;
++                      strcpy(password, tmp);
++              } else {
++                      ast_log(LOG_ERROR, "Out of memory error.\n");
++                      return -1;
++              }
++      } else {
++              ast_log(LOG_WARNING, "MySQL database password not specified.  Assuming blank\n");
++              password = "";
++      }
++
++      tmp = ast_variable_retrieve(cfg, "global", "port");
++      if (tmp) {
++              if (sscanf(tmp, "%d", &dbport) < 1) {
++                      ast_log(LOG_WARNING, "Invalid MySQL port number.  Using default\n");
++                      dbport = 0;
++              }
++      }
++
++      tmp = ast_variable_retrieve(cfg, "global", "timeout");
++      if (tmp) {
++              if (sscanf(tmp,"%d", &timeout) < 1) {
++                      ast_log(LOG_WARNING, "Invalid MySQL timeout number.  Using default\n");
++                      timeout = 0;
++              }
++      }
++      
++      tmp = ast_variable_retrieve(cfg, "global", "userfield");
++      if (tmp) {
++              if (sscanf(tmp, "%d", &userfield) < 1) {
++                      ast_log(LOG_WARNING, "Invalid MySQL configurtation file\n");
++                      userfield = 0;
++              }
++      }
++      
++      ast_config_destroy(cfg);
++
++      ast_log(LOG_DEBUG, "cdr_mysql: got hostname of %s\n", hostname);
++      ast_log(LOG_DEBUG, "cdr_mysql: got port of %d\n", dbport);
++      ast_log(LOG_DEBUG, "cdr_mysql: got a timeout of %d\n", timeout);
++      if (dbsock)
++              ast_log(LOG_DEBUG, "cdr_mysql: got sock file of %s\n", dbsock);
++      ast_log(LOG_DEBUG, "cdr_mysql: got user of %s\n", dbuser);
++      ast_log(LOG_DEBUG, "cdr_mysql: got dbname of %s\n", dbname);
++      ast_log(LOG_DEBUG, "cdr_mysql: got password of %s\n", password);
++
++      mysql_init(&mysql);
++
++      if (timeout && mysql_options(&mysql, MYSQL_OPT_CONNECT_TIMEOUT, (char *)&timeout)!=0) {
++              ast_log(LOG_ERROR, "cdr_mysql: mysql_options returned (%d) %s\n", mysql_errno(&mysql), mysql_error(&mysql));
++      }
++
++      if (!mysql_real_connect(&mysql, hostname, dbuser, password, dbname, dbport, dbsock, 0)) {
++              ast_log(LOG_ERROR, "Failed to connect to mysql database %s on %s.\n", dbname, hostname);
++              connected = 0;
++              records = 0;
++      } else {
++              ast_log(LOG_DEBUG, "Successfully connected to MySQL database.\n");
++              connected = 1;
++              records = 0;
++              connect_time = time(NULL);
++      }
++
++      res = ast_cdr_register(name, desc, mysql_log);
++      if (res) {
++              ast_log(LOG_ERROR, "Unable to register MySQL CDR handling\n");
++      } else {
++              res = ast_cli_register(&cdr_mysql_status_cli);
++      }
++
++      return res;
++}
++
++int load_module(void)
++{
++      return my_load_module();
++}
++
++int unload_module(void)
++{
++      return my_unload_module();
++}
++
++int reload(void)
++{
++      int ret;
++
++      ast_mutex_lock(&mysql_lock);    
++      my_unload_module();
++      ret = my_load_module();
++      ast_mutex_unlock(&mysql_lock);
++
++      return ret;
++}
++
++int usecount(void)
++{
++      /* Simplistic use count */
++      if (ast_mutex_trylock(&mysql_lock)) {
++              return 1;
++      } else {
++              ast_mutex_unlock(&mysql_lock);
++              return 0;
++      }
++}
++
++char *key()
++{
++      return ASTERISK_GPL_KEY;
++}
diff --git a/openwrt/package/asterisk/patches/asterisk-1.2.0-chan_bluetooth.patch b/openwrt/package/asterisk/patches/asterisk-1.2.0-chan_bluetooth.patch
new file mode 100644 (file)
index 0000000..6b9da79
--- /dev/null
@@ -0,0 +1,11 @@
+diff -ruN asterisk-1.2.0-old/channels/chan_bluetooth.c asterisk-1.2.0-new/channels/chan_bluetooth.c
+--- asterisk-1.2.0-old/channels/chan_bluetooth.c       2005-12-04 04:48:40.000000000 +0100
++++ asterisk-1.2.0-new/channels/chan_bluetooth.c       2005-12-04 23:07:19.000000000 +0100
+@@ -104,6 +104,7 @@
+ #include <asterisk/options.h>
+ #include <asterisk/cli.h>
+ #include <asterisk/callerid.h>
++#include <asterisk/version.h>
+ #include <sys/socket.h>
+ #include <sys/signal.h>
+ #include <sys/time.h>
diff --git a/openwrt/package/asterisk/patches/asterisk-1.2.0-compat-getloadavg.patch b/openwrt/package/asterisk/patches/asterisk-1.2.0-compat-getloadavg.patch
new file mode 100644 (file)
index 0000000..a909513
--- /dev/null
@@ -0,0 +1,13 @@
+diff -ruN asterisk-1.2.0-old/include/asterisk/compat.h asterisk-1.2.0-new/include/asterisk/compat.h
+--- asterisk-1.2.0-old/include/asterisk/compat.h       2005-11-08 05:13:19.000000000 +0100
++++ asterisk-1.2.0-new/include/asterisk/compat.h       2005-12-04 05:32:31.000000000 +0100
+@@ -75,7 +75,9 @@
+ #define HAVE_STRTOQ
+ #ifdef _BSD_SOURCE
++#ifndef __UCLIBC__
+ #define HAVE_GETLOADAVG
++#endif /* __UCLIBC__ */
+ #endif
+ #ifdef __linux__
diff --git a/openwrt/package/asterisk/patches/asterisk-1.2.0-res_mysql.patch b/openwrt/package/asterisk/patches/asterisk-1.2.0-res_mysql.patch
new file mode 100644 (file)
index 0000000..5de8107
--- /dev/null
@@ -0,0 +1,698 @@
+diff -ruN asterisk-1.2.0-old/configs/res_mysql.conf.sample asterisk-1.2.0-new/configs/res_mysql.conf.sample
+--- asterisk-1.2.0-old/configs/res_mysql.conf.sample   1970-01-01 01:00:00.000000000 +0100
++++ asterisk-1.2.0-new/configs/res_mysql.conf.sample   2004-12-03 15:33:44.000000000 +0100
+@@ -0,0 +1,15 @@
++;
++; Sample configuration for res_config_mysql.c
++;
++; The value of dbhost may be either a hostname or an IP address.
++; If dbhost is commented out or the string "localhost", a connection
++; to the local host is assumed and dbsock is used instead of TCP/IP
++; to connect to the server.
++;
++[general]
++;dbhost = 127.0.0.1
++;dbname = asterisk
++;dbuser = myuser
++;dbpass = mypass
++;dbport = 3306
++;dbsock = /tmp/mysql.sock
+diff -ruN asterisk-1.2.0-old/res/res_config_mysql.c asterisk-1.2.0-new/res/res_config_mysql.c
+--- asterisk-1.2.0-old/res/res_config_mysql.c  1970-01-01 01:00:00.000000000 +0100
++++ asterisk-1.2.0-new/res/res_config_mysql.c  2005-10-13 21:43:54.000000000 +0200
+@@ -0,0 +1,675 @@
++/*
++ * Asterisk -- A telephony toolkit for Linux.
++ *
++ * Copyright (C) 1999-2005, Digium, Inc.
++ *
++ * Mark Spencer <markster@digium.com>  - Asterisk Author
++ * Matthew Boehm <mboehm@cytelcom.com> - MySQL RealTime Driver Author
++ *
++ * res_config_mysql.c <mysql plugin for RealTime configuration engine>
++ *
++ * v2.0   - (10-07-05) - mutex_lock fixes (bug #4973, comment #0034602)
++ *
++ * v1.9   - (08-19-05) - Added support to correctly honor the family database specified
++ *                       in extconfig.conf (bug #4973)
++ *
++ * v1.8   - (04-21-05) - Modified return values of update_mysql to better indicate
++ *                       what really happened.
++ *
++ * v1.7   - (01-28-05) - Fixed non-initialization of ast_category struct
++ *                       in realtime_multi_mysql function which caused segfault. 
++ *
++ * v1.6   - (00-00-00) - Skipped to bring comments into sync with version number in CVS.
++ *
++ * v1.5.1 - (01-26-05) - Added better(?) locking stuff
++ *
++ * v1.5   - (01-26-05) - Brought up to date with new config.h changes (bug #3406)
++ *                     - Added in extra locking provided by georg (bug #3248)
++ *
++ * v1.4   - (12-02-04) - Added realtime_multi_mysql function
++ *                        This function will return an ast_config with categories,
++ *                        unlike standard realtime_mysql which only returns
++ *                        a linked list of ast_variables
++ *
++ * v1.3   - (12-01-04) - Added support other operators
++ *                       Ex: =, !=, LIKE, NOT LIKE, RLIKE, etc...
++ *
++ * v1.2   - (11-DD-04) - Added reload. Updated load and unload.
++ *                       Code beautification (doc/CODING-GUIDELINES)
++ */
++
++#include <asterisk/channel.h>
++#include <asterisk/logger.h>
++#include <asterisk/config.h>
++#include <asterisk/module.h>
++#include <asterisk/lock.h>
++#include <asterisk/options.h>
++#include <asterisk/cli.h>
++#include <asterisk/utils.h>
++#include <stdlib.h>
++#include <string.h>
++#include <mysql.h>
++#include <mysql_version.h>
++#include <errmsg.h>
++
++static char *res_config_mysql_desc = "MySQL RealTime Configuration Driver";
++
++AST_MUTEX_DEFINE_STATIC(mysql_lock);
++#define RES_CONFIG_MYSQL_CONF "res_mysql.conf"
++MYSQL         mysql;
++static char   dbhost[50];
++static char   dbuser[50];
++static char   dbpass[50];
++static char   dbname[50];
++static char   dbsock[50];
++static int    dbport;
++static int    connected;
++static time_t connect_time;
++
++static int parse_config(void);
++static int mysql_reconnect(const char *database);
++static int realtime_mysql_status(int fd, int argc, char **argv);
++
++STANDARD_LOCAL_USER;
++
++LOCAL_USER_DECL;
++
++static char cli_realtime_mysql_status_usage[] =
++"Usage: realtime mysql status\n"
++"       Shows connection information for the MySQL RealTime driver\n";
++
++static struct ast_cli_entry cli_realtime_mysql_status = {
++        { "realtime", "mysql", "status", NULL }, realtime_mysql_status,
++        "Shows connection information for the MySQL RealTime driver", cli_realtime_mysql_status_usage, NULL };
++
++static struct ast_variable *realtime_mysql(const char *database, const char *table, va_list ap)
++{
++      MYSQL_RES *result;
++      MYSQL_ROW row;
++      MYSQL_FIELD *fields;
++      int numFields, i;
++      char sql[256];
++      char *stringp;
++      char *chunk;
++      char *op;
++      const char *newparam, *newval;
++      struct ast_variable *var=NULL, *prev=NULL;
++
++      if(!table) {
++              ast_log(LOG_WARNING, "MySQL RealTime: No table specified.\n");
++              return NULL;
++      }
++
++      /* 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_WARNING, "MySQL RealTime: Realtime retrieval requires at least 1 parameter and 1 value to search on.\n");
++              mysql_close(&mysql);
++              return NULL;
++      }
++
++      /* 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(newparam, ' ')) op = " ="; else op = "";
++
++      snprintf(sql, sizeof(sql), "SELECT * FROM %s WHERE %s%s '%s'", table, newparam, op, newval);
++      while((newparam = va_arg(ap, const char *))) {
++              newval = va_arg(ap, const char *);
++              if(!strchr(newparam, ' ')) op = " ="; else op = "";
++              snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), " AND %s%s '%s'", newparam, op, newval);
++      }
++      va_end(ap);
++
++      ast_log(LOG_DEBUG, "MySQL RealTime: Retrieve SQL: %s\n", sql);
++
++      /* We now have our complete statement; Lets connect to the server and execute it. */
++      ast_mutex_lock(&mysql_lock);
++      if(!mysql_reconnect(database)) {
++              ast_mutex_unlock(&mysql_lock);
++              return NULL;
++      }
++
++      if(mysql_real_query(&mysql, sql, strlen(sql))) {
++              ast_log(LOG_WARNING, "MySQL RealTime: Failed to query database. Check debug for more info.\n");
++              ast_log(LOG_DEBUG, "MySQL RealTime: Query: %s\n", sql);
++              ast_log(LOG_DEBUG, "MySQL RealTime: Query Failed because: %s\n", mysql_error(&mysql));
++              ast_mutex_unlock(&mysql_lock);
++              return NULL;
++      }
++
++      if((result = mysql_store_result(&mysql))) {
++              numFields = mysql_num_fields(result);
++              fields = mysql_fetch_fields(result);
++
++              while((row = mysql_fetch_row(result))) {
++                      for(i = 0; i < numFields; i++) {
++                              stringp = row[i];
++                              while(stringp) {
++                                      chunk = strsep(&stringp, ";");
++                                      if(chunk && !ast_strlen_zero(ast_strip(chunk))) {
++                                              if(prev) {
++                                                      prev->next = ast_variable_new(fields[i].name, chunk);
++                                                      if (prev->next) {
++                                                              prev = prev->next;
++                                                      }
++                                              } else {
++                                                      prev = var = ast_variable_new(fields[i].name, chunk);
++                                              }
++                                      }
++                              }
++                      }
++              }
++      } else {                                
++              ast_log(LOG_WARNING, "MySQL RealTime: Could not find any rows in table %s.\n", table);
++      }
++
++      ast_mutex_unlock(&mysql_lock);
++      mysql_free_result(result);
++
++      return var;
++}
++
++static struct ast_config *realtime_multi_mysql(const char *database, const char *table, va_list ap)
++{
++      MYSQL_RES *result;
++      MYSQL_ROW row;
++      MYSQL_FIELD *fields;
++      int numFields, i;
++      char sql[256];
++      const char *initfield = NULL;
++      char *stringp;
++      char *chunk;
++      char *op;
++      const char *newparam, *newval;
++      struct ast_realloca ra;
++      struct ast_variable *var=NULL;
++      struct ast_config *cfg = NULL;
++      struct ast_category *cat = NULL;
++
++      if(!table) {
++              ast_log(LOG_WARNING, "MySQL RealTime: No table specified.\n");
++              return NULL;
++      }
++      
++      memset(&ra, 0, sizeof(ra));
++
++      cfg = ast_config_new();
++      if (!cfg) {
++              /* If I can't alloc memory at this point, why bother doing anything else? */
++              ast_log(LOG_WARNING, "Out of memory!\n");
++              return NULL;
++      }
++
++      /* 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_WARNING, "MySQL RealTime: Realtime retrieval requires at least 1 parameter and 1 value to search on.\n");
++              mysql_close(&mysql);
++              return NULL;
++      }
++
++      initfield = ast_strdupa(newparam);
++      if(initfield && (op = strchr(initfield, ' '))) {
++              *op = '\0';
++      }
++
++      /* 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(newparam, ' ')) op = " ="; else op = "";
++
++      snprintf(sql, sizeof(sql), "SELECT * FROM %s WHERE %s%s '%s'", table, newparam, op, newval);
++      while((newparam = va_arg(ap, const char *))) {
++              newval = va_arg(ap, const char *);
++              if(!strchr(newparam, ' ')) op = " ="; else op = "";
++              snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), " AND %s%s '%s'", newparam, op, newval);
++      }
++
++      if(initfield) {
++              snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), " ORDER BY %s", initfield);
++      }
++
++      va_end(ap);
++
++      ast_log(LOG_DEBUG, "MySQL RealTime: Retrieve SQL: %s\n", sql);
++
++      /* We now have our complete statement; Lets connect to the server and execute it. */
++      ast_mutex_lock(&mysql_lock);
++      if(!mysql_reconnect(database)) {
++              ast_mutex_unlock(&mysql_lock);
++              return NULL;
++      }
++
++      if(mysql_real_query(&mysql, sql, strlen(sql))) {
++              ast_log(LOG_WARNING, "MySQL RealTime: Failed to query database. Check debug for more info.\n");
++              ast_log(LOG_DEBUG, "MySQL RealTime: Query: %s\n", sql);
++              ast_log(LOG_DEBUG, "MySQL RealTime: Query Failed because: %s\n", mysql_error(&mysql));
++              ast_mutex_unlock(&mysql_lock);
++              return NULL;
++      }
++
++      if((result = mysql_store_result(&mysql))) {
++              numFields = mysql_num_fields(result);
++              fields = mysql_fetch_fields(result);
++
++              while((row = mysql_fetch_row(result))) {
++                      var = NULL;
++                      cat = ast_category_new("");
++                      if(!cat) {
++                              ast_log(LOG_WARNING, "Out of memory!\n");
++                              continue;
++                      }
++                      for(i = 0; i < numFields; i++) {
++                              stringp = row[i];
++                              while(stringp) {
++                                      chunk = strsep(&stringp, ";");
++                                      if(chunk && !ast_strlen_zero(ast_strip(chunk))) {
++                                              if(initfield && !strcmp(initfield, fields[i].name)) {
++                                                      ast_category_rename(cat, chunk);
++                                              }
++                                              var = ast_variable_new(fields[i].name, chunk);
++                                              ast_variable_append(cat, var);
++                                      }
++                              }
++                      }
++                      ast_category_append(cfg, cat);
++              }
++      } else {
++              ast_log(LOG_WARNING, "MySQL RealTime: Could not find any rows in table %s.\n", table);
++      }
++
++      ast_mutex_unlock(&mysql_lock);
++      mysql_free_result(result);
++
++      return cfg;
++}
++
++static int update_mysql(const char *database, const char *table, const char *keyfield, const char *lookup, va_list ap)
++{
++      my_ulonglong numrows;
++      char sql[256];
++      const char *newparam, *newval;
++
++      if(!table) {
++              ast_log(LOG_WARNING, "MySQL RealTime: No table specified.\n");
++               return -1;
++      }
++
++      /* 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_WARNING, "MySQL RealTime: Realtime retrieval requires at least 1 parameter and 1 value to search on.\n");
++              mysql_close(&mysql);
++               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 */
++
++      snprintf(sql, sizeof(sql), "UPDATE %s SET %s = '%s'", table, newparam, newval);
++      while((newparam = va_arg(ap, const char *))) {
++              newval = va_arg(ap, const char *);
++              snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), ", %s = '%s'", newparam, newval);
++      }
++      va_end(ap);
++      snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), " WHERE %s = '%s'", keyfield, lookup);
++
++      ast_log(LOG_DEBUG,"MySQL RealTime: Update SQL: %s\n", sql);
++
++      /* We now have our complete statement; Lets connect to the server and execute it. */
++      ast_mutex_lock(&mysql_lock);
++      if(!mysql_reconnect(database)) {
++              ast_mutex_unlock(&mysql_lock);
++              return -1;
++      }
++
++      if(mysql_real_query(&mysql, sql, strlen(sql))) {
++              ast_log(LOG_WARNING, "MySQL RealTime: Failed to query database. Check debug for more info.\n");
++              ast_log(LOG_DEBUG, "MySQL RealTime: Query: %s\n", sql);
++              ast_log(LOG_DEBUG, "MySQL RealTime: Query Failed because: %s\n", mysql_error(&mysql));
++              ast_mutex_unlock(&mysql_lock);
++              return -1;
++      }
++
++      numrows = mysql_affected_rows(&mysql);
++      ast_mutex_unlock(&mysql_lock);
++
++      ast_log(LOG_DEBUG,"MySQL RealTime: Updated %llu rows on table: %s\n", numrows, table);
++
++      /* From http://dev.mysql.com/doc/mysql/en/mysql-affected-rows.html
++       * An integer greater than zero indicates the number of rows affected
++       * Zero indicates that no records were updated
++       * -1 indicates that the query returned an error (although, if the query failed, it should have been caught above.)
++      */
++
++      if(numrows >= 0)
++              return (int)numrows;
++
++      return -1;
++}
++
++static struct ast_config *config_mysql(const char *database, const char *table, const char *file, struct ast_config *cfg)
++{
++      MYSQL_RES *result;
++      MYSQL_ROW row;
++      my_ulonglong num_rows;
++      struct ast_config *new;
++      struct ast_variable *cur_v, *new_v;
++      struct ast_category *cur_cat, *new_cat;
++      char sql[250] = "";
++      char last[80] = "";
++      int cat_started = 0;
++      int var_started = 0;
++      int last_cat_metric = 0;
++
++      last[0] = '\0';
++
++      if(!file || !strcmp(file, RES_CONFIG_MYSQL_CONF)) {
++              ast_log(LOG_WARNING, "MySQL RealTime: Cannot configure myself.\n");
++              return NULL;
++      }
++
++      snprintf(sql, sizeof(sql), "SELECT category, var_name, var_val, cat_metric FROM %s WHERE filename='%s' and commented=0 ORDER BY filename, cat_metric desc, var_metric asc, category, var_name, var_val, id", table, file);
++
++      ast_log(LOG_DEBUG, "MySQL RealTime: Static SQL: %s\n", sql);
++
++      /* We now have our complete statement; Lets connect to the server and execute it. */
++      ast_mutex_lock(&mysql_lock);
++      if(!mysql_reconnect(database)) {
++              ast_mutex_unlock(&mysql_lock);
++              return NULL;
++      }
++
++      if(mysql_real_query(&mysql, sql, strlen(sql))) {
++              ast_log(LOG_WARNING, "MySQL RealTime: Failed to query database. Check debug for more info.\n");
++              ast_log(LOG_DEBUG, "MySQL RealTime: Query: %s\n", sql);
++              ast_log(LOG_DEBUG, "MySQL RealTime: Query Failed because: %s\n", mysql_error(&mysql));
++              ast_mutex_unlock(&mysql_lock);
++              return NULL;
++      }
++
++      if((result = mysql_store_result(&mysql))) {
++              num_rows = mysql_num_rows(result);
++              ast_log(LOG_DEBUG, "MySQL RealTime: Found %llu rows.\n", num_rows);
++
++              /* There might exist a better way to access the column names other than counting,
++                   but I believe that would require another loop that we don't need. */
++
++              while((row = mysql_fetch_row(result))) {
++                      if(!strcmp(row[1], "#include")) {
++                              if (!ast_config_internal_load(row[2], cfg)) {
++                                      mysql_free_result(result);
++                                      ast_mutex_unlock(&mysql_lock);
++                                      return NULL;
++                              }
++                              continue;
++                      }
++
++                      if(strcmp(last, row[0]) || last_cat_metric != atoi(row[3])) {
++                              cur_cat = ast_category_new(row[0]);
++                              if (!cur_cat) {
++                                      ast_log(LOG_WARNING, "Out of memory!\n");
++                                      break;
++                              }
++                              strcpy(last, row[0]);
++                              last_cat_metric = atoi(row[3]);
++                              ast_category_append(cfg, cur_cat);
++                      }
++                      new_v = ast_variable_new(row[1], row[2]);
++                      ast_variable_append(cur_cat, new_v);
++              }
++      } else {
++              ast_log(LOG_WARNING, "MySQL RealTime: Could not find config '%s' in database.\n", file);
++      }
++
++      mysql_free_result(result);
++      ast_mutex_unlock(&mysql_lock);
++
++      return cfg;
++}
++
++static struct ast_config_engine mysql_engine = {
++      .name = "mysql",
++      .load_func = config_mysql,
++      .realtime_func = realtime_mysql,
++      .realtime_multi_func = realtime_multi_mysql,
++      .update_func = update_mysql
++};
++
++int load_module (void)
++{
++      parse_config();
++
++      ast_mutex_lock(&mysql_lock);
++
++      if(!mysql_reconnect(NULL)) {
++              ast_log(LOG_WARNING, "MySQL RealTime: Couldn't establish connection. Check debug.\n");
++              ast_log(LOG_DEBUG, "MySQL RealTime: Cannot Connect: %s\n", mysql_error(&mysql));
++      }
++
++      ast_config_engine_register(&mysql_engine);
++      if(option_verbose) {
++              ast_verbose("MySQL RealTime driver loaded.\n");
++      }
++      ast_cli_register(&cli_realtime_mysql_status);
++
++      ast_mutex_unlock(&mysql_lock);
++
++      return 0;
++}
++
++int unload_module (void)
++{
++      /* Aquire control before doing anything to the module itself. */
++      ast_mutex_lock(&mysql_lock);
++
++      mysql_close(&mysql);
++      ast_cli_unregister(&cli_realtime_mysql_status);
++      ast_config_engine_deregister(&mysql_engine);
++      if(option_verbose) {
++              ast_verbose("MySQL RealTime unloaded.\n");
++      }
++
++      STANDARD_HANGUP_LOCALUSERS;
++
++      /* Unlock so something else can destroy the lock. */
++      ast_mutex_unlock(&mysql_lock);
++
++      return 0;
++}
++
++int reload (void)
++{
++      /* Aquire control before doing anything to the module itself. */
++      ast_mutex_lock(&mysql_lock);
++
++      mysql_close(&mysql);
++      connected = 0;
++      parse_config();
++
++      if(!mysql_reconnect(NULL)) {
++              ast_log(LOG_WARNING, "MySQL RealTime: Couldn't establish connection. Check debug.\n");
++              ast_log(LOG_DEBUG, "MySQL RealTime: Cannot Connect: %s\n", mysql_error(&mysql));
++      }
++
++      ast_verbose(VERBOSE_PREFIX_2 "MySQL RealTime reloaded.\n");
++
++      /* Done reloading. Release lock so others can now use driver. */
++      ast_mutex_unlock(&mysql_lock);
++
++      return 0;
++}
++
++int parse_config (void)
++{
++      struct ast_config *config;
++      char *s;
++
++      config = ast_config_load(RES_CONFIG_MYSQL_CONF);
++
++      if(config) {
++              if(!(s=ast_variable_retrieve(config, "general", "dbuser"))) {
++                      ast_log(LOG_WARNING, "MySQL RealTime: No database user found, using 'asterisk' as default.\n");
++                      strncpy(dbuser, "asterisk", sizeof(dbuser) - 1);
++              } else {
++                      strncpy(dbuser, s, sizeof(dbuser) - 1);
++              }
++
++              if(!(s=ast_variable_retrieve(config, "general", "dbpass"))) {
++                        ast_log(LOG_WARNING, "MySQL RealTime: No database password found, using 'asterisk' as default.\n");
++                        strncpy(dbpass, "asterisk", sizeof(dbpass) - 1);
++                } else {
++                        strncpy(dbpass, s, sizeof(dbpass) - 1);
++                }
++
++              if(!(s=ast_variable_retrieve(config, "general", "dbhost"))) {
++                        ast_log(LOG_WARNING, "MySQL RealTime: No database host found, using localhost via socket.\n");
++                      dbhost[0] = '\0';
++                } else {
++                        strncpy(dbhost, s, sizeof(dbhost) - 1);
++                }
++
++              if(!(s=ast_variable_retrieve(config, "general", "dbname"))) {
++                        ast_log(LOG_WARNING, "MySQL RealTime: No database name found, using 'asterisk' as default.\n");
++                      strncpy(dbname, "asterisk", sizeof(dbname) - 1);
++                } else {
++                        strncpy(dbname, s, sizeof(dbname) - 1);
++                }
++
++              if(!(s=ast_variable_retrieve(config, "general", "dbport"))) {
++                        ast_log(LOG_WARNING, "MySQL RealTime: No database port found, using 3306 as default.\n");
++                      dbport = 3306;
++                } else {
++                      dbport = atoi(s);
++                }
++
++              if(dbhost && !(s=ast_variable_retrieve(config, "general", "dbsock"))) {
++                        ast_log(LOG_WARNING, "MySQL RealTime: No database socket found, using '/tmp/mysql.sock' as default.\n");
++                        strncpy(dbsock, "/tmp/mysql.sock", sizeof(dbsock) - 1);
++                } else {
++                        strncpy(dbsock, s, sizeof(dbsock) - 1);
++                }
++      }
++      ast_config_destroy(config);
++
++      if(dbhost) {
++              ast_log(LOG_DEBUG, "MySQL RealTime Host: %s\n", dbhost);
++              ast_log(LOG_DEBUG, "MySQL RealTime Port: %i\n", dbport);
++      } else {
++              ast_log(LOG_DEBUG, "MySQL RealTime Socket: %s\n", dbsock);
++      }
++      ast_log(LOG_DEBUG, "MySQL RealTime User: %s\n", dbuser);
++      ast_log(LOG_DEBUG, "MySQL RealTime Password: %s\n", dbpass);
++
++      return 1;
++}
++
++char *description (void)
++{
++      return res_config_mysql_desc;
++}
++
++int usecount (void)
++{
++      /* Try and get a lock. If unsuccessful, than that means another thread is using the mysql object. */
++      if(ast_mutex_trylock(&mysql_lock)) {
++              ast_log(LOG_DEBUG, "MySQL RealTime: Module usage count is 1.\n");
++              return 1;
++      }
++      ast_mutex_unlock(&mysql_lock);
++      return 0;
++}
++
++char *key ()
++{
++      return ASTERISK_GPL_KEY;
++}
++
++static int mysql_reconnect(const char *database)
++{
++      char my_database[50];
++
++      if(!database || ast_strlen_zero(database))
++              ast_copy_string(my_database, dbname, sizeof(my_database));
++      else
++              ast_copy_string(my_database, database, sizeof(my_database));
++
++      /* mutex lock should have been locked before calling this function. */
++
++      if((!connected) && (dbhost || dbsock) && dbuser && dbpass && my_database) {
++              if(!mysql_init(&mysql)) {
++                      ast_log(LOG_WARNING, "MySQL RealTime: Insufficient memory to allocate MySQL resource.\n");
++                      connected = 0;
++                      return 0;
++              }
++              if(mysql_real_connect(&mysql, dbhost, dbuser, dbpass, my_database, dbport, dbsock, 0)) {
++                      ast_log(LOG_DEBUG, "MySQL RealTime: Successfully connected to database.\n");
++                      connected = 1;
++                      connect_time = time(NULL);
++                      return 1;
++              } else {
++                      ast_log(LOG_ERROR, "MySQL RealTime: Failed to connect database server %s on %s. Check debug for more info.\n", dbname, dbhost);
++                      ast_log(LOG_DEBUG, "MySQL RealTime: Cannot Connect: %s\n", mysql_error(&mysql));
++                      connected = 0;
++                      return 0;
++              }
++      } else {
++              if(mysql_ping(&mysql) != 0) {
++                      connected = 0;
++                      ast_log(LOG_ERROR, "MySQL RealTime: Failed to reconnect. Check debug for more info.\n");
++                      ast_log(LOG_DEBUG, "MySQL RealTime: Server Error: %s\n", mysql_error(&mysql));
++                      return 0;
++              }
++
++              connected = 1;
++
++              if(mysql_select_db(&mysql, my_database) != 0) {
++                      ast_log(LOG_WARNING, "MySQL RealTime: Unable to select database: %s. Still Connected.\n", my_database);
++                      ast_log(LOG_DEBUG, "MySQL RealTime: Database Select Failed: %s\n", mysql_error(&mysql));
++                      return 0;
++              }
++
++              ast_log(LOG_DEBUG, "MySQL RealTime: Everything is fine.\n");
++              return 1;
++      }
++}
++
++static int realtime_mysql_status(int fd, int argc, char **argv)
++{
++      char status[256], status2[100] = "";
++      int ctime = time(NULL) - connect_time;
++
++      if(mysql_reconnect(NULL)) {
++              if(dbhost) {
++                      snprintf(status, 255, "Connected to %s@%s, port %d", dbname, dbhost, dbport);
++              } else if(dbsock) {
++                      snprintf(status, 255, "Connected to %s on socket file %s", dbname, dbsock);
++              } else {
++                      snprintf(status, 255, "Connected to %s@%s", dbname, dbhost);
++              }
++
++              if(dbuser && *dbuser) {
++                      snprintf(status2, 99, " with username %s", dbuser);
++              }
++
++              if (ctime > 31536000) {
++                      ast_cli(fd, "%s%s for %d years, %d days, %d hours, %d minutes, %d seconds.\n", status, status2, ctime / 31536000, (ctime % 31536000) / 86400, (ctime % 86400) / 3600, (ctime % 3600) / 60, ctime % 60);
++              } else if (ctime > 86400) {
++                      ast_cli(fd, "%s%s for %d days, %d hours, %d minutes, %d seconds.\n", status, status2, ctime / 86400, (ctime % 86400) / 3600, (ctime % 3600) / 60, ctime % 60);
++              } else if (ctime > 3600) {
++                      ast_cli(fd, "%s%s for %d hours, %d minutes, %d seconds.\n", status, status2, ctime / 3600, (ctime % 3600) / 60, ctime % 60);
++              } else if (ctime > 60) {
++                      ast_cli(fd, "%s%s for %d minutes, %d seconds.\n", status, status2, ctime / 60, ctime % 60);
++              } else {
++                      ast_cli(fd, "%s%s for %d seconds.\n", status, status2, ctime);
++              }
++
++              return RESULT_SUCCESS;
++      } else {
++              return RESULT_FAILURE;
++      }
++}
diff --git a/openwrt/package/asterisk/patches/asterisk-1.2.1-Makefile-versionnum.patch b/openwrt/package/asterisk/patches/asterisk-1.2.1-Makefile-versionnum.patch
new file mode 100644 (file)
index 0000000..2307642
--- /dev/null
@@ -0,0 +1,11 @@
+--- asterisk-1.2.1/Makefile.orig       2005-12-09 10:22:06.000000000 +0100
++++ asterisk-1.2.1/Makefile    2005-12-09 10:28:46.000000000 +0100
+@@ -322,8 +322,6 @@
+   ifneq ($(wildcard .svn),)
+     ASTERISKVERSIONNUM=999999
+     ASTERISKVERSION=SVN-$(shell build_tools/make_svn_branch_name)
+-  else
+-    ASTERISKVERSIONNUM=000000
+   endif
+ endif
diff --git a/openwrt/package/asterisk/patches/mysql+postgres-support.diff b/openwrt/package/asterisk/patches/mysql+postgres-support.diff
deleted file mode 100644 (file)
index c9665fe..0000000
+++ /dev/null
@@ -1,1024 +0,0 @@
-diff -ruN asterisk-1.0.7-orig/apps/Makefile asterisk-1.0.7-2/apps/Makefile
---- asterisk-1.0.7-orig/apps/Makefile  2004-09-24 23:32:56.000000000 +0200
-+++ asterisk-1.0.7-2/apps/Makefile     2005-03-19 17:38:06.000000000 +0100
-@@ -79,11 +80,17 @@
- endif
- endif
-+app_sql_mysql.o: app_sql_mysql.c
-+      $(CC) $(CFLAGS) $(MYSQL_CFLAGS) -c -o $@ $<
-+
-+app_sql_mysql.so: app_sql_mysql.o
-+      $(CC) $(SOLINK) -o $@ $< $(LDFLAGS_EXTRA) -lmysqlclient -lz $(MYSQL_LFLAGS) 
-+
- app_sql_postgres.o: app_sql_postgres.c
--      $(CC) -pipe -I/usr/local/pgsql/include $(CFLAGS) -c -o app_sql_postgres.o app_sql_postgres.c
-+      $(CC) $(CFLAGS) $(PGSQL_CFLAGS) -c -o $@ $<
- app_sql_postgres.so: app_sql_postgres.o
--      $(CC) $(SOLINK) -o $@ $< -L/usr/local/pgsql/lib -lpq
-+      $(CC) $(SOLINK) -o $@ $< $(LDFLAGS_EXTRA) -lpq -lz $(PGSQL_LFLAGS)
- app_sql_odbc.so: app_sql_odbc.o
-       $(CC) $(SOLINK) -o $@ $< -lodbc
-diff -ruN asterisk-1.0.7-orig/apps/app_sql_mysql.c asterisk-1.0.7-2/apps/app_sql_mysql.c
---- asterisk-1.0.7-orig/apps/app_sql_mysql.c   1970-01-01 01:00:00.000000000 +0100
-+++ asterisk-1.0.7-2/apps/app_sql_mysql.c      2005-03-19 18:01:13.000000000 +0100
-@@ -0,0 +1,443 @@
-+/*
-+ * Asterisk -- A telephony toolkit for Linux.
-+ *
-+ * Connect to PostgreSQL
-+ * 
-+ * Copyright (C) 2004, Constantine Filin and Christos Ricudis
-+ *
-+ * Christos Ricudis <ricudis@itc.auth.gr>
-+ * Constantine Filin <cf@intermedia.net>
-+ *
-+ * This program is free software, distributed under the terms of
-+ * the GNU General Public License
-+ */
-+
-+#include <asterisk/file.h>
-+#include <asterisk/logger.h>
-+#include <asterisk/channel.h>
-+#include <asterisk/pbx.h>
-+#include <asterisk/module.h>
-+#include <asterisk/linkedlists.h>
-+#include <asterisk/chanvars.h>
-+#include <asterisk/lock.h>
-+#include <stdlib.h>
-+#include <unistd.h>
-+#include <string.h>
-+#include <stdlib.h>
-+#include <sys/types.h>
-+#include <stdio.h>
-+#include <unistd.h>
-+
-+#include <mysql/mysql.h>
-+
-+#define EXTRA_LOG 0
-+
-+static char *tdesc = "Simple Mysql Interface";
-+
-+static char *app = "MYSQL";
-+
-+static char *synopsis = "Do several mySQLy things";
-+
-+static char *descrip = 
-+"MYSQL():  Do several mySQLy things\n"
-+"Syntax:\n"
-+"  MYSQL(Connect connid dhhost dbuser dbpass dbname)\n"
-+"    Connects to a database.  Arguments contain standard MySQL parameters\n"
-+"    passed to function mysql_real_connect.  Connection identifer returned\n"
-+"    in ${var}\n"
-+"  MYSQL(Query resultid ${connid} query-string)\n"
-+"    Executes standard MySQL query contained in query-string using established\n"
-+"    connection identified by ${connection_identifier}. Result of query is\n"
-+"    is stored in ${var}.\n"
-+"  MYSQL(Fetch fetchid ${resultid} var1 var2 ... varN)\n"
-+"    Fetches a single row from a result set contained in ${result_identifier}.\n"
-+"    Assigns returned fields to ${var1} ... ${varn}.  ${fetchid} is set TRUE\n"
-+"    if additional rows exist in result set.\n"
-+"  MYSQL(Clear ${resultid})\n"
-+"    Frees memory and datastructures associated with result set.\n" 
-+"  MYSQL(Disconnect ${connid})\n"
-+"    Disconnects from named connection to MySQL.\n" ;
-+
-+/*    
-+EXAMPLES OF USE : 
-+
-+exten => s,2,MYSQL(Connect connid localhost asterisk mypass credit)
-+exten => s,3,MYSQL(Query resultid ${connid} SELECT username,credit FROM credit WHERE callerid=${CALLERIDNUM})
-+exten => s,4,MYSQL(Fetch fetchid ${resultid} datavar1 datavar2)
-+exten => s,5,GotoIf(${fetchid}?6:8)
-+exten => s,6,Festival("User ${datavar1} currently has credit balance of ${datavar2} dollars.")        
-+exten => s,7,Goto(s,4)
-+exten => s,8,MYSQL(Clear ${resultid})
-+exten => s,9,MYSQL(Disconnect ${connid})
-+*/
-+
-+STANDARD_LOCAL_USER;
-+LOCAL_USER_DECL;
-+
-+AST_MUTEX_DEFINE_STATIC(_mysql_mutex);
-+
-+extern void pbx_builtin_setvar_helper(struct ast_channel *chan, char *name, char *value); 
-+
-+#define AST_MYSQL_ID_DUMMY   0
-+#define AST_MYSQL_ID_CONNID  1
-+#define AST_MYSQL_ID_RESID   2
-+#define AST_MYSQL_ID_FETCHID 3
-+
-+struct ast_MYSQL_id {
-+      int identifier_type; /* 0=dummy, 1=connid, 2=resultid */
-+      int identifier;
-+      void *data;
-+      AST_LIST_ENTRY(ast_MYSQL_id) entries;
-+} *ast_MYSQL_id;
-+
-+AST_LIST_HEAD(MYSQLidshead,ast_MYSQL_id) _mysql_ids_head;
-+
-+/* helpful procs */
-+static void *find_identifier(int identifier,int identifier_type) {
-+      struct MYSQLidshead *headp;
-+      struct ast_MYSQL_id *i;
-+      void *res=NULL;
-+      int found=0;
-+      
-+      headp=&_mysql_ids_head;
-+      
-+      if (AST_LIST_LOCK(headp)) {
-+              ast_log(LOG_WARNING,"Unable to lock identifiers list\n");
-+      } else {
-+              AST_LIST_TRAVERSE(headp,i,entries) {
-+                      if ((i->identifier==identifier) && (i->identifier_type==identifier_type)) {
-+                              found=1;
-+                              res=i->data;
-+                              break;
-+                      }
-+              }
-+              if (!found) {
-+                      ast_log(LOG_WARNING,"Identifier %d, identifier_type %d not found in identifier list\n",identifier,identifier_type);
-+              }
-+              AST_LIST_UNLOCK(headp);
-+      }
-+      
-+      return res;
-+}
-+
-+static int add_identifier(int identifier_type,void *data) {
-+      struct ast_MYSQL_id *i,*j;
-+      struct MYSQLidshead *headp;
-+      int maxidentifier=0;
-+      
-+      headp=&_mysql_ids_head;
-+      i=NULL;
-+      j=NULL;
-+      
-+      if (AST_LIST_LOCK(headp)) {
-+              ast_log(LOG_WARNING,"Unable to lock identifiers list\n");
-+              return(-1);
-+      } else {
-+              i=malloc(sizeof(struct ast_MYSQL_id));
-+              AST_LIST_TRAVERSE(headp,j,entries) {
-+                      if (j->identifier>maxidentifier) {
-+                              maxidentifier=j->identifier;
-+                      }
-+              }
-+              i->identifier=maxidentifier+1;
-+              i->identifier_type=identifier_type;
-+              i->data=data;
-+              AST_LIST_INSERT_HEAD(headp,i,entries);
-+              AST_LIST_UNLOCK(headp);
-+      }
-+      return i->identifier;
-+}
-+
-+static int del_identifier(int identifier,int identifier_type) {
-+      struct ast_MYSQL_id *i;
-+      struct MYSQLidshead *headp;
-+      int found=0;
-+      
-+        headp=&_mysql_ids_head;
-+        
-+        if (AST_LIST_LOCK(headp)) {
-+              ast_log(LOG_WARNING,"Unable to lock identifiers list\n");
-+      } else {
-+              AST_LIST_TRAVERSE(headp,i,entries) {
-+                      if ((i->identifier==identifier) && 
-+                          (i->identifier_type==identifier_type)) {
-+                              AST_LIST_REMOVE(headp,i,ast_MYSQL_id,entries);
-+                              free(i);
-+                              found=1;
-+                              break;
-+                      }
-+              }
-+              AST_LIST_UNLOCK(headp);
-+      }
-+                      
-+      if (found==0) {
-+              ast_log(LOG_WARNING,"Could not find identifier %d, identifier_type %d in list to delete\n",identifier,identifier_type);
-+              return(-1);
-+      } else {
-+              return(0);
-+      }
-+}
-+
-+static int set_asterisk_int(struct ast_channel *chan, char *varname, int id) {
-+      if( id>=0 ) {
-+              char s[100] = "";
-+              snprintf(s, sizeof(s)-1, "%d", id);
-+#if EXTRA_LOG
-+              ast_log(LOG_WARNING,"MYSQL: setting var '%s' to value '%s'\n",varname,s);
-+#endif
-+              pbx_builtin_setvar_helper(chan,varname,s);
-+      }
-+      return id;
-+}
-+
-+static int add_identifier_and_set_asterisk_int(struct ast_channel *chan, char *varname, int identifier_type, void *data) {
-+      return set_asterisk_int(chan,varname,add_identifier(identifier_type,data));
-+}
-+
-+static int safe_scan_int( char** data, char* delim, int def ) {
-+      char* end;
-+      int res = def;
-+      char* s = strsep(data,delim);
-+      if( s ) {
-+              res = strtol(s,&end,10);
-+              if (*end) res = def;  /* not an integer */
-+      }
-+      return res;
-+}
-+
-+/* MYSQL operations */
-+static int aMYSQL_connect(struct ast_channel *chan, char *data) {
-+      
-+      MYSQL *mysql;
-+
-+      char *connid_var;
-+      char *dbhost;
-+      char *dbuser;
-+      char *dbpass;
-+      char *dbname;
-+       
-+      strsep(&data," "); // eat the first token, we already know it :P 
-+
-+      connid_var=strsep(&data," ");
-+      dbhost=strsep(&data," ");
-+      dbuser=strsep(&data," ");
-+      dbpass=strsep(&data," ");
-+      dbname=strsep(&data,"\n");
-+      
-+      if( connid_var && dbhost && dbuser && dbpass && dbname ) {
-+              mysql = mysql_init(NULL);
-+              if (mysql) {
-+                      if (mysql_real_connect(mysql,dbhost,dbuser,dbpass,dbname,0,NULL,0)) {
-+                              add_identifier_and_set_asterisk_int(chan,connid_var,AST_MYSQL_ID_CONNID,mysql);
-+                              return 0;
-+                      }
-+                      else {
-+                              ast_log(LOG_WARNING,"mysql_real_connect(mysql,%s,%s,dbpass,%s,...) failed\n",dbhost,dbuser,dbname);
-+                      }
-+              }
-+              else {
-+                      ast_log(LOG_WARNING,"myslq_init returned NULL\n");
-+              }
-+      }
-+      else {
-+              ast_log(LOG_WARNING,"MYSQL(connect is missing some arguments\n");
-+      }
-+
-+      return -1;
-+}
-+
-+static int aMYSQL_query(struct ast_channel *chan, char *data) {
-+      
-+      MYSQL       *mysql;
-+      MYSQL_RES   *mysqlres;
-+
-+      char *resultid_var;
-+      int connid;
-+      char *querystring;
-+
-+      strsep(&data," "); // eat the first token, we already know it :P 
-+
-+      resultid_var = strsep(&data," ");
-+      connid       = safe_scan_int(&data," ",-1);
-+      querystring  = strsep(&data,"\n");
-+
-+      if (resultid_var && (connid>=0) && querystring) {
-+              if ((mysql=find_identifier(connid,AST_MYSQL_ID_CONNID))!=NULL) {
-+                      mysql_query(mysql,querystring);
-+                      if ((mysqlres=mysql_use_result(mysql))!=NULL) {
-+                              add_identifier_and_set_asterisk_int(chan,resultid_var,AST_MYSQL_ID_RESID,mysqlres);
-+                              return 0;
-+                      }
-+                      else if( mysql_field_count(mysql)==0 ) {
-+                              return 0;  // See http://dev.mysql.com/doc/mysql/en/mysql_field_count.html
-+                      }
-+                      else {
-+                              ast_log(LOG_WARNING,"aMYSQL_query: mysql_store_result() failed on query %s\n",querystring);
-+                      }
-+              }
-+              else {
-+                      ast_log(LOG_WARNING,"aMYSQL_query: Invalid connection identifier %d passed in aMYSQL_query\n",connid);
-+              }
-+      }
-+      else {
-+              ast_log(LOG_WARNING,"aMYSQL_query: missing some arguments\n");
-+      }
-+      
-+      return -1;
-+}
-+
-+
-+static int aMYSQL_fetch(struct ast_channel *chan, char *data) {
-+      
-+      MYSQL_RES *mysqlres;
-+      MYSQL_ROW mysqlrow;
-+
-+      char *fetchid_var,*s5,*s6;
-+      int resultid,numFields,j;
-+      
-+      strsep(&data," "); // eat the first token, we already know it :P 
-+
-+      fetchid_var = strsep(&data," ");
-+      resultid    = safe_scan_int(&data," ",-1);
-+
-+      if (fetchid_var && (resultid>=0) ) {
-+              if ((mysqlres=find_identifier(resultid,AST_MYSQL_ID_RESID))!=NULL) {
-+                      /* Grab the next row */
-+                      if ((mysqlrow=mysql_fetch_row(mysqlres))!=NULL) {
-+                              numFields=mysql_num_fields(mysqlres);
-+                              for (j=0;j<numFields;j++) {
-+                                      s5=strsep(&data," ");
-+                                      if (s5==NULL) {
-+                                              ast_log(LOG_WARNING,"ast_MYSQL_fetch: More fields (%d) than variables (%d)\n",numFields,j);
-+                                              break;
-+                                      }
-+                                      s6=mysqlrow[j];
-+                                      pbx_builtin_setvar_helper(chan,s5, s6 ? s6 : "NULL");
-+                              }
-+#ifdef EXTRA_LOG
-+                              ast_log(LOG_WARNING,"ast_MYSQL_fetch: numFields=%d\n",numFields);
-+#endif
-+                              set_asterisk_int(chan,fetchid_var,1); // try more rows
-+                      } else {
-+#if EXTRA_LOG
-+                              ast_log(LOG_WARNING,"ast_MYSQL_fetch : EOF\n");
-+#endif
-+                              set_asterisk_int(chan,fetchid_var,0); // no more rows
-+                      }
-+                      return 0;
-+              }
-+              else {
-+                      ast_log(LOG_WARNING,"aMYSQL_fetch: Invalid result identifier %d passed\n",resultid);
-+              }
-+      }
-+      else {
-+              ast_log(LOG_WARNING,"aMYSQL_fetch: missing some arguments\n");
-+      }
-+
-+      return -1;
-+}
-+
-+static int aMYSQL_clear(struct ast_channel *chan, char *data) {
-+
-+      MYSQL_RES *mysqlres;
-+
-+      int id;
-+      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 {
-+              mysql_free_result(mysqlres);
-+              del_identifier(id,AST_MYSQL_ID_RESID);
-+      }
-+
-+      return 0;
-+}
-+
-+static int aMYSQL_disconnect(struct ast_channel *chan, char *data) {
-+      
-+      MYSQL *mysql;
-+      int id;
-+      strsep(&data," "); // eat the first token, we already know it :P 
-+
-+      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 {
-+              mysql_close(mysql);
-+              del_identifier(id,AST_MYSQL_ID_CONNID);
-+      } 
-+
-+      return 0;
-+}
-+
-+static int MYSQL_exec(struct ast_channel *chan, void *data)
-+{
-+      struct localuser *u;
-+      int result;
-+
-+#if EXTRA_LOG
-+      fprintf(stderr,"MYSQL_exec: data=%s\n",(char*)data);
-+#endif
-+
-+      if (!data) {
-+              ast_log(LOG_WARNING, "APP_MYSQL requires an argument (see manual)\n");
-+              return -1;
-+      }
-+
-+      LOCAL_USER_ADD(u);
-+      result=0;
-+
-+      ast_mutex_lock(&_mysql_mutex);
-+
-+      if (strncasecmp("connect",data,strlen("connect"))==0) {
-+              result=aMYSQL_connect(chan,ast_strdupa(data));
-+      } else  if (strncasecmp("query",data,strlen("query"))==0) {
-+              result=aMYSQL_query(chan,ast_strdupa(data));
-+      } else  if (strncasecmp("fetch",data,strlen("fetch"))==0) {
-+              result=aMYSQL_fetch(chan,ast_strdupa(data));
-+      } else  if (strncasecmp("clear",data,strlen("clear"))==0) {
-+              result=aMYSQL_clear(chan,ast_strdupa(data));
-+      } else  if (strncasecmp("disconnect",data,strlen("disconnect"))==0) {
-+              result=aMYSQL_disconnect(chan,ast_strdupa(data));
-+      } else {
-+              ast_log(LOG_WARNING, "Unknown argument to MYSQL application : %s\n",(char *)data);
-+              result=-1;      
-+      }
-+              
-+      ast_mutex_unlock(&_mysql_mutex);
-+
-+      LOCAL_USER_REMOVE(u);                                                                                
-+      return result;
-+
-+}
-+
-+int unload_module(void)
-+{
-+      STANDARD_HANGUP_LOCALUSERS;
-+      return ast_unregister_application(app);
-+}
-+
-+int load_module(void)
-+{
-+      struct MYSQLidshead *headp = &_mysql_ids_head;
-+      AST_LIST_HEAD_INIT(headp);
-+      return ast_register_application(app, MYSQL_exec, synopsis, descrip);
-+}
-+
-+char *description(void)
-+{
-+      return tdesc;
-+}
-+
-+int usecount(void)
-+{
-+      int res;
-+      STANDARD_USECOUNT(res);
-+      return res;
-+}
-+
-+char *key()
-+{
-+      return ASTERISK_GPL_KEY;
-+}
-diff -ruN asterisk-1.0.7-orig/cdr/Makefile asterisk-1.0.7-2/cdr/Makefile
---- asterisk-1.0.7-orig/cdr/Makefile   2004-08-31 18:33:00.000000000 +0200
-+++ asterisk-1.0.7-2/cdr/Makefile      2005-03-19 17:38:06.000000000 +0100
-@@ -37,36 +37,36 @@
- #
- # unixODBC stuff...
- #
--MODS+=$(shell if [ -f "/usr/include/odbcinst.h" ]; then echo "cdr_odbc.so"; fi)
--MODS+=$(shell if [ -f "/usr/local/include/odbcinst.h" ]; then echo "cdr_odbc.so"; fi) 
-+#MODS+=$(shell if [ -f "/usr/include/odbcinst.h" ]; then echo "cdr_odbc.so"; fi)
-+#MODS+=$(shell if [ -f "/usr/local/include/odbcinst.h" ]; then echo "cdr_odbc.so"; fi) 
- #
- # FreeTDS stuff...
- #
--MODS+=$(shell if [ -f "/usr/include/tds.h" ]; then echo "cdr_tds.so"; fi)
--MODS+=$(shell if [ -f "/usr/local/include/tds.h" ]; then echo "cdr_tds.so"; fi)
-+#MODS+=$(shell if [ -f "/usr/include/tds.h" ]; then echo "cdr_tds.so"; fi)
-+#MODS+=$(shell if [ -f "/usr/local/include/tds.h" ]; then echo "cdr_tds.so"; fi)
- #
- # PGSQL stuff...  Autoconf anyone??
- #
--MODS+=$(shell if [ -d /usr/local/pgsql/include ] || [ -d /usr/include/pgsql ] || [ -d /usr/local/include/pgsql ] || [ -d /opt/pgsql/include ] || [ -f /usr/include/libpq-fe.h ] ; then echo "cdr_pgsql.so"; fi)
--CFLAGS+=$(shell if [ -d /usr/local/pgsql/include ]; then echo "-I/usr/local/pgsql/include"; fi)
--CFLAGS+=$(shell if [ -d /usr/include/pgsql ]; then echo "-I/usr/include/pgsql"; fi)
--CFLAGS+=$(shell if [ -d /usr/include/postgresql ]; then echo "-I/usr/include/postgresql"; fi)
--CFLAGS+=$(shell if [ -d /usr/local/include/pgsql ]; then echo "-I/usr/local/include/pgsql"; fi)
--CFLAGS+=$(shell if [ -d /opt/pgsql/include ]; then echo "-I/opt/pgsql/include"; fi)
-+#MODS+=$(shell if [ -d /usr/local/pgsql/include ] || [ -d /usr/include/pgsql ] || [ -d /usr/local/include/pgsql ] || [ -d /opt/pgsql/include ] || [ -f /usr/include/libpq-fe.h ] ; then echo "cdr_pgsql.so"; fi)
-+#CFLAGS+=$(shell if [ -d /usr/local/pgsql/include ]; then echo "-I/usr/local/pgsql/include"; fi)
-+#CFLAGS+=$(shell if [ -d /usr/include/pgsql ]; then echo "-I/usr/include/pgsql"; fi)
-+#CFLAGS+=$(shell if [ -d /usr/include/postgresql ]; then echo "-I/usr/include/postgresql"; fi)
-+#CFLAGS+=$(shell if [ -d /usr/local/include/pgsql ]; then echo "-I/usr/local/include/pgsql"; fi)
-+#CFLAGS+=$(shell if [ -d /opt/pgsql/include ]; then echo "-I/opt/pgsql/include"; fi)
- #CFLAGS+=$(shell if [ -f /usr/include/libpq-fe.h ]; then echo "-I/usr/include"; fi)
- MLFLAGS=
--MLFLAGS+=$(shell if [ -d /usr/lib/pgsql ]; then echo "-L/usr/lib/pgsql"; fi)
--MLFLAGS+=$(shell if [ -d /usr/local/pgsql/lib ]; then echo "-L/usr/local/pgsql/lib"; fi)
--MLFLAGS+=$(shell if [ -d /usr/local/lib/pgsql ]; then echo "-L/usr/local/lib/pgsql"; fi)
--MLFLAGS+=$(shell if [ -d /opt/pgsql/lib ]; then echo "-L/opt/pgsql/lib"; fi)
--MLFLAGS+=$(shell if [ -f /usr/lib/libpq.so ]; then echo "-L/usr/lib"; fi)
-+#MLFLAGS+=$(shell if [ -d /usr/lib/pgsql ]; then echo "-L/usr/lib/pgsql"; fi)
-+#MLFLAGS+=$(shell if [ -d /usr/local/pgsql/lib ]; then echo "-L/usr/local/pgsql/lib"; fi)
-+#MLFLAGS+=$(shell if [ -d /usr/local/lib/pgsql ]; then echo "-L/usr/local/lib/pgsql"; fi)
-+#MLFLAGS+=$(shell if [ -d /opt/pgsql/lib ]; then echo "-L/opt/pgsql/lib"; fi)
-+#MLFLAGS+=$(shell if [ -f /usr/lib/libpq.so ]; then echo "-L/usr/lib"; fi)
- #
- # SQLIte stuff...
- #
--MODS+=$(shell if [ -f "/usr/include/sqlite.h" ]; then echo "cdr_sqlite.so"; fi)
-+#MODS+=$(shell if [ -f "/usr/include/sqlite.h" ]; then echo "cdr_sqlite.so"; fi)
- all: depend $(MODS)
-@@ -89,8 +89,17 @@
- cdr_tds.so: cdr_tds.o
-       $(CC) $(SOLINK) -o $@ $< -ltds $(MLFLAGS)
-+cdr_mysql.o: cdr_mysql.c
-+      $(CC) $(CFLAGS) $(MYSQL_CFLAGS) -c -o $@ $<
-+
-+cdr_mysql.so: cdr_mysql.o
-+      $(CC) $(SOLINK) -o $@ $< $(LDFLAGS_EXTRA) -lmysqlclient -lz $(MYSQL_LFLAGS)
-+
-+cdr_pgsql.o: cdr_pgsql.c
-+      $(CC) $(CFLAGS) $(PGSQL_CFLAGS) -c -o $@ $<
-+
- cdr_pgsql.so: cdr_pgsql.o
--      $(CC) $(SOLINK) -o $@ $< -lpq -lz $(MLFLAGS)
-+      $(CC) $(SOLINK) -o $@ $< $(LDFLAGS_EXTRA) -lpq -lz $(PGSQL_LFLAGS)
- cdr_sqlite.so: cdr_sqlite.o
-       $(CC) $(SOLINK) -o $@ $< -lsqlite $(MLFLAGS)
-diff -ruN asterisk-1.0.7-orig/cdr/cdr_mysql.c asterisk-1.0.7-2/cdr/cdr_mysql.c
---- asterisk-1.0.7-orig/cdr/cdr_mysql.c        1970-01-01 01:00:00.000000000 +0100
-+++ asterisk-1.0.7-2/cdr/cdr_mysql.c   2005-03-19 17:46:30.000000000 +0100
-@@ -0,0 +1,450 @@
-+/*
-+ * Asterisk -- A telephony toolkit for Linux.
-+ *
-+ * MySQL CDR logger 
-+ * 
-+ * James Sharp <jsharp@psychoses.org>
-+ *
-+ * Modified August 2003
-+ * Tilghman Lesher <asterisk__cdr__cdr_mysql__200308@the-tilghman.com>
-+ *
-+ * This program is free software, distributed under the terms of
-+ * the GNU General Public License.
-+ *
-+ */
-+
-+#include <sys/types.h>
-+#include <asterisk/config.h>
-+#include <asterisk/options.h>
-+#include <asterisk/channel.h>
-+#include <asterisk/cdr.h>
-+#include <asterisk/module.h>
-+#include <asterisk/logger.h>
-+#include <asterisk/cli.h>
-+#include "../asterisk.h"
-+
-+#include <stdio.h>
-+#include <string.h>
-+
-+#include <stdlib.h>
-+#include <unistd.h>
-+#include <time.h>
-+
-+#include <mysql/mysql.h>
-+#include <mysql/errmsg.h>
-+
-+#define DATE_FORMAT "%Y-%m-%d %T"
-+
-+static char *desc = "MySQL CDR Backend";
-+static char *name = "mysql";
-+static char *config = "cdr_mysql.conf";
-+static char *hostname = NULL, *dbname = NULL, *dbuser = NULL, *password = NULL, *dbsock = NULL, *dbtable = NULL;
-+static int hostname_alloc = 0, dbname_alloc = 0, dbuser_alloc = 0, password_alloc = 0, dbsock_alloc = 0, dbtable_alloc = 0;
-+static int dbport = 0;
-+static int connected = 0;
-+static time_t connect_time = 0;
-+static int records = 0;
-+static int totalrecords = 0;
-+static int userfield = 0;
-+
-+AST_MUTEX_DEFINE_STATIC(mysql_lock);
-+
-+static MYSQL mysql;
-+
-+static char cdr_mysql_status_help[] =
-+"Usage: cdr mysql status\n"
-+"       Shows current connection status for cdr_mysql\n";
-+
-+static int handle_cdr_mysql_status(int fd, int argc, char *argv[])
-+{
-+      if (connected) {
-+              char status[256], status2[100] = "";
-+              int ctime = time(NULL) - connect_time;
-+              if (dbport)
-+                      snprintf(status, 255, "Connected to %s@%s, port %d", dbname, hostname, dbport);
-+              else if (dbsock)
-+                      snprintf(status, 255, "Connected to %s on socket file %s", dbname, dbsock);
-+              else
-+                      snprintf(status, 255, "Connected to %s@%s", dbname, hostname);
-+
-+              if (dbuser && *dbuser)
-+                      snprintf(status2, 99, " with username %s", dbuser);
-+              if (dbtable && *dbtable)
-+                      snprintf(status2, 99, " using table %s", dbtable);
-+              if (ctime > 31536000) {
-+                      ast_cli(fd, "%s%s for %d years, %d days, %d hours, %d minutes, %d seconds.\n", status, status2, ctime / 31536000, (ctime % 31536000) / 86400, (ctime % 86400) / 3600, (ctime % 3600) / 60, ctime % 60);
-+              } else if (ctime > 86400) {
-+                      ast_cli(fd, "%s%s for %d days, %d hours, %d minutes, %d seconds.\n", status, status2, ctime / 86400, (ctime % 86400) / 3600, (ctime % 3600) / 60, ctime % 60);
-+              } else if (ctime > 3600) {
-+                      ast_cli(fd, "%s%s for %d hours, %d minutes, %d seconds.\n", status, status2, ctime / 3600, (ctime % 3600) / 60, ctime % 60);
-+              } else if (ctime > 60) {
-+                      ast_cli(fd, "%s%s for %d minutes, %d seconds.\n", status, status2, ctime / 60, ctime % 60);
-+              } else {
-+                      ast_cli(fd, "%s%s for %d seconds.\n", status, status2, ctime);
-+              }
-+              if (records == totalrecords)
-+                      ast_cli(fd, "  Wrote %d records since last restart.\n", totalrecords);
-+              else
-+                      ast_cli(fd, "  Wrote %d records since last restart and %d records since last reconnect.\n", totalrecords, records);
-+              return RESULT_SUCCESS;
-+      } else {
-+              ast_cli(fd, "Not currently connected to a MySQL server.\n");
-+              return RESULT_FAILURE;
-+      }
-+}
-+
-+static struct ast_cli_entry cdr_mysql_status_cli =
-+      { { "cdr", "mysql", "status", NULL },
-+      handle_cdr_mysql_status, "Show connection status of cdr_mysql",
-+      cdr_mysql_status_help, NULL };
-+
-+static int mysql_log(struct ast_cdr *cdr)
-+{
-+      struct tm tm;
-+      struct timeval tv;
-+      struct localuser *u;
-+      char *userfielddata = NULL;
-+      char sqlcmd[2048], timestr[128];
-+
-+      ast_mutex_lock(&mysql_lock);
-+
-+      memset(sqlcmd,0,2048);
-+
-+      localtime_r(&cdr->start.tv_sec,&tm);
-+      strftime(timestr,128,DATE_FORMAT,&tm);
-+
-+      if ((!connected) && (hostname || dbsock) && dbuser && password && dbname && dbtable ) {
-+              /* Attempt to connect */
-+              mysql_init(&mysql);
-+              if (mysql_real_connect(&mysql, hostname, dbuser, password, dbname, dbport, dbsock, 0)) {
-+                      connected = 1;
-+                      connect_time = time(NULL);
-+                      records = 0;
-+              } else {
-+                      ast_log(LOG_ERROR, "cdr_mysql: cannot connect to database server %s.  Call will not be logged\n", hostname);
-+              }
-+      } else {
-+              /* Long connection - ping the server */
-+              int error;
-+              if ((error = mysql_ping(&mysql))) {
-+                      connected = 0;
-+                      records = 0;
-+                      switch (error) {
-+                              case CR_SERVER_GONE_ERROR:
-+                                      ast_log(LOG_ERROR, "cdr_mysql: Server has gone away\n");
-+                                      break;
-+                              default:
-+                                      ast_log(LOG_ERROR, "cdr_mysql: Unknown connection error\n");
-+                      }
-+              }
-+      }
-+
-+      if (connected) {
-+              char *clid=NULL, *dcontext=NULL, *channel=NULL, *dstchannel=NULL, *lastapp=NULL, *lastdata=NULL;
-+#ifdef MYSQL_LOGUNIQUEID
-+              char *uniqueid=NULL;
-+#endif
-+
-+              /* Maximum space needed would be if all characters needed to be escaped, plus a trailing NULL */
-+              if ((clid = alloca(strlen(cdr->clid) * 2 + 1)) != NULL)
-+                      mysql_real_escape_string(&mysql, clid, cdr->clid, strlen(cdr->clid));
-+              if ((dcontext = alloca(strlen(cdr->dcontext) * 2 + 1)) != NULL)
-+                      mysql_real_escape_string(&mysql, dcontext, cdr->dcontext, strlen(cdr->dcontext));
-+              if ((channel = alloca(strlen(cdr->channel) * 2 + 1)) != NULL)
-+                      mysql_real_escape_string(&mysql, channel, cdr->channel, strlen(cdr->channel));
-+              if ((dstchannel = alloca(strlen(cdr->dstchannel) * 2 + 1)) != NULL)
-+                      mysql_real_escape_string(&mysql, dstchannel, cdr->dstchannel, strlen(cdr->dstchannel));
-+              if ((lastapp = alloca(strlen(cdr->lastapp) * 2 + 1)) != NULL)
-+                      mysql_real_escape_string(&mysql, lastapp, cdr->lastapp, strlen(cdr->lastapp));
-+              if ((lastdata = alloca(strlen(cdr->lastdata) * 2 + 1)) != NULL)
-+                      mysql_real_escape_string(&mysql, lastdata, cdr->lastdata, strlen(cdr->lastdata));
-+#ifdef MYSQL_LOGUNIQUEID
-+              if ((uniqueid = alloca(strlen(cdr->uniqueid) * 2 + 1)) != NULL)
-+                      mysql_real_escape_string(&mysql, uniqueid, cdr->uniqueid, strlen(cdr->uniqueid));
-+#endif
-+
-+              if (userfield && ((userfielddata = alloca(strlen(cdr->userfield) * 2 + 1)) != NULL))
-+                      mysql_real_escape_string(&mysql, userfielddata, cdr->userfield, strlen(cdr->userfield));                
-+
-+              /* Check for all alloca failures above at once */
-+#ifdef MYSQL_LOGUNIQUEID
-+              if ((!clid) || (!dcontext) || (!channel) || (!dstchannel) || (!lastapp) || (!lastdata) || (!uniqueid)) {
-+#else
-+              if ((!clid) || (!dcontext) || (!channel) || (!dstchannel) || (!lastapp) || (!lastdata)) {
-+#endif
-+                      ast_log(LOG_ERROR, "cdr_mysql:  Out of memory error (insert fails)\n");
-+                      ast_mutex_unlock(&mysql_lock);
-+                      return -1;
-+              }
-+
-+              ast_log(LOG_DEBUG,"cdr_mysql: inserting a CDR record.\n");
-+
-+              if (userfield && userfielddata)
-+              {
-+#ifdef MYSQL_LOGUNIQUEID
-+                      sprintf(sqlcmd,"INSERT INTO %s (calldate,clid,src,dst,dcontext,channel,dstchannel,lastapp,lastdata,duration,billsec,disposition,amaflags,accountcode,uniqueid,userfield) VALUES ('%s','%s','%s','%s','%s', '%s','%s','%s','%s',%i,%i,'%s',%i,'%s','%s','%s')",dbtable,timestr,clid,cdr->src, cdr->dst, dcontext,channel, dstchannel, lastapp, lastdata,cdr->duration,cdr->billsec,ast_cdr_disp2str(cdr->disposition),cdr->amaflags, cdr->accountcode, uniqueid, userfielddata);
-+#else
-+                      sprintf(sqlcmd,"INSERT INTO %s (calldate,clid,src,dst,dcontext,channel,dstchannel,lastapp,lastdata,duration,billsec,disposition,amaflags,accountcode,userfield) VALUES ('%s','%s','%s','%s','%s', '%s','%s','%s','%s',%i,%i,'%s',%i,'%s','%s')",dbtable,timestr,clid,cdr->src, cdr->dst, dcontext,channel, dstchannel, lastapp, lastdata,cdr->duration,cdr->billsec,ast_cdr_disp2str(cdr->disposition),cdr->amaflags, cdr->accountcode, userfielddata);
-+#endif  
-+              }
-+              else
-+              {
-+#ifdef MYSQL_LOGUNIQUEID
-+                      sprintf(sqlcmd,"INSERT INTO %s (calldate,clid,src,dst,dcontext,channel,dstchannel,lastapp,lastdata,duration,billsec,disposition,amaflags,accountcode,uniqueid) VALUES ('%s','%s','%s','%s','%s', '%s','%s','%s','%s',%i,%i,'%s',%i,'%s','%s')",dbtable,timestr,clid,cdr->src, cdr->dst, dcontext,channel, dstchannel, lastapp, lastdata,cdr->duration,cdr->billsec,ast_cdr_disp2str(cdr->disposition),cdr->amaflags, cdr->accountcode, uniqueid);
-+#else
-+                      sprintf(sqlcmd,"INSERT INTO %s (calldate,clid,src,dst,dcontext,channel,dstchannel,lastapp,lastdata,duration,billsec,disposition,amaflags,accountcode) VALUES ('%s','%s','%s','%s','%s', '%s','%s','%s','%s',%i,%i,'%s',%i,'%s')",dbtable,timestr,clid,cdr->src, cdr->dst, dcontext,channel, dstchannel, lastapp, lastdata,cdr->duration,cdr->billsec,ast_cdr_disp2str(cdr->disposition),cdr->amaflags, cdr->accountcode);
-+#endif  
-+              }
-+              
-+              ast_log(LOG_DEBUG,"cdr_mysql: SQL command as follows:  %s\n",sqlcmd);
-+      
-+              if (mysql_real_query(&mysql,sqlcmd,strlen(sqlcmd))) {
-+                      ast_log(LOG_ERROR,"Failed to insert into database.");
-+                      ast_mutex_unlock(&mysql_lock);
-+                      return -1;
-+              } else {
-+                      records++;
-+                      totalrecords++;
-+              }
-+      }
-+      ast_mutex_unlock(&mysql_lock);
-+      return 0;
-+}
-+
-+char *description(void)
-+{
-+      return desc;
-+}
-+
-+static int my_unload_module(void)
-+{ 
-+      ast_cli_unregister(&cdr_mysql_status_cli);
-+      if (connected) {
-+              mysql_close(&mysql);
-+              connected = 0;
-+              records = 0;
-+      }
-+      if (hostname && hostname_alloc) {
-+              free(hostname);
-+              hostname = NULL;
-+              hostname_alloc = 0;
-+      }
-+      if (dbname && dbname_alloc) {
-+              free(dbname);
-+              dbname = NULL;
-+              dbname_alloc = 0;
-+      }
-+      if (dbuser && dbuser_alloc) {
-+              free(dbuser);
-+              dbuser = NULL;
-+              dbuser_alloc = 0;
-+      }
-+      if (dbsock && dbsock_alloc) {
-+              free(dbsock);
-+              dbsock = NULL;
-+              dbsock_alloc = 0;
-+      }
-+      if (dbtable && dbtable_alloc) {
-+              free(dbtable);
-+              dbtable = NULL;
-+              dbtable_alloc = 0;
-+      }
-+      if (password && password_alloc) {
-+              free(password);
-+              password = NULL;
-+              password_alloc = 0;
-+      }
-+      dbport = 0;
-+      ast_cdr_unregister(name);
-+      return 0;
-+}
-+
-+static int my_load_module(void)
-+{
-+      int res;
-+      struct ast_config *cfg;
-+      struct ast_variable *var;
-+      char *tmp;
-+
-+      cfg = ast_config_load(config);
-+      if (!cfg) {
-+              ast_log(LOG_WARNING, "Unable to load config for mysql CDR's: %s\n", config);
-+              return 0;
-+      }
-+      
-+      var = ast_variable_browse(cfg, "global");
-+      if (!var) {
-+              /* nothing configured */
-+              return 0;
-+      }
-+
-+      tmp = ast_variable_retrieve(cfg,"global","hostname");
-+      if (tmp) {
-+              hostname = malloc(strlen(tmp) + 1);
-+              if (hostname != NULL) {
-+                      hostname_alloc = 1;
-+                      strcpy(hostname,tmp);
-+              } else {
-+                      ast_log(LOG_ERROR,"Out of memory error.\n");
-+                      return -1;
-+              }
-+      } else {
-+              ast_log(LOG_WARNING,"MySQL server hostname not specified.  Assuming localhost\n");
-+              hostname = "localhost";
-+      }
-+
-+      tmp = ast_variable_retrieve(cfg,"global","dbname");
-+      if (tmp) {
-+              dbname = malloc(strlen(tmp) + 1);
-+              if (dbname != NULL) {
-+                      dbname_alloc = 1;
-+                      strcpy(dbname,tmp);
-+              } else {
-+                      ast_log(LOG_ERROR,"Out of memory error.\n");
-+                      return -1;
-+              }
-+      } else {
-+              ast_log(LOG_WARNING,"MySQL database not specified.  Assuming asteriskcdrdb\n");
-+              dbname = "asteriskcdrdb";
-+      }
-+
-+      tmp = ast_variable_retrieve(cfg,"global","user");
-+      if (tmp) {
-+              dbuser = malloc(strlen(tmp) + 1);
-+              if (dbuser != NULL) {
-+                      dbuser_alloc = 1;
-+                      strcpy(dbuser,tmp);
-+              } else {
-+                      ast_log(LOG_ERROR,"Out of memory error.\n");
-+                      return -1;
-+              }
-+      } else {
-+              ast_log(LOG_WARNING,"MySQL database user not specified.  Assuming root\n");
-+              dbuser = "root";
-+      }
-+
-+      tmp = ast_variable_retrieve(cfg,"global","sock");
-+      if (tmp) {
-+              dbsock = malloc(strlen(tmp) + 1);
-+              if (dbsock != NULL) {
-+                      dbsock_alloc = 1;
-+                      strcpy(dbsock,tmp);
-+              } else {
-+                      ast_log(LOG_ERROR,"Out of memory error.\n");
-+                      return -1;
-+              }
-+      } else {
-+              ast_log(LOG_WARNING,"MySQL database sock file not specified.  Using default\n");
-+              dbsock = NULL;
-+      }
-+
-+      tmp = ast_variable_retrieve(cfg,"global","table");
-+      if (tmp) {
-+              dbtable = malloc(strlen(tmp) + 1);
-+              if (dbtable != NULL) {
-+                      dbtable_alloc = 1;
-+                      strcpy(dbtable,tmp);
-+              } else {
-+                      ast_log(LOG_ERROR,"Out of memory error.\n");
-+                      return -1;
-+              }
-+      } else {
-+              ast_log(LOG_NOTICE,"MySQL database table not specified.  Assuming \"cdr\"\n");
-+              dbtable = "cdr";
-+      }
-+
-+      tmp = ast_variable_retrieve(cfg,"global","password");
-+      if (tmp) {
-+              password = malloc(strlen(tmp) + 1);
-+              if (password != NULL) {
-+                      password_alloc = 1;
-+                      strcpy(password,tmp);
-+              } else {
-+                      ast_log(LOG_ERROR,"Out of memory error.\n");
-+                      return -1;
-+              }
-+      } else {
-+              ast_log(LOG_WARNING,"MySQL database password not specified.  Assuming blank\n");
-+              password = "";
-+      }
-+
-+      tmp = ast_variable_retrieve(cfg,"global","port");
-+      if (tmp) {
-+              if (sscanf(tmp,"%d",&dbport) < 1) {
-+                      ast_log(LOG_WARNING,"Invalid MySQL port number.  Using default\n");
-+                      dbport = 0;
-+              }
-+      }
-+      
-+      tmp = ast_variable_retrieve(cfg,"global","userfield");
-+      if (tmp) {
-+              if (sscanf(tmp,"%d",&userfield) < 1) {
-+                      ast_log(LOG_WARNING,"Invalid MySQL configurtation file\n");
-+                      userfield = 0;
-+              }
-+      }
-+      
-+      ast_config_destroy(cfg);
-+
-+      ast_log(LOG_DEBUG,"cdr_mysql: got hostname of %s\n",hostname);
-+      ast_log(LOG_DEBUG,"cdr_mysql: got port of %d\n",dbport);
-+      if (dbsock)
-+              ast_log(LOG_DEBUG,"cdr_mysql: got sock file of %s\n",dbsock);
-+      ast_log(LOG_DEBUG,"cdr_mysql: got user of %s\n",dbuser);
-+      ast_log(LOG_DEBUG,"cdr_mysql: got dbname of %s\n",dbname);
-+      ast_log(LOG_DEBUG,"cdr_mysql: got password of %s\n",password);
-+
-+      mysql_init(&mysql);
-+
-+      if (!mysql_real_connect(&mysql, hostname, dbuser, password, dbname, dbport, dbsock, 0)) {
-+              ast_log(LOG_ERROR, "Failed to connect to mysql database %s on %s.\n", dbname, hostname);
-+              connected = 0;
-+              records = 0;
-+      } else {
-+              ast_log(LOG_DEBUG,"Successfully connected to MySQL database.\n");
-+              connected = 1;
-+              records = 0;
-+              connect_time = time(NULL);
-+      }
-+
-+      res = ast_cdr_register(name, desc, mysql_log);
-+      if (res) {
-+              ast_log(LOG_ERROR, "Unable to register MySQL CDR handling\n");
-+      } else {
-+              res = ast_cli_register(&cdr_mysql_status_cli);
-+      }
-+
-+      return res;
-+}
-+
-+int load_module(void)
-+{
-+      return my_load_module();
-+}
-+
-+int unload_module(void)
-+{
-+      return my_unload_module();
-+}
-+
-+int reload(void)
-+{
-+      my_unload_module();
-+      return my_load_module();
-+}
-+
-+int usecount(void)
-+{
-+      /* Simplistic use count */
-+      if (ast_mutex_trylock(&mysql_lock)) {
-+              return 1;
-+      } else {
-+              ast_mutex_unlock(&mysql_lock);
-+              return 0;
-+      }
-+}
-+
-+char *key()
-+{
-+      return ASTERISK_GPL_KEY;
-+}
-diff -ruN asterisk-1.0.7-orig/configs/cdr_mysql.conf.sample asterisk-1.0.7-2/configs/cdr_mysql.conf.sample
---- asterisk-1.0.7-orig/configs/cdr_mysql.conf.sample  1970-01-01 01:00:00.000000000 +0100
-+++ asterisk-1.0.7-2/configs/cdr_mysql.conf.sample     2005-01-21 02:43:19.000000000 +0100
-@@ -0,0 +1,21 @@
-+;
-+; Note - if the database server is hosted on the same machine as the
-+; asterisk server, you can achieve a local Unix socket connection by
-+; setting hostname=localhost
-+;
-+; port and sock are both optional parameters.  If hostname is specified
-+; and is not "localhost", then cdr_mysql will attempt to connect to the
-+; port specified or use the default port.  If hostname is not specified
-+; or if hostname is "localhost", then cdr_mysql will attempt to connect
-+; to the socket file specified by sock or otherwise use the default socket
-+; file.
-+;
-+;[global]
-+;hostname=database.host.name
-+;dbname=asteriskcdrdb
-+;table=cdr
-+;password=password 
-+;user=asteriskcdruser
-+;port=3306
-+;sock=/tmp/mysql.sock
-+;userfield=1
This page took 0.257071 seconds and 4 git commands to generate.