From: Nicolas Thill Date: Sat, 30 Dec 2006 18:15:19 +0000 (+0000) Subject: update asterisk to v1.2.14 (closes: #1097), thanks to zandbelt. - add app-meetme... X-Git-Url: http://git.lede-project.org./?a=commitdiff_plain;h=8c96a07b5c0b5f387ba5d1099f497f9ac1985197;p=openwrt%2Fsvn-archive%2Fpackages.git update asterisk to v1.2.14 (closes: #1097), thanks to zandbelt. - add app-meetme - put res-crypto in a separate package - fix asterisk-mini dependency on asterisk SVN-Revision: 5938 --- diff --git a/net/asterisk/Makefile b/net/asterisk/Makefile index 49e228a0c..6f3de4868 100644 --- a/net/asterisk/Makefile +++ b/net/asterisk/Makefile @@ -9,12 +9,12 @@ include $(TOPDIR)/rules.mk PKG_NAME:=asterisk -PKG_VERSION:=1.2.1 +PKG_VERSION:=1.2.14 PKG_RELEASE:=1 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz PKG_SOURCE_URL:=http://ftp.digium.com/pub/asterisk/old-releases/ ftp://ftp.digium.com/pub/asterisk/old-releases/ -PKG_MD5SUM:=04657086791e80f319c0d728af705001 +PKG_MD5SUM:=2ce03466b99e0b9471e6c791ed14a5f2 PKG_CAT:=zcat PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-$(PKG_VERSION) @@ -31,13 +31,13 @@ define Package/asterisk/Default protocols, and can interoperate with almost all standards-based telephony \\\ equipment using relatively inexpensive hardware. URL:=http://www.asterisk.org/ + SUBMENU:=asterisk (Complete Open Source PBX) endef define Package/asterisk $(call Package/asterisk/Default) DEPENDS:=+libncurses +libpthread - TITLE:=Complete open source PBX - MENU:=1 + TITLE:=Complete Open Source PBX endef define Package/asterisk/conffiles @@ -66,11 +66,13 @@ endef define Package/asterisk-mini $(call Package/asterisk/Default) - DEPENDS:=asterisk - TITLE:=Minimal open source PBX + DEPENDS:=+libncurses +libpthread + PROVIDES:=asterisk + TITLE:=Minimal Open Source PBX DESCRIPTION+=\\\ \\\ This package contains only the following modules: \\\ + - app_dial\\\ - chan_iax2\\\ - chan_local\\\ - chan_sip\\\ @@ -101,6 +103,78 @@ define Package/asterisk-mini/conffiles /etc/asterisk/sip.conf endef +define Package/asterisk-mysql + $(call Package/asterisk/Default) + DEPENDS:=asterisk +libmysqlclient + TITLE:=MySQL support + DESCRIPTION+=\\\ + \\\ + This package contains MySQL support modules for Asterisk. +endef + +define Package/asterisk-mysql/conffiles +/etc/asterisk/cdr_mysql.conf +endef + +define Package/asterisk-pgsql + $(call Package/asterisk/Default) + DEPENDS:=asterisk +libpq + TITLE:=PostgreSQL support + DESCRIPTION+=\\\ + \\\ + This package contains PostgreSQL support modules for Asterisk. +endef + +define Package/asterisk-pgsql/conffiles +/etc/asterisk/cdr_pgsql.conf +endef + +define Package/asterisk-sqlite + $(call Package/asterisk/Default) + DEPENDS:=asterisk +libsqlite2 + TITLE:=SQLite modules + DESCRIPTION+=\\\ + \\\ + This package contains SQLite support modules for Asterisk. +endef + +define Package/asterisk-sounds + $(call Package/asterisk) + MENU:=0 + DEPENDS:=asterisk + TITLE:=Sound files + DESCRIPTION+=\\\ + \\\ + This package contains sound files for Asterisk. +endef + +define Package/asterisk-voicemail + $(call Package/asterisk/Default) + DEPENDS:=asterisk + TITLE:=Voicemail support + DESCRIPTION+=\\\ + \\\ + This package contains voicemail related modules for Asterisk. +endef + +define Package/asterisk-voicemail/conffiles +/etc/asterisk/voicemail.conf +endef + +define Package/asterisk-app-meetme + $(call Package/asterisk/Default) + DEPENDS:=asterisk +zaptel-libtonezone + TITLE:=MeetMe Confererencing support + DESCRIPTION+=\\\ + \\\ + This package provides the application MeetMe and conferencing support to \\\ + Asterisk. +endef + +define Package/asterisk-app-meetme/conffiles +/etc/asterisk/meetme.conf +endef + define Package/asterisk-chan-bluetooth $(call Package/asterisk/Default) DEPENDS:=asterisk +bluez-libs @@ -209,72 +283,27 @@ define Package/asterisk-res-agi Asterisk. endef -define Package/asterisk-mysql - $(call Package/asterisk/Default) - DEPENDS:=asterisk +libmysqlclient - TITLE:=MySQL support - DESCRIPTION+=\\\ - \\\ - This package contains MySQL support modules for Asterisk. -endef - -define Package/asterisk-mysql/conffiles -/etc/asterisk/cdr_mysql.conf -endef - -define Package/asterisk-pgsql - $(call Package/asterisk/Default) - DEPENDS:=asterisk +libpq - TITLE:=PostgreSQL support - DESCRIPTION+=\\\ - \\\ - This package contains PostgreSQL support modules for Asterisk. -endef - -define Package/asterisk-pgsql/conffiles -/etc/asterisk/cdr_pgsql.conf -endef - -define Package/asterisk-sqlite - $(call Package/asterisk/Default) - DEPENDS:=asterisk +libsqlite2 - TITLE:=SQLite modules - DESCRIPTION+=\\\ - \\\ - This package contains SQLite support modules for Asterisk. -endef - -define Package/asterisk-sounds - $(call Package/asterisk) - MENU:=0 - DEPENDS:=asterisk - TITLE:=Sound files - DESCRIPTION+=\\\ - \\\ - This package contains sound files for Asterisk. -endef - -define Package/asterisk-voicemail +define Package/asterisk-res-crypto $(call Package/asterisk/Default) - DEPENDS:=asterisk - TITLE:=Voicemail support + DEPENDS:=asterisk +libopenssl + TITLE:=Cryptographic Digital Signatures support DESCRIPTION+=\\\ - \\\ - This package contains voicemail related modules for Asterisk. + \\\ + This package provides Cryptographic Digital Signatures support to \\\ + Asterisk. endef -define Package/asterisk-voicemail/conffiles -/etc/asterisk/voicemail.conf -endef ifneq ($(SDK),) # Make sure the options below are enabled when building with the SDK CONFIG_PACKAGE_asterisk-mysql:=m CONFIG_PACKAGE_asterisk-pgsql:=m CONFIG_PACKAGE_asterisk-sqlite:=m + CONFIG_PACKAGE_asterisk-app-meetme:=m CONFIG_PACKAGE_asterisk-chan-bluetooth:=m CONFIG_PACKAGE_asterisk-chan-h323:=m CONFIG_PACKAGE_asterisk-codec-speex:=m + CONFIG_PACKAGE_asterisk-res-crypto:=m endif EXTRA_CFLAGS:= -I$(STAGING_DIR)/usr/include -I$(STAGING_DIR)/include @@ -294,6 +323,9 @@ endif ifneq ($(CONFIG_PACKAGE_asterisk-sqlite),) EXTRA_CDR_MODULES+= cdr_sqlite.so endif +ifneq ($(CONFIG_PACKAGE_asterisk-app-meetme),) + EXTRA_APP_MODULES+= app_meetme.so +endif ifneq ($(CONFIG_PACKAGE_asterisk-chan-bluetooth),) EXTRA_CHAN_MODULES+= chan_bluetooth.so endif @@ -308,6 +340,9 @@ ifneq ($(CONFIG_PACKAGE_asterisk-codec-speex),) EXTRA_CFLAGS+= -I$(STAGING_DIR)/usr/include/speex EXTRA_CODEC_MODULES+= codec_speex.so endif +ifneq ($(CONFIG_PACKAGE_asterisk-res-crypto),) + EXTRA_RES_MODULES+= res_crypto.so +endif define Build/Configure endef @@ -375,6 +410,7 @@ define Package/asterisk/install rm -f codec_lpc10.so ; \ rm -f pbx_dundi.so ; \ rm -f res_agi.so ; \ + rm -f res_crypto.so ; \ ) (cd $(1)/etc/asterisk; \ rm -f *odbc* *mysql* *postgres* *pgsql* *voicemail* *adsi* *oss* *alsa* \ @@ -455,6 +491,13 @@ define Package/asterisk-voicemail/install $(CP) $(PKG_BUILD_DIR)/sounds/vm-*.gsm $(1)/usr/lib/asterisk/sounds/ endef +define Package/asterisk-app-meetme/install + $(INSTALL_DIR) $(1)/etc/asterisk + $(INSTALL_DATA) $(PKG_BUILD_DIR)/configs/meetme.conf.sample $(1)/etc/asterisk/meetme.conf + $(INSTALL_DIR) $(1)/usr/lib/asterisk/modules + $(INSTALL_BIN) $(PKG_BUILD_DIR)/apps/app_meetme.so $(1)/usr/lib/asterisk/modules/ +endef + define Package/asterisk-chan-bluetooth/install $(INSTALL_DIR) $(1)/etc/asterisk $(INSTALL_DATA) $(PKG_BUILD_DIR)/configs/bluetooth.conf $(1)/etc/asterisk/bluetooth.conf @@ -512,13 +555,18 @@ define Package/asterisk-res-agi/install $(INSTALL_BIN) $(PKG_BUILD_DIR)/res/res_agi.so $(1)/usr/lib/asterisk/modules/ endef +define Package/asterisk-res-crypto/install + $(INSTALL_DIR) $(1)/usr/lib/asterisk/modules + $(INSTALL_BIN) $(PKG_BUILD_DIR)/res/res_crypto.so $(1)/usr/lib/asterisk/modules/ +endef + $(eval $(call BuildPackage,asterisk)) -$(eval $(call BuildPackage,asterisk-mini)) $(eval $(call BuildPackage,asterisk-mysql)) $(eval $(call BuildPackage,asterisk-pgsql)) $(eval $(call BuildPackage,asterisk-sqlite)) -$(eval $(call BuildPackage,asterisk-voicemail)) $(eval $(call BuildPackage,asterisk-sounds)) +$(eval $(call BuildPackage,asterisk-voicemail)) +$(eval $(call BuildPackage,asterisk-app-meetme)) $(eval $(call BuildPackage,asterisk-chan-bluetooth)) $(eval $(call BuildPackage,asterisk-chan-h323)) $(eval $(call BuildPackage,asterisk-chan-mgcp)) @@ -528,3 +576,5 @@ $(eval $(call BuildPackage,asterisk-codec-lpc10)) $(eval $(call BuildPackage,asterisk-codec-speex)) $(eval $(call BuildPackage,asterisk-pbx-dundi)) $(eval $(call BuildPackage,asterisk-res-agi)) +$(eval $(call BuildPackage,asterisk-res-crypto)) +$(eval $(call BuildPackage,asterisk-mini)) diff --git a/net/asterisk/patches/01-chan_iax2-tmp_path.patch b/net/asterisk/patches/01-chan_iax2-tmp_path.patch new file mode 100644 index 000000000..fad3d21a3 --- /dev/null +++ b/net/asterisk/patches/01-chan_iax2-tmp_path.patch @@ -0,0 +1,12 @@ +diff -Nru asterisk-1.2.14.org/channels/chan_iax2.c asterisk-1.2.14/channels/chan_iax2.c +--- asterisk-1.2.14.org/channels/chan_iax2.c 2006-12-09 16:45:37.000000000 +0100 ++++ asterisk-1.2.14/channels/chan_iax2.c 2006-12-27 08:46:38.000000000 +0100 +@@ -1191,7 +1191,7 @@ + last++; + else + last = s; +- snprintf(s2, strlen(s) + 100, "/var/tmp/%s-%ld", last, (unsigned long)rand()); ++ snprintf(s2, strlen(s) + 100, "/tmp/%s-%ld", last, (unsigned long)rand()); + res = stat(s, &stbuf); + if (res < 0) { + ast_log(LOG_WARNING, "Failed to stat '%s': %s\n", s, strerror(errno)); diff --git a/net/asterisk/patches/02-dns.patch b/net/asterisk/patches/02-dns.patch new file mode 100644 index 000000000..e44d8d65f --- /dev/null +++ b/net/asterisk/patches/02-dns.patch @@ -0,0 +1,18 @@ +diff -Nru asterisk-1.2.14.org/dns.c asterisk-1.2.14/dns.c +--- asterisk-1.2.14.org/dns.c 2005-11-29 19:24:39.000000000 +0100 ++++ asterisk-1.2.14/dns.c 2006-12-27 08:50:05.000000000 +0100 +@@ -175,7 +175,13 @@ + + #if defined(res_ninit) + #define HAS_RES_NINIT +-#else ++#endif ++ ++#ifdef __UCLIBC__ ++#undef HAS_RES_NINIT ++#endif ++ ++#ifndef HAS_RES_NINIT + AST_MUTEX_DEFINE_STATIC(res_lock); + #if 0 + #warning "Warning, res_ninit is missing... Could have reentrancy issues" diff --git a/net/asterisk/patches/03-Makefile-astdb.patch b/net/asterisk/patches/03-Makefile-astdb.patch new file mode 100644 index 000000000..56226a428 --- /dev/null +++ b/net/asterisk/patches/03-Makefile-astdb.patch @@ -0,0 +1,14 @@ +diff -Nru asterisk-1.2.14.org/db1-ast/Makefile asterisk-1.2.14/db1-ast/Makefile +--- asterisk-1.2.14.org/db1-ast/Makefile 2006-04-30 16:27:56.000000000 +0200 ++++ asterisk-1.2.14/db1-ast/Makefile 2006-12-27 08:52:14.000000000 +0100 +@@ -32,8 +32,8 @@ + + $(LIBDB): $(OBJS) + rm -f $@ +- ar cq $@ $(OBJS) +- ranlib $@ ++ $(AR) cq $@ $(OBJS) ++ $(RANLIB) $@ + + $(LIBDBSO): $(SHOBJS) + $(CC) -Wl,-O1 -Wl,--version-script=libdb.map -Wl,-soname=$(LIBDBSO) -shared -o $@ $^ diff --git a/net/asterisk/patches/04-Makefile-codecs-lpc10.patch b/net/asterisk/patches/04-Makefile-codecs-lpc10.patch new file mode 100644 index 000000000..d3ff35445 --- /dev/null +++ b/net/asterisk/patches/04-Makefile-codecs-lpc10.patch @@ -0,0 +1,28 @@ +diff -Nru asterisk-1.2.14.org/codecs/lpc10/Makefile asterisk-1.2.14/codecs/lpc10/Makefile +--- asterisk-1.2.14.org/codecs/lpc10/Makefile 2005-11-29 19:24:39.000000000 +0100 ++++ asterisk-1.2.14/codecs/lpc10/Makefile 2006-12-27 08:54:16.000000000 +0100 +@@ -34,6 +34,7 @@ + ifneq ($(PROC),ppc) + ifneq ($(PROC),x86_64) + ifneq ($(PROC),alpha) ++ifneq ($(PROC),mipsel) + #The problem with sparc is the best stuff is in newer versions of gcc (post 3.0) only. + #This works for even old (2.96) versions of gcc and provides a small boost either way. + #A ultrasparc cpu is really v9 but the stock debian stable 3.0 gcc doesn.t support it. +@@ -53,6 +54,7 @@ + endif + endif + endif ++endif + + LIB = $(LIB_TARGET_DIR)/liblpc10.a + +@@ -69,7 +71,7 @@ + + $(LIB): $(OBJ) + $(AR) cr $@ $(OBJ) +- ranlib $@ ++ $(RANLIB) $@ + + clean: + -rm -f *.o $(LIB) diff --git a/net/asterisk/patches/05-Makefile-stdtime.patch b/net/asterisk/patches/05-Makefile-stdtime.patch new file mode 100644 index 000000000..12de7ec70 --- /dev/null +++ b/net/asterisk/patches/05-Makefile-stdtime.patch @@ -0,0 +1,14 @@ +diff -Nru asterisk-1.2.14.org/stdtime/Makefile asterisk-1.2.14/stdtime/Makefile +--- asterisk-1.2.14.org/stdtime/Makefile 2005-11-29 19:24:39.000000000 +0100 ++++ asterisk-1.2.14/stdtime/Makefile 2006-12-27 08:56:14.000000000 +0100 +@@ -3,8 +3,8 @@ + all: libtime.a + + libtime.a: $(OBJS) +- ar rv $@ $(OBJS) +- ranlib $@ ++ $(AR) rv $@ $(OBJS) ++ $(RANLIB) $@ + + install: + diff --git a/net/asterisk/patches/06-chan_bluetooth.patch b/net/asterisk/patches/06-chan_bluetooth.patch new file mode 100644 index 000000000..21d967094 --- /dev/null +++ b/net/asterisk/patches/06-chan_bluetooth.patch @@ -0,0 +1,3670 @@ +diff -Nru asterisk-1.2.14.org/channels/chan_bluetooth.c asterisk-1.2.14/channels/chan_bluetooth.c +--- asterisk-1.2.14.org/channels/chan_bluetooth.c 1970-01-01 01:00:00.000000000 +0100 ++++ asterisk-1.2.14/channels/chan_bluetooth.c 2006-12-27 09:04:03.000000000 +0100 +@@ -0,0 +1,3599 @@ ++/* ++ * Asterisk -- A telephony toolkit for Linux. ++ * ++ * Asterisk Bluetooth Channel ++ * ++ * Author: Theo Zourzouvillys ++ * ++ * Adaptive Linux Solutions ++ * ++ * Copyright (C) 2004 Adaptive Linux Solutions ++ * ++ * This program is free software, distributed under the terms of ++ * the GNU General Public License ++ * ++ * ******************* NOTE NOTE NOTE NOTE NOTE ********************* ++ * ++ * This code is not at all tested, and only been developed with a ++ * HBH-200 headset and a Nokia 6310i right now. ++ * ++ * Expect it to crash, dial random numbers, and steal all your money. ++ * ++ * PLEASE try any headsets and phones, and let me know the results, ++ * working or not, along with all debug output! ++ * ++ * ------------------------------------------------------------------ ++ * ++ * Asterisk Bluetooth Support ++ * ++ * Well, here we go - Attempt to provide Handsfree profile support in ++ * both AG and HF modes, AG (AudioGateway) mode support for using ++ * headsets, and HF (Handsfree) mode for utilising mobile/cell phones ++ * ++ * It would be nice to also provide Headset support at some time in ++ * the future, however, a working Handsfree profile is nice for now, ++ * and as far as I can see, almost all new HS devices also support HF ++ * ++ * ------------------------------------------------------------------ ++ * INSTRUCTIONS ++ * ++ * You need to have bluez's bluetooth stack, along with user space ++ * tools (>=v2.10), and running hcid and sdsp. ++ * ++ * See bluetooth.conf for configuration details. ++ * ++ * - Ensure bluetooth subsystem is up and running. 'hciconfig' ++ * should show interface as UP. ++ * ++ * - If you're trying to use a headset/HS, start up asterisk, and try ++ * to pair it as you normally would. ++ * ++ * - If you're trying to use a Phone/AG, just make sure bluetooth is ++ * enabled on your phone, and start up asterisk. ++ * ++ * - 'bluetooth show peers' will show all bluetooth devices states. ++ * ++ * - Send a call out by using Dial(BLT/DevName/0123456). Call a HS ++ * with Dial(BLT/DevName) ++ * ++ * ------------------------------------------------------------------ ++ * BUGS ++ * ++ * - What should happen when an AG is paired with asterisk and ++ * someone uses the AG dalling a number manually? My test phone ++ * seems to try to open an SCO link. Perhaps an extension to ++ * route the call to, or maybe drop the RFCOM link all together? ++ * ++ * ------------------------------------------------------------------ ++ * COMPATIBILITY ++ * ++ * PLEASE email with the results of ANY ++ * device not listed in here (working or not), or if the device is ++ * listed and it doesn't work! Please also email full debug output ++ * for any device not working correctly or generating errors in log. ++ * ++ * HandsFree Profile: ++ * ++ * HS (HeadSet): ++ * - Ericsson HBH-200 ++ * ++ * AG (AudioGateway): ++ * - Nokia 6310i ++ * ++ * ------------------------------------------------------------------ ++ * ++ * Questions, bugs, or (preferably) patches to: ++ * ++ * ++ * ++ * ------------------------------------------------------------------ ++ */ ++ ++/* ---------------------------------- */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* --- Data types and definitions --- */ ++ ++#ifndef HANDSFREE_AUDIO_GW_SVCLASS_ID ++# define HANDSFREE_AUDIO_GW_SVCLASS_ID 0x111f ++#endif ++#define BLUETOOTH_FORMAT AST_FORMAT_SLINEAR ++#define BLT_CHAN_NAME "BLT" ++#define BLT_CONFIG_FILE "bluetooth.conf" ++#define BLT_RDBUFF_MAX 1024 ++#define BLT_DEFAULT_HCI_DEV 0 ++#define BLT_SVN_REVISION "$Rev$" ++ ++/* ---------------------------------- */ ++ ++typedef enum { ++ BLT_ROLE_NONE = 0, // Unknown Device ++ BLT_ROLE_HS = 1, // Device is a Headset ++ BLT_ROLE_AG = 2, // Device is an Audio Gateway ++ BLT_ROLE_GUI = 3 // Device is used as an GUI ++} blt_role_t; ++ ++/* State when we're in HS mode */ ++ ++typedef enum { ++ BLT_STATE_WANT_R = 0, ++ BLT_STATE_WANT_N = 1, ++ BLT_STATE_WANT_CMD = 2, ++ BLT_STATE_WANT_N2 = 3, ++} blt_state_t; ++ ++typedef enum { ++ BLT_STATUS_DOWN, ++ BLT_STATUS_CONNECTING, ++ BLT_STATUS_NEGOTIATING, ++ BLT_STATUS_READY, ++ BLT_STATUS_RINGING, ++ BLT_STATUS_IN_CALL, ++} blt_status_t; ++ ++/* ---------------------------------- */ ++ ++/* Default config settings */ ++ ++#define BLT_DEFAULT_CHANNEL_AG 5 ++#define BLT_DEFAULT_CHANNEL_HS 6 ++#define BLT_DEFAULT_CHANNEL_GUI 1 ++#define BLT_DEFAULT_ROLE BLT_ROLE_HS ++#define BLT_OBUF_LEN (48 * 25) ++ ++#define BUFLEN (4800) ++ ++/* ---------------------------------- */ ++ ++typedef struct blt_dev blt_dev_t; ++ ++void ag_cgmi_response(blt_dev_t * dev, char * cmd); ++void ag_unknown_response(blt_dev_t * dev, char * cmd); ++void ag_cgmi_valid_response(blt_dev_t * dev, char * cmd); ++void ag_clip_response(blt_dev_t * dev, char * cmd); ++void ag_cmer_response(blt_dev_t * dev, char * cmd); ++void ag_cind_status_response(blt_dev_t * dev, char * cmd); ++void ag_cind_response(blt_dev_t * dev, char * cmd); ++void ag_brsf_response(blt_dev_t * dev, char * cmd); ++void remove_sdp_records(void); ++ ++void gui_easm_response(blt_dev_t * dev, char * cmd); ++ ++int sock_err(int fd); ++int parse_clip(const char * str, char *number, int number_len, char * name, int name_len, int *type); ++int set_buffer(char * ring, char * data, int circular_len, int * pos, int data_len); ++int get_buffer(char * dst, char * ring, int ring_size, int * head, int to_copy); ++void gui_eaid_response(blt_dev_t * dev, char * cmd); ++ ++ ++ ++struct blt_ring { ++ unsigned char buf[BUFLEN]; ++}; ++// XXX:T: Tidy this lot up. ++struct blt_dev { ++ ++ blt_status_t status; /* Device Status */ ++ ++ struct ast_channel * owner; /* Channel we belong to, possibly NULL */ ++ blt_dev_t * dev; /* The bluetooth device channel is for */ ++ struct ast_frame fr; /* Recieved frame */ ++ ++ /* SCO Handler */ ++ int sco_pipe[2]; /* SCO alert pipe */ ++ int sco; /* SCO fd */ ++ int sco_handle; /* SCO Handle */ ++ int sco_mtu; /* SCO MTU */ ++ int sco_running; /* 1 when sCO thread should be running */ ++ pthread_t sco_thread; /* SCO thread */ ++ ast_mutex_t sco_lock; /* SCO lock */ ++ int sco_pos_in; /* Reader in position (drain)*/ ++ int sco_pos_inrcv; /* Reader in position (fill) */ ++ int wakeread; /* blt_read() needs to be woken */ ++ int sco_pos_out; /* Reader out position */ ++ int sco_sending; /* Sending SCO packets */ ++ char buf[1200]; /* Incoming data buffer */ ++ int bufpos; ++ char sco_buf_out[BUFLEN]; /* 24 chunks of 48 */ ++ char sco_buf_in[BUFLEN]; /* 24 chunks of 48 */ ++ ++ char dnid[1024]; /* Outgoi gncall dialed number */ ++ unsigned char * obuf[BLT_OBUF_LEN]; /* Outgoing data buffer */ ++ int obuf_len; /* Output Buffer Position */ ++ int obuf_wpos; /* Buffer Reader */ ++ ++ // device ++ int autoconnect; /* 1 for autoconnect */ ++ int outgoing_id; /* Outgoing connection scheduler id */ ++ char * name; /* Devices friendly name */ ++ blt_role_t role; /* Device role (HS or AG) */ ++ bdaddr_t bdaddr; /* remote address */ ++ int channel; /* remote channel */ ++ int rd; /* RFCOMM fd */ ++ int tmp_rd; /* RFCOMM fd */ ++ int call_cnt; /* Number of attempted calls */ ++ ast_mutex_t lock; /* RFCOMM socket lock */ ++ char rd_buff[BLT_RDBUFF_MAX]; /* RFCOMM input buffer */ ++ int rd_buff_pos; /* RFCOMM input buffer position */ ++ int ready; /* 1 When ready */ ++ char *context; ++ ++ /* AG mode */ ++ char last_ok_cmd[BLT_RDBUFF_MAX]; /* Runtime[AG]: Last AT command that was OK */ ++ int cind; /* Runtime[AG]: Recieved +CIND */ ++ int call_pos, service_pos, callsetup_pos; /* Runtime[AG]: Positions in CIND/CMER */ ++ int call, service, callsetup; /* Runtime[AG]: Values */ ++ char cid_num[AST_MAX_EXTENSION]; ++ char cid_name[AST_MAX_EXTENSION]; ++ ++ /* HS mode */ ++ blt_state_t state; /* Runtime: Device state (AG mode only) */ ++ int ring_timer; /* Runtime:Ring Timer */ ++ char last_err_cmd[BLT_RDBUFF_MAX]; /* Runtime: Last AT command that was OK */ ++ void (*cb)(blt_dev_t * dev, char * str); /* Runtime: Callback when in HS mode */ ++ ++ int brsf; /* Runtime: Bluetooth Retrieve Supported Features */ ++ int bvra; /* Runtime: Bluetooth Voice Recognised Activation */ ++ int gain_speaker; /* Runtime: Gain Of Speaker */ ++ int clip; /* Runtime: Supports CLID */ ++ int colp; /* Runtime: Connected Line ID */ ++ int elip; /* Runtime: (Ericsson) Supports CLID */ ++ int eolp; /* Runtime: (Ericsson) Connected Line ID */ ++ int ringing; /* Runtime: Device is ringing */ ++ ++ blt_dev_t * next; /* Next in linked list */ ++ ++}; ++ ++typedef struct blt_atcb { ++ ++ /* The command */ ++ char * str; ++ ++ /* DTE callbacks: */ ++ int (*set)(blt_dev_t * dev, const char * arg, int len); ++ int (*read)(blt_dev_t * dev); ++ int (*execute)(blt_dev_t * dev, const char * data); ++ int (*test)(blt_dev_t * dev); ++ ++ /* DCE callbacks: */ ++ int (*unsolicited)(blt_dev_t * dev, const char * value); ++ ++} blt_atcb_t; ++ ++/* ---------------------------------- */ ++ ++static void rd_close(blt_dev_t * dev, int reconnect, int err); ++static int send_atcmd(blt_dev_t * device, const char * fmt, ...); ++static int sco_connect(blt_dev_t * dev); ++static int sco_start(blt_dev_t * dev, int fd); ++ ++/* ---------------------------------- */ ++ ++/* RFCOMM channel we listen on*/ ++static int rfcomm_channel_ag = BLT_DEFAULT_CHANNEL_AG; ++static int rfcomm_channel_hs = BLT_DEFAULT_CHANNEL_HS; ++static int rfcomm_channel_gui = BLT_DEFAULT_CHANNEL_GUI; ++ ++static char* gui_default_sip_number = ""; ++static char* gui_default_sip_address = ""; ++ ++/* Address of local bluetooth interface */ ++static int hcidev_id; ++static bdaddr_t local_bdaddr; ++ ++/* All the current sockets */ ++AST_MUTEX_DEFINE_STATIC(iface_lock); ++static blt_dev_t * iface_head; ++static int ifcount = 0; ++ ++static int sdp_record_hs = -1; ++static int sdp_record_ag = -1; ++static int sdp_record_gui = -1; ++ ++/* RFCOMM listen socket */ ++static int rfcomm_sock_ag = -1; ++static int rfcomm_sock_hs = -1; ++static int rfcomm_sock_gui = -1; ++ ++static int sco_socket = -1; ++ ++static int monitor_pid = -1; ++ ++/* The socket monitoring thread */ ++static pthread_t monitor_thread = AST_PTHREADT_NULL; ++AST_MUTEX_DEFINE_STATIC(monitor_lock); ++ ++/* Count how many times this module is currently in use */ ++static int usecnt = 0; ++AST_MUTEX_DEFINE_STATIC(usecnt_lock); ++ ++static struct sched_context * sched = NULL; ++ ++/* ---------------------------------- */ ++ ++#if ASTERISK_VERSION_NUM <= 010107 ++#include ++#define tech_pvt pvt->pvt ++#else /* CVS. FIXME: Version number */ ++static struct ast_channel *blt_request(const char *type, int format, void *data, int *cause); ++static int blt_hangup(struct ast_channel *c); ++static int blt_answer(struct ast_channel *c); ++static struct ast_frame *blt_read(struct ast_channel *chan); ++static int blt_call(struct ast_channel *c, char *dest, int timeout); ++static int blt_write(struct ast_channel *chan, struct ast_frame *f); ++static int blt_indicate(struct ast_channel *chan, int cond); ++ ++static const struct ast_channel_tech blt_tech = { ++ .type = BLT_CHAN_NAME, ++ .description = "Bluetooth Channel Driver", ++ .capabilities = BLUETOOTH_FORMAT, ++ .requester = blt_request, ++ .hangup = blt_hangup, ++ .answer = blt_answer, ++ .read = blt_read, ++ .call = blt_call, ++ .write = blt_write, ++ .indicate = blt_indicate, ++}; ++#endif ++/* ---------------------------------- */ ++ ++static const char * ++role2str(blt_role_t role) ++{ ++ switch (role) { ++ case BLT_ROLE_HS: ++ return "HS"; ++ case BLT_ROLE_AG: ++ return "AG"; ++ case BLT_ROLE_GUI: ++ return "GUI"; ++ case BLT_ROLE_NONE: ++ default: ++ return "??"; ++ } ++} ++ ++static const char * ++status2str(blt_status_t status) ++{ ++ switch (status) { ++ case BLT_STATUS_DOWN: ++ return "Down"; ++ case BLT_STATUS_CONNECTING: ++ return "Connecting"; ++ case BLT_STATUS_NEGOTIATING: ++ return "Negotiating"; ++ case BLT_STATUS_READY: ++ return "Ready"; ++ case BLT_STATUS_RINGING: ++ return "Ringing"; ++ case BLT_STATUS_IN_CALL: ++ return "InCall"; ++ }; ++ return "Unknown"; ++} ++ ++int sock_err(int fd) ++{ ++ int ret; ++ int len = sizeof(ret); ++ getsockopt(fd, SOL_SOCKET, SO_ERROR, &ret, &len); ++ return ret; ++} ++ ++/* ---------------------------------- */ ++int parse_clip(const char * str, char *number, int number_len, char * name, int name_len, int *type) ++{ ++ const char *c = str; ++ const char *start; ++ int length; ++ char typestr[256]; ++ ++ memset(number, 0, number_len); ++ memset(name, 0, name_len); ++ *type = 0; ++ ++ number[0] = '\0'; ++ name[0] = '\0'; ++ while(*c && *c != '"') ++ c++; ++ c++; ++ start = c; ++ while(*c && *c != '"') ++ c++; ++ length = c - start < number_len ? c - start : number_len; ++ strncpy(number, start, length); ++ number[length] = '\0'; ++ c++; ++ while(*c && *c != ',') ++ c++; ++ c++; ++ start = c; ++ while(*c && *c != ',') ++ c++; ++ length = c - start < number_len ? c - start : number_len; ++ strncpy(typestr, start, length); ++ typestr[length] = '\0'; ++ *type = atoi(typestr); ++ c++; ++ while(*c && *c != ',') ++ c++; ++ c++; ++ while(*c && *c != ',') ++ c++; ++ c++; ++ while(*c && *c != '"') ++ c++; ++ c++; ++ start = c; ++ while(*c && *c != '"') ++ c++; ++ length = c - start < number_len ? c - start : number_len; ++ strncpy(name, start, length); ++ name[length] = '\0'; ++ ++ return(1); ++} ++ ++ ++static const char * ++parse_cind(const char * str, char * name, int name_len) ++{ ++ int c = 0; ++ ++ memset(name, 0, name_len); ++ ++ while (*str) { ++ if (*str == '(') { ++ if (++c == 1 && *(str+1) == '"') { ++ const char * start = str + 2; ++ int len = 0; ++ str += 2; ++ while (*str && *str != '"') { ++ len++; ++ str++; ++ } ++ if (len == 0) ++ return NULL; ++ strncpy(name, start, (len > name_len) ? name_len : len); ++ } ++ } else if (*str == ')') ++ c--; ++ else if (c == 0 && *str == ',') ++ return str + 1; ++ str++; ++ } ++ return NULL; ++} ++ ++static void ++set_cind(blt_dev_t * dev, int indicator, int val) ++{ ++ ++ ast_log(LOG_DEBUG, "CIND %d set to %d\n", indicator, val); ++ ++ if (indicator == dev->callsetup_pos) { ++ ++ // call progress ++ ++ dev->callsetup = val; ++ ++ switch (val) { ++ case 3: ++ // Outgoing ringing ++ if ((dev->owner && dev->role == BLT_ROLE_AG) || ++ (dev->owner && dev->role == BLT_ROLE_GUI)) ++ ast_queue_control(dev->owner, AST_CONTROL_RINGING); ++ break; ++ case 2: ++ break; ++ case 1: ++ break; ++ case 0: ++ if ((dev->owner && dev->role == BLT_ROLE_AG && dev->call == 0) || ++ (dev->owner && dev->role == BLT_ROLE_AG && dev->call == 0)) ++ ast_queue_control(dev->owner, AST_CONTROL_CONGESTION); ++ break; ++ } ++ ++ } else if (indicator == dev->service_pos) { ++ ++ // Signal ++ ++ if (val == 0) ++ ast_log(LOG_NOTICE, "Audio Gateway %s lost signal\n", dev->name); ++ else if (dev->service == 0 && val > 0) ++ ast_log(LOG_NOTICE, "Audio Gateway %s got signal\n", dev->name); ++ ++ dev->service = val; ++ ++ } else if (indicator == dev->call_pos) { ++ ++ // Call ++ ++ dev->call = val; ++ ++ if (dev->owner) { ++ if (val == 1) { ++ sco_start(dev, -1); ++ ast_queue_control(dev->owner, AST_CONTROL_ANSWER); ++ } else if (val == 0) ++ ast_queue_control(dev->owner, AST_CONTROL_HANGUP); ++ } ++ ++ } ++ ++ ++} ++ ++/* ---------------------------------- */ ++ ++int ++set_buffer(char * ring, char * data, int circular_len, int * pos, int data_len) ++{ ++ int start_pos = *(pos); ++ int done = 0; ++ int copy; ++ ++ while (data_len) { ++ // Set can_do to the most we can do in this copy. ++ ++ copy = MIN(circular_len - start_pos, data_len); ++ memcpy(ring + start_pos, data + done, copy); ++ done += copy; ++ start_pos += copy; ++ data_len -= copy; ++ ++ if (start_pos == circular_len) { ++ start_pos = 0; ++ } ++ } ++ *(pos) = start_pos; ++ return 0; ++} ++ ++int ++get_buffer(char * dst, char * ring, int ring_size, int * head, int to_copy) ++{ ++ int copy; ++ ++ // |1|2|3|4|5|6|7|8|9| ++ // |-----| ++ ++ while (to_copy) { ++ ++ // Set can_do to the most we can do in this copy. ++ copy = MIN(ring_size - *head, to_copy); ++ ++ // ast_log(LOG_DEBUG, "Getting: %d bytes, From pos %d\n", copy, *head); ++#if __BYTE_ORDER == __LITTLE_ENDIAN ++ memcpy(dst, ring + *head, copy); ++#else ++ // memcpy(dst, ring + *head, copy); ++ ast_swapcopy_samples(dst, ring+*head, copy/2); ++#endif ++ memset(ring+*head, 0, copy); ++ dst += copy; ++ *head += copy; ++ to_copy -= copy; ++ ++ if (*head == ring_size ) { ++ *head = 0; ++ } ++ ++ } ++ ++ return 0; ++} ++ ++/* Handle SCO audio sync. ++ * ++ * If we are the MASTER, then we control the timing, ++ * in 48 byte chunks. If we're the SLAVE, we send ++ * as and when we recieve a packet. ++ * ++ * Because of packet/timing nessecity, we ++ * start up a thread when we're passing audio, so ++ * that things are timed exactly right. ++ * ++ * sco_thread() is the function that handles it. ++ * ++ */ ++ ++static void * ++sco_thread(void * data) ++{ ++ blt_dev_t * dev = (blt_dev_t*)data; ++ int res; ++ struct pollfd pfd[2]; ++ int in_pos = 0; ++ int out_pos = 0; ++ char c = 1; ++ int sending; ++ char buf[1024]; ++ int len; ++ ++ // Avoid deadlock in odd circumstances ++ ++ ast_log(LOG_WARNING, "SCO thread started on fd %d, pid %d\n", dev->sco, getpid()); ++ ++ if (fcntl(dev->sco_pipe[1], F_SETFL, O_RDWR|O_NONBLOCK)) { ++ ast_log(LOG_WARNING, "fcntl failed on sco_pipe\n"); ++ } ++ ++ // dev->status = BLT_STATUS_IN_CALL; ++ // ast_queue_control(dev->owner, AST_CONTROL_ANSWER); ++ // Set buffer to silence, just incase. ++ ++ ast_mutex_lock(&(dev->sco_lock)); ++ ++ memset(dev->sco_buf_in, 0, BUFLEN); ++ memset(dev->sco_buf_out, 0, BUFLEN); ++ ++ dev->sco_pos_in = 0; ++ dev->sco_pos_out = 0; ++ dev->sco_pos_inrcv = 0; ++ dev->wakeread = 1; ++ ++ ast_mutex_unlock(&(dev->sco_lock)); ++ ++ while (1) { ++ ++ ast_mutex_lock(&(dev->sco_lock)); ++ ++ if (dev->sco_running != 1) { ++ ast_log(LOG_DEBUG, "SCO stopped.\n"); ++ break; ++ } ++ ++ pfd[0].fd = dev->sco; ++ pfd[0].events = POLLIN; ++ ++ pfd[1].fd = dev->sco_pipe[1]; ++ pfd[1].events = POLLIN; ++ ++ ast_mutex_unlock(&(dev->sco_lock)); ++ ++ res = poll(pfd, 2, 50); ++ ++ if (res == -1 && errno != EINTR) { ++ ast_log(LOG_DEBUG, "SCO poll() error\n"); ++ break; ++ } ++ ++ if (res == 0) ++ continue; ++ ++ ++ if (pfd[0].revents & POLLIN) { ++ ++ len = read(dev->sco, buf, 48); ++ ++ if (len) { ++ ast_mutex_lock(&(dev->lock)); ++ ++ if (dev->owner && dev->owner->_state == AST_STATE_UP) { ++ ast_mutex_lock(&(dev->sco_lock)); ++ set_buffer(dev->sco_buf_in, buf, BUFLEN, &in_pos, len); ++ dev->sco_pos_inrcv = in_pos; ++ ++ get_buffer(buf, dev->sco_buf_out, BUFLEN, &out_pos, len); ++ if (write(dev->sco, buf, len) != len) ++ ast_log(LOG_WARNING, "Wrote <48 to sco\n"); ++ ++ if (dev->wakeread) { ++ /* blt_read has caught up. Kick it */ ++ dev->wakeread = 0; ++ if(write(dev->sco_pipe[1], &c, 1) != 1) ++ ast_log(LOG_WARNING, "write to kick sco_pipe failed\n"); ++ } ++ ast_mutex_unlock(&(dev->sco_lock)); ++ } ++ ast_mutex_unlock(&(dev->lock)); ++ } ++ ++ } else if (pfd[0].revents) { ++ ++ int e = sock_err(pfd[0].fd); ++ ast_log(LOG_ERROR, "SCO connection error: %s (errno %d)\n", strerror(e), e); ++ break; ++ ++ } else if (pfd[1].revents & POLLIN) { ++ ++ int len; ++ ++ len = read(pfd[1].fd, &c, 1); ++ sending = (sending) ? 0 : 1; ++ ++ ast_mutex_unlock(&(dev->sco_lock)); ++ ++ } else if (pfd[1].revents) { ++ ++ int e = sock_err(pfd[1].fd); ++ ast_log(LOG_ERROR, "SCO pipe connection event %d on pipe[1]=%d: %s (errno %d)\n", pfd[1].revents, pfd[1].fd, strerror(e), e); ++ break; ++ ++ } else { ++ ast_log(LOG_NOTICE, "Unhandled poll output\n"); ++ ast_mutex_unlock(&(dev->sco_lock)); ++ } ++ ++ } ++ ++ ast_mutex_lock(&(dev->lock)); ++ close(dev->sco); ++ dev->sco = -1; ++ dev->sco_running = -1; ++ ++ memset(dev->sco_buf_in, 0, BUFLEN); ++ memset(dev->sco_buf_out, 0, BUFLEN); ++ ++ dev->sco_pos_in = 0; ++ dev->sco_pos_out = 0; ++ dev->sco_pos_inrcv = 0; ++ ++ ast_mutex_unlock(&(dev->sco_lock)); ++ if (dev->owner) ++ ast_queue_control(dev->owner, AST_CONTROL_HANGUP); ++ ast_mutex_unlock(&(dev->lock)); ++ ast_log(LOG_DEBUG, "SCO thread stopped\n"); ++ return NULL; ++} ++ ++/* Start SCO thread. Must be called with dev->lock */ ++ ++static int ++sco_start(blt_dev_t * dev, int fd) ++{ ++ ++ if (dev->sco_pipe[1] <= 0) { ++ ast_log(LOG_ERROR, "SCO pipe[1] == %d\n", dev->sco_pipe[1]); ++ return -1; ++ } ++ ++ ast_mutex_lock(&(dev->sco_lock)); ++ ++ if (dev->sco_running != -1) { ++ ast_log(LOG_ERROR, "Tried to start SCO thread while already running\n"); ++ ast_mutex_unlock(&(dev->sco_lock)); ++ return -1; ++ } ++ ++ if (dev->sco == -1) { ++ if (fd > 0) { ++ dev->sco = fd; ++ } else if (sco_connect(dev) != 0) { ++ ast_log(LOG_ERROR, "SCO fd invalid\n"); ++ ast_mutex_unlock(&(dev->sco_lock)); ++ return -1; ++ } ++ } ++ ++ dev->sco_running = 1; ++ ++ if (ast_pthread_create(&(dev->sco_thread), NULL, sco_thread, dev) < 0) { ++ ast_log(LOG_ERROR, "Unable to start SCO thread.\n"); ++ dev->sco_running = -1; ++ ast_mutex_unlock(&(dev->sco_lock)); ++ return -1; ++ } ++ ++ ast_mutex_unlock(&(dev->sco_lock)); ++ ++ return 0; ++} ++ ++/* Stop SCO thread. Must be called with dev->lock */ ++ ++static int ++sco_stop(blt_dev_t * dev) ++{ ++ ast_mutex_lock(&(dev->sco_lock)); ++ if (dev->sco_running == 1) ++ dev->sco_running = 0; ++ else ++ dev->sco_running = -1; ++ dev->sco_sending = 0; ++ ast_mutex_unlock(&(dev->sco_lock)); ++ return 0; ++} ++ ++/* ---------------------------------- */ ++ ++/* Answer the call. Call with lock held on device */ ++ ++static int ++answer(blt_dev_t * dev) ++{ ++ ++ if ( (!dev->owner) || (dev->ready != 1) || (dev->status != BLT_STATUS_READY && dev->status != BLT_STATUS_RINGING)) { ++ ast_log(LOG_ERROR, "Attempt to answer() in invalid state (owner=%p, ready=%d, status=%s)\n", ++ dev->owner, dev->ready, status2str(dev->status)); ++ return -1; ++ } ++ ++ // dev->sd = sco_connect(&local_bdaddr, &(dev->bdaddr), NULL, NULL, 0); ++ // dev->status = BLT_STATUS_IN_CALL; ++ // dev->owner->fds[0] = dev->sd; ++ // if we are answering (hitting button): ++ ast_queue_control(dev->owner, AST_CONTROL_ANSWER); ++ // if asterisk signals us to answer: ++ // ast_setstate(ast, AST_STATE_UP); ++ ++ /* Start SCO link */ ++ sco_start(dev, -1); ++ return 0; ++} ++ ++/* ---------------------------------- */ ++ ++static int ++blt_write(struct ast_channel * ast, struct ast_frame * frame) ++{ ++ blt_dev_t * dev = ast->tech_pvt; ++ ++ /* Write a frame of (presumably voice) data */ ++ ++ if (frame->frametype != AST_FRAME_VOICE) { ++ ast_log(LOG_WARNING, "Don't know what to do with frame type '%d'\n", frame->frametype); ++ return 0; ++ } ++ ++ if (!(frame->subclass & BLUETOOTH_FORMAT)) { ++ static int fish = 5; ++ if (fish) { ++ ast_log(LOG_WARNING, "Cannot handle frames in format %d\n", frame->subclass); ++ fish--; ++ } ++ return 0; ++ } ++ ++ if (ast->_state != AST_STATE_UP) { ++ return 0; ++ } ++ ++ ast_mutex_lock(&(dev->sco_lock)); ++ set_buffer(dev->sco_buf_out, frame->data, BUFLEN, &(dev->sco_pos_out), MIN(frame->datalen, BUFLEN)); ++ ast_mutex_unlock(&(dev->sco_lock)); ++ ++ return 0; ++ ++} ++ ++static struct ast_frame * ++blt_read(struct ast_channel * ast) ++{ ++ blt_dev_t * dev = ast->tech_pvt; ++ char c = 1; ++ int len; ++ static int fish = 0; ++ /* Some nice norms */ ++ ++ dev->fr.datalen = 0; ++ dev->fr.samples = 0; ++ dev->fr.data = NULL; ++ dev->fr.src = BLT_CHAN_NAME; ++ dev->fr.offset = 0; ++ dev->fr.mallocd = AST_MALLOCD_DATA; ++ dev->fr.delivery.tv_sec = 0; ++ dev->fr.delivery.tv_usec = 0; ++ read(dev->sco_pipe[0], &c, 1); ++ ast_mutex_lock(&(dev->sco_lock)); ++ dev->sco_sending = 1; ++ ++ if (dev->sco_pos_inrcv < dev->sco_pos_in) { ++ /* Buffer wrapped. Read only till the end */ ++ len = BUFLEN - dev->sco_pos_in + dev->sco_pos_inrcv; ++ } else { ++ len = dev->sco_pos_inrcv - dev->sco_pos_in; ++ } ++ dev->fr.data = malloc(AST_FRIENDLY_OFFSET+len) + AST_FRIENDLY_OFFSET; ++ ++ get_buffer(dev->fr.data, dev->sco_buf_in, BUFLEN, &(dev->sco_pos_in), len); ++ dev->wakeread = 1; ++ ast_mutex_unlock(&(dev->sco_lock)); ++ if (fish) { ++ unsigned char *x = dev->fr.data; ++ ast_log(LOG_WARNING, "blt_read %d: %02x %02x %02x %02x %02x %02x\n", ++ dev->fr.datalen, x[0], x[1], x[2], x[3], x[4], x[5]); ++ fish--; ++ } ++ ++ dev->fr.samples = len / 2; ++ dev->fr.datalen = len; ++ dev->fr.frametype = AST_FRAME_VOICE; ++ dev->fr.subclass = BLUETOOTH_FORMAT; ++ dev->fr.offset = AST_FRIENDLY_OFFSET; ++ return &dev->fr; ++} ++ ++/* Escape Any '"' in str. Return malloc()ed string */ ++static char * ++escape_str(char * str) ++{ ++ char * ptr = str; ++ char * pret; ++ char * ret; ++ int len = 0; ++ ++ while (*ptr) { ++ if (*ptr == '"') ++ len++; ++ len++; ++ ptr++; ++ } ++ ++ ret = malloc(len + 1); ++ pret = memset(ret, 0, len + 1); ++ ++ ptr = str; ++ ++ while (*ptr) { ++ if (*ptr == '"') ++ *pret++ = '\\'; ++ *pret++ = *ptr++; ++ } ++ ++ return ret; ++} ++ ++static int ++ring_hs(blt_dev_t * dev) ++{ ++#if (ASTERISK_VERSION_NUM < 010100) ++ char tmp[AST_MAX_EXTENSION]; ++ char *name, *num; ++#endif ++ ++ ast_mutex_lock(&(dev->lock)); ++ ++ if (dev->owner == NULL) { ++ ast_mutex_unlock(&(dev->lock)); ++ return 0; ++ } ++ ++ dev->ringing = 1; ++ dev->status = BLT_STATUS_RINGING; ++ ++ send_atcmd(dev, "RING"); ++ ++ dev->owner->rings++; ++ ++ // XXX:T: '"' needs to be escaped in ELIP. ++ ++#if (ASTERISK_VERSION_NUM < 010100) ++ ++ if (dev->owner->callerid) { ++ ++ memset(tmp, 0, sizeof(tmp)); ++ strncpy(tmp, dev->owner->callerid, sizeof(tmp)-1); ++ ++ if (!ast_callerid_parse(tmp, &name, &num)) { ++ ++ if (dev->clip && num) ++ send_atcmd(dev, "+CLIP: \"%s\",129", num); ++ ++ if (dev->elip && name) { ++ char * esc = escape_str(name); ++ send_atcmd(dev, "*ELIP: \"%s\"", esc); ++ free(esc); ++ } ++ } ++ } ++ ++ ++#else ++ ++ if (dev->clip && dev->owner->cid.cid_num) ++ send_atcmd(dev, "+CLIP: \"%s\",129", dev->owner->cid.cid_num); ++ ++ if (dev->elip && dev->owner->cid.cid_name) { ++ char * esc = escape_str(dev->owner->cid.cid_name); ++ send_atcmd(dev, "*ELIP: \"%s\"", esc); ++ free(esc); ++ } ++ ++#endif ++ ++ ast_mutex_unlock(&(dev->lock)); ++ ++ return 1; ++} ++ ++/* ++ * If the HS is already connected, then just send RING, otherwise, things get a ++ * little more sticky. We first have to find the channel for HS using SDP, ++ * then initiate the connection. Once we've done that, we can start the call. ++ */ ++ ++static int ++blt_call(struct ast_channel * ast, char * dest, int timeout) ++{ ++ blt_dev_t * dev = ast->tech_pvt; ++ ++ if ((ast->_state != AST_STATE_DOWN) && (ast->_state != AST_STATE_RESERVED)) { ++ ast_log(LOG_WARNING, "blt_call called on %s, neither down nor reserved\n", ast->name); ++ return -1; ++ } ++ ++ ast_log(LOG_DEBUG, "Calling %s on %s [t: %d]\n", dest, ast->name, timeout); ++ ++ if (ast_mutex_lock(&iface_lock)) { ++ ast_log(LOG_ERROR, "Failed to get iface_lock.\n"); ++ return -1; ++ } ++ ++// ast_mutex_lock(&(dev->lock)); ++ ++ if (dev->ready == 0) { ++ ast_log(LOG_WARNING, "Tried to call a device not ready/connected.\n"); ++ ast_setstate(ast, AST_CONTROL_CONGESTION); ++// ast_mutex_unlock(&(dev->lock)); ++ ast_mutex_unlock(&iface_lock); ++ return 0; ++ } ++ ++ if (dev->role == BLT_ROLE_HS) { ++ ++ send_atcmd(dev, "+CIEV: 3,1"); ++ ++ dev->ring_timer = ast_sched_add(sched, 5000, AST_SCHED_CB(ring_hs), dev); ++ ++ ring_hs(dev); ++ ++ ast_setstate(ast, AST_STATE_RINGING); ++ ast_queue_control(ast, AST_CONTROL_RINGING); ++ ++ } else if (dev->role == BLT_ROLE_AG) { ++ ++ send_atcmd(dev, "ATD%s;", dev->dnid); ++// it does not seem like we should start the audio until the call is connected ++// sco_start(dev, -1); ++ } else if (dev->role == BLT_ROLE_GUI) { ++ ++ send_atcmd(dev, "ATD%s;", dev->dnid); ++ ++ } else { ++ ++ ast_setstate(ast, AST_CONTROL_CONGESTION); ++ ast_log(LOG_ERROR, "Unknown device role\n"); ++ ++ } ++ ++// ast_mutex_unlock(&(dev->lock)); ++ ast_mutex_unlock(&iface_lock); ++ ++ return 0; ++} ++ ++static int ++blt_hangup(struct ast_channel * ast) ++{ ++ blt_dev_t * dev = ast->tech_pvt; ++ ++ ast_log(LOG_DEBUG, "blt_hangup(%s)\n", ast->name); ++ ++ if (!ast->tech_pvt) { ++ ast_log(LOG_WARNING, "Asked to hangup channel not connected\n"); ++ return 0; ++ } ++ ++ if (ast_mutex_lock(&iface_lock)) { ++ ast_log(LOG_ERROR, "Failed to get iface_lock\n"); ++ return 0; ++ } ++ ++ ast_mutex_lock(&(dev->lock)); ++ ++ sco_stop(dev); ++ dev->sco_sending = 0; ++ ++ if (dev->role == BLT_ROLE_HS) { ++ ++ if (dev->ringing == 0) { ++ // Actual call in progress ++ send_atcmd(dev, "+CIEV: 2,0"); ++ } else { ++ ++ // Just ringing still ++ ++ if (dev->role == BLT_ROLE_HS) ++ send_atcmd(dev, "+CIEV: 3,0"); ++ ++ if (dev->ring_timer >= 0) ++ ast_sched_del(sched, dev->ring_timer); ++ ++ dev->ring_timer = -1; ++ dev->ringing = 0; ++ ++ } ++ ++ } else if (dev->role == BLT_ROLE_AG) { ++ ++ // Cancel call. ++ send_atcmd(dev, "ATH"); ++ send_atcmd(dev, "AT+CHUP"); ++ ++ } ++ ++ if (dev->status == BLT_STATUS_IN_CALL || dev->status == BLT_STATUS_RINGING) ++ dev->status = BLT_STATUS_READY; ++ ++ ast->tech_pvt = NULL; ++ dev->owner = NULL; ++ ast_mutex_unlock(&(dev->lock)); ++ ast_setstate(ast, AST_STATE_DOWN); ++ ast_mutex_unlock(&(iface_lock)); ++ ++ return 0; ++} ++ ++static int ++blt_indicate(struct ast_channel * c, int condition) ++{ ++ ast_log(LOG_DEBUG, "blt_indicate (%d)\n", condition); ++ ++ switch(condition) { ++ case AST_CONTROL_RINGING: ++ return -1; ++ default: ++ ast_log(LOG_WARNING, "Don't know how to condition %d\n", condition); ++ break; ++ } ++ return -1; ++} ++ ++static int ++blt_answer(struct ast_channel * ast) ++{ ++ blt_dev_t * dev = ast->tech_pvt; ++ ++ ast_mutex_lock(&dev->lock); ++ ++ // if (dev->ring_timer >= 0) ++ // ast_sched_del(sched, dev->ring_timer); ++ // dev->ring_timer = -1; ++ ++ ast_log(LOG_DEBUG, "Answering interface\n"); ++ ++ if (ast->_state != AST_STATE_UP) { ++ send_atcmd(dev, "+CIEV: 2,1"); ++ send_atcmd(dev, "+CIEV: 3,0"); ++ sco_start(dev, -1); ++ ast_setstate(ast, AST_STATE_UP); ++ } ++ ++ ast_mutex_unlock(&dev->lock); ++ ++ return 0; ++} ++ ++static struct ast_channel * ++blt_new(blt_dev_t * dev, int state, const char * context, const char * number) ++{ ++ struct ast_channel * ast; ++ char c = 0; ++ ++ if ((ast = ast_channel_alloc(1)) == NULL) { ++ ast_log(LOG_WARNING, "Unable to allocate channel structure\n"); ++ return NULL; ++ } ++ ++ snprintf(ast->name, sizeof(ast->name), "BLT/%s", dev->name); ++ ++ // ast->fds[0] = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_SCO); ++ ++ ast->nativeformats = BLUETOOTH_FORMAT; ++ //ast->rawreadformat = BLUETOOTH_FORMAT; ++ //ast->rawwriteformat = BLUETOOTH_FORMAT; ++ ast->writeformat = BLUETOOTH_FORMAT; ++ ast->readformat = BLUETOOTH_FORMAT; ++ ++ ast_setstate(ast, state); ++ ++ ast->type = BLT_CHAN_NAME; ++ ++ ast->tech_pvt = dev; ++#if ASTERISK_VERSION_NUM > 010107 ++ ast->tech = &blt_tech; ++#else ++ ast->pvt->call = blt_call; ++ ast->pvt->indicate = blt_indicate; ++ ast->pvt->hangup = blt_hangup; ++ ast->pvt->read = blt_read; ++ ast->pvt->write = blt_write; ++ ast->pvt->answer = blt_answer; ++#endif ++ strncpy(ast->context, context, sizeof(ast->context)-1); ++ strncpy(ast->exten, number, sizeof(ast->exten) - 1); ++ if(0 == strcmp(number, "s")) ++ { ++ //ast_set_callerid(ast, dev->cid_num, dev->cid_name, dev->cid_num); ++ } ++ ++ ast->language[0] = '\0'; ++ ++ ast->fds[0] = dev->sco_pipe[0]; ++ write(dev->sco_pipe[1], &c, 1); ++ ++ dev->owner = ast; ++ ++ ast_mutex_lock(&usecnt_lock); ++ usecnt++; ++ ast_mutex_unlock(&usecnt_lock); ++ ++ ast_update_use_count(); ++ ++ if (state != AST_STATE_DOWN) { ++ if (ast_pbx_start(ast)) { ++ ast_log(LOG_WARNING, "Unable to start PBX on %s\n", ast->name); ++ ast_hangup(ast); ++ } ++ } ++ ++ return ast; ++} ++ ++static struct ast_channel * ++#if (ASTERISK_VERSION_NUM < 010100) ++blt_request(char * type, int format, void * local_data) ++#elif (ASTERISK_VERSION_NUM <= 010107) ++blt_request(const char * type, int format, void * local_data) ++#else ++blt_request(const char * type, int format, void * local_data, int *cause) ++#endif ++{ ++ char * data = (char*)local_data; ++ int oldformat; ++ blt_dev_t * dev = NULL; ++ struct ast_channel * ast = NULL; ++ char * number = data, * dname; ++ ++ dname = strsep(&number, "/"); ++ ++ oldformat = format; ++ ++ format &= BLUETOOTH_FORMAT; ++ ++ if (!format) { ++ ast_log(LOG_NOTICE, "Asked to get a channel of unsupported format '%d'\n", oldformat); ++ return NULL; ++ } ++ ++ ast_log(LOG_DEBUG, "Dialing '%s' via '%s'\n", number, dname); ++ ++ if (ast_mutex_lock(&iface_lock)) { ++ ast_log(LOG_ERROR, "Unable to lock iface_list\n"); ++ return NULL; ++ } ++ ++ dev = iface_head; ++ ++ while (dev) { ++ if (strcmp(dev->name, dname) == 0) { ++ ast_mutex_lock(&(dev->lock)); ++ if (!dev->ready) { ++ ast_log(LOG_ERROR, "Device %s is not connected\n", dev->name); ++ ast_mutex_unlock(&(dev->lock)); ++ ast_mutex_unlock(&iface_lock); ++ return NULL; ++ } ++ break; ++ } ++ dev = dev->next; ++ } ++ ++ ast_mutex_unlock(&iface_lock); ++ ++ if (!dev) { ++ ast_log(LOG_WARNING, "Failed to find device named '%s'\n", dname); ++ return NULL; ++ } ++ ++ if (number && dev->role != BLT_ROLE_AG) { ++ ast_log(LOG_WARNING, "Tried to send a call out on non AG\n"); ++ ast_mutex_unlock(&(dev->lock)); ++ return NULL; ++ } ++ ++ if (dev->role == BLT_ROLE_AG) ++ strncpy(dev->dnid, number, sizeof(dev->dnid) - 1); ++ ++ ast = blt_new(dev, AST_STATE_DOWN, dev->context, "s"); ++ ++ ast_mutex_unlock(&(dev->lock)); ++ ++ return ast; ++} ++ ++/* ---------------------------------- */ ++ ++ ++/* ---- AT COMMAND SOCKET STUFF ---- */ ++ ++static int ++send_atcmd(blt_dev_t * dev, const char * fmt, ...) ++{ ++ char buf[1024]; ++ va_list ap; ++ int len; ++ ++ va_start(ap, fmt); ++ len = vsnprintf(buf, 1023, fmt, ap); ++ va_end(ap); ++ ++ if (option_verbose) ++ ast_verbose(VERBOSE_PREFIX_1 "[%s] %*s < %s\n", role2str(dev->role), 10, dev->name, buf); ++ ++ write(dev->rd, "\r\n", 2); ++ len = write(dev->rd, buf, len); ++ write(dev->rd, "\r\n", 2); ++ return (len) ? 0 : -1; ++} ++ ++ ++static int ++send_atcmd_ok(blt_dev_t * dev, const char * cmd) ++{ ++ int len; ++ strncpy(dev->last_ok_cmd, cmd, BLT_RDBUFF_MAX - 1); ++ if (option_verbose) ++ ast_verbose(VERBOSE_PREFIX_1 "[%s] %*s < OK\n", role2str(dev->role), 10, dev->name); ++ len = write(dev->rd, "\r\nOK\r\n", 6); ++ return (len) ? 0 : -1; ++} ++ ++static int ++send_atcmd_error(blt_dev_t * dev) ++{ ++ int len; ++ ++ if (option_verbose) ++ ast_verbose(VERBOSE_PREFIX_1 "[%s] %*s < ERROR\n", role2str(dev->role), 10, dev->name); ++ ++// write(dev->rd, "\r\n", 2); ++// len = write(dev->rd, dev->last_ok_cmd, 5); ++ write(dev->rd, "\r\n", 2); ++ len = write(dev->rd, "ERROR", 5); ++ write(dev->rd, "\r\n", 2); ++ ++ return (len) ? 0 : -1; ++} ++ ++ ++/* ---------------------------------- */ ++ ++/* -- Handle negotiation when we're an AG -- */ ++ ++/* Bluetooth Support */ ++ ++static int ++atcmd_brsf_set(blt_dev_t * dev, const char * arg, int len) ++{ ++ ast_log(LOG_DEBUG, "Device Supports: %s\n", arg); ++ dev->brsf = atoi(arg); ++ send_atcmd(dev, "+BRSF: %d", 23); ++ return 0; ++} ++ ++/* Bluetooth Voice Recognition */ ++ ++static int ++atcmd_bvra_set(blt_dev_t * dev, const char * arg, int len) ++{ ++ ast_log(LOG_WARNING, "+BVRA Not Yet Supported\n"); ++ return -1; ++#if 0 ++ // XXX:T: Fix voice recognition somehow! ++ int action = atoi(arg); ++ ast_log(LOG_DEBUG, "Voice Recognition: %s\n", (a) ? "ACTIVATED" : "DEACTIVATED"); ++ if ((action == 0) & (dev->bvra == 1)) { ++ /* Disable it */ ++ dev->bvra = 0; ++ // XXX:T: Shutdown any active bvra channel ++ ast_log(LOG_DEBUG, "Voice Recognition: DISABLED\n"); ++ } else if ((action == 1) && (dev->bvra == 0)) { ++ /* Enable it */ ++ dev->bvra = 1; ++ // XXX:T: Schedule connection to voice recognition extension/application ++ ast_log(LOG_DEBUG, "Voice Recognition: ENABLED\n"); ++ } else { ++ ast_log(LOG_ERROR, "+BVRA out of sync (we think %d, but HS wants %d)\n", dev->bvra, action); ++ return -1; ++ } ++ return 0; ++#endif ++} ++ ++/* Clock */ ++ ++static int ++atcmd_cclk_read(blt_dev_t * dev) ++{ ++ struct tm t, *tp; ++ const time_t ti = time(0); ++ tp = localtime_r(&ti, &t); ++ send_atcmd(dev, "+CCLK: \"%02d/%02d/%02d,%02d:%02d:%02d+%02d\"", ++ (tp->tm_year % 100), (tp->tm_mon + 1), (tp->tm_mday), ++ tp->tm_hour, tp->tm_min, tp->tm_sec, ((tp->tm_gmtoff / 60) / 15)); ++ return 0; ++} ++ ++/* CHUP - Hangup Call */ ++ ++static int ++atcmd_chup_execute(blt_dev_t * dev, const char * data) ++{ ++ if (!dev->owner) { ++ ast_log(LOG_ERROR, "Request to hangup call when none in progress\n"); ++ return -1; ++ } ++ ast_log(LOG_DEBUG, "Hangup Call\n"); ++ ast_queue_control(dev->owner, AST_CONTROL_HANGUP); ++ return 0; ++} ++ ++/* CIND - Call Indicator */ ++ ++static int ++atcmd_cind_read(blt_dev_t * dev) ++{ ++ send_atcmd(dev, "+CIND: 1,0,0"); ++ return 0; ++} ++ ++static int ++atcmd_cind_test(blt_dev_t * dev) ++{ ++ send_atcmd(dev, "+CIND: (\"service\",(0,1)),(\"call\",(0,1)),(\"callsetup\",(0-4))"); ++ return 0; ++} ++ ++/* Set Language */ ++ ++static int ++atcmd_clan_read(blt_dev_t * dev) ++{ ++ send_atcmd(dev, "+CLAN: \"en\""); ++ return 0; ++} ++ ++/* Caller Id Presentation */ ++ ++static int ++atcmd_clip_set(blt_dev_t * dev, const char * arg, int len) ++{ ++ dev->clip = atoi(arg); ++ return 0; ++} ++ ++/* Connected Line Identification Presentation */ ++ ++static int ++atcmd_colp_set(blt_dev_t * dev, const char * arg, int len) ++{ ++ dev->colp = atoi(arg); ++ return 0; ++} ++ ++/* CMER - Mobile Equipment Event Reporting */ ++ ++static int ++atcmd_cmer_set(blt_dev_t * dev, const char * arg, int len) ++{ ++ dev->ready = 1; ++ dev->status = BLT_STATUS_READY; ++ return 0; ++} ++ ++/* PhoneBook Types: ++ * ++ * - FD - SIM Fixed Dialing Phone Book ++ * - ME - ME Phone book ++ * - SM - SIM Phone Book ++ * - DC - ME dialled-calls list ++ * - RC - ME recieved-calls lisr ++ * - MC - ME missed-calls list ++ * - MV - ME Voice Activated Dialing List ++ * - HP - Hierachial Phone Book ++ * - BC - Own Business Card (PIN2 required) ++ * ++ */ ++ ++/* Read Phone Book Entry */ ++ ++static int ++atcmd_cpbr_set(blt_dev_t * dev, const char * arg, int len) ++{ ++ // XXX:T: Fix the phone book! ++ // * Maybe add res_phonebook or something? */ ++ send_atcmd(dev, "+CPBR: %d,\"%s\",128,\"%s\"", atoi(arg), arg, arg); ++ return 0; ++} ++ ++/* Select Phone Book */ ++ ++static int ++atcmd_cpbs_set(blt_dev_t * dev, const char * arg, int len) ++{ ++ // XXX:T: I guess we'll just accept any? ++ return 0; ++} ++ ++static int ++atcmd_cscs_set(blt_dev_t * dev, const char * arg, int len) ++{ ++ // XXX:T: Language ++ return 0; ++} ++ ++static int ++atcmd_eips_set(blt_dev_t * dev, const char * arg, int len) ++{ ++ ast_log(LOG_DEBUG, "Identify Presentation Set: %s=%s\n", ++ (*(arg) == 49) ? "ELIP" : "EOLP", ++ (*(arg+2) == 49) ? "ON" : "OFF"); ++ ++ if (*(arg) == 49) ++ dev->eolp = (*(arg+2) == 49) ? 1 : 0; ++ else ++ dev->elip = (*(arg+2) == 49) ? 1 : 0; ++ ++ return 0; ++} ++ ++/* VGS - Speaker Volume Gain */ ++ ++static int ++atcmd_vgs_set(blt_dev_t * dev, const char * arg, int len) ++{ ++ dev->gain_speaker = atoi(arg); ++ return 0; ++} ++ ++void ++gui_eaid_response(blt_dev_t * dev, char * cmd) ++{ ++ ast_log(LOG_NOTICE, "Submenu displayed.\n"); ++} ++ ++static int ++atcmd_eami_execute(blt_dev_t * dev, const char * data) ++{ ++ char * number = NULL; ++ ++ number = strndup(data, strlen(data)); ++ int menuitem = atoi(number); ++ ++ ast_log(LOG_NOTICE, "Menu Item '%d'.\n", menuitem); ++ ++ dev->cb = gui_eaid_response; ++ ++ if (menuitem == 1) { ++ char command[1024] = ""; ++ const char* c1 = "AT*EAID=8,1,\"Make a SIP call\",\"Number\",\""; ++ const char* c2 = "\""; ++ ++ (void)strncat(command, c1, sizeof(command) - strlen(command) - 1); ++ (void)strncat(command, gui_default_sip_number, sizeof(command) - strlen(command) - 1); ++ (void)strncat(command, c2, sizeof(command) - strlen(command) - 1); ++ ++ //strcat(command, "AT*EAID=8,1,\"Make a SIP call\",\"Number\",\""); ++ //strcat(command, gui_default_sip_number); ++ //strcat(command, "\""); ++ send_atcmd(dev, command); ++ } else if (menuitem == 2) { ++ char command[1024] = ""; ++ const char* c1 = "AT*EAID=11,1,\"Make a SIP call\",\"SIP Address\",100,\""; ++ const char* c2 = "\""; ++ ++ (void)strncat(command, c1, sizeof(command) - strlen(command) - 1); ++ (void)strncat(command, gui_default_sip_address, sizeof(command) - strlen(command) - 1); ++ (void)strncat(command, c2, sizeof(command) - strlen(command) - 1); ++ ++ //strcat(command, "AT*EAID=11,1,\"Make a SIP call\",\"SIP Address\",100,\""); ++ //strcat(command, gui_default_sip_address); ++ //strcat(command, "\""); ++ send_atcmd(dev, command); ++ } else if (menuitem == 0) { ++ dev->cb = gui_easm_response; ++// send_atcmd(dev,"AT*EASM=\"SIP Menu\",1,1,3,\"Call Number\",\"Call Address\",\"More Options\",1"); ++ send_atcmd(dev,"AT*EASM=\"SIP Menu\",1,1,2,\"Call Number\",\"Call Address\",1"); ++ } else { ++ ast_log(LOG_ERROR, "Menu item not implementented.\n"); ++ } ++ return 0; ++} ++ ++static int ++atcmd_eaii_execute(blt_dev_t * dev, const char * data) ++{ ++ int pos = 1, len = 0; ++ char type[128]; ++ char val[128]; ++ const char * start = data; ++ struct sockaddr_in addr; ++ ++ while (*data) { ++ if (*data == ',') { ++ memset(type, 0, 128); ++ strncpy(type, start, len); ++ ++ ast_log(LOG_NOTICE, "Number(8)/Address(11): '%s'.\n", type); ++ ++ pos++; ++ len = 0; ++ data++; ++ start = data; ++ continue; ++ } ++ len++; ++ data++; ++ } ++ ++ memset(val, 0, 128); ++ strncpy(val, start, len); ++ ++ char del[]= "\""; ++ char* address; ++ address = strtok(val, del); ++ int type_int = atoi(type); ++ ++ if (strcmp(address, " 0") == 0) { ++ ast_log(LOG_NOTICE, "Spurious EAII:\n"); ++ ast_log(LOG_NOTICE, data); ++ return 0; ++ } ++ ++ if (type_int == 8) { ++ (void)strncat(address, "@sipgate.de", sizeof(address) - strlen(address) - 1); ++ } ++ ++ ast_log(LOG_NOTICE, "SIP number/address: '%i','%s'.\n", type_int, address); ++ ++ if (type_int == 8 || type_int == 11) { ++ ++ char messagebox[1024] = ""; ++ const char* mb1 = "AT*EAID=1,1,\"Setting up SIP call to "; ++ const char* mb2 = "\",30"; ++ ++ (void)strncat(messagebox, mb1, sizeof(messagebox) - strlen(messagebox) - 1); ++ (void)strncat(messagebox, address, sizeof(messagebox) - strlen(messagebox) - 1); ++ (void)strncat(messagebox, mb2, sizeof(messagebox) - strlen(messagebox) - 1); ++ ++ //strcat(messagebox, "AT*EAID=1,1,\"Setting up SIP call to "); ++ //strcat(messagebox, address); ++ //strcat(messagebox, "\",30"); ++ send_atcmd(dev, messagebox); ++ ++ send_atcmd(dev, "AT*ESKS=2"); ++ send_atcmd(dev, "AT*EKSP"); ++ send_atcmd(dev, "AT*ESKS=0"); ++ ++ //Create manager connection to create call ++ int s = socket(AF_INET,SOCK_STREAM,0); ++ if (s < 0) { ++ ast_log(LOG_ERROR, "Manager connection failed."); ++ ++ dev->cb = ag_cgmi_response; ++ send_atcmd(dev, "AT*EAID=1,1,\"Call failed\""); ++ return -1; ++ } ++ addr.sin_family = AF_INET; ++ addr.sin_port = htons(5038); ++ addr.sin_addr.s_addr = inet_addr("127.0.0.1"); ++ memset(&(addr.sin_zero), '\0', 8); ++ ++ if (connect(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) { ++ ast_log(LOG_ERROR, "Manager connection failed. (2)"); ++ dev->cb = ag_cgmi_response; ++ send_atcmd(dev, "AT*EAID=1,1,\"Call failed\""); ++ return -1; ++ } ++ char* command = "Action: login\r\nUsername: markus\r\nSecret: supAEr\r\n\r\n"; ++ if (write(s,command,strlen(command)) < 0) { ++ ast_log(LOG_ERROR, "Manager connection failed. (3)"); ++ dev->cb = ag_cgmi_response; ++ send_atcmd(dev, "AT*EAID=1,1,\"Call failed\""); ++ return -1; ++ } ++ ++ char command3[1024] = ""; ++ const char* action = "Action: Originate\r\nChannel: SIP/"; ++ const char* action2 = "\r\nExten: 1235\r\nPriority: 1\r\nContext: sipgate.de\r\n\r\nAction: logoff\r\n\r\n"; ++ ++ (void)strncat(command3, action, sizeof(command3) - strlen(command3) - 1); ++ (void)strncat(command3, address, sizeof(command3) - strlen(command3) - 1); ++ (void)strncat(command3, action2, sizeof(command3) - strlen(command3) - 1); ++ ++ //strcat(command3, "Action: Originate\r\nChannel: SIP/"); ++ //strcat(command3, address); ++ //strcat(command3, "\r\nExten: 1235\r\nPriority: 1\r\nContext: sipgate.de\r\n\r\n"); ++ ast_log(LOG_NOTICE, command3); ++ ++ if (write(s,command3,strlen(command3)) < 0) { ++ ast_log(LOG_ERROR, "Manager connection failed. (5)"); ++ return -1; ++ } ++ } ++ //dev->cb = ag_cgmi_response; ++ return 0; ++} ++ ++/* Dial */ ++static int ++atcmd_dial_execute(blt_dev_t * dev, const char * data) ++{ ++ char * number = NULL; ++ ++ /* Make sure there is a ';' at the end of the line */ ++ if (*(data + (strlen(data) - 1)) != ';') { ++ ast_log(LOG_WARNING, "Can't dial non-voice right now: %s\n", data); ++ return -1; ++ } ++ ++ number = strndup(data, strlen(data) - 1); ++ ast_log(LOG_NOTICE, "Dial: [%s]\n", number); ++ ++ send_atcmd(dev, "+CIEV: 2,1"); ++ send_atcmd(dev, "+CIEV: 3,0"); ++ ++ sco_start(dev, -1); ++ ++ if (blt_new(dev, AST_STATE_UP, dev->context, number) == NULL) { ++ sco_stop(dev); ++ } ++ ++ free(number); ++ ++ return 0; ++} ++ ++static int atcmd_bldn_execute(blt_dev_t * dev, const char *data) ++{ ++ return atcmd_dial_execute(dev, "bldn;"); ++} ++ ++/* Answer */ ++ ++static int ++atcmd_answer_execute(blt_dev_t * dev, const char * data) ++{ ++ ++ if (!dev->ringing || !dev->owner) { ++ ast_log(LOG_WARNING, "Can't answer non existant call\n"); ++ return -1; ++ } ++ ++ dev->ringing = 0; ++ ++ if (dev->ring_timer >= 0) ++ ast_sched_del(sched, dev->ring_timer); ++ ++ dev->ring_timer = -1; ++ ++ send_atcmd(dev, "+CIEV: 2,1"); ++ send_atcmd(dev, "+CIEV: 3,0"); ++ ++ return answer(dev); ++} ++ ++static int ++ag_unsol_ciev(blt_dev_t * dev, const char * data) ++{ ++ const char * orig = data; ++ int indicator; ++ int status; ++ ++ while (*(data) && *(data) == ' ') ++ data++; ++ ++ if (*(data) == 0) { ++ ast_log(LOG_WARNING, "Invalid value[1] for '+CIEV:%s'\n", orig); ++ return -1; ++ } ++ ++ indicator = *(data++) - 48; ++ ++ if (*(data++) != ',') { ++ ast_log(LOG_WARNING, "Invalid value[2] for '+CIEV:%s'\n", orig); ++ return -1; ++ } ++ ++ if (*(data) == 0) { ++ ast_log(LOG_WARNING, "Invalid value[3] for '+CIEV:%s'\n", orig); ++ return -1; ++ } ++ ++ status = *(data) - 48; ++ ++ set_cind(dev, indicator, status); ++ ++ return 0; ++} ++ ++static int ++ag_unsol_cind(blt_dev_t * dev, const char * data) ++{ ++ ++ while (*(data) && *(data) == ' ') ++ data++; ++ ++ ++ if (dev->cind == 0) ++ { ++ int pos = 1; ++ char name[1024]; ++ ++ while ((data = parse_cind(data, name, 1023)) != NULL) { ++ ast_log(LOG_DEBUG, "CIND: %d=%s\n", pos, name); ++ if (strcmp(name, "call") == 0) ++ dev->call_pos = pos; ++ else if (strcmp(name, "service") == 0) ++ dev->service_pos = pos; ++ else if (strcmp(name, "call_setup") == 0 || strcmp(name, "callsetup") == 0) ++ dev->callsetup_pos = pos; ++ pos++; ++ } ++ ++ ast_log(LOG_DEBUG, "CIND: %d=%s\n", pos, name); ++ ++ } else { ++ ++ int pos = 1, len = 0; ++ char val[128]; ++ const char * start = data; ++ ++ while (*data) { ++ if (*data == ',') { ++ memset(val, 0, 128); ++ strncpy(val, start, len); ++ set_cind(dev, pos, atoi(val)); ++ pos++; ++ len = 0; ++ data++; ++ start = data; ++ continue; ++ } ++ len++; ++ data++; ++ } ++ ++ memset(val, 0, 128); ++ strncpy(val, start, len); ++ ast_log(LOG_DEBUG, "CIND IND %d set to %d [%s]\n", pos, atoi(val), val); ++ ++ ++ } ++ ++ return 0; ++} ++ ++/* ++ * handle an incoming call ++ */ ++static int ++ag_unsol_clip(blt_dev_t * dev, const char * data) ++{ ++ const char * orig = data; ++ char name[256]; ++ char number[64]; ++ int type; ++ ++ while (*(data) && *(data) == ' ') ++ data++; ++ ++ if (*(data) == 0) { ++ ast_log(LOG_WARNING, "Invalid value[1] for '+CLIP:%s'\n", orig); ++ return -1; ++ } ++ ++ parse_clip(data, number, sizeof(number)-1, name, sizeof(name)-1, &type); ++ ast_log(LOG_NOTICE, "Parsed '+CLIP: %s' number='%s' type='%d' name='%s'\n", data, number, type, name); ++ ++ blt_new(dev, AST_STATE_RING, dev->context, "s"); ++ ++ return 0; ++} ++ ++ ++ ++static blt_atcb_t ++atcmd_list[] = ++{ ++ { "A", NULL, NULL, atcmd_answer_execute, NULL, NULL }, ++ { "D", NULL, NULL, atcmd_dial_execute, NULL, NULL }, ++ { "+BRSF", atcmd_brsf_set, NULL, NULL, NULL, NULL }, ++ { "+BVRA", atcmd_bvra_set, NULL, NULL, NULL, NULL }, ++ { "+CCLK", NULL, atcmd_cclk_read, NULL, NULL, NULL }, ++ { "+CHUP", NULL, NULL, atcmd_chup_execute, NULL, NULL }, ++ { "+CIEV", NULL, NULL, NULL, NULL, ag_unsol_ciev }, ++ { "+CIND", NULL, atcmd_cind_read, NULL, atcmd_cind_test, ag_unsol_cind }, ++ { "*EAMI", NULL, NULL, atcmd_eami_execute, NULL, NULL}, ++ { "*EAII", NULL, NULL, atcmd_eaii_execute, NULL, NULL}, ++ ++ { "+CLAN", NULL, atcmd_clan_read, NULL, NULL, NULL }, ++ { "+CLIP", atcmd_clip_set, NULL, NULL, NULL, ag_unsol_clip }, ++ { "+COLP", atcmd_colp_set, NULL, NULL, NULL, NULL }, ++ { "+CMER", atcmd_cmer_set, NULL, NULL, NULL, NULL }, ++ { "+CPBR", atcmd_cpbr_set, NULL, NULL, NULL, NULL }, ++ { "+CPBS", atcmd_cpbs_set, NULL, NULL, NULL, NULL }, ++ { "+CSCS", atcmd_cscs_set, NULL, NULL, NULL, NULL }, ++ { "*EIPS", atcmd_eips_set, NULL, NULL, NULL, NULL }, ++ { "+VGS", atcmd_vgs_set, NULL, NULL, NULL, NULL }, ++ { "+BLDN", NULL, NULL, atcmd_bldn_execute, NULL, NULL }, ++}; ++ ++#define ATCMD_LIST_LEN (sizeof(atcmd_list) / sizeof(blt_atcb_t)) ++ ++/* ---------------------------------- */ ++ ++/* -- Handle negotiation when we're a HS -- */ ++ ++void ++ag_unknown_response(blt_dev_t * dev, char * cmd) ++{ ++ ast_log(LOG_DEBUG, "Got UNKN response: %s\n", cmd); ++ ++ // DELAYED ++ // NO CARRIER ++ ++} ++ ++void ++gui_easm_response(blt_dev_t * dev, char * cmd) ++{ ++ ast_log(LOG_NOTICE, "Menu displayed.\n"); ++} ++ ++void ++ag_cgmi_response(blt_dev_t * dev, char * cmd) ++{ ++ // CGMM - Phone Model ++ // CGMR - Phone Revision ++ // CGSN - IMEI ++ // AT* ++ // VTS - send tone ++ // CREG ++ // CBC - BATTERY ++ // CSQ - SIGANL ++ // CSMS - SMS STUFFS ++ // CMGL ++ // CMGR ++ // CMGS ++ // CSCA - sms CENTER NUMBER ++ // CNMI - SMS INDICATION ++ // ast_log(LOG_DEBUG, "Manufacturer: %s\n", cmd); ++ ++ if (dev->role == BLT_ROLE_GUI) { ++ ast_log(LOG_NOTICE, "Displaying Menu.\n"); ++ dev->cb = gui_easm_response; ++// send_atcmd(dev,"AT*EASM=\"SIP Menu\",1,1,3,\"Call Number\",\"Call Address\",\"More Options\",1"); ++ send_atcmd(dev,"AT*EASM=\"SIP Menu\",1,1,2,\"Call Number\",\"Call Address\",1"); ++ } else { ++ dev->cb = ag_unknown_response; ++ } ++} ++ ++void ++ag_cgmi_valid_response(blt_dev_t * dev, char * cmd) ++{ ++ // send_atcmd(dev, "AT+WS46?"); ++ // send_atcmd(dev, "AT+CRC=1"); ++ // send_atcmd(dev, "AT+CNUM"); ++ ++ if (strcmp(cmd, "OK") == 0) { ++ send_atcmd(dev, "AT+CGMI"); ++ dev->cb = ag_cgmi_response; ++ } else { ++ dev->cb = ag_unknown_response; ++ } ++} ++ ++void ++ag_clip_response(blt_dev_t * dev, char * cmd) ++{ ++ send_atcmd(dev, "AT+CGMI=?"); ++ dev->cb = ag_cgmi_valid_response; ++} ++ ++void ++ag_cmer_response(blt_dev_t * dev, char * cmd) ++{ ++ dev->cb = ag_clip_response; ++ dev->ready = 1; ++ dev->status = BLT_STATUS_READY; ++ send_atcmd(dev, "AT+CLIP=1"); ++} ++ ++void ++ag_cind_status_response(blt_dev_t * dev, char * cmd) ++{ ++ // XXX:T: Handle response. ++ dev->cb = ag_cmer_response; ++ send_atcmd(dev, "AT+CMER=3,0,0,1"); ++ // Initiliase SCO link! ++} ++ ++void ++ag_cind_response(blt_dev_t * dev, char * cmd) ++{ ++ dev->cb = ag_cind_status_response; ++ dev->cind = 1; ++ send_atcmd(dev, "AT+CIND?"); ++} ++ ++void ++ag_brsf_response(blt_dev_t * dev, char * cmd) ++{ ++ dev->cb = ag_cind_response; ++ ast_log(LOG_DEBUG, "Bluetooth features: %s\n", cmd); ++ dev->cind = 0; ++ send_atcmd(dev, "AT+CIND=?"); ++} ++ ++/* ---------------------------------- */ ++ ++static int ++sdp_register(sdp_session_t * session) ++{ ++ // XXX:T: Fix this horrible function so it makes some sense and is extensible! ++ sdp_list_t *svclass_id, *pfseq, *apseq, *root; ++ uuid_t root_uuid, svclass_uuid, ga_svclass_uuid, l2cap_uuid, rfcomm_uuid; ++ sdp_profile_desc_t profile; ++ sdp_list_t *aproto, *proto[2]; ++ sdp_record_t record; ++ uint8_t u8 = rfcomm_channel_ag; ++ uint8_t u8_hs = rfcomm_channel_hs; ++ sdp_data_t *channel; ++ int ret = 0; ++ ++ memset((void *)&record, 0, sizeof(sdp_record_t)); ++ record.handle = 0xffffffff; ++ sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP); ++ root = sdp_list_append(0, &root_uuid); ++ sdp_set_browse_groups(&record, root); ++ ++ // Register as an AG ++ ++ sdp_uuid16_create(&svclass_uuid, HANDSFREE_AUDIO_GW_SVCLASS_ID); ++ svclass_id = sdp_list_append(0, &svclass_uuid); ++ sdp_uuid16_create(&ga_svclass_uuid, GENERIC_AUDIO_SVCLASS_ID); ++ svclass_id = sdp_list_append(svclass_id, &ga_svclass_uuid); ++ sdp_set_service_classes(&record, svclass_id); ++ sdp_uuid16_create(&profile.uuid, 0x111f); ++ profile.version = 0x0100; ++ pfseq = sdp_list_append(0, &profile); ++ ++ sdp_set_profile_descs(&record, pfseq); ++ ++ sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID); ++ proto[0] = sdp_list_append(0, &l2cap_uuid); ++ apseq = sdp_list_append(0, proto[0]); ++ ++ sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID); ++ proto[1] = sdp_list_append(0, &rfcomm_uuid); ++ channel = sdp_data_alloc(SDP_UINT8, &u8); ++ proto[1] = sdp_list_append(proto[1], channel); ++ apseq = sdp_list_append(apseq, proto[1]); ++ ++ aproto = sdp_list_append(0, apseq); ++ sdp_set_access_protos(&record, aproto); ++ ++ sdp_set_info_attr(&record, "Voice Gateway", 0, 0); ++ ++ if (sdp_record_register(session, &record, SDP_RECORD_PERSIST) < 0) { ++ ast_log(LOG_ERROR, "Service Record registration failed\n"); ++ ret = -1; ++ goto end; ++ } ++ ++ sdp_record_ag = record.handle; ++ sdp_record_gui = record.handle; ++ ++ ast_log(LOG_NOTICE, "HeadsetAudioGateway service registered\n"); ++ ++ sdp_data_free(channel); ++ sdp_list_free(proto[0], 0); ++ sdp_list_free(proto[1], 0); ++ sdp_list_free(apseq, 0); ++ sdp_list_free(aproto, 0); ++ ++ // ------------- ++ ++ memset((void *)&record, 0, sizeof(sdp_record_t)); ++ record.handle = 0xffffffff; ++ sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP); ++ root = sdp_list_append(0, &root_uuid); ++ sdp_set_browse_groups(&record, root); ++ ++ // Register as an HS ++ ++ sdp_uuid16_create(&svclass_uuid, HANDSFREE_AUDIO_GW_SVCLASS_ID); ++ svclass_id = sdp_list_append(0, &svclass_uuid); ++ sdp_uuid16_create(&ga_svclass_uuid, GENERIC_AUDIO_SVCLASS_ID); ++ svclass_id = sdp_list_append(svclass_id, &ga_svclass_uuid); ++ sdp_set_service_classes(&record, svclass_id); ++ sdp_uuid16_create(&profile.uuid, 0x111e); ++ profile.version = 0x0100; ++ pfseq = sdp_list_append(0, &profile); ++ sdp_set_profile_descs(&record, pfseq); ++ ++ sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID); ++ proto[0] = sdp_list_append(0, &l2cap_uuid); ++ apseq = sdp_list_append(0, proto[0]); ++ ++ sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID); ++ proto[1] = sdp_list_append(0, &rfcomm_uuid); ++ channel = sdp_data_alloc(SDP_UINT8, &u8_hs); ++ proto[1] = sdp_list_append(proto[1], channel); ++ apseq = sdp_list_append(apseq, proto[1]); ++ ++ aproto = sdp_list_append(0, apseq); ++ sdp_set_access_protos(&record, aproto); ++ sdp_set_info_attr(&record, "Voice Gateway", 0, 0); ++ ++ if (sdp_record_register(session, &record, SDP_RECORD_PERSIST) < 0) { ++ ast_log(LOG_ERROR, "Service Record registration failed\n"); ++ ret = -1; ++ goto end; ++ } ++ ++ sdp_record_hs = record.handle; ++ ++ ast_log(LOG_NOTICE, "HeadsetAudioGateway service registered\n"); ++ ++end: ++ sdp_data_free(channel); ++ sdp_list_free(proto[0], 0); ++ sdp_list_free(proto[1], 0); ++ sdp_list_free(apseq, 0); ++ sdp_list_free(aproto, 0); ++ ++ return ret; ++} ++ ++static int ++rfcomm_listen(bdaddr_t * bdaddr, int channel) ++{ ++ ++ int sock = -1; ++ struct sockaddr_rc loc_addr; ++ int on = 1; ++ ++ if ((sock = socket(PF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM)) < 0) { ++ ast_log(LOG_ERROR, "Can't create socket: %s (errno: %d)\n", strerror(errno), errno); ++ return -1; ++ } ++ ++ loc_addr.rc_family = AF_BLUETOOTH; ++ ++ /* Local Interface Address */ ++ bacpy(&loc_addr.rc_bdaddr, bdaddr); ++ ++ /* Channel */ ++ loc_addr.rc_channel = channel; ++ ++ if (bind(sock, (struct sockaddr *)&loc_addr, sizeof(loc_addr)) < 0) { ++ ast_log(LOG_ERROR, "Can't bind socket: %s (errno: %d)\n", strerror(errno), errno); ++ close(sock); ++ return -1; ++ } ++ ++ if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) == -1) { ++ ast_log(LOG_ERROR, "Set socket SO_REUSEADDR option on failed: errno %d, %s", errno, strerror(errno)); ++ close(sock); ++ return -1; ++ } ++ ++ if (fcntl(sock, F_SETFL, O_RDWR|O_NONBLOCK) != 0) ++ ast_log(LOG_ERROR, "Can't set RFCOMM socket to NBIO\n"); ++ ++ if (listen(sock, 10) < 0) { ++ ast_log(LOG_ERROR,"Can not listen on the socket. %s(%d)\n", strerror(errno), errno); ++ close(sock); ++ return -1; ++ } ++ ++ ast_log(LOG_NOTICE, "Listening for RFCOMM channel %d connections on FD %d\n", channel, sock); ++ ++ return sock; ++} ++ ++ ++static int ++sco_listen(bdaddr_t * bdaddr) ++{ ++ int sock = -1; ++ int on = 1; ++ struct sockaddr_sco loc_addr; ++ ++ memset(&loc_addr, 0, sizeof(loc_addr)); ++ ++ if ((sock = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_SCO)) < 0) { ++ ast_log(LOG_ERROR, "Can't create SCO socket: %s (errno: %d)\n", strerror(errno), errno); ++ return -1; ++ } ++ ++ loc_addr.sco_family = AF_BLUETOOTH; ++ bacpy(&loc_addr.sco_bdaddr, BDADDR_ANY); ++ ++ if (bind(sock, (struct sockaddr *)&loc_addr, sizeof(loc_addr)) < 0) { ++ ast_log(LOG_ERROR, "Can't bind SCO socket: %s (errno: %d)\n", strerror(errno), errno); ++ close(sock); ++ return -1; ++ } ++ ++ if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) == -1) { ++ ast_log(LOG_ERROR, "Set SCO socket SO_REUSEADDR option on failed: errno %d, %s", errno, strerror(errno)); ++ close(sock); ++ return -1; ++ } ++ ++ if (fcntl(sock, F_SETFL, O_RDWR|O_NONBLOCK) != 0) ++ ast_log(LOG_ERROR, "Can't set SCO socket to NBIO\n"); ++ ++ if (listen(sock, 10) < 0) { ++ ast_log(LOG_ERROR,"Can not listen on SCO socket: %s(%d)\n", strerror(errno), errno); ++ close(sock); ++ return -1; ++ } ++ ++ ast_log(LOG_NOTICE, "Listening for SCO connections on FD %d\n", sock); ++ ++ return sock; ++} ++ ++static int ++rfcomm_connect(bdaddr_t * src, bdaddr_t * dst, int channel, int nbio) ++{ ++ struct sockaddr_rc addr; ++ int s; ++ ++ if ((s = socket(PF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM)) < 0) { ++ return -1; ++ } ++ ++ memset(&addr, 0, sizeof(addr)); ++ addr.rc_family = AF_BLUETOOTH; ++ bacpy(&addr.rc_bdaddr, src); ++ addr.rc_channel = 0; ++ ++ if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) { ++ close(s); ++ return -1; ++ } ++ ++ memset(&addr, 0, sizeof(addr)); ++ addr.rc_family = AF_BLUETOOTH; ++ bacpy(&addr.rc_bdaddr, dst); ++ addr.rc_channel = channel; ++ ++ if (nbio) { ++ if (fcntl(s, F_SETFL, O_RDWR|O_NONBLOCK) != 0) ++ ast_log(LOG_ERROR, "Can't set RFCOMM socket to NBIO\n"); ++ } ++ ++ if (connect(s, (struct sockaddr *)&addr, sizeof(addr)) < 0 && (nbio != 1 || (errno != EAGAIN))) { ++ close(s); ++ return -1; ++ } ++ ++ return s; ++} ++ ++/* Must be called with dev->lock held */ ++ ++static int ++sco_connect(blt_dev_t * dev) ++{ ++ struct sockaddr_sco addr; ++ // struct sco_conninfo conn; ++ // struct sco_options opts; ++ // int size; ++ // bdaddr_t * src = &local_bdaddr; ++ ++ int s; ++ bdaddr_t * dst = &(dev->bdaddr); ++ ++ if (dev->sco != -1) { ++ ast_log(LOG_ERROR, "SCO fd already open.\n"); ++ return -1; ++ } ++ ++ if ((s = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_SCO)) < 0) { ++ ast_log(LOG_ERROR, "Can't create SCO socket(): %s\n", strerror(errno)); ++ return -1; ++ } ++ ++ memset(&addr, 0, sizeof(addr)); ++ ++ addr.sco_family = AF_BLUETOOTH; ++ bacpy(&addr.sco_bdaddr, BDADDR_ANY); ++ ++ if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) { ++ ast_log(LOG_ERROR, "Can't bind() SCO socket: %s\n", strerror(errno)); ++ close(s); ++ return -1; ++ } ++ ++ memset(&addr, 0, sizeof(addr)); ++ addr.sco_family = AF_BLUETOOTH; ++ bacpy(&addr.sco_bdaddr, dst); ++ ++ if (fcntl(s, F_SETFL, O_RDWR|O_NONBLOCK) != 0) ++ ast_log(LOG_ERROR, "Can't set SCO socket to NBIO\n"); ++ ++ if ((connect(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) && (errno != EAGAIN)) { ++ ast_log(LOG_ERROR, "Can't connect() SCO socket: %s (errno %d)\n", strerror(errno), errno); ++ close(s); ++ return -1; ++ } ++ ++ //size = sizeof(conn); ++ ++ ++/* XXX:T: HERE, fix getting SCO conninfo. ++ ++ if (getsockopt(s, SOL_SCO, SCO_CONNINFO, &conn, &size) < 0) { ++ ast_log(LOG_ERROR, "Can't getsockopt SCO_CONNINFO on SCO socket: %s\n", strerror(errno)); ++ close(s); ++ return -1; ++ } ++ ++ size = sizeof(opts); ++ ++ if (getsockopt(s, SOL_SCO, SCO_OPTIONS, &opts, &size) < 0) { ++ ast_log(LOG_ERROR, "Can't getsockopt SCO_OPTIONS on SCO socket: %s\n", strerror(errno)); ++ close(s); ++ return -1; ++ } ++ ++ dev->sco_handle = conn.hci_handle; ++ dev->sco_mtu = opts.mtu; ++ ++*/ ++ ++ ast_log(LOG_DEBUG, "SCO: %d\n", s); ++ ++ dev->sco = s; ++ ++ return 0; ++} ++ ++ ++/* ---------------------------------- */ ++ ++/* Non blocking (async) outgoing bluetooth connection */ ++ ++static int ++try_connect(blt_dev_t * dev) ++{ ++ int fd; ++ ast_mutex_lock(&(dev->lock)); ++ ++ if (dev->status != BLT_STATUS_CONNECTING && dev->status != BLT_STATUS_DOWN) { ++ ast_mutex_unlock(&(dev->lock)); ++ return 0; ++ } ++ ++ if (dev->rd != -1) { ++ ++ int ret; ++ struct pollfd pfd; ++ ++ if (dev->status != BLT_STATUS_CONNECTING) { ++ ast_mutex_unlock(&(dev->lock)); ++ dev->outgoing_id = -1; ++ return 0; ++ } ++ ++ // ret = connect(dev->rd, (struct sockaddr *)&(dev->addr), sizeof(struct sockaddr_rc)); // ++ ++ pfd.fd = dev->rd; ++ pfd.events = POLLIN | POLLOUT; ++ ++ ret = poll(&pfd, 1, 0); ++ ++ if (ret == -1) { ++ close(dev->rd); ++ dev->rd = -1; ++ dev->status = BLT_STATUS_DOWN; ++ dev->outgoing_id = ast_sched_add(sched, 10000, AST_SCHED_CB(try_connect), dev); ++ ast_mutex_unlock(&(dev->lock)); ++ return 0; ++ } ++ ++ if (ret > 0) { ++ ++ int len = sizeof(ret); ++ getsockopt(dev->rd, SOL_SOCKET, SO_ERROR, &ret, &len); ++ ++ if (ret == 0) { ++ ++ ast_log(LOG_NOTICE, "Initialised bluetooth link to device %s\n", dev->name); ++ ++#if 0 ++ { ++ struct hci_conn_info_req * cr; ++ int dd; ++ char name[248]; ++ ++ cr = malloc(sizeof(*cr) + sizeof(struct hci_conn_info)); ++ dd = hci_open_dev(hcidev_id); ++ cr->type = ACL_LINK; ++ bacpy(&cr->bdaddr, &(dev->bdaddr)); ++ ++ if (ioctl(dd, HCIGETCONNINFO, (unsigned long)cr) < 0) { ++ ast_log(LOG_ERROR, "Failed to get connection info: %s\n", strerror(errno)); ++ } else { ++ ast_log(LOG_DEBUG, "HCI Handle: %d\n", cr->conn_info->handle); ++ } ++ ++ if (hci_read_remote_name(dd, &(dev->bdaddr), sizeof(name), name, 25000) == 0) ++ ast_log(LOG_DEBUG, "Remote Name: %s\n", name); ++ free(cr); ++ } ++#endif ++ ++ dev->status = BLT_STATUS_NEGOTIATING; ++ ++ /* If this device is an AG/GUI, we initiate the negotiation. */ ++ ++ if (dev->role == BLT_ROLE_AG || ++ dev->role == BLT_ROLE_GUI) { ++ dev->cb = ag_brsf_response; ++ send_atcmd(dev, "AT+BRSF=23"); ++ } ++ ++ dev->outgoing_id = -1; ++ ast_mutex_unlock(&(dev->lock)); ++ return 0; ++ ++ } else { ++ ++ if (ret != EHOSTDOWN) ++ ast_log(LOG_NOTICE, "Connect to device %s failed: %s (errno %d)\n", dev->name, strerror(ret), ret); ++ ++ close(dev->rd); ++ dev->rd = -1; ++ dev->status = BLT_STATUS_DOWN; ++ dev->outgoing_id = ast_sched_add(sched, (ret == EHOSTDOWN) ? 10000 : 2500, AST_SCHED_CB(try_connect), dev); ++ ast_mutex_unlock(&(dev->lock)); ++ return 0; ++ ++ } ++ ++ } ++ ++ dev->outgoing_id = ast_sched_add(sched, 100, AST_SCHED_CB(try_connect), dev); ++ ast_mutex_unlock(&(dev->lock)); ++ return 0; ++ } ++ ++ ast_log(LOG_NOTICE, "RFCOMM connect start.\n"); ++ fd = rfcomm_connect(&local_bdaddr, &(dev->bdaddr), dev->channel, 1); ++ ast_log(LOG_NOTICE, "RFCOMM connect done.\n"); ++ ++ if (fd == -1) { ++ ast_log(LOG_WARNING, "NBIO connect() to %s returned %d: %s\n", dev->name, errno, strerror(errno)); ++ dev->outgoing_id = ast_sched_add(sched, 5000, AST_SCHED_CB(try_connect), dev); ++ ast_mutex_unlock(&(dev->lock)); ++ return 0; ++ } ++ ++ dev->rd = fd; ++ dev->status = BLT_STATUS_CONNECTING; ++ dev->outgoing_id = ast_sched_add(sched, 100, AST_SCHED_CB(try_connect), dev); ++ ast_mutex_unlock(&(dev->lock)); ++ return 0; ++} ++ ++ ++/* Called whenever a new command is received while we're the AG */ ++ ++ ++static int ++process_rfcomm_cmd(blt_dev_t * dev, char * cmd) ++{ ++ int i; ++ char * fullcmd = cmd; ++ ++ if (option_verbose) ++ ast_verbose(VERBOSE_PREFIX_1 "[%s] %*s > %s\n", role2str(dev->role), 10, dev->name, cmd); ++ ++ /* Read the 'AT' from the start of the string */ ++ if (strncmp(cmd, "AT", 2)) { ++ ast_log(LOG_WARNING, "Unknown command without 'AT': %s\n", cmd); ++ send_atcmd_error(dev); ++ return 0; ++ } ++ ++ cmd += 2; ++ ++ // Don't forget 'AT' on its own is OK. ++ ++ if (strlen(cmd) == 0) { ++ send_atcmd_ok(dev, fullcmd); ++ return 0; ++ } ++ ++ for (i = 0 ; i < ATCMD_LIST_LEN ; i++) { ++ if (strncmp(atcmd_list[i].str, cmd, strlen(atcmd_list[i].str)) == 0) { ++ char * pos = (cmd + strlen(atcmd_list[i].str)); ++ if ((strncmp(pos, "=?", 2) == 0) && (strlen(pos) == 2)) { ++ /* TEST command */ ++ if (atcmd_list[i].test) { ++ if (atcmd_list[i].test(dev) == 0) ++ send_atcmd_ok(dev, fullcmd); ++ else ++ send_atcmd_error(dev); ++ } else { ++ send_atcmd_ok(dev, fullcmd); ++ } ++ } else if ((strncmp(pos, "?", 1) == 0) && (strlen(pos) == 1)) { ++ /* READ command */ ++ if (atcmd_list[i].read) { ++ if (atcmd_list[i].read(dev) == 0) ++ send_atcmd_ok(dev, fullcmd); ++ else ++ send_atcmd_error(dev); ++ } else { ++ ast_log(LOG_WARNING, "AT Command: '%s' missing READ function\n", fullcmd); ++ send_atcmd_error(dev); ++ } ++ } else if (strncmp(pos, "=", 1) == 0) { ++ /* SET command */ ++ if (atcmd_list[i].set) { ++ if (atcmd_list[i].set(dev, (pos + 1), (*(pos + 1)) ? strlen(pos + 1) : 0) == 0) ++ send_atcmd_ok(dev, fullcmd); ++ else ++ send_atcmd_error(dev); ++ } else { ++ ast_log(LOG_WARNING, "AT Command: '%s' missing SET function\n", fullcmd); ++ send_atcmd_error(dev); ++ } ++ } else { ++ /* EXECUTE command */ ++ if (atcmd_list[i].execute) { ++ if (atcmd_list[i].execute(dev, cmd + strlen(atcmd_list[i].str)) == 0) ++ send_atcmd_ok(dev, fullcmd); ++ else ++ send_atcmd_error(dev); ++ } else { ++ ast_log(LOG_WARNING, "AT Command: '%s' missing EXECUTE function\n", fullcmd); ++ send_atcmd_error(dev); ++ } ++ } ++ return 0; ++ } ++ } ++ ++ ast_log(LOG_NOTICE, "Unknown AT Command: '%s' (%s)\n", fullcmd, cmd); ++ send_atcmd_error(dev); ++ ++ return 0; ++} ++ ++/* Called when a socket is incoming */ ++ ++static void ++handle_incoming(int fd, blt_role_t role) ++{ ++ blt_dev_t * dev; ++ struct sockaddr_rc addr; ++ int len = sizeof(addr); ++ ++ // Got a new incoming socket. ++ ast_log(LOG_DEBUG, "Incoming RFCOMM socket\n"); ++ ++ ast_mutex_lock(&iface_lock); ++ ++ fd = accept(fd, (struct sockaddr*)&addr, &len); ++ ++ dev = iface_head; ++ while (dev) { ++ if (bacmp(&(dev->bdaddr), &addr.rc_bdaddr) == 0) { ++ ast_log(LOG_DEBUG, "Connect from %s\n", dev->name); ++ ast_mutex_lock(&(dev->lock)); ++ /* Kill any outstanding connect attempt. */ ++ if (dev->outgoing_id > -1) { ++ ast_sched_del(sched, dev->outgoing_id); ++ dev->outgoing_id = -1; ++ } ++ ++ rd_close(dev, 0, 0); ++ ++ dev->status = BLT_STATUS_NEGOTIATING; ++ dev->rd = fd; ++ ++ if (dev->role == BLT_ROLE_AG || ++ dev->role == BLT_ROLE_GUI) { ++ dev->cb = ag_brsf_response; ++ send_atcmd(dev, "AT+BRSF=23"); ++ } ++ ast_mutex_unlock(&(dev->lock)); ++ break; ++ } ++ dev = dev->next; ++ } ++ ++ if (dev == NULL) { ++ ast_log(LOG_WARNING, "Connect from unknown device\n"); ++ close(fd); ++ } ++ ast_mutex_unlock(&iface_lock); ++ ++ return; ++} ++ ++static void ++handle_incoming_sco(int master) ++{ ++ ++ blt_dev_t * dev; ++ struct sockaddr_sco addr; ++ struct sco_conninfo conn; ++ struct sco_options opts; ++ int len = sizeof(addr); ++ int fd; ++ ++ ast_log(LOG_DEBUG, "Incoming SCO socket\n"); ++ ++ fd = accept(master, (struct sockaddr*)&addr, &len); ++ ++ if (fcntl(fd, F_SETFL, O_RDWR|O_NONBLOCK) != 0) { ++ ast_log(LOG_ERROR, "Can't set SCO socket to NBIO\n"); ++ close(fd); ++ return; ++ } ++ ++ len = sizeof(conn); ++ ++ if (getsockopt(fd, SOL_SCO, SCO_CONNINFO, &conn, &len) < 0) { ++ ast_log(LOG_ERROR, "Can't getsockopt SCO_CONNINFO on SCO socket: %s\n", strerror(errno)); ++ close(fd); ++ return; ++ } ++ ++ len = sizeof(opts); ++ ++ if (getsockopt(fd, SOL_SCO, SCO_OPTIONS, &opts, &len) < 0) { ++ ast_log(LOG_ERROR, "Can't getsockopt SCO_OPTIONS on SCO socket: %s\n", strerror(errno)); ++ close(fd); ++ return; ++ } ++ ++ ast_mutex_lock(&iface_lock); ++ dev = iface_head; ++ while (dev) { ++ if (bacmp(&(dev->bdaddr), &addr.sco_bdaddr) == 0) { ++ ast_log(LOG_DEBUG, "SCO Connect from %s\n", dev->name); ++ ast_mutex_lock(&(dev->lock)); ++ if (dev->sco_running != -1) { ++ ast_log(LOG_ERROR, "Incoming SCO socket, but SCO thread already running.\n"); ++ } else { ++ sco_start(dev, fd); ++ } ++ ast_mutex_unlock(&(dev->lock)); ++ break; ++ } ++ dev = dev->next; ++ } ++ ++ ast_mutex_unlock(&iface_lock); ++ ++ if (dev == NULL) { ++ ast_log(LOG_WARNING, "SCO Connect from unknown device\n"); ++ close(fd); ++ } else { ++ // XXX:T: We need to handle the fact we might have an outgoing connection attempt in progress. ++ ast_log(LOG_DEBUG, "SCO: %d, HCIHandle=%d, MUT=%d\n", fd, conn.hci_handle, opts.mtu); ++ } ++ ++ ++ ++ return; ++} ++ ++/* Called when there is data waiting on a socket */ ++ ++static int ++handle_rd_data(blt_dev_t * dev) ++{ ++ char c; ++ int ret; ++ ++ while ((ret = read(dev->rd, &c, 1)) == 1) { ++ ++ // log_buf[i++] = c; ++ ++ if (dev->role == BLT_ROLE_HS) { ++ ++ if (c == '\r') { ++ ret = process_rfcomm_cmd(dev, dev->rd_buff); ++ dev->rd_buff_pos = 0; ++ memset(dev->rd_buff, 0, BLT_RDBUFF_MAX); ++ return ret; ++ } ++ ++ if (dev->rd_buff_pos >= BLT_RDBUFF_MAX) ++ return 0; ++ ++ dev->rd_buff[dev->rd_buff_pos++] = c; ++ ++ } else if (dev->role == BLT_ROLE_AG || ++ dev->role == BLT_ROLE_GUI) { ++ ++ //ast_log(LOG_ERROR, "%s: %c\n", dev->name, c); ++ ++ switch (dev->state) { ++ case BLT_STATE_WANT_R: ++ if (c == '\r' || c == 10) { ++ dev->state = BLT_STATE_WANT_N; ++ } else if (c == '+') { ++ dev->state = BLT_STATE_WANT_CMD; ++ dev->rd_buff[dev->rd_buff_pos++] = '+'; ++ } else { ++ ast_log(LOG_ERROR, "Device %s: Expected '\\r', got %d. state=BLT_STATE_WANT_R\n", dev->name, c); ++ return -1; ++ } ++ break; ++ ++ case BLT_STATE_WANT_N: ++ if (c == '\n' || c == 13) ++ dev->state = BLT_STATE_WANT_CMD; ++ else { ++ ast_log(LOG_ERROR, "Device %s: Expected '\\n', got %d. state=BLT_STATE_WANT_N\n", dev->name, c); ++ return -1; ++ } ++ break; ++ ++ case BLT_STATE_WANT_CMD: ++ if (c == '\r' || c == 10) ++ dev->state = BLT_STATE_WANT_N2; ++ else { ++ if (dev->rd_buff_pos >= BLT_RDBUFF_MAX) { ++ ast_log(LOG_ERROR, "Device %s: Buffer exceeded\n", dev->name); ++ return -1; ++ } ++ dev->rd_buff[dev->rd_buff_pos++] = c; ++ } ++ break; ++ ++ case BLT_STATE_WANT_N2: ++ if (c == '\n' || c == 13) { ++ ++ dev->state = BLT_STATE_WANT_R; ++ ++ if (dev->rd_buff[0] == '+') { ++ int i; ++ // find unsolicited ++ for (i = 0 ; i < ATCMD_LIST_LEN ; i++) { ++ if (strncmp(atcmd_list[i].str, dev->rd_buff, strlen(atcmd_list[i].str)) == 0) { ++ if (atcmd_list[i].unsolicited) ++ atcmd_list[i].unsolicited(dev, dev->rd_buff + strlen(atcmd_list[i].str) + 1); ++ else ++ ast_log(LOG_WARNING, "Device %s: Unhandled Unsolicited: %s\n", dev->name, dev->rd_buff); ++ break; ++ } ++ } ++ ++ if (option_verbose) ++ ast_verbose(VERBOSE_PREFIX_1 "[%s] %*s > %s\n", role2str(dev->role), 10, dev->name, dev->rd_buff); ++ ++ if (i == ATCMD_LIST_LEN) ++ ast_log(LOG_NOTICE, "Device %s: Got unsolicited message: %s\n", dev->name, dev->rd_buff); ++ ++ } else if (dev->rd_buff[0] == '*') { ++ if (option_verbose) ++ ast_verbose(VERBOSE_PREFIX_1 "[%s]* %*s > %s\n", role2str(dev->role), 9, dev->name, dev->rd_buff); ++ ++ int i; ++ // find execute ++ for (i = 0 ; i < ATCMD_LIST_LEN ; i++) { ++ if (strncmp(atcmd_list[i].str, dev->rd_buff, strlen(atcmd_list[i].str)) == 0) { ++ if (atcmd_list[i].execute) ++ atcmd_list[i].execute(dev, dev->rd_buff + strlen(atcmd_list[i].str) + 1); ++ else ++ ast_log(LOG_ERROR, "Device %s: Unhandled Execute: %s\n", dev->name, dev->rd_buff); ++ break; ++ } ++ } ++ ++ ++ } else { ++ ++ if ( ++ strcmp(dev->rd_buff, "OK") != 0 && ++ strcmp(dev->rd_buff, "CONNECT") != 0 && ++ strcmp(dev->rd_buff, "RING") != 0 && ++ strcmp(dev->rd_buff, "NO CARRIER") != 0 && ++ strcmp(dev->rd_buff, "ERROR") != 0 && ++ strcmp(dev->rd_buff, "NO DIALTONE") != 0 && ++ strcmp(dev->rd_buff, "BUSY") != 0 && ++ strcmp(dev->rd_buff, "NO ANSWER") != 0 && ++ strcmp(dev->rd_buff, "DELAYED") != 0 ++ ){ ++ // It must be a multiline error ++ strncpy(dev->last_err_cmd, dev->rd_buff, 1023); ++ if (option_verbose) ++ ast_verbose(VERBOSE_PREFIX_1 "[%s] %*s > %s\n", role2str(dev->role), 10, dev->name, dev->rd_buff); ++ } else if (dev->cb) { ++ if (option_verbose) ++ ast_verbose(VERBOSE_PREFIX_1 "[%s] %*s > %s\n", role2str(dev->role), 10, dev->name, dev->rd_buff); ++ dev->cb(dev, dev->rd_buff); ++ } else { ++ ast_log(LOG_ERROR, "Device %s: Data on socket in HS mode, but no callback\n", dev->name); ++ } ++ ++ } ++ ++ dev->rd_buff_pos = 0; ++ memset(dev->rd_buff, 0, BLT_RDBUFF_MAX); ++ } else { ++ ++ ast_log(LOG_ERROR, "Device %s: Expected '\\n' got %d. state = BLT_STATE_WANT_N2:\n", dev->name, c); ++ return -1; ++ ++ } ++ ++ break; ++ ++ default: ++ ast_log(LOG_ERROR, "Device %s: Unknown device state %d\n", dev->name, dev->state); ++ return -1; ++ ++ } ++ ++ } ++ ++ } ++ ++ return 0; ++} ++ ++/* Close the devices RFCOMM socket, and SCO if it exists. Must hold dev->lock */ ++ ++static void ++rd_close(blt_dev_t * dev, int reconnect, int e) ++{ ++ dev->ready = 0; ++ ++ if (dev->rd) ++ close(dev->rd); ++ ++ dev->rd = -1; ++ ++ dev->status = BLT_STATUS_DOWN; ++ ++ sco_stop(dev); ++ ++ if (dev->owner) { ++ ast_setstate(dev->owner, AST_STATE_DOWN); ++ ast_queue_control(dev->owner, AST_CONTROL_HANGUP); ++ } ++ ++ /* Schedule a reconnect */ ++ if (reconnect && dev->autoconnect) { ++ dev->outgoing_id = ast_sched_add(sched, 5000, AST_SCHED_CB(try_connect), dev); ++ ++ if (monitor_thread == pthread_self()) { ++ // Because we're not the monitor thread, we needd to inturrupt poll(). ++ pthread_kill(monitor_thread, SIGURG); ++ } ++ ++ if (e) ++ ast_log(LOG_NOTICE, "Device %s disconnected, scheduled reconnect in 5 seconds: %s (errno %d)\n", dev->name, strerror(e), e); ++ } else if (e) { ++ ast_log(LOG_NOTICE, "Device %s disconnected: %s (errno %d)\n", dev->name, strerror(e), e); ++ } ++ ++ return; ++} ++ ++/* ++ * Remember that we can only add to the scheduler from ++ * the do_monitor thread, as it calculates time to next one from ++ * this loop. ++ */ ++ ++static void * ++do_monitor(void * data) ++{ ++#define SRV_SOCK_CNT 4 ++ ++ int res = 0; ++ blt_dev_t * dev; ++ struct pollfd * pfds = malloc(sizeof(struct pollfd) * (ifcount + SRV_SOCK_CNT)); ++ ++ /* -- We start off by trying to connect all of our devices (non blocking) -- */ ++ ++ monitor_pid = getpid(); ++ ++ if (ast_mutex_lock(&iface_lock)) { ++ ast_log(LOG_ERROR, "Failed to get iface_lock.\n"); ++ return NULL; ++ } ++ ++ dev = iface_head; ++ while (dev) { ++ ++ if (socketpair(PF_UNIX, SOCK_STREAM, 0, dev->sco_pipe) != 0) { ++ ast_log(LOG_ERROR, "Failed to create socket pair: %s (errno %d)\n", strerror(errno), errno); ++ ast_mutex_unlock(&iface_lock); ++ return NULL; ++ } ++ ++ if (dev->autoconnect && dev->status == BLT_STATUS_DOWN) ++ dev->outgoing_id = ast_sched_add(sched, 1500, AST_SCHED_CB(try_connect), dev); ++ dev = dev->next; ++ } ++ ast_mutex_unlock(&iface_lock); ++ ++ /* -- Now, Scan all sockets, and service scheduler -- */ ++ ++ pfds[0].fd = rfcomm_sock_ag; ++ pfds[0].events = POLLIN; ++ ++ pfds[1].fd = rfcomm_sock_hs; ++ pfds[1].events = POLLIN; ++ ++ pfds[2].fd = rfcomm_sock_gui; ++ pfds[2].events = POLLIN; ++ ++ pfds[3].fd = sco_socket; ++ pfds[3].events = POLLIN; ++ ++ while (1) { ++ int cnt = SRV_SOCK_CNT; ++ int i; ++ ++ /* -- Build pfds -- */ ++ ++ if (ast_mutex_lock(&iface_lock)) { ++ ast_log(LOG_ERROR, "Failed to get iface_lock.\n"); ++ return NULL; ++ } ++ dev = iface_head; ++ while (dev) { ++ ast_mutex_lock(&(dev->lock)); ++ if (dev->rd > 0 && ((dev->status != BLT_STATUS_DOWN) && (dev->status != BLT_STATUS_CONNECTING))) { ++ pfds[cnt].fd = dev->rd; ++ pfds[cnt].events = POLLIN; ++ cnt++; ++ } ++ ast_mutex_unlock(&(dev->lock)); ++ dev = dev->next; ++ } ++ ast_mutex_unlock(&iface_lock); ++ ++ /* -- End Build pfds -- */ ++ ++ res = ast_sched_wait(sched); ++ res = poll(pfds, cnt, MAX(100, MIN(100, res))); ++ ++ if (res == 0) ++ ast_sched_runq(sched); ++ ++ if (pfds[0].revents) { ++ handle_incoming(rfcomm_sock_ag, BLT_ROLE_AG); ++ res--; ++ } ++ ++ if (pfds[1].revents) { ++ handle_incoming(rfcomm_sock_hs, BLT_ROLE_HS); ++ res--; ++ } ++ ++ if (pfds[2].revents) { ++ handle_incoming(rfcomm_sock_gui, BLT_ROLE_GUI); ++ res--; ++ } ++ ++ if (pfds[3].revents) { ++ handle_incoming_sco(sco_socket); ++ res--; ++ } ++ ++ if (res == 0) ++ continue; ++ ++ for (i = SRV_SOCK_CNT ; i < cnt ; i++) { ++ ++ /* Optimise a little bit */ ++ if (res == 0) ++ break; ++ else if (pfds[i].revents == 0) ++ continue; ++ ++ /* -- Find the socket that has activity -- */ ++ ++ if (ast_mutex_lock(&iface_lock)) { ++ ast_log(LOG_ERROR, "Failed to get iface_lock.\n"); ++ return NULL; ++ } ++ ++ dev = iface_head; ++ ++ while (dev) { ++ if (pfds[i].fd == dev->rd) { ++ ast_mutex_lock(&(dev->lock)); ++ if (pfds[i].revents & POLLIN) { ++ if (handle_rd_data(dev) == -1) { ++ rd_close(dev, 0, 0); ++ } ++ } else { ++ rd_close(dev, 1, sock_err(dev->rd)); ++ } ++ ast_mutex_unlock(&(dev->lock)); ++ res--; ++ break; ++ } ++ dev = dev->next; ++ } ++ ++ if (dev == NULL) { ++ ast_log(LOG_ERROR, "Unhandled fd from poll()\n"); ++ close(pfds[i].fd); ++ } ++ ++ ast_mutex_unlock(&iface_lock); ++ ++ /* -- End find socket with activity -- */ ++ ++ } ++ ++ } ++ ++ return NULL; ++} ++ ++static int ++restart_monitor(void) ++{ ++ ++ if (monitor_thread == AST_PTHREADT_STOP) ++ return 0; ++ ++ if (ast_mutex_lock(&monitor_lock)) { ++ ast_log(LOG_WARNING, "Unable to lock monitor\n"); ++ return -1; ++ } ++ ++ if (monitor_thread == pthread_self()) { ++ ast_mutex_unlock(&monitor_lock); ++ ast_log(LOG_WARNING, "Cannot kill myself\n"); ++ return -1; ++ } ++ ++ if (monitor_thread != AST_PTHREADT_NULL) { ++ ++ /* Just signal it to be sure it wakes up */ ++ pthread_cancel(monitor_thread); ++ pthread_kill(monitor_thread, SIGURG); ++ ast_log(LOG_DEBUG, "Waiting for monitor thread to join...\n"); ++ pthread_join(monitor_thread, NULL); ++ ast_log(LOG_DEBUG, "joined\n"); ++ ++ } else { ++ ++ /* Start a new monitor */ ++ if (ast_pthread_create(&monitor_thread, NULL, do_monitor, NULL) < 0) { ++ ast_mutex_unlock(&monitor_lock); ++ ast_log(LOG_ERROR, "Unable to start monitor thread.\n"); ++ return -1; ++ } ++ ++ } ++ ++ ast_mutex_unlock(&monitor_lock); ++ return 0; ++} ++ ++static int ++blt_parse_config(void) ++{ ++ struct ast_config * cfg; ++ struct ast_variable * v; ++ char * cat; ++ ++ cfg = ast_config_load(BLT_CONFIG_FILE); ++ ++ if (!cfg) { ++ ast_log(LOG_NOTICE, "Unable to load Bluetooth config: %s. Bluetooth disabled\n", BLT_CONFIG_FILE); ++ return -1; ++ } ++ ++ v = ast_variable_browse(cfg, "general"); ++ ++ while (v) { ++ if (!strcasecmp(v->name, "rfchannel_ag")) { ++ rfcomm_channel_ag = atoi(v->value); ++ } else if (!strcasecmp(v->name, "rfchannel_hs")) { ++ rfcomm_channel_hs = atoi(v->value); ++ } else if (!strcasecmp(v->name, "rfchannel_gui")) { ++ rfcomm_channel_gui = atoi(v->value); ++ } else if (!strcasecmp(v->name, "interface")) { ++ hcidev_id = atoi(v->value); ++ } else if (!strcasecmp(v->name, "gui_default_sip_number")) { ++ gui_default_sip_number = v->value; ++ } else if (!strcasecmp(v->name, "gui_default_sip_address")) { ++ gui_default_sip_address = v->value; ++ } else { ++ ast_log(LOG_WARNING, "Unknown config key '%s' in section [general]\n", v->name); ++ } ++ v = v->next; ++ } ++ cat = ast_category_browse(cfg, NULL); ++ ++ while(cat) { ++ ++ char * str; ++ ++ if (strcasecmp(cat, "general")) { ++ blt_dev_t * device = malloc(sizeof(blt_dev_t)); ++ memset(device, 0, sizeof(blt_dev_t)); ++ device->sco_running = -1; ++ device->sco = -1; ++ device->rd = -1; ++ device->outgoing_id = -1; ++ device->status = BLT_STATUS_DOWN; ++ str2ba(cat, &(device->bdaddr)); ++ device->name = ast_variable_retrieve(cfg, cat, "name"); ++ ++ str = ast_variable_retrieve(cfg, cat, "type"); ++ ++ if (str == NULL) { ++ ast_log(LOG_ERROR, "Device [%s] has no role. Specify type=\n", cat); ++ return -1; ++ } else if (strcasecmp(str, "HS") == 0) { ++ device->role = BLT_ROLE_HS; ++ } else if (strcasecmp(str, "AG") == 0) { ++ device->role = BLT_ROLE_AG; ++ } else if (strcasecmp(str, "GUI") == 0) { ++ device->role = BLT_ROLE_GUI; ++ } else { ++ ast_log(LOG_ERROR, "Device [%s] has invalid role '%s'\n", cat, str); ++ return -1; ++ } ++ ++ /* XXX:T: Find channel to use using SDP. ++ * However, this needs to be non blocking, and I can't see ++ * anything in sdp_lib.h that will allow non blocking calls. ++ */ ++ ++ device->channel = 1; ++ ++ if ((str = ast_variable_retrieve(cfg, cat, "channel")) != NULL) ++ device->channel = atoi(str); ++ ++ if ((str = ast_variable_retrieve(cfg, cat, "autoconnect")) != NULL) ++ device->autoconnect = (strcasecmp(str, "yes") == 0 || strcmp(str, "1") == 0) ? 1 : 0; ++ ++ if ((str = ast_variable_retrieve(cfg, cat, "context")) != NULL) ++ device->context = str; ++ else ++ device->context = "bluetooth"; ++ ++ device->next = iface_head; ++ iface_head = device; ++ ifcount++; ++ } ++ ++ cat = ast_category_browse(cfg, cat); ++ } ++ return 0; ++} ++ ++ ++static int ++blt_show_peers(int fd, int argc, char *argv[]) ++{ ++ blt_dev_t * dev; ++ ++ if (ast_mutex_lock(&iface_lock)) { ++ ast_log(LOG_ERROR, "Failed to get Iface lock\n"); ++ ast_cli(fd, "Failed to get iface lock\n"); ++ return RESULT_FAILURE; ++ } ++ ++ dev = iface_head; ++ ++ ast_cli(fd, "BDAddr Name Role Status A/C SCOCon/Fd/Th Sig\n"); ++ ast_cli(fd, "----------------- ---------- ---- ----------- --- ------------ ---\n"); ++ ++ while (dev) { ++ char b1[18]; ++ ba2str(&(dev->bdaddr), b1); ++ ast_cli(fd, "%s %-10s %-4s %-11s %-3s %2d/%02d/%-6ld %s\n", ++ b1, dev->name, ++// (dev->role == BLT_ROLE_HS) ? "HS" : "AG", ++ (dev->role == BLT_ROLE_HS) ? "HS" : (dev->role == BLT_ROLE_AG) ? "AG" : "GUI", ++ status2str(dev->status), ++ (dev->autoconnect) ? "Yes" : "No", ++ dev->sco_running, ++ dev->sco, ++ dev->sco_thread, ++ (dev->role == BLT_ROLE_AG) ? (dev->service) ? "Yes" : "No" : "N/A" ++ ); ++ dev = dev->next; ++ } ++ ++ ast_mutex_unlock(&iface_lock); ++ return RESULT_SUCCESS; ++} ++ ++static int ++blt_show_information(int fd, int argc, char *argv[]) ++{ ++ char b1[18]; ++ ba2str(&local_bdaddr, b1); ++ ast_cli(fd, "-------------------------------------------\n"); ++ ast_cli(fd, " Version : %s\n", BLT_SVN_REVISION); ++ ast_cli(fd, " Monitor PID : %d\n", monitor_pid); ++ ast_cli(fd, " RFCOMM AG : Channel %d, FD %d\n", rfcomm_channel_ag, rfcomm_sock_ag); ++ ast_cli(fd, " RFCOMM HS : Channel %d, FD %d\n", rfcomm_channel_hs, rfcomm_sock_hs); ++ ast_cli(fd, " RFCOMM GUI : Channel %d, FD %d\n", rfcomm_channel_gui, rfcomm_sock_gui); ++ ast_cli(fd, " Device : hci%d, MAC Address %s\n", hcidev_id, b1); ++ ast_cli(fd, "-------------------------------------------\n"); ++ return RESULT_SUCCESS; ++} ++ ++static int ++blt_ag_sendcmd(int fd, int argc, char *argv[]) ++{ ++ blt_dev_t * dev; ++ ++ if (argc != 4) ++ return RESULT_SHOWUSAGE; ++ ++ ast_mutex_lock(&iface_lock); ++ dev = iface_head; ++ while (dev) { ++ if (!strcasecmp(argv[2], dev->name)) ++ break; ++ dev = dev->next; ++ } ++ ast_mutex_unlock(&iface_lock); ++ ++ if (!dev) { ++ ast_cli(fd, "Device '%s' does not exist\n", argv[2]); ++ return RESULT_FAILURE; ++ } ++ ++ if ((dev->role != BLT_ROLE_AG) && (dev->role != BLT_ROLE_GUI)) { ++ ast_cli(fd, "Device '%s' is not an AG or GUI\n", argv[2]); ++ return RESULT_FAILURE; ++ } ++ ++ if (dev->status == BLT_STATUS_DOWN || dev->status == BLT_STATUS_NEGOTIATING) { ++ ast_cli(fd, "Device '%s' is not connected\n", argv[2]); ++ return RESULT_FAILURE; ++ } ++ ++ if (*(argv[3] + strlen(argv[3]) - 1) == '.') ++ *(argv[3] + strlen(argv[3]) - 1) = '?'; ++ ++ ast_cli(fd, "Sending AT command to %s: %s\n", dev->name, argv[3]); ++ ++ ast_mutex_lock(&(dev->lock)); ++ send_atcmd(dev, argv[3]); ++ ast_mutex_unlock(&(dev->lock)); ++ ++ return RESULT_SUCCESS; ++} ++ ++static char * ++complete_device(char * line, char * word, int pos, int state, int rpos, blt_role_t role) ++{ ++ blt_dev_t * dev; ++ int which = 0; ++ char *ret; ++ ++ if (pos != rpos) ++ return NULL; ++ ++ ast_mutex_lock(&iface_lock); ++ ++ dev = iface_head; ++ ++ while (dev) { ++ ++ if ((dev->role == role) && (!strncasecmp(word, dev->name, strlen(word)))) { ++ if (++which > state) ++ break; ++ } ++ ++ dev = dev->next; ++ } ++ ++ if (dev) ++ ret = strdup(dev->name); ++ else ++ ret = NULL; ++ ++ ast_mutex_unlock(&iface_lock); ++ ++ return ret; ++} ++ ++static char * ++complete_device_2_ag_gui(char * line, char * word, int pos, int state) ++{ ++ return complete_device(line, word, pos, state, 2, BLT_ROLE_AG); ++} ++ ++static char show_peers_usage[] = ++"Usage: bluetooth show peers\n" ++" List all bluetooth peers and their status\n"; ++ ++static struct ast_cli_entry ++cli_show_peers = ++ { { "bluetooth", "show", "peers", NULL }, blt_show_peers, "List Bluetooth Peers", show_peers_usage }; ++ ++ ++static char ag_sendcmd[] = ++"Usage: bluetooth sendcmd \n" ++" Sends a AT cmd over the RFCOMM link, and print result (AG only)\n"; ++ ++static struct ast_cli_entry ++cli_ag_sendcmd = ++ { { "bluetooth", "sendcmd", NULL }, blt_ag_sendcmd, "Send AG/GUI an AT command", ag_sendcmd, complete_device_2_ag_gui }; ++ ++static char show_information[] = ++"Usage: bluetooth show information\n" ++" Lists information about the bluetooth subsystem\n"; ++ ++static struct ast_cli_entry ++cli_show_information = ++ { { "bluetooth", "show", "information", NULL }, blt_show_information, "List Bluetooth Info", show_information }; ++ ++void ++remove_sdp_records(void) ++{ ++ ++ sdp_session_t * sdp; ++ sdp_list_t * attr; ++ sdp_record_t * rec; ++ int res = -1; ++ uint32_t range = 0x0000ffff; ++ ++ if (sdp_record_ag == -1 || sdp_record_gui == -1 || sdp_record_hs == -1) ++ return; ++ ++ ast_log(LOG_DEBUG, "Removing SDP records\n"); ++ ++ sdp = sdp_connect(BDADDR_ANY, BDADDR_LOCAL, SDP_RETRY_IF_BUSY); ++ ++ if (!sdp) ++ return; ++ ++ attr = sdp_list_append(0, &range); ++ rec = sdp_service_attr_req(sdp, sdp_record_ag, SDP_ATTR_REQ_RANGE, attr); ++ sdp_list_free(attr, 0); ++ ++ if (rec) ++ if (sdp_record_unregister(sdp, rec) == 0) ++ res = 0; ++ ++ rec = sdp_service_attr_req(sdp, sdp_record_gui, SDP_ATTR_REQ_RANGE, attr); ++ sdp_list_free(attr, 0); ++ ++ if (rec) ++ if (sdp_record_unregister(sdp, rec) == 0) ++ res = 0; ++ ++ attr = sdp_list_append(0, &range); ++ rec = sdp_service_attr_req(sdp, sdp_record_hs, SDP_ATTR_REQ_RANGE, attr); ++ sdp_list_free(attr, 0); ++ ++ if (rec) ++ if (sdp_record_unregister(sdp, rec) == 0) ++ res = 0; ++ ++ sdp_close(sdp); ++ ++ if (res == 0) ++ ast_log(LOG_NOTICE, "Removed SDP records\n"); ++ else ++ ast_log(LOG_ERROR, "Failed to remove SDP records\n"); ++ ++} ++ ++static int ++__unload_module(void) ++{ ++ ++#if ASTERISK_VERSION_NUM <= 010107 ++ ast_channel_unregister(BLT_CHAN_NAME); ++#else ++ ast_channel_unregister(&blt_tech); ++#endif ++ ++ if (monitor_thread != AST_PTHREADT_NULL) { ++ ++ if (ast_mutex_lock(&monitor_lock)) { ++ ++ if (monitor_thread && (monitor_thread != AST_PTHREADT_STOP) && (monitor_thread != AST_PTHREADT_NULL)) { ++ pthread_cancel(monitor_thread); ++ pthread_kill(monitor_thread, SIGURG); ++ fprintf(stderr, "Waiting for monitor thread to join...\n"); ++ pthread_join(monitor_thread, NULL); ++ fprintf(stderr, "joined\n"); ++ } ++ monitor_thread = AST_PTHREADT_STOP; ++ ast_mutex_unlock(&monitor_lock); ++ ++ } else { ++ ++ ast_log(LOG_WARNING, "Unable to lock the monitor\n"); ++ return -1; ++ ++ } ++ ++ } ++ ++ ast_unregister_atexit(remove_sdp_records); ++ remove_sdp_records(); ++ return 0; ++} ++ ++int ++load_module() ++{ ++ sdp_session_t * sess; ++ int dd; ++ uint16_t vs; ++ ++ hcidev_id = BLT_DEFAULT_HCI_DEV; ++ ++ if (blt_parse_config() != 0) { ++ ast_log(LOG_ERROR, "Bluetooth configuration error. Bluetooth Disabled\n"); ++ return unload_module(); ++ } ++ ++ dd = hci_open_dev(hcidev_id); ++ if (dd == -1) { ++ ast_log(LOG_ERROR, "Unable to open interface hci%d: %s.\n", hcidev_id, strerror(errno)); ++ return -1; ++ } ++ ++ hci_read_voice_setting(dd, &vs, 1000); ++ vs = htobs(vs); ++ close(dd); ++ ++ if (vs != 0x0060) { ++ ast_log(LOG_ERROR, "Bluetooth voice setting must be 0x0060, not 0x%04x\n", vs); ++ unload_module(); ++ return 0; ++ } ++ ++ if ((sched = sched_context_create()) == NULL) { ++ ast_log(LOG_WARNING, "Unable to create schedule context\n"); ++ return -1; ++ } ++ ++ memset(&local_bdaddr, 0, sizeof(local_bdaddr)); ++ ++ hci_devba(hcidev_id, &local_bdaddr); ++ ++ /* --- Add SDP record --- */ ++ ++ sess = sdp_connect(&local_bdaddr, BDADDR_LOCAL, SDP_RETRY_IF_BUSY); ++ ++ if ((rfcomm_sock_ag = rfcomm_listen(&local_bdaddr, rfcomm_channel_ag)) < 0) { ++ return -1; ++ } ++ ++ if ((rfcomm_sock_hs = rfcomm_listen(&local_bdaddr, rfcomm_channel_hs)) < 0) ++ return -1; ++ ++ if ((rfcomm_sock_gui = rfcomm_listen(&local_bdaddr, rfcomm_channel_gui)) < 0) ++ return -1; ++ ++ if ((sco_socket = sco_listen(&local_bdaddr)) < 0) ++ return -1; ++ ++ if (!sess) { ++ ast_log(LOG_ERROR, "Failed to connect to SDP server: %s\n", strerror(errno)); ++ return -1; ++ } ++ ++ if (sdp_register(sess) != 0) { ++ ast_log(LOG_ERROR, "Failed to register HeadsetAudioGateway in SDP\n"); ++ return -1; ++ } ++ ++ sdp_close(sess); ++ ++ if (restart_monitor() != 0) ++ return -1; ++ ++#if ASTERISK_VERSION_NUM <= 010107 ++ if (ast_channel_register(BLT_CHAN_NAME, "Bluetooth Driver", BLUETOOTH_FORMAT, blt_request)) { ++#else ++ if (ast_channel_register(&blt_tech)) { ++#endif ++ ast_log(LOG_ERROR, "Unable to register channel class BTL\n"); ++ __unload_module(); ++ return -1; ++ } ++ ++ ast_cli_register(&cli_show_information); ++ ast_cli_register(&cli_show_peers); ++ ast_cli_register(&cli_ag_sendcmd); ++ ++ ast_register_atexit(remove_sdp_records); ++ ++ ast_log(LOG_NOTICE, "Loaded Bluetooth support, %s\n", BLT_SVN_REVISION + 1); ++ ++ return 0; ++} ++ ++int ++unload_module(void) ++{ ++ ast_cli_unregister(&cli_ag_sendcmd); ++ ast_cli_unregister(&cli_show_peers); ++ ast_cli_unregister(&cli_show_information); ++ return __unload_module(); ++} ++ ++int ++usecount() ++{ ++ int res; ++ ast_mutex_lock(&usecnt_lock); ++ res = usecnt; ++ ast_mutex_unlock(&usecnt_lock); ++ return res; ++} ++ ++char *description() ++{ ++ return "Bluetooth Channel Driver"; ++} ++ ++char * ++key() ++{ ++ return ASTERISK_GPL_KEY; ++} ++ ++ +diff -Nru asterisk-1.2.14.org/channels/Makefile asterisk-1.2.14/channels/Makefile +--- asterisk-1.2.14.org/channels/Makefile 2006-08-17 23:57:19.000000000 +0200 ++++ asterisk-1.2.14/channels/Makefile 2006-12-27 09:03:53.000000000 +0100 +@@ -249,6 +249,13 @@ + #chan_modem.so : chan_modem.o + # $(CC) -rdynamic -shared -Xlinker -x -o $@ $< + ++# ++# Asterisk Bluetooth Support ++# http://www.crazygreek.co.uk/content/chan_bluetooth ++# ++chan_bluetooth.so: chan_bluetooth.o ++ $(CC) $(SOLINK) -o $@ $< $(EXTRA_LDFLAGS) -lbluetooth ++ + install: all + for x in $(CHANNEL_LIBS); do $(INSTALL) -m 755 $$x $(DESTDIR)$(MODULES_DIR) ; done + if ! [ -f chan_iax.so ]; then rm -f $(DESTDIR)$(MODULES_DIR)/chan_iax.so ; fi +diff -Nru asterisk-1.2.14.org/configs/bluetooth.conf asterisk-1.2.14/configs/bluetooth.conf +--- asterisk-1.2.14.org/configs/bluetooth.conf 1970-01-01 01:00:00.000000000 +0100 ++++ asterisk-1.2.14/configs/bluetooth.conf 2006-12-27 09:03:53.000000000 +0100 +@@ -0,0 +1,46 @@ ++[general] ++; Channel we listen on as a HS (Headset) ++rfchannel_hs = 2 ++; Channel we listen on as an AG (AudioGateway) ++rfchannel_ag = 3 ++; Channel we listen on as GUI ++rfchannel_gui = 4 ++; hci interface to use (number - e.g '0') ++interface = 0 ++ ++; RFCOMM channel to connect to. For a HandsSet: ++; sdptool search --bdaddr xx:xx:xx:xx:xx:xx 0x111E ++; or,for an AudioGateway (Phone): ++; sdptool search --bdaddr xx:xx:xx:xx:xx:xx 0x111F ++; ++; Find the 'channel' value under RFCOMM. ++; ++;channel = 6 ++; Automatically connect? ++;autoconnect = yes ++ ++;example for a SonyEricsson mobile as a GUI device ++[00:0F:DE:6E:77:6B] ++name = T610 ++type = GUI ++channel = 6 ++;channel = 1 ++autoconnect = yes ++ ++;[00:0E:6D:1A:3D:86] ++;name = Nokia ++;type = AG ++;channel = 13 ++;autoconnect = yes ++ ++[00:0E:A1:01:49:AE] ++name = AutoBlue ++type = HS ++channel = 2 ++autoconnect = yes ++ ++;[00:0A:D9:EB:FD:D8] ++;name = P900 ++;type = AG ++;channel = 8 ++;autoconnect = no diff --git a/net/asterisk/patches/07-app_mysql.patch b/net/asterisk/patches/07-app_mysql.patch new file mode 100644 index 000000000..f757b1105 --- /dev/null +++ b/net/asterisk/patches/07-app_mysql.patch @@ -0,0 +1,449 @@ +diff -Nru asterisk-1.2.14.org/apps/app_sql_mysql.c asterisk-1.2.14/apps/app_sql_mysql.c +--- asterisk-1.2.14.org/apps/app_sql_mysql.c 1970-01-01 01:00:00.000000000 +0100 ++++ asterisk-1.2.14/apps/app_sql_mysql.c 2006-12-27 09:00:04.000000000 +0100 +@@ -0,0 +1,445 @@ ++/* ++ * Asterisk -- A telephony toolkit for Linux. ++ * ++ * Connect to MySQL ++ * ++ * Copyright (C) 2004, Constantine Filin and Christos Ricudis ++ * ++ * Christos Ricudis ++ * Constantine Filin ++ * ++ * This program is free software, distributed under the terms of ++ * the GNU General Public License ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#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 ++ * ++ * Modified August 2003 ++ * Tilghman Lesher ++ * ++ * Modified August 6, 2005 ++ * Joseph Benden ++ * 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 ++ ++#include ++#include ++ ++#include ++#include ++#include ++ ++#include ++#include ++ ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#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 -Nru asterisk-1.2.14.org/configs/cdr_mysql.conf.sample asterisk-1.2.14/configs/cdr_mysql.conf.sample +--- asterisk-1.2.14.org/configs/cdr_mysql.conf.sample 1970-01-01 01:00:00.000000000 +0100 ++++ asterisk-1.2.14/configs/cdr_mysql.conf.sample 2006-12-27 09:02:18.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 --git a/net/asterisk/patches/09-compat-getloadavg.patch b/net/asterisk/patches/09-compat-getloadavg.patch new file mode 100644 index 000000000..5ddde4508 --- /dev/null +++ b/net/asterisk/patches/09-compat-getloadavg.patch @@ -0,0 +1,13 @@ +diff -Nru asterisk-1.2.14.org/include/asterisk/compat.h asterisk-1.2.14/include/asterisk/compat.h +--- asterisk-1.2.14.org/include/asterisk/compat.h 2005-11-29 19:24:39.000000000 +0100 ++++ asterisk-1.2.14/include/asterisk/compat.h 2006-12-27 09:07:28.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/net/asterisk/patches/10-Makefile-apps.patch b/net/asterisk/patches/10-Makefile-apps.patch new file mode 100644 index 000000000..7cc3851f1 --- /dev/null +++ b/net/asterisk/patches/10-Makefile-apps.patch @@ -0,0 +1,42 @@ +diff -Nru asterisk-1.2.14.org/apps/Makefile asterisk-1.2.14/apps/Makefile +--- asterisk-1.2.14.org/apps/Makefile 2006-04-30 15:38:22.000000000 +0200 ++++ asterisk-1.2.14/apps/Makefile 2006-12-27 09:08:57.000000000 +0100 +@@ -45,7 +45,7 @@ + #APPS+=app_rpt.so + + ifndef WITHOUT_ZAPTEL +-ifneq ($(wildcard $(CROSS_COMPILE_TARGET)/usr/include/linux/zaptel.h)$(wildcard $(CROSS_COMPILE_TARGET)/usr/local/include/zaptel.h),) ++ifneq ($(wildcard $(STAGING_DIR)/usr/include/linux/zaptel.h)$(wildcard $(CROSS_COMPILE_TARGET)/usr/local/include/zaptel.h),) + APPS+=app_zapras.so app_meetme.so app_flash.so app_zapbarge.so app_zapscan.so app_page.so + endif + endif # WITHOUT_ZAPTEL +@@ -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$(CROSS_COMPILE_TARGET)/usr/local/pgsql/include -I$(CROSS_COMPILE_TARGET)/usr/include/postgresql $(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 + + ifeq (SunOS,$(shell uname)) + app_chanspy.so: app_chanspy.o diff --git a/net/asterisk/patches/11-Makefile-cdr.patch b/net/asterisk/patches/11-Makefile-cdr.patch new file mode 100644 index 000000000..971021075 --- /dev/null +++ b/net/asterisk/patches/11-Makefile-cdr.patch @@ -0,0 +1,37 @@ +diff -Nru asterisk-1.2.14.org/cdr/Makefile asterisk-1.2.14/cdr/Makefile +--- asterisk-1.2.14.org/cdr/Makefile 2006-11-16 21:29:28.000000000 +0100 ++++ asterisk-1.2.14/cdr/Makefile 2006-12-27 09:10:57.000000000 +0100 +@@ -111,6 +111,9 @@ + MODS+=cdr_sqlite.so + endif + ++CFLAGS += $(EXTRA_CFLAGS) ++MODS += $(EXTRA_CDR_MODULES) ++ + all: depend $(MODS) + + install: all +@@ -127,16 +130,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_mysql.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/net/asterisk/patches/12-Makefile-channels.patch b/net/asterisk/patches/12-Makefile-channels.patch new file mode 100644 index 000000000..4c7ce6de8 --- /dev/null +++ b/net/asterisk/patches/12-Makefile-channels.patch @@ -0,0 +1,40 @@ +diff -Nru asterisk-1.2.14.org/channels/Makefile asterisk-1.2.14/channels/Makefile +--- asterisk-1.2.14.org/channels/Makefile 2006-08-17 23:57:19.000000000 +0200 ++++ asterisk-1.2.14/channels/Makefile 2006-12-27 09:12:28.000000000 +0100 +@@ -110,7 +110,7 @@ + endif + + ifndef WITHOUT_ZAPTEL +-ifneq ($(wildcard $(CROSS_COMPILE_TARGET)/usr/include/linux/zaptel.h)$(wildcard $(CROSS_COMPILE_TARGET)/usr/local/include/zaptel.h)$(wildcard $(CROSS_COMPILE_TARGET)/usr/pkg/include/zaptel.h),) ++ifneq ($(wildcard $(STAGING_DIR)/usr/include/linux/zaptel.h)$(wildcard $(CROSS_COMPILE_TARGET)/usr/local/include/zaptel.h)$(wildcard $(CROSS_COMPILE_TARGET)/usr/pkg/include/zaptel.h),) + ifeq (${OSARCH},NetBSD) + SOLINK+=-L$(CROSS_COMPILE_TARGET)/usr/pkg/lib + endif +@@ -151,6 +151,9 @@ + + #CFLAGS+=$(shell [ -f $(ZAPDIR)/libzap.a ] && echo "-I$(ZAPDIR)") + ++CFLAGS += $(EXTRA_CFLAGS) ++CHANNEL_LIBS += $(EXTRA_CHAN_MODULES) ++ + all: depend $(CHANNEL_LIBS) + + clean: +@@ -158,7 +161,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 +@@ -204,7 +207,7 @@ + $(CC) -c $(CFLAGS) -o chan_zap.o chan_zap.c + + chan_zap.so: chan_zap.o +- $(CC) $(SOLINK) -o $@ $< $(ZAPPRI) $(ZAPR2) -ltonezone ++ $(CC) $(SOLINK) -o $@ $< $(ZAPPRI) $(ZAPR2) $(EXTRA_LDFLAGS) -ltonezone + + chan_sip.so: chan_sip.o + $(CC) $(SOLINK) -o $@ ${CYGSOLINK} chan_sip.o ${CYGSOLIB} diff --git a/net/asterisk/patches/13-Makefile-codecs-gsm.patch b/net/asterisk/patches/13-Makefile-codecs-gsm.patch new file mode 100644 index 000000000..23c7e0bab --- /dev/null +++ b/net/asterisk/patches/13-Makefile-codecs-gsm.patch @@ -0,0 +1,39 @@ +diff -Nru asterisk-1.2.14.org/codecs/gsm/Makefile asterisk-1.2.14/codecs/gsm/Makefile +--- asterisk-1.2.14.org/codecs/gsm/Makefile 2006-07-24 19:05:56.000000000 +0200 ++++ asterisk-1.2.14/codecs/gsm/Makefile 2006-12-27 09:14:51.000000000 +0100 +@@ -241,6 +241,8 @@ + ifneq ($(shell uname -m),armv4l) + ifneq ($(shell uname -m),sparc64) + ifneq (${PROC},arm) ++ifneq (${PROC},mipsel) ++ifneq (${PROC},mips) + ifneq ($(shell uname -m), parisc) + ifneq ($(shell uname -m),s390) + GSM_SOURCES+= $(SRC)/k6opt.s +@@ -255,6 +257,8 @@ + endif + endif + endif ++endif ++endif + + TOAST_SOURCES = $(SRC)/toast.c \ + $(SRC)/toast_lin.c \ +@@ -308,6 +312,8 @@ + ifneq ($(shell uname -m), alpha) + ifneq ($(shell uname -m), sparc64) + ifneq ($(shell uname -m), armv4l) ++ifneq (${PROC}, mipsel) ++ifneq (${PROC}, mips) + ifneq ($(shell uname -m), parisc) + ifneq ($(shell uname -m),s390) + GSM_OBJECTS+= $(SRC)/k6opt.o +@@ -321,6 +327,8 @@ + endif + endif + endif ++endif ++endif + + TOAST_OBJECTS = $(SRC)/toast.o \ + $(SRC)/toast_lin.o \ diff --git a/net/asterisk/patches/14-Makefile-codecs.patch b/net/asterisk/patches/14-Makefile-codecs.patch new file mode 100644 index 000000000..d8369f7a5 --- /dev/null +++ b/net/asterisk/patches/14-Makefile-codecs.patch @@ -0,0 +1,13 @@ +diff -Nru asterisk-1.2.14.org/codecs/Makefile asterisk-1.2.14/codecs/Makefile +--- asterisk-1.2.14.org/codecs/Makefile 2005-11-29 19:24:39.000000000 +0100 ++++ asterisk-1.2.14/codecs/Makefile 2006-12-27 09:15:57.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/net/asterisk/patches/15-Makefile.patch b/net/asterisk/patches/15-Makefile.patch new file mode 100644 index 000000000..e36bb1e1f --- /dev/null +++ b/net/asterisk/patches/15-Makefile.patch @@ -0,0 +1,53 @@ +diff -Nru asterisk-1.2.14.org/Makefile asterisk-1.2.14/Makefile +--- asterisk-1.2.14.org/Makefile 2006-12-11 22:55:43.000000000 +0100 ++++ asterisk-1.2.14/Makefile 2006-12-27 09:16:50.000000000 +0100 +@@ -356,16 +356,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 +@@ -420,8 +410,6 @@ + HAVEDOT=no + endif + +-LIBS+=-lssl +- + _all: all + @echo " +--------- Asterisk Build Complete ---------+" + @echo " + Asterisk has successfully been built, but +" +@@ -447,12 +435,12 @@ + cd editline && unset CFLAGS LIBS && CFLAGS="$(OPTIMIZE)" ./configure ; \ + + editline/libedit.a: FORCE +- cd editline && unset CFLAGS LIBS && test -f config.h || CFLAGS="$(OPTIMIZE)" ./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; \ +@@ -530,7 +518,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/net/asterisk/patches/16-Makefile-pbx.patch b/net/asterisk/patches/16-Makefile-pbx.patch new file mode 100644 index 000000000..7bb5d8c09 --- /dev/null +++ b/net/asterisk/patches/16-Makefile-pbx.patch @@ -0,0 +1,22 @@ +diff -Nru asterisk-1.2.14.org/pbx/Makefile asterisk-1.2.14/pbx/Makefile +--- asterisk-1.2.14.org/pbx/Makefile 2005-11-29 19:24:39.000000000 +0100 ++++ asterisk-1.2.14/pbx/Makefile 2006-12-27 09:17:58.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/net/asterisk/patches/17-Makefile-res.patch b/net/asterisk/patches/17-Makefile-res.patch new file mode 100644 index 000000000..25b28147a --- /dev/null +++ b/net/asterisk/patches/17-Makefile-res.patch @@ -0,0 +1,44 @@ +diff -Nru asterisk-1.2.14.org/res/Makefile asterisk-1.2.14/res/Makefile +--- asterisk-1.2.14.org/res/Makefile 2005-11-29 19:24:39.000000000 +0100 ++++ asterisk-1.2.14/res/Makefile 2006-12-27 09:18:45.000000000 +0100 +@@ -55,7 +55,7 @@ + CFLAGS+= + + ifndef WITHOUT_ZAPTEL +-ifneq ($(wildcard $(CROSS_COMPILE_TARGET)/usr/include/linux/zaptel.h)$(wildcard $(CROSS_COMPILE_TARGET)/usr/local/include/zaptel.h),) ++ifneq ($(wildcard $(STAGING_DIR)/usr/include/linux/zaptel.h)$(wildcard $(CROSS_COMPILE_TARGET)/usr/local/include/zaptel.h),) + CFLAGS+=-DZAPATA_MOH + endif + endif # WITHOUT_ZAPTEL +@@ -69,6 +69,9 @@ + CFLAGS+=-DOPENSSL_NO_KRB5 -fPIC + endif + ++CFLAGS += $(EXTRA_CFLAGS) ++MODS += $(EXTRA_RES_MODULES) ++ + all: depend $(MODS) + + install: all +@@ -89,7 +92,7 @@ + fi + + res_crypto.so: res_crypto.o +- $(CC) $(SOLINK) -o $@ ${CYGSOLINK} $< ${CYGSOLIB} $(CRYPTO_LIBS) ++ $(CC) $(SOLINK) -o $@ ${CYGSOLINK} $< ${CYGSOLIB} $(EXTRA_LDFLAGS) $(CRYPTO_LIBS) + + clean: + rm -f *.so *.o .depend +@@ -109,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/net/asterisk/patches/18-res_mysql.patch b/net/asterisk/patches/18-res_mysql.patch new file mode 100644 index 000000000..d66c7f70c --- /dev/null +++ b/net/asterisk/patches/18-res_mysql.patch @@ -0,0 +1,698 @@ +diff -Nru asterisk-1.2.14.org/configs/res_mysql.conf.sample asterisk-1.2.14/configs/res_mysql.conf.sample +--- asterisk-1.2.14.org/configs/res_mysql.conf.sample 1970-01-01 01:00:00.000000000 +0100 ++++ asterisk-1.2.14/configs/res_mysql.conf.sample 2006-12-27 09:19:45.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 -Nru asterisk-1.2.14.org/res/res_config_mysql.c asterisk-1.2.14/res/res_config_mysql.c +--- asterisk-1.2.14.org/res/res_config_mysql.c 1970-01-01 01:00:00.000000000 +0100 ++++ asterisk-1.2.14/res/res_config_mysql.c 2006-12-27 09:19:45.000000000 +0100 +@@ -0,0 +1,675 @@ ++/* ++ * Asterisk -- A telephony toolkit for Linux. ++ * ++ * Copyright (C) 1999-2005, Digium, Inc. ++ * ++ * Mark Spencer - Asterisk Author ++ * Matthew Boehm - MySQL RealTime Driver Author ++ * ++ * res_config_mysql.c ++ * ++ * 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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++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/net/asterisk/patches/19-Makefile-codecs-ilbc.patch b/net/asterisk/patches/19-Makefile-codecs-ilbc.patch new file mode 100644 index 000000000..81829dc5d --- /dev/null +++ b/net/asterisk/patches/19-Makefile-codecs-ilbc.patch @@ -0,0 +1,21 @@ +diff -Nru asterisk-1.2.14.org/codecs/ilbc/Makefile asterisk-1.2.14/codecs/ilbc/Makefile +--- asterisk-1.2.14.org/codecs/ilbc/Makefile 2005-11-29 19:24:39.000000000 +0100 ++++ asterisk-1.2.14/codecs/ilbc/Makefile 2006-12-27 09:21:07.000000000 +0100 +@@ -1,5 +1,5 @@ + ARCH=$(PROC) +-CFLAGS+=-Wall -O3 -funroll-loops ++CFLAGS+=-Wall $(OPTIMIZE) -funroll-loops + ifneq (${OSARCH},CYGWIN) + CFLAGS += -fPIC + endif +@@ -15,8 +15,8 @@ + + + $(LIB): $(OBJS) +- ar cr $(LIB) $(OBJS) +- ranlib $(LIB) ++ $(AR) cr $(LIB) $(OBJS) ++ $(RANLIB) $(LIB) + + clean: + rm -f $(LIB) *.o diff --git a/net/asterisk/patches/20-chan_h323.patch b/net/asterisk/patches/20-chan_h323.patch new file mode 100644 index 000000000..954245237 --- /dev/null +++ b/net/asterisk/patches/20-chan_h323.patch @@ -0,0 +1,32 @@ +diff -Nru asterisk-1.2.14.org/channels/h323/Makefile asterisk-1.2.14/channels/h323/Makefile +--- asterisk-1.2.14.org/channels/h323/Makefile 2005-11-29 19:24:39.000000000 +0100 ++++ asterisk-1.2.14/channels/h323/Makefile 2006-12-27 09:22:09.000000000 +0100 +@@ -30,7 +30,7 @@ + touch $(SOURCES) + + libchanh323.a: $(OBJS) +- ar crv $@ $(OBJS) ++ $(AR) crv $@ $(OBJS) + + Makefile.ast: FORCE + @echo H323CFLAGS = $(STDCCFLAGS) $(OPTCCFLAGS) $(CFLAGS) >$@.tmp +diff -Nru asterisk-1.2.14.org/channels/Makefile asterisk-1.2.14/channels/Makefile +--- asterisk-1.2.14.org/channels/Makefile 2006-08-17 23:57:19.000000000 +0200 ++++ asterisk-1.2.14/channels/Makefile 2006-12-27 09:22:09.000000000 +0100 +@@ -15,6 +15,7 @@ + # + + CHANNEL_LIBS=chan_sip.so chan_agent.so chan_mgcp.so chan_iax2.so chan_local.so chan_skinny.so chan_features.so ++CXXLIBS=-lstdc++ + + ifneq (${OSARCH},CYGWIN) + # if you really, really want to use these drivers, uncomment the line below +@@ -228,7 +229,7 @@ + + ifeq (${OSARCH},Linux) + chan_h323.so: chan_h323.o h323/libchanh323.a h323/Makefile.ast +- $(CC) $(SOLINK) $(H323LDFLAGS) -o $@ $< h323/libchanh323.a $(H323LDLIBS) -lstdc++ ++ $(CC) $(SOLINK) $(H323LDFLAGS) -o $@ $< h323/libchanh323.a $(H323LDLIBS) $(CXXLIBS) + else + chan_h323.so: chan_h323.o h323/libchanh323.a + $(CC) $(SOLINK) -o $@ $< h323/libchanh323.a $(CHANH323LIB) -L$(PWLIBDIR)/lib $(PTLIB) -L$(OPENH323DIR)/lib $(H323LIB) -L/usr/lib -lcrypto -lssl -lexpat diff --git a/net/asterisk/patches/asterisk-1.0.7-Makefile-astdb.patch b/net/asterisk/patches/asterisk-1.0.7-Makefile-astdb.patch deleted file mode 100644 index bd2c4ab9a..000000000 --- a/net/asterisk/patches/asterisk-1.0.7-Makefile-astdb.patch +++ /dev/null @@ -1,14 +0,0 @@ -diff -ruN asterisk-1.0.7-old/db1-ast/Makefile asterisk-1.0.7-new/db1-ast/Makefile ---- asterisk-1.0.7-old/db1-ast/Makefile 2004-08-31 18:33:00.000000000 +0200 -+++ asterisk-1.0.7-new/db1-ast/Makefile 2005-03-19 17:38:06.000000000 +0100 -@@ -32,8 +32,8 @@ - - $(LIBDB): $(OBJS) - rm -f $@ -- ar cq $@ $(OBJS) -- ranlib $@ -+ $(AR) cq $@ $(OBJS) -+ $(RANLIB) $@ - - $(LIBDBSO): $(SHOBJS) - $(CC) -Wl,-O1 -Wl,--version-script=libdb.map -Wl,-soname=$(LIBDBSO) -shared -o $@ $^ diff --git a/net/asterisk/patches/asterisk-1.0.7-Makefile-codecs-lpc10.patch b/net/asterisk/patches/asterisk-1.0.7-Makefile-codecs-lpc10.patch deleted file mode 100644 index 7d422500e..000000000 --- a/net/asterisk/patches/asterisk-1.0.7-Makefile-codecs-lpc10.patch +++ /dev/null @@ -1,28 +0,0 @@ -diff -ruN asterisk-1.0.7-old/codecs/lpc10/Makefile asterisk-1.0.7-new/codecs/lpc10/Makefile ---- asterisk-1.0.7-old/codecs/lpc10/Makefile 2004-08-31 18:33:00.000000000 +0200 -+++ asterisk-1.0.7-new/codecs/lpc10/Makefile 2005-03-19 17:38:06.000000000 +0100 -@@ -31,6 +31,7 @@ - ifneq ($(PROC),ppc) - ifneq ($(PROC),x86_64) - ifneq ($(PROC),alpha) -+ifneq ($(PROC),mipsel) - #The problem with sparc is the best stuff is in newer versions of gcc (post 3.0) only. - #This works for even old (2.96) versions of gcc and provides a small boost either way. - #A ultrasparc cpu is really v9 but the stock debian stable 3.0 gcc doesn.t support it. -@@ -46,6 +47,7 @@ - endif - endif - endif -+endif - - LIB = $(LIB_TARGET_DIR)/liblpc10.a - -@@ -62,7 +64,7 @@ - - $(LIB): $(OBJ) - $(AR) cr $@ $(OBJ) -- ranlib $@ -+ $(RANLIB) $@ - - clean: - -rm -f *.o $(LIB) diff --git a/net/asterisk/patches/asterisk-1.0.7-Makefile-stdtime.patch b/net/asterisk/patches/asterisk-1.0.7-Makefile-stdtime.patch deleted file mode 100644 index c454b3e41..000000000 --- a/net/asterisk/patches/asterisk-1.0.7-Makefile-stdtime.patch +++ /dev/null @@ -1,14 +0,0 @@ -diff -ruN asterisk-1.0.7-old/stdtime/Makefile asterisk-1.0.7-new/stdtime/Makefile ---- asterisk-1.0.7-old/stdtime/Makefile 2003-11-05 07:19:41.000000000 +0100 -+++ asterisk-1.0.7-new/stdtime/Makefile 2005-03-19 17:38:06.000000000 +0100 -@@ -3,8 +3,8 @@ - all: libtime.a - - libtime.a: $(OBJS) -- ar rv $@ $(OBJS) -- ranlib $@ -+ $(AR) rv $@ $(OBJS) -+ $(RANLIB) $@ - - install: - diff --git a/net/asterisk/patches/asterisk-1.0.7-chan_iax2-tmp_path.patch b/net/asterisk/patches/asterisk-1.0.7-chan_iax2-tmp_path.patch deleted file mode 100644 index 916496ea8..000000000 --- a/net/asterisk/patches/asterisk-1.0.7-chan_iax2-tmp_path.patch +++ /dev/null @@ -1,12 +0,0 @@ -diff -ruN asterisk-1.0.7-old/channels/chan_iax2.c asterisk-1.0.7-new/channels/chan_iax2.c ---- asterisk-1.0.7-old/channels/chan_iax2.c 2005-10-25 02:06:35.000000000 +0200 -+++ asterisk-1.0.7-new/channels/chan_iax2.c 2005-10-25 04:35:11.000000000 +0200 -@@ -960,7 +960,7 @@ - last++; - else - last = s; -- snprintf(s2, strlen(s) + 100, "/var/tmp/%s-%ld", last, (unsigned long)rand()); -+ snprintf(s2, strlen(s) + 100, "/tmp/%s-%ld", last, (unsigned long)rand()); - res = stat(s, &stbuf); - if (res < 0) { - ast_log(LOG_WARNING, "Failed to stat '%s': %s\n", s, strerror(errno)); diff --git a/net/asterisk/patches/asterisk-1.0.7-dns.patch b/net/asterisk/patches/asterisk-1.0.7-dns.patch deleted file mode 100644 index 23657bcc7..000000000 --- a/net/asterisk/patches/asterisk-1.0.7-dns.patch +++ /dev/null @@ -1,18 +0,0 @@ -diff -ruN asterisk-1.0.7-old/dns.c asterisk-1.0.7-new/dns.c ---- asterisk-1.0.7-old/dns.c 2004-06-22 22:11:15.000000000 +0200 -+++ asterisk-1.0.7-new/dns.c 2005-03-19 17:38:06.000000000 +0100 -@@ -153,7 +153,13 @@ - - #if defined(res_ninit) - #define HAS_RES_NINIT --#else -+#endif -+ -+#ifdef __UCLIBC__ -+#undef HAS_RES_NINIT -+#endif -+ -+#ifndef HAS_RES_NINIT - AST_MUTEX_DEFINE_STATIC(res_lock); - #if 0 - #warning "Warning, res_ninit is missing... Could have reentrancy issues" diff --git a/net/asterisk/patches/asterisk-1.0.9-chan_bluetooth.patch b/net/asterisk/patches/asterisk-1.0.9-chan_bluetooth.patch deleted file mode 100644 index 4f3425db3..000000000 --- a/net/asterisk/patches/asterisk-1.0.9-chan_bluetooth.patch +++ /dev/null @@ -1,3669 +0,0 @@ -diff -ruN asterisk-1.0.9-old/channels/Makefile asterisk-1.0.9-new/channels/Makefile ---- asterisk-1.0.9-old/channels/Makefile 2005-08-22 20:42:22.000000000 +0200 -+++ asterisk-1.0.9-new/channels/Makefile 2005-08-22 21:12:14.000000000 +0200 -@@ -202,6 +202,13 @@ - chan_h323.so: chan_h323.o h323/libchanh323.a - $(CC) $(SOLINK) -o $@ $< h323/libchanh323.a $(CHANH323LIB) -L$(PWLIBDIR)/lib $(PTLIB) -L$(OPENH323DIR)/lib $(H323LIB) -L/usr/lib -lcrypto -lssl -lexpat - -+# -+# Asterisk Bluetooth Support -+# http://www.crazygreek.co.uk/content/chan_bluetooth -+# -+chan_bluetooth.so: chan_bluetooth.o -+ $(CC) $(SOLINK) -o $@ $< $(EXTRA_LDFLAGS) -lbluetooth -+ - - #chan_modem.so : chan_modem.o - # $(CC) -rdynamic -shared -Xlinker -x -o $@ $< -diff -ruN asterisk-1.0.9-old/channels/chan_bluetooth.c asterisk-1.0.9-new/channels/chan_bluetooth.c ---- asterisk-1.0.9-old/channels/chan_bluetooth.c 1970-01-01 01:00:00.000000000 +0100 -+++ asterisk-1.0.9-new/channels/chan_bluetooth.c 2005-09-06 22:51:30.000000000 +0200 -@@ -0,0 +1,3598 @@ -+/* -+ * Asterisk -- A telephony toolkit for Linux. -+ * -+ * Asterisk Bluetooth Channel -+ * -+ * Author: Theo Zourzouvillys -+ * -+ * Adaptive Linux Solutions -+ * -+ * Copyright (C) 2004 Adaptive Linux Solutions -+ * -+ * This program is free software, distributed under the terms of -+ * the GNU General Public License -+ * -+ * ******************* NOTE NOTE NOTE NOTE NOTE ********************* -+ * -+ * This code is not at all tested, and only been developed with a -+ * HBH-200 headset and a Nokia 6310i right now. -+ * -+ * Expect it to crash, dial random numbers, and steal all your money. -+ * -+ * PLEASE try any headsets and phones, and let me know the results, -+ * working or not, along with all debug output! -+ * -+ * ------------------------------------------------------------------ -+ * -+ * Asterisk Bluetooth Support -+ * -+ * Well, here we go - Attempt to provide Handsfree profile support in -+ * both AG and HF modes, AG (AudioGateway) mode support for using -+ * headsets, and HF (Handsfree) mode for utilising mobile/cell phones -+ * -+ * It would be nice to also provide Headset support at some time in -+ * the future, however, a working Handsfree profile is nice for now, -+ * and as far as I can see, almost all new HS devices also support HF -+ * -+ * ------------------------------------------------------------------ -+ * INSTRUCTIONS -+ * -+ * You need to have bluez's bluetooth stack, along with user space -+ * tools (>=v2.10), and running hcid and sdsp. -+ * -+ * See bluetooth.conf for configuration details. -+ * -+ * - Ensure bluetooth subsystem is up and running. 'hciconfig' -+ * should show interface as UP. -+ * -+ * - If you're trying to use a headset/HS, start up asterisk, and try -+ * to pair it as you normally would. -+ * -+ * - If you're trying to use a Phone/AG, just make sure bluetooth is -+ * enabled on your phone, and start up asterisk. -+ * -+ * - 'bluetooth show peers' will show all bluetooth devices states. -+ * -+ * - Send a call out by using Dial(BLT/DevName/0123456). Call a HS -+ * with Dial(BLT/DevName) -+ * -+ * ------------------------------------------------------------------ -+ * BUGS -+ * -+ * - What should happen when an AG is paired with asterisk and -+ * someone uses the AG dalling a number manually? My test phone -+ * seems to try to open an SCO link. Perhaps an extension to -+ * route the call to, or maybe drop the RFCOM link all together? -+ * -+ * ------------------------------------------------------------------ -+ * COMPATIBILITY -+ * -+ * PLEASE email with the results of ANY -+ * device not listed in here (working or not), or if the device is -+ * listed and it doesn't work! Please also email full debug output -+ * for any device not working correctly or generating errors in log. -+ * -+ * HandsFree Profile: -+ * -+ * HS (HeadSet): -+ * - Ericsson HBH-200 -+ * -+ * AG (AudioGateway): -+ * - Nokia 6310i -+ * -+ * ------------------------------------------------------------------ -+ * -+ * Questions, bugs, or (preferably) patches to: -+ * -+ * -+ * -+ * ------------------------------------------------------------------ -+ */ -+ -+/* ---------------------------------- */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+/* --- Data types and definitions --- */ -+ -+#ifndef HANDSFREE_AUDIO_GW_SVCLASS_ID -+# define HANDSFREE_AUDIO_GW_SVCLASS_ID 0x111f -+#endif -+#define BLUETOOTH_FORMAT AST_FORMAT_SLINEAR -+#define BLT_CHAN_NAME "BLT" -+#define BLT_CONFIG_FILE "bluetooth.conf" -+#define BLT_RDBUFF_MAX 1024 -+#define BLT_DEFAULT_HCI_DEV 0 -+#define BLT_SVN_REVISION "$Rev$" -+ -+/* ---------------------------------- */ -+ -+typedef enum { -+ BLT_ROLE_NONE = 0, // Unknown Device -+ BLT_ROLE_HS = 1, // Device is a Headset -+ BLT_ROLE_AG = 2, // Device is an Audio Gateway -+ BLT_ROLE_GUI = 3 // Device is used as an GUI -+} blt_role_t; -+ -+/* State when we're in HS mode */ -+ -+typedef enum { -+ BLT_STATE_WANT_R = 0, -+ BLT_STATE_WANT_N = 1, -+ BLT_STATE_WANT_CMD = 2, -+ BLT_STATE_WANT_N2 = 3, -+} blt_state_t; -+ -+typedef enum { -+ BLT_STATUS_DOWN, -+ BLT_STATUS_CONNECTING, -+ BLT_STATUS_NEGOTIATING, -+ BLT_STATUS_READY, -+ BLT_STATUS_RINGING, -+ BLT_STATUS_IN_CALL, -+} blt_status_t; -+ -+/* ---------------------------------- */ -+ -+/* Default config settings */ -+ -+#define BLT_DEFAULT_CHANNEL_AG 5 -+#define BLT_DEFAULT_CHANNEL_HS 6 -+#define BLT_DEFAULT_CHANNEL_GUI 1 -+#define BLT_DEFAULT_ROLE BLT_ROLE_HS -+#define BLT_OBUF_LEN (48 * 25) -+ -+#define BUFLEN (4800) -+ -+/* ---------------------------------- */ -+ -+typedef struct blt_dev blt_dev_t; -+ -+void ag_cgmi_response(blt_dev_t * dev, char * cmd); -+void ag_unknown_response(blt_dev_t * dev, char * cmd); -+void ag_cgmi_valid_response(blt_dev_t * dev, char * cmd); -+void ag_clip_response(blt_dev_t * dev, char * cmd); -+void ag_cmer_response(blt_dev_t * dev, char * cmd); -+void ag_cind_status_response(blt_dev_t * dev, char * cmd); -+void ag_cind_response(blt_dev_t * dev, char * cmd); -+void ag_brsf_response(blt_dev_t * dev, char * cmd); -+void remove_sdp_records(void); -+ -+void gui_easm_response(blt_dev_t * dev, char * cmd); -+ -+int sock_err(int fd); -+int parse_clip(const char * str, char *number, int number_len, char * name, int name_len, int *type); -+int set_buffer(char * ring, char * data, int circular_len, int * pos, int data_len); -+int get_buffer(char * dst, char * ring, int ring_size, int * head, int to_copy); -+void gui_eaid_response(blt_dev_t * dev, char * cmd); -+ -+ -+ -+struct blt_ring { -+ unsigned char buf[BUFLEN]; -+}; -+// XXX:T: Tidy this lot up. -+struct blt_dev { -+ -+ blt_status_t status; /* Device Status */ -+ -+ struct ast_channel * owner; /* Channel we belong to, possibly NULL */ -+ blt_dev_t * dev; /* The bluetooth device channel is for */ -+ struct ast_frame fr; /* Recieved frame */ -+ -+ /* SCO Handler */ -+ int sco_pipe[2]; /* SCO alert pipe */ -+ int sco; /* SCO fd */ -+ int sco_handle; /* SCO Handle */ -+ int sco_mtu; /* SCO MTU */ -+ int sco_running; /* 1 when sCO thread should be running */ -+ pthread_t sco_thread; /* SCO thread */ -+ ast_mutex_t sco_lock; /* SCO lock */ -+ int sco_pos_in; /* Reader in position (drain)*/ -+ int sco_pos_inrcv; /* Reader in position (fill) */ -+ int wakeread; /* blt_read() needs to be woken */ -+ int sco_pos_out; /* Reader out position */ -+ int sco_sending; /* Sending SCO packets */ -+ char buf[1200]; /* Incoming data buffer */ -+ int bufpos; -+ char sco_buf_out[BUFLEN]; /* 24 chunks of 48 */ -+ char sco_buf_in[BUFLEN]; /* 24 chunks of 48 */ -+ -+ char dnid[1024]; /* Outgoi gncall dialed number */ -+ unsigned char * obuf[BLT_OBUF_LEN]; /* Outgoing data buffer */ -+ int obuf_len; /* Output Buffer Position */ -+ int obuf_wpos; /* Buffer Reader */ -+ -+ // device -+ int autoconnect; /* 1 for autoconnect */ -+ int outgoing_id; /* Outgoing connection scheduler id */ -+ char * name; /* Devices friendly name */ -+ blt_role_t role; /* Device role (HS or AG) */ -+ bdaddr_t bdaddr; /* remote address */ -+ int channel; /* remote channel */ -+ int rd; /* RFCOMM fd */ -+ int tmp_rd; /* RFCOMM fd */ -+ int call_cnt; /* Number of attempted calls */ -+ ast_mutex_t lock; /* RFCOMM socket lock */ -+ char rd_buff[BLT_RDBUFF_MAX]; /* RFCOMM input buffer */ -+ int rd_buff_pos; /* RFCOMM input buffer position */ -+ int ready; /* 1 When ready */ -+ char *context; -+ -+ /* AG mode */ -+ char last_ok_cmd[BLT_RDBUFF_MAX]; /* Runtime[AG]: Last AT command that was OK */ -+ int cind; /* Runtime[AG]: Recieved +CIND */ -+ int call_pos, service_pos, callsetup_pos; /* Runtime[AG]: Positions in CIND/CMER */ -+ int call, service, callsetup; /* Runtime[AG]: Values */ -+ char cid_num[AST_MAX_EXTENSION]; -+ char cid_name[AST_MAX_EXTENSION]; -+ -+ /* HS mode */ -+ blt_state_t state; /* Runtime: Device state (AG mode only) */ -+ int ring_timer; /* Runtime:Ring Timer */ -+ char last_err_cmd[BLT_RDBUFF_MAX]; /* Runtime: Last AT command that was OK */ -+ void (*cb)(blt_dev_t * dev, char * str); /* Runtime: Callback when in HS mode */ -+ -+ int brsf; /* Runtime: Bluetooth Retrieve Supported Features */ -+ int bvra; /* Runtime: Bluetooth Voice Recognised Activation */ -+ int gain_speaker; /* Runtime: Gain Of Speaker */ -+ int clip; /* Runtime: Supports CLID */ -+ int colp; /* Runtime: Connected Line ID */ -+ int elip; /* Runtime: (Ericsson) Supports CLID */ -+ int eolp; /* Runtime: (Ericsson) Connected Line ID */ -+ int ringing; /* Runtime: Device is ringing */ -+ -+ blt_dev_t * next; /* Next in linked list */ -+ -+}; -+ -+typedef struct blt_atcb { -+ -+ /* The command */ -+ char * str; -+ -+ /* DTE callbacks: */ -+ int (*set)(blt_dev_t * dev, const char * arg, int len); -+ int (*read)(blt_dev_t * dev); -+ int (*execute)(blt_dev_t * dev, const char * data); -+ int (*test)(blt_dev_t * dev); -+ -+ /* DCE callbacks: */ -+ int (*unsolicited)(blt_dev_t * dev, const char * value); -+ -+} blt_atcb_t; -+ -+/* ---------------------------------- */ -+ -+static void rd_close(blt_dev_t * dev, int reconnect, int err); -+static int send_atcmd(blt_dev_t * device, const char * fmt, ...); -+static int sco_connect(blt_dev_t * dev); -+static int sco_start(blt_dev_t * dev, int fd); -+ -+/* ---------------------------------- */ -+ -+/* RFCOMM channel we listen on*/ -+static int rfcomm_channel_ag = BLT_DEFAULT_CHANNEL_AG; -+static int rfcomm_channel_hs = BLT_DEFAULT_CHANNEL_HS; -+static int rfcomm_channel_gui = BLT_DEFAULT_CHANNEL_GUI; -+ -+static char* gui_default_sip_number = ""; -+static char* gui_default_sip_address = ""; -+ -+/* Address of local bluetooth interface */ -+static int hcidev_id; -+static bdaddr_t local_bdaddr; -+ -+/* All the current sockets */ -+AST_MUTEX_DEFINE_STATIC(iface_lock); -+static blt_dev_t * iface_head; -+static int ifcount = 0; -+ -+static int sdp_record_hs = -1; -+static int sdp_record_ag = -1; -+static int sdp_record_gui = -1; -+ -+/* RFCOMM listen socket */ -+static int rfcomm_sock_ag = -1; -+static int rfcomm_sock_hs = -1; -+static int rfcomm_sock_gui = -1; -+ -+static int sco_socket = -1; -+ -+static int monitor_pid = -1; -+ -+/* The socket monitoring thread */ -+static pthread_t monitor_thread = AST_PTHREADT_NULL; -+AST_MUTEX_DEFINE_STATIC(monitor_lock); -+ -+/* Count how many times this module is currently in use */ -+static int usecnt = 0; -+AST_MUTEX_DEFINE_STATIC(usecnt_lock); -+ -+static struct sched_context * sched = NULL; -+ -+/* ---------------------------------- */ -+ -+#if ASTERISK_VERSION_NUM <= 010107 -+#include -+#define tech_pvt pvt->pvt -+#else /* CVS. FIXME: Version number */ -+static struct ast_channel *blt_request(const char *type, int format, void *data, int *cause); -+static int blt_hangup(struct ast_channel *c); -+static int blt_answer(struct ast_channel *c); -+static struct ast_frame *blt_read(struct ast_channel *chan); -+static int blt_call(struct ast_channel *c, char *dest, int timeout); -+static int blt_write(struct ast_channel *chan, struct ast_frame *f); -+static int blt_indicate(struct ast_channel *chan, int cond); -+ -+static const struct ast_channel_tech blt_tech = { -+ .type = BLT_CHAN_NAME, -+ .description = "Bluetooth Channel Driver", -+ .capabilities = BLUETOOTH_FORMAT, -+ .requester = blt_request, -+ .hangup = blt_hangup, -+ .answer = blt_answer, -+ .read = blt_read, -+ .call = blt_call, -+ .write = blt_write, -+ .indicate = blt_indicate, -+}; -+#endif -+/* ---------------------------------- */ -+ -+static const char * -+role2str(blt_role_t role) -+{ -+ switch (role) { -+ case BLT_ROLE_HS: -+ return "HS"; -+ case BLT_ROLE_AG: -+ return "AG"; -+ case BLT_ROLE_GUI: -+ return "GUI"; -+ case BLT_ROLE_NONE: -+ default: -+ return "??"; -+ } -+} -+ -+static const char * -+status2str(blt_status_t status) -+{ -+ switch (status) { -+ case BLT_STATUS_DOWN: -+ return "Down"; -+ case BLT_STATUS_CONNECTING: -+ return "Connecting"; -+ case BLT_STATUS_NEGOTIATING: -+ return "Negotiating"; -+ case BLT_STATUS_READY: -+ return "Ready"; -+ case BLT_STATUS_RINGING: -+ return "Ringing"; -+ case BLT_STATUS_IN_CALL: -+ return "InCall"; -+ }; -+ return "Unknown"; -+} -+ -+int sock_err(int fd) -+{ -+ int ret; -+ int len = sizeof(ret); -+ getsockopt(fd, SOL_SOCKET, SO_ERROR, &ret, &len); -+ return ret; -+} -+ -+/* ---------------------------------- */ -+int parse_clip(const char * str, char *number, int number_len, char * name, int name_len, int *type) -+{ -+ const char *c = str; -+ const char *start; -+ int length; -+ char typestr[256]; -+ -+ memset(number, 0, number_len); -+ memset(name, 0, name_len); -+ *type = 0; -+ -+ number[0] = '\0'; -+ name[0] = '\0'; -+ while(*c && *c != '"') -+ c++; -+ c++; -+ start = c; -+ while(*c && *c != '"') -+ c++; -+ length = c - start < number_len ? c - start : number_len; -+ strncpy(number, start, length); -+ number[length] = '\0'; -+ c++; -+ while(*c && *c != ',') -+ c++; -+ c++; -+ start = c; -+ while(*c && *c != ',') -+ c++; -+ length = c - start < number_len ? c - start : number_len; -+ strncpy(typestr, start, length); -+ typestr[length] = '\0'; -+ *type = atoi(typestr); -+ c++; -+ while(*c && *c != ',') -+ c++; -+ c++; -+ while(*c && *c != ',') -+ c++; -+ c++; -+ while(*c && *c != '"') -+ c++; -+ c++; -+ start = c; -+ while(*c && *c != '"') -+ c++; -+ length = c - start < number_len ? c - start : number_len; -+ strncpy(name, start, length); -+ name[length] = '\0'; -+ -+ return(1); -+} -+ -+ -+static const char * -+parse_cind(const char * str, char * name, int name_len) -+{ -+ int c = 0; -+ -+ memset(name, 0, name_len); -+ -+ while (*str) { -+ if (*str == '(') { -+ if (++c == 1 && *(str+1) == '"') { -+ const char * start = str + 2; -+ int len = 0; -+ str += 2; -+ while (*str && *str != '"') { -+ len++; -+ str++; -+ } -+ if (len == 0) -+ return NULL; -+ strncpy(name, start, (len > name_len) ? name_len : len); -+ } -+ } else if (*str == ')') -+ c--; -+ else if (c == 0 && *str == ',') -+ return str + 1; -+ str++; -+ } -+ return NULL; -+} -+ -+static void -+set_cind(blt_dev_t * dev, int indicator, int val) -+{ -+ -+ ast_log(LOG_DEBUG, "CIND %d set to %d\n", indicator, val); -+ -+ if (indicator == dev->callsetup_pos) { -+ -+ // call progress -+ -+ dev->callsetup = val; -+ -+ switch (val) { -+ case 3: -+ // Outgoing ringing -+ if ((dev->owner && dev->role == BLT_ROLE_AG) || -+ (dev->owner && dev->role == BLT_ROLE_GUI)) -+ ast_queue_control(dev->owner, AST_CONTROL_RINGING); -+ break; -+ case 2: -+ break; -+ case 1: -+ break; -+ case 0: -+ if ((dev->owner && dev->role == BLT_ROLE_AG && dev->call == 0) || -+ (dev->owner && dev->role == BLT_ROLE_AG && dev->call == 0)) -+ ast_queue_control(dev->owner, AST_CONTROL_CONGESTION); -+ break; -+ } -+ -+ } else if (indicator == dev->service_pos) { -+ -+ // Signal -+ -+ if (val == 0) -+ ast_log(LOG_NOTICE, "Audio Gateway %s lost signal\n", dev->name); -+ else if (dev->service == 0 && val > 0) -+ ast_log(LOG_NOTICE, "Audio Gateway %s got signal\n", dev->name); -+ -+ dev->service = val; -+ -+ } else if (indicator == dev->call_pos) { -+ -+ // Call -+ -+ dev->call = val; -+ -+ if (dev->owner) { -+ if (val == 1) { -+ sco_start(dev, -1); -+ ast_queue_control(dev->owner, AST_CONTROL_ANSWER); -+ } else if (val == 0) -+ ast_queue_control(dev->owner, AST_CONTROL_HANGUP); -+ } -+ -+ } -+ -+ -+} -+ -+/* ---------------------------------- */ -+ -+int -+set_buffer(char * ring, char * data, int circular_len, int * pos, int data_len) -+{ -+ int start_pos = *(pos); -+ int done = 0; -+ int copy; -+ -+ while (data_len) { -+ // Set can_do to the most we can do in this copy. -+ -+ copy = MIN(circular_len - start_pos, data_len); -+ memcpy(ring + start_pos, data + done, copy); -+ done += copy; -+ start_pos += copy; -+ data_len -= copy; -+ -+ if (start_pos == circular_len) { -+ start_pos = 0; -+ } -+ } -+ *(pos) = start_pos; -+ return 0; -+} -+ -+int -+get_buffer(char * dst, char * ring, int ring_size, int * head, int to_copy) -+{ -+ int copy; -+ -+ // |1|2|3|4|5|6|7|8|9| -+ // |-----| -+ -+ while (to_copy) { -+ -+ // Set can_do to the most we can do in this copy. -+ copy = MIN(ring_size - *head, to_copy); -+ -+ // ast_log(LOG_DEBUG, "Getting: %d bytes, From pos %d\n", copy, *head); -+#if __BYTE_ORDER == __LITTLE_ENDIAN -+ memcpy(dst, ring + *head, copy); -+#else -+ // memcpy(dst, ring + *head, copy); -+ ast_swapcopy_samples(dst, ring+*head, copy/2); -+#endif -+ memset(ring+*head, 0, copy); -+ dst += copy; -+ *head += copy; -+ to_copy -= copy; -+ -+ if (*head == ring_size ) { -+ *head = 0; -+ } -+ -+ } -+ -+ return 0; -+} -+ -+/* Handle SCO audio sync. -+ * -+ * If we are the MASTER, then we control the timing, -+ * in 48 byte chunks. If we're the SLAVE, we send -+ * as and when we recieve a packet. -+ * -+ * Because of packet/timing nessecity, we -+ * start up a thread when we're passing audio, so -+ * that things are timed exactly right. -+ * -+ * sco_thread() is the function that handles it. -+ * -+ */ -+ -+static void * -+sco_thread(void * data) -+{ -+ blt_dev_t * dev = (blt_dev_t*)data; -+ int res; -+ struct pollfd pfd[2]; -+ int in_pos = 0; -+ int out_pos = 0; -+ char c = 1; -+ int sending; -+ char buf[1024]; -+ int len; -+ -+ // Avoid deadlock in odd circumstances -+ -+ ast_log(LOG_WARNING, "SCO thread started on fd %d, pid %d\n", dev->sco, getpid()); -+ -+ if (fcntl(dev->sco_pipe[1], F_SETFL, O_RDWR|O_NONBLOCK)) { -+ ast_log(LOG_WARNING, "fcntl failed on sco_pipe\n"); -+ } -+ -+ // dev->status = BLT_STATUS_IN_CALL; -+ // ast_queue_control(dev->owner, AST_CONTROL_ANSWER); -+ // Set buffer to silence, just incase. -+ -+ ast_mutex_lock(&(dev->sco_lock)); -+ -+ memset(dev->sco_buf_in, 0, BUFLEN); -+ memset(dev->sco_buf_out, 0, BUFLEN); -+ -+ dev->sco_pos_in = 0; -+ dev->sco_pos_out = 0; -+ dev->sco_pos_inrcv = 0; -+ dev->wakeread = 1; -+ -+ ast_mutex_unlock(&(dev->sco_lock)); -+ -+ while (1) { -+ -+ ast_mutex_lock(&(dev->sco_lock)); -+ -+ if (dev->sco_running != 1) { -+ ast_log(LOG_DEBUG, "SCO stopped.\n"); -+ break; -+ } -+ -+ pfd[0].fd = dev->sco; -+ pfd[0].events = POLLIN; -+ -+ pfd[1].fd = dev->sco_pipe[1]; -+ pfd[1].events = POLLIN; -+ -+ ast_mutex_unlock(&(dev->sco_lock)); -+ -+ res = poll(pfd, 2, 50); -+ -+ if (res == -1 && errno != EINTR) { -+ ast_log(LOG_DEBUG, "SCO poll() error\n"); -+ break; -+ } -+ -+ if (res == 0) -+ continue; -+ -+ -+ if (pfd[0].revents & POLLIN) { -+ -+ len = read(dev->sco, buf, 48); -+ -+ if (len) { -+ ast_mutex_lock(&(dev->lock)); -+ -+ if (dev->owner && dev->owner->_state == AST_STATE_UP) { -+ ast_mutex_lock(&(dev->sco_lock)); -+ set_buffer(dev->sco_buf_in, buf, BUFLEN, &in_pos, len); -+ dev->sco_pos_inrcv = in_pos; -+ -+ get_buffer(buf, dev->sco_buf_out, BUFLEN, &out_pos, len); -+ if (write(dev->sco, buf, len) != len) -+ ast_log(LOG_WARNING, "Wrote <48 to sco\n"); -+ -+ if (dev->wakeread) { -+ /* blt_read has caught up. Kick it */ -+ dev->wakeread = 0; -+ if(write(dev->sco_pipe[1], &c, 1) != 1) -+ ast_log(LOG_WARNING, "write to kick sco_pipe failed\n"); -+ } -+ ast_mutex_unlock(&(dev->sco_lock)); -+ } -+ ast_mutex_unlock(&(dev->lock)); -+ } -+ -+ } else if (pfd[0].revents) { -+ -+ int e = sock_err(pfd[0].fd); -+ ast_log(LOG_ERROR, "SCO connection error: %s (errno %d)\n", strerror(e), e); -+ break; -+ -+ } else if (pfd[1].revents & POLLIN) { -+ -+ int len; -+ -+ len = read(pfd[1].fd, &c, 1); -+ sending = (sending) ? 0 : 1; -+ -+ ast_mutex_unlock(&(dev->sco_lock)); -+ -+ } else if (pfd[1].revents) { -+ -+ int e = sock_err(pfd[1].fd); -+ ast_log(LOG_ERROR, "SCO pipe connection event %d on pipe[1]=%d: %s (errno %d)\n", pfd[1].revents, pfd[1].fd, strerror(e), e); -+ break; -+ -+ } else { -+ ast_log(LOG_NOTICE, "Unhandled poll output\n"); -+ ast_mutex_unlock(&(dev->sco_lock)); -+ } -+ -+ } -+ -+ ast_mutex_lock(&(dev->lock)); -+ close(dev->sco); -+ dev->sco = -1; -+ dev->sco_running = -1; -+ -+ memset(dev->sco_buf_in, 0, BUFLEN); -+ memset(dev->sco_buf_out, 0, BUFLEN); -+ -+ dev->sco_pos_in = 0; -+ dev->sco_pos_out = 0; -+ dev->sco_pos_inrcv = 0; -+ -+ ast_mutex_unlock(&(dev->sco_lock)); -+ if (dev->owner) -+ ast_queue_control(dev->owner, AST_CONTROL_HANGUP); -+ ast_mutex_unlock(&(dev->lock)); -+ ast_log(LOG_DEBUG, "SCO thread stopped\n"); -+ return NULL; -+} -+ -+/* Start SCO thread. Must be called with dev->lock */ -+ -+static int -+sco_start(blt_dev_t * dev, int fd) -+{ -+ -+ if (dev->sco_pipe[1] <= 0) { -+ ast_log(LOG_ERROR, "SCO pipe[1] == %d\n", dev->sco_pipe[1]); -+ return -1; -+ } -+ -+ ast_mutex_lock(&(dev->sco_lock)); -+ -+ if (dev->sco_running != -1) { -+ ast_log(LOG_ERROR, "Tried to start SCO thread while already running\n"); -+ ast_mutex_unlock(&(dev->sco_lock)); -+ return -1; -+ } -+ -+ if (dev->sco == -1) { -+ if (fd > 0) { -+ dev->sco = fd; -+ } else if (sco_connect(dev) != 0) { -+ ast_log(LOG_ERROR, "SCO fd invalid\n"); -+ ast_mutex_unlock(&(dev->sco_lock)); -+ return -1; -+ } -+ } -+ -+ dev->sco_running = 1; -+ -+ if (ast_pthread_create(&(dev->sco_thread), NULL, sco_thread, dev) < 0) { -+ ast_log(LOG_ERROR, "Unable to start SCO thread.\n"); -+ dev->sco_running = -1; -+ ast_mutex_unlock(&(dev->sco_lock)); -+ return -1; -+ } -+ -+ ast_mutex_unlock(&(dev->sco_lock)); -+ -+ return 0; -+} -+ -+/* Stop SCO thread. Must be called with dev->lock */ -+ -+static int -+sco_stop(blt_dev_t * dev) -+{ -+ ast_mutex_lock(&(dev->sco_lock)); -+ if (dev->sco_running == 1) -+ dev->sco_running = 0; -+ else -+ dev->sco_running = -1; -+ dev->sco_sending = 0; -+ ast_mutex_unlock(&(dev->sco_lock)); -+ return 0; -+} -+ -+/* ---------------------------------- */ -+ -+/* Answer the call. Call with lock held on device */ -+ -+static int -+answer(blt_dev_t * dev) -+{ -+ -+ if ( (!dev->owner) || (dev->ready != 1) || (dev->status != BLT_STATUS_READY && dev->status != BLT_STATUS_RINGING)) { -+ ast_log(LOG_ERROR, "Attempt to answer() in invalid state (owner=%p, ready=%d, status=%s)\n", -+ dev->owner, dev->ready, status2str(dev->status)); -+ return -1; -+ } -+ -+ // dev->sd = sco_connect(&local_bdaddr, &(dev->bdaddr), NULL, NULL, 0); -+ // dev->status = BLT_STATUS_IN_CALL; -+ // dev->owner->fds[0] = dev->sd; -+ // if we are answering (hitting button): -+ ast_queue_control(dev->owner, AST_CONTROL_ANSWER); -+ // if asterisk signals us to answer: -+ // ast_setstate(ast, AST_STATE_UP); -+ -+ /* Start SCO link */ -+ sco_start(dev, -1); -+ return 0; -+} -+ -+/* ---------------------------------- */ -+ -+static int -+blt_write(struct ast_channel * ast, struct ast_frame * frame) -+{ -+ blt_dev_t * dev = ast->tech_pvt; -+ -+ /* Write a frame of (presumably voice) data */ -+ -+ if (frame->frametype != AST_FRAME_VOICE) { -+ ast_log(LOG_WARNING, "Don't know what to do with frame type '%d'\n", frame->frametype); -+ return 0; -+ } -+ -+ if (!(frame->subclass & BLUETOOTH_FORMAT)) { -+ static int fish = 5; -+ if (fish) { -+ ast_log(LOG_WARNING, "Cannot handle frames in format %d\n", frame->subclass); -+ fish--; -+ } -+ return 0; -+ } -+ -+ if (ast->_state != AST_STATE_UP) { -+ return 0; -+ } -+ -+ ast_mutex_lock(&(dev->sco_lock)); -+ set_buffer(dev->sco_buf_out, frame->data, BUFLEN, &(dev->sco_pos_out), MIN(frame->datalen, BUFLEN)); -+ ast_mutex_unlock(&(dev->sco_lock)); -+ -+ return 0; -+ -+} -+ -+static struct ast_frame * -+blt_read(struct ast_channel * ast) -+{ -+ blt_dev_t * dev = ast->tech_pvt; -+ char c = 1; -+ int len; -+ static int fish = 0; -+ /* Some nice norms */ -+ -+ dev->fr.datalen = 0; -+ dev->fr.samples = 0; -+ dev->fr.data = NULL; -+ dev->fr.src = BLT_CHAN_NAME; -+ dev->fr.offset = 0; -+ dev->fr.mallocd = AST_MALLOCD_DATA; -+ dev->fr.delivery.tv_sec = 0; -+ dev->fr.delivery.tv_usec = 0; -+ read(dev->sco_pipe[0], &c, 1); -+ ast_mutex_lock(&(dev->sco_lock)); -+ dev->sco_sending = 1; -+ -+ if (dev->sco_pos_inrcv < dev->sco_pos_in) { -+ /* Buffer wrapped. Read only till the end */ -+ len = BUFLEN - dev->sco_pos_in + dev->sco_pos_inrcv; -+ } else { -+ len = dev->sco_pos_inrcv - dev->sco_pos_in; -+ } -+ dev->fr.data = malloc(AST_FRIENDLY_OFFSET+len) + AST_FRIENDLY_OFFSET; -+ -+ get_buffer(dev->fr.data, dev->sco_buf_in, BUFLEN, &(dev->sco_pos_in), len); -+ dev->wakeread = 1; -+ ast_mutex_unlock(&(dev->sco_lock)); -+ if (fish) { -+ unsigned char *x = dev->fr.data; -+ ast_log(LOG_WARNING, "blt_read %d: %02x %02x %02x %02x %02x %02x\n", -+ dev->fr.datalen, x[0], x[1], x[2], x[3], x[4], x[5]); -+ fish--; -+ } -+ -+ dev->fr.samples = len / 2; -+ dev->fr.datalen = len; -+ dev->fr.frametype = AST_FRAME_VOICE; -+ dev->fr.subclass = BLUETOOTH_FORMAT; -+ dev->fr.offset = AST_FRIENDLY_OFFSET; -+ return &dev->fr; -+} -+ -+/* Escape Any '"' in str. Return malloc()ed string */ -+static char * -+escape_str(char * str) -+{ -+ char * ptr = str; -+ char * pret; -+ char * ret; -+ int len = 0; -+ -+ while (*ptr) { -+ if (*ptr == '"') -+ len++; -+ len++; -+ ptr++; -+ } -+ -+ ret = malloc(len + 1); -+ pret = memset(ret, 0, len + 1); -+ -+ ptr = str; -+ -+ while (*ptr) { -+ if (*ptr == '"') -+ *pret++ = '\\'; -+ *pret++ = *ptr++; -+ } -+ -+ return ret; -+} -+ -+static int -+ring_hs(blt_dev_t * dev) -+{ -+#if (ASTERISK_VERSION_NUM < 010100) -+ char tmp[AST_MAX_EXTENSION]; -+ char *name, *num; -+#endif -+ -+ ast_mutex_lock(&(dev->lock)); -+ -+ if (dev->owner == NULL) { -+ ast_mutex_unlock(&(dev->lock)); -+ return 0; -+ } -+ -+ dev->ringing = 1; -+ dev->status = BLT_STATUS_RINGING; -+ -+ send_atcmd(dev, "RING"); -+ -+ dev->owner->rings++; -+ -+ // XXX:T: '"' needs to be escaped in ELIP. -+ -+#if (ASTERISK_VERSION_NUM < 010100) -+ -+ if (dev->owner->callerid) { -+ -+ memset(tmp, 0, sizeof(tmp)); -+ strncpy(tmp, dev->owner->callerid, sizeof(tmp)-1); -+ -+ if (!ast_callerid_parse(tmp, &name, &num)) { -+ -+ if (dev->clip && num) -+ send_atcmd(dev, "+CLIP: \"%s\",129", num); -+ -+ if (dev->elip && name) { -+ char * esc = escape_str(name); -+ send_atcmd(dev, "*ELIP: \"%s\"", esc); -+ free(esc); -+ } -+ } -+ } -+ -+ -+#else -+ -+ if (dev->clip && dev->owner->cid.cid_num) -+ send_atcmd(dev, "+CLIP: \"%s\",129", dev->owner->cid.cid_num); -+ -+ if (dev->elip && dev->owner->cid.cid_name) { -+ char * esc = escape_str(dev->owner->cid.cid_name); -+ send_atcmd(dev, "*ELIP: \"%s\"", esc); -+ free(esc); -+ } -+ -+#endif -+ -+ ast_mutex_unlock(&(dev->lock)); -+ -+ return 1; -+} -+ -+/* -+ * If the HS is already connected, then just send RING, otherwise, things get a -+ * little more sticky. We first have to find the channel for HS using SDP, -+ * then initiate the connection. Once we've done that, we can start the call. -+ */ -+ -+static int -+blt_call(struct ast_channel * ast, char * dest, int timeout) -+{ -+ blt_dev_t * dev = ast->tech_pvt; -+ -+ if ((ast->_state != AST_STATE_DOWN) && (ast->_state != AST_STATE_RESERVED)) { -+ ast_log(LOG_WARNING, "blt_call called on %s, neither down nor reserved\n", ast->name); -+ return -1; -+ } -+ -+ ast_log(LOG_DEBUG, "Calling %s on %s [t: %d]\n", dest, ast->name, timeout); -+ -+ if (ast_mutex_lock(&iface_lock)) { -+ ast_log(LOG_ERROR, "Failed to get iface_lock.\n"); -+ return -1; -+ } -+ -+// ast_mutex_lock(&(dev->lock)); -+ -+ if (dev->ready == 0) { -+ ast_log(LOG_WARNING, "Tried to call a device not ready/connected.\n"); -+ ast_setstate(ast, AST_CONTROL_CONGESTION); -+// ast_mutex_unlock(&(dev->lock)); -+ ast_mutex_unlock(&iface_lock); -+ return 0; -+ } -+ -+ if (dev->role == BLT_ROLE_HS) { -+ -+ send_atcmd(dev, "+CIEV: 3,1"); -+ -+ dev->ring_timer = ast_sched_add(sched, 5000, AST_SCHED_CB(ring_hs), dev); -+ -+ ring_hs(dev); -+ -+ ast_setstate(ast, AST_STATE_RINGING); -+ ast_queue_control(ast, AST_CONTROL_RINGING); -+ -+ } else if (dev->role == BLT_ROLE_AG) { -+ -+ send_atcmd(dev, "ATD%s;", dev->dnid); -+// it does not seem like we should start the audio until the call is connected -+// sco_start(dev, -1); -+ } else if (dev->role == BLT_ROLE_GUI) { -+ -+ send_atcmd(dev, "ATD%s;", dev->dnid); -+ -+ } else { -+ -+ ast_setstate(ast, AST_CONTROL_CONGESTION); -+ ast_log(LOG_ERROR, "Unknown device role\n"); -+ -+ } -+ -+// ast_mutex_unlock(&(dev->lock)); -+ ast_mutex_unlock(&iface_lock); -+ -+ return 0; -+} -+ -+static int -+blt_hangup(struct ast_channel * ast) -+{ -+ blt_dev_t * dev = ast->tech_pvt; -+ -+ ast_log(LOG_DEBUG, "blt_hangup(%s)\n", ast->name); -+ -+ if (!ast->tech_pvt) { -+ ast_log(LOG_WARNING, "Asked to hangup channel not connected\n"); -+ return 0; -+ } -+ -+ if (ast_mutex_lock(&iface_lock)) { -+ ast_log(LOG_ERROR, "Failed to get iface_lock\n"); -+ return 0; -+ } -+ -+ ast_mutex_lock(&(dev->lock)); -+ -+ sco_stop(dev); -+ dev->sco_sending = 0; -+ -+ if (dev->role == BLT_ROLE_HS) { -+ -+ if (dev->ringing == 0) { -+ // Actual call in progress -+ send_atcmd(dev, "+CIEV: 2,0"); -+ } else { -+ -+ // Just ringing still -+ -+ if (dev->role == BLT_ROLE_HS) -+ send_atcmd(dev, "+CIEV: 3,0"); -+ -+ if (dev->ring_timer >= 0) -+ ast_sched_del(sched, dev->ring_timer); -+ -+ dev->ring_timer = -1; -+ dev->ringing = 0; -+ -+ } -+ -+ } else if (dev->role == BLT_ROLE_AG) { -+ -+ // Cancel call. -+ send_atcmd(dev, "ATH"); -+ send_atcmd(dev, "AT+CHUP"); -+ -+ } -+ -+ if (dev->status == BLT_STATUS_IN_CALL || dev->status == BLT_STATUS_RINGING) -+ dev->status = BLT_STATUS_READY; -+ -+ ast->tech_pvt = NULL; -+ dev->owner = NULL; -+ ast_mutex_unlock(&(dev->lock)); -+ ast_setstate(ast, AST_STATE_DOWN); -+ ast_mutex_unlock(&(iface_lock)); -+ -+ return 0; -+} -+ -+static int -+blt_indicate(struct ast_channel * c, int condition) -+{ -+ ast_log(LOG_DEBUG, "blt_indicate (%d)\n", condition); -+ -+ switch(condition) { -+ case AST_CONTROL_RINGING: -+ return -1; -+ default: -+ ast_log(LOG_WARNING, "Don't know how to condition %d\n", condition); -+ break; -+ } -+ return -1; -+} -+ -+static int -+blt_answer(struct ast_channel * ast) -+{ -+ blt_dev_t * dev = ast->tech_pvt; -+ -+ ast_mutex_lock(&dev->lock); -+ -+ // if (dev->ring_timer >= 0) -+ // ast_sched_del(sched, dev->ring_timer); -+ // dev->ring_timer = -1; -+ -+ ast_log(LOG_DEBUG, "Answering interface\n"); -+ -+ if (ast->_state != AST_STATE_UP) { -+ send_atcmd(dev, "+CIEV: 2,1"); -+ send_atcmd(dev, "+CIEV: 3,0"); -+ sco_start(dev, -1); -+ ast_setstate(ast, AST_STATE_UP); -+ } -+ -+ ast_mutex_unlock(&dev->lock); -+ -+ return 0; -+} -+ -+static struct ast_channel * -+blt_new(blt_dev_t * dev, int state, const char * context, const char * number) -+{ -+ struct ast_channel * ast; -+ char c = 0; -+ -+ if ((ast = ast_channel_alloc(1)) == NULL) { -+ ast_log(LOG_WARNING, "Unable to allocate channel structure\n"); -+ return NULL; -+ } -+ -+ snprintf(ast->name, sizeof(ast->name), "BLT/%s", dev->name); -+ -+ // ast->fds[0] = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_SCO); -+ -+ ast->nativeformats = BLUETOOTH_FORMAT; -+ //ast->rawreadformat = BLUETOOTH_FORMAT; -+ //ast->rawwriteformat = BLUETOOTH_FORMAT; -+ ast->writeformat = BLUETOOTH_FORMAT; -+ ast->readformat = BLUETOOTH_FORMAT; -+ -+ ast_setstate(ast, state); -+ -+ ast->type = BLT_CHAN_NAME; -+ -+ ast->tech_pvt = dev; -+#if ASTERISK_VERSION_NUM > 010107 -+ ast->tech = &blt_tech; -+#else -+ ast->pvt->call = blt_call; -+ ast->pvt->indicate = blt_indicate; -+ ast->pvt->hangup = blt_hangup; -+ ast->pvt->read = blt_read; -+ ast->pvt->write = blt_write; -+ ast->pvt->answer = blt_answer; -+#endif -+ strncpy(ast->context, context, sizeof(ast->context)-1); -+ strncpy(ast->exten, number, sizeof(ast->exten) - 1); -+ if(0 == strcmp(number, "s")) -+ { -+ //ast_set_callerid(ast, dev->cid_num, dev->cid_name, dev->cid_num); -+ } -+ -+ ast->language[0] = '\0'; -+ -+ ast->fds[0] = dev->sco_pipe[0]; -+ write(dev->sco_pipe[1], &c, 1); -+ -+ dev->owner = ast; -+ -+ ast_mutex_lock(&usecnt_lock); -+ usecnt++; -+ ast_mutex_unlock(&usecnt_lock); -+ -+ ast_update_use_count(); -+ -+ if (state != AST_STATE_DOWN) { -+ if (ast_pbx_start(ast)) { -+ ast_log(LOG_WARNING, "Unable to start PBX on %s\n", ast->name); -+ ast_hangup(ast); -+ } -+ } -+ -+ return ast; -+} -+ -+static struct ast_channel * -+#if (ASTERISK_VERSION_NUM < 010100) -+blt_request(char * type, int format, void * local_data) -+#elif (ASTERISK_VERSION_NUM <= 010107) -+blt_request(const char * type, int format, void * local_data) -+#else -+blt_request(const char * type, int format, void * local_data, int *cause) -+#endif -+{ -+ char * data = (char*)local_data; -+ int oldformat; -+ blt_dev_t * dev = NULL; -+ struct ast_channel * ast = NULL; -+ char * number = data, * dname; -+ -+ dname = strsep(&number, "/"); -+ -+ oldformat = format; -+ -+ format &= BLUETOOTH_FORMAT; -+ -+ if (!format) { -+ ast_log(LOG_NOTICE, "Asked to get a channel of unsupported format '%d'\n", oldformat); -+ return NULL; -+ } -+ -+ ast_log(LOG_DEBUG, "Dialing '%s' via '%s'\n", number, dname); -+ -+ if (ast_mutex_lock(&iface_lock)) { -+ ast_log(LOG_ERROR, "Unable to lock iface_list\n"); -+ return NULL; -+ } -+ -+ dev = iface_head; -+ -+ while (dev) { -+ if (strcmp(dev->name, dname) == 0) { -+ ast_mutex_lock(&(dev->lock)); -+ if (!dev->ready) { -+ ast_log(LOG_ERROR, "Device %s is not connected\n", dev->name); -+ ast_mutex_unlock(&(dev->lock)); -+ ast_mutex_unlock(&iface_lock); -+ return NULL; -+ } -+ break; -+ } -+ dev = dev->next; -+ } -+ -+ ast_mutex_unlock(&iface_lock); -+ -+ if (!dev) { -+ ast_log(LOG_WARNING, "Failed to find device named '%s'\n", dname); -+ return NULL; -+ } -+ -+ if (number && dev->role != BLT_ROLE_AG) { -+ ast_log(LOG_WARNING, "Tried to send a call out on non AG\n"); -+ ast_mutex_unlock(&(dev->lock)); -+ return NULL; -+ } -+ -+ if (dev->role == BLT_ROLE_AG) -+ strncpy(dev->dnid, number, sizeof(dev->dnid) - 1); -+ -+ ast = blt_new(dev, AST_STATE_DOWN, dev->context, "s"); -+ -+ ast_mutex_unlock(&(dev->lock)); -+ -+ return ast; -+} -+ -+/* ---------------------------------- */ -+ -+ -+/* ---- AT COMMAND SOCKET STUFF ---- */ -+ -+static int -+send_atcmd(blt_dev_t * dev, const char * fmt, ...) -+{ -+ char buf[1024]; -+ va_list ap; -+ int len; -+ -+ va_start(ap, fmt); -+ len = vsnprintf(buf, 1023, fmt, ap); -+ va_end(ap); -+ -+ if (option_verbose) -+ ast_verbose(VERBOSE_PREFIX_1 "[%s] %*s < %s\n", role2str(dev->role), 10, dev->name, buf); -+ -+ write(dev->rd, "\r\n", 2); -+ len = write(dev->rd, buf, len); -+ write(dev->rd, "\r\n", 2); -+ return (len) ? 0 : -1; -+} -+ -+ -+static int -+send_atcmd_ok(blt_dev_t * dev, const char * cmd) -+{ -+ int len; -+ strncpy(dev->last_ok_cmd, cmd, BLT_RDBUFF_MAX - 1); -+ if (option_verbose) -+ ast_verbose(VERBOSE_PREFIX_1 "[%s] %*s < OK\n", role2str(dev->role), 10, dev->name); -+ len = write(dev->rd, "\r\nOK\r\n", 6); -+ return (len) ? 0 : -1; -+} -+ -+static int -+send_atcmd_error(blt_dev_t * dev) -+{ -+ int len; -+ -+ if (option_verbose) -+ ast_verbose(VERBOSE_PREFIX_1 "[%s] %*s < ERROR\n", role2str(dev->role), 10, dev->name); -+ -+// write(dev->rd, "\r\n", 2); -+// len = write(dev->rd, dev->last_ok_cmd, 5); -+ write(dev->rd, "\r\n", 2); -+ len = write(dev->rd, "ERROR", 5); -+ write(dev->rd, "\r\n", 2); -+ -+ return (len) ? 0 : -1; -+} -+ -+ -+/* ---------------------------------- */ -+ -+/* -- Handle negotiation when we're an AG -- */ -+ -+/* Bluetooth Support */ -+ -+static int -+atcmd_brsf_set(blt_dev_t * dev, const char * arg, int len) -+{ -+ ast_log(LOG_DEBUG, "Device Supports: %s\n", arg); -+ dev->brsf = atoi(arg); -+ send_atcmd(dev, "+BRSF: %d", 23); -+ return 0; -+} -+ -+/* Bluetooth Voice Recognition */ -+ -+static int -+atcmd_bvra_set(blt_dev_t * dev, const char * arg, int len) -+{ -+ ast_log(LOG_WARNING, "+BVRA Not Yet Supported\n"); -+ return -1; -+#if 0 -+ // XXX:T: Fix voice recognition somehow! -+ int action = atoi(arg); -+ ast_log(LOG_DEBUG, "Voice Recognition: %s\n", (a) ? "ACTIVATED" : "DEACTIVATED"); -+ if ((action == 0) & (dev->bvra == 1)) { -+ /* Disable it */ -+ dev->bvra = 0; -+ // XXX:T: Shutdown any active bvra channel -+ ast_log(LOG_DEBUG, "Voice Recognition: DISABLED\n"); -+ } else if ((action == 1) && (dev->bvra == 0)) { -+ /* Enable it */ -+ dev->bvra = 1; -+ // XXX:T: Schedule connection to voice recognition extension/application -+ ast_log(LOG_DEBUG, "Voice Recognition: ENABLED\n"); -+ } else { -+ ast_log(LOG_ERROR, "+BVRA out of sync (we think %d, but HS wants %d)\n", dev->bvra, action); -+ return -1; -+ } -+ return 0; -+#endif -+} -+ -+/* Clock */ -+ -+static int -+atcmd_cclk_read(blt_dev_t * dev) -+{ -+ struct tm t, *tp; -+ const time_t ti = time(0); -+ tp = localtime_r(&ti, &t); -+ send_atcmd(dev, "+CCLK: \"%02d/%02d/%02d,%02d:%02d:%02d+%02d\"", -+ (tp->tm_year % 100), (tp->tm_mon + 1), (tp->tm_mday), -+ tp->tm_hour, tp->tm_min, tp->tm_sec, ((tp->tm_gmtoff / 60) / 15)); -+ return 0; -+} -+ -+/* CHUP - Hangup Call */ -+ -+static int -+atcmd_chup_execute(blt_dev_t * dev, const char * data) -+{ -+ if (!dev->owner) { -+ ast_log(LOG_ERROR, "Request to hangup call when none in progress\n"); -+ return -1; -+ } -+ ast_log(LOG_DEBUG, "Hangup Call\n"); -+ ast_queue_control(dev->owner, AST_CONTROL_HANGUP); -+ return 0; -+} -+ -+/* CIND - Call Indicator */ -+ -+static int -+atcmd_cind_read(blt_dev_t * dev) -+{ -+ send_atcmd(dev, "+CIND: 1,0,0"); -+ return 0; -+} -+ -+static int -+atcmd_cind_test(blt_dev_t * dev) -+{ -+ send_atcmd(dev, "+CIND: (\"service\",(0,1)),(\"call\",(0,1)),(\"callsetup\",(0-4))"); -+ return 0; -+} -+ -+/* Set Language */ -+ -+static int -+atcmd_clan_read(blt_dev_t * dev) -+{ -+ send_atcmd(dev, "+CLAN: \"en\""); -+ return 0; -+} -+ -+/* Caller Id Presentation */ -+ -+static int -+atcmd_clip_set(blt_dev_t * dev, const char * arg, int len) -+{ -+ dev->clip = atoi(arg); -+ return 0; -+} -+ -+/* Connected Line Identification Presentation */ -+ -+static int -+atcmd_colp_set(blt_dev_t * dev, const char * arg, int len) -+{ -+ dev->colp = atoi(arg); -+ return 0; -+} -+ -+/* CMER - Mobile Equipment Event Reporting */ -+ -+static int -+atcmd_cmer_set(blt_dev_t * dev, const char * arg, int len) -+{ -+ dev->ready = 1; -+ dev->status = BLT_STATUS_READY; -+ return 0; -+} -+ -+/* PhoneBook Types: -+ * -+ * - FD - SIM Fixed Dialing Phone Book -+ * - ME - ME Phone book -+ * - SM - SIM Phone Book -+ * - DC - ME dialled-calls list -+ * - RC - ME recieved-calls lisr -+ * - MC - ME missed-calls list -+ * - MV - ME Voice Activated Dialing List -+ * - HP - Hierachial Phone Book -+ * - BC - Own Business Card (PIN2 required) -+ * -+ */ -+ -+/* Read Phone Book Entry */ -+ -+static int -+atcmd_cpbr_set(blt_dev_t * dev, const char * arg, int len) -+{ -+ // XXX:T: Fix the phone book! -+ // * Maybe add res_phonebook or something? */ -+ send_atcmd(dev, "+CPBR: %d,\"%s\",128,\"%s\"", atoi(arg), arg, arg); -+ return 0; -+} -+ -+/* Select Phone Book */ -+ -+static int -+atcmd_cpbs_set(blt_dev_t * dev, const char * arg, int len) -+{ -+ // XXX:T: I guess we'll just accept any? -+ return 0; -+} -+ -+static int -+atcmd_cscs_set(blt_dev_t * dev, const char * arg, int len) -+{ -+ // XXX:T: Language -+ return 0; -+} -+ -+static int -+atcmd_eips_set(blt_dev_t * dev, const char * arg, int len) -+{ -+ ast_log(LOG_DEBUG, "Identify Presentation Set: %s=%s\n", -+ (*(arg) == 49) ? "ELIP" : "EOLP", -+ (*(arg+2) == 49) ? "ON" : "OFF"); -+ -+ if (*(arg) == 49) -+ dev->eolp = (*(arg+2) == 49) ? 1 : 0; -+ else -+ dev->elip = (*(arg+2) == 49) ? 1 : 0; -+ -+ return 0; -+} -+ -+/* VGS - Speaker Volume Gain */ -+ -+static int -+atcmd_vgs_set(blt_dev_t * dev, const char * arg, int len) -+{ -+ dev->gain_speaker = atoi(arg); -+ return 0; -+} -+ -+void -+gui_eaid_response(blt_dev_t * dev, char * cmd) -+{ -+ ast_log(LOG_NOTICE, "Submenu displayed.\n"); -+} -+ -+static int -+atcmd_eami_execute(blt_dev_t * dev, const char * data) -+{ -+ char * number = NULL; -+ -+ number = strndup(data, strlen(data)); -+ int menuitem = atoi(number); -+ -+ ast_log(LOG_NOTICE, "Menu Item '%d'.\n", menuitem); -+ -+ dev->cb = gui_eaid_response; -+ -+ if (menuitem == 1) { -+ char command[1024] = ""; -+ const char* c1 = "AT*EAID=8,1,\"Make a SIP call\",\"Number\",\""; -+ const char* c2 = "\""; -+ -+ (void)strncat(command, c1, sizeof(command) - strlen(command) - 1); -+ (void)strncat(command, gui_default_sip_number, sizeof(command) - strlen(command) - 1); -+ (void)strncat(command, c2, sizeof(command) - strlen(command) - 1); -+ -+ //strcat(command, "AT*EAID=8,1,\"Make a SIP call\",\"Number\",\""); -+ //strcat(command, gui_default_sip_number); -+ //strcat(command, "\""); -+ send_atcmd(dev, command); -+ } else if (menuitem == 2) { -+ char command[1024] = ""; -+ const char* c1 = "AT*EAID=11,1,\"Make a SIP call\",\"SIP Address\",100,\""; -+ const char* c2 = "\""; -+ -+ (void)strncat(command, c1, sizeof(command) - strlen(command) - 1); -+ (void)strncat(command, gui_default_sip_address, sizeof(command) - strlen(command) - 1); -+ (void)strncat(command, c2, sizeof(command) - strlen(command) - 1); -+ -+ //strcat(command, "AT*EAID=11,1,\"Make a SIP call\",\"SIP Address\",100,\""); -+ //strcat(command, gui_default_sip_address); -+ //strcat(command, "\""); -+ send_atcmd(dev, command); -+ } else if (menuitem == 0) { -+ dev->cb = gui_easm_response; -+// send_atcmd(dev,"AT*EASM=\"SIP Menu\",1,1,3,\"Call Number\",\"Call Address\",\"More Options\",1"); -+ send_atcmd(dev,"AT*EASM=\"SIP Menu\",1,1,2,\"Call Number\",\"Call Address\",1"); -+ } else { -+ ast_log(LOG_ERROR, "Menu item not implementented.\n"); -+ } -+ return 0; -+} -+ -+static int -+atcmd_eaii_execute(blt_dev_t * dev, const char * data) -+{ -+ int pos = 1, len = 0; -+ char type[128]; -+ char val[128]; -+ const char * start = data; -+ struct sockaddr_in addr; -+ -+ while (*data) { -+ if (*data == ',') { -+ memset(type, 0, 128); -+ strncpy(type, start, len); -+ -+ ast_log(LOG_NOTICE, "Number(8)/Address(11): '%s'.\n", type); -+ -+ pos++; -+ len = 0; -+ data++; -+ start = data; -+ continue; -+ } -+ len++; -+ data++; -+ } -+ -+ memset(val, 0, 128); -+ strncpy(val, start, len); -+ -+ char del[]= "\""; -+ char* address; -+ address = strtok(val, del); -+ int type_int = atoi(type); -+ -+ if (strcmp(address, " 0") == 0) { -+ ast_log(LOG_NOTICE, "Spurious EAII:\n"); -+ ast_log(LOG_NOTICE, data); -+ return 0; -+ } -+ -+ if (type_int == 8) { -+ (void)strncat(address, "@sipgate.de", sizeof(address) - strlen(address) - 1); -+ } -+ -+ ast_log(LOG_NOTICE, "SIP number/address: '%i','%s'.\n", type_int, address); -+ -+ if (type_int == 8 || type_int == 11) { -+ -+ char messagebox[1024] = ""; -+ const char* mb1 = "AT*EAID=1,1,\"Setting up SIP call to "; -+ const char* mb2 = "\",30"; -+ -+ (void)strncat(messagebox, mb1, sizeof(messagebox) - strlen(messagebox) - 1); -+ (void)strncat(messagebox, address, sizeof(messagebox) - strlen(messagebox) - 1); -+ (void)strncat(messagebox, mb2, sizeof(messagebox) - strlen(messagebox) - 1); -+ -+ //strcat(messagebox, "AT*EAID=1,1,\"Setting up SIP call to "); -+ //strcat(messagebox, address); -+ //strcat(messagebox, "\",30"); -+ send_atcmd(dev, messagebox); -+ -+ send_atcmd(dev, "AT*ESKS=2"); -+ send_atcmd(dev, "AT*EKSP"); -+ send_atcmd(dev, "AT*ESKS=0"); -+ -+ //Create manager connection to create call -+ int s = socket(AF_INET,SOCK_STREAM,0); -+ if (s < 0) { -+ ast_log(LOG_ERROR, "Manager connection failed."); -+ -+ dev->cb = ag_cgmi_response; -+ send_atcmd(dev, "AT*EAID=1,1,\"Call failed\""); -+ return -1; -+ } -+ addr.sin_family = AF_INET; -+ addr.sin_port = htons(5038); -+ addr.sin_addr.s_addr = inet_addr("127.0.0.1"); -+ memset(&(addr.sin_zero), '\0', 8); -+ -+ if (connect(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) { -+ ast_log(LOG_ERROR, "Manager connection failed. (2)"); -+ dev->cb = ag_cgmi_response; -+ send_atcmd(dev, "AT*EAID=1,1,\"Call failed\""); -+ return -1; -+ } -+ char* command = "Action: login\r\nUsername: markus\r\nSecret: supAEr\r\n\r\n"; -+ if (write(s,command,strlen(command)) < 0) { -+ ast_log(LOG_ERROR, "Manager connection failed. (3)"); -+ dev->cb = ag_cgmi_response; -+ send_atcmd(dev, "AT*EAID=1,1,\"Call failed\""); -+ return -1; -+ } -+ -+ char command3[1024] = ""; -+ const char* action = "Action: Originate\r\nChannel: SIP/"; -+ const char* action2 = "\r\nExten: 1235\r\nPriority: 1\r\nContext: sipgate.de\r\n\r\nAction: logoff\r\n\r\n"; -+ -+ (void)strncat(command3, action, sizeof(command3) - strlen(command3) - 1); -+ (void)strncat(command3, address, sizeof(command3) - strlen(command3) - 1); -+ (void)strncat(command3, action2, sizeof(command3) - strlen(command3) - 1); -+ -+ //strcat(command3, "Action: Originate\r\nChannel: SIP/"); -+ //strcat(command3, address); -+ //strcat(command3, "\r\nExten: 1235\r\nPriority: 1\r\nContext: sipgate.de\r\n\r\n"); -+ ast_log(LOG_NOTICE, command3); -+ -+ if (write(s,command3,strlen(command3)) < 0) { -+ ast_log(LOG_ERROR, "Manager connection failed. (5)"); -+ return -1; -+ } -+ } -+ //dev->cb = ag_cgmi_response; -+ return 0; -+} -+ -+/* Dial */ -+static int -+atcmd_dial_execute(blt_dev_t * dev, const char * data) -+{ -+ char * number = NULL; -+ -+ /* Make sure there is a ';' at the end of the line */ -+ if (*(data + (strlen(data) - 1)) != ';') { -+ ast_log(LOG_WARNING, "Can't dial non-voice right now: %s\n", data); -+ return -1; -+ } -+ -+ number = strndup(data, strlen(data) - 1); -+ ast_log(LOG_NOTICE, "Dial: [%s]\n", number); -+ -+ send_atcmd(dev, "+CIEV: 2,1"); -+ send_atcmd(dev, "+CIEV: 3,0"); -+ -+ sco_start(dev, -1); -+ -+ if (blt_new(dev, AST_STATE_UP, dev->context, number) == NULL) { -+ sco_stop(dev); -+ } -+ -+ free(number); -+ -+ return 0; -+} -+ -+static int atcmd_bldn_execute(blt_dev_t * dev, const char *data) -+{ -+ return atcmd_dial_execute(dev, "bldn;"); -+} -+ -+/* Answer */ -+ -+static int -+atcmd_answer_execute(blt_dev_t * dev, const char * data) -+{ -+ -+ if (!dev->ringing || !dev->owner) { -+ ast_log(LOG_WARNING, "Can't answer non existant call\n"); -+ return -1; -+ } -+ -+ dev->ringing = 0; -+ -+ if (dev->ring_timer >= 0) -+ ast_sched_del(sched, dev->ring_timer); -+ -+ dev->ring_timer = -1; -+ -+ send_atcmd(dev, "+CIEV: 2,1"); -+ send_atcmd(dev, "+CIEV: 3,0"); -+ -+ return answer(dev); -+} -+ -+static int -+ag_unsol_ciev(blt_dev_t * dev, const char * data) -+{ -+ const char * orig = data; -+ int indicator; -+ int status; -+ -+ while (*(data) && *(data) == ' ') -+ data++; -+ -+ if (*(data) == 0) { -+ ast_log(LOG_WARNING, "Invalid value[1] for '+CIEV:%s'\n", orig); -+ return -1; -+ } -+ -+ indicator = *(data++) - 48; -+ -+ if (*(data++) != ',') { -+ ast_log(LOG_WARNING, "Invalid value[2] for '+CIEV:%s'\n", orig); -+ return -1; -+ } -+ -+ if (*(data) == 0) { -+ ast_log(LOG_WARNING, "Invalid value[3] for '+CIEV:%s'\n", orig); -+ return -1; -+ } -+ -+ status = *(data) - 48; -+ -+ set_cind(dev, indicator, status); -+ -+ return 0; -+} -+ -+static int -+ag_unsol_cind(blt_dev_t * dev, const char * data) -+{ -+ -+ while (*(data) && *(data) == ' ') -+ data++; -+ -+ -+ if (dev->cind == 0) -+ { -+ int pos = 1; -+ char name[1024]; -+ -+ while ((data = parse_cind(data, name, 1023)) != NULL) { -+ ast_log(LOG_DEBUG, "CIND: %d=%s\n", pos, name); -+ if (strcmp(name, "call") == 0) -+ dev->call_pos = pos; -+ else if (strcmp(name, "service") == 0) -+ dev->service_pos = pos; -+ else if (strcmp(name, "call_setup") == 0 || strcmp(name, "callsetup") == 0) -+ dev->callsetup_pos = pos; -+ pos++; -+ } -+ -+ ast_log(LOG_DEBUG, "CIND: %d=%s\n", pos, name); -+ -+ } else { -+ -+ int pos = 1, len = 0; -+ char val[128]; -+ const char * start = data; -+ -+ while (*data) { -+ if (*data == ',') { -+ memset(val, 0, 128); -+ strncpy(val, start, len); -+ set_cind(dev, pos, atoi(val)); -+ pos++; -+ len = 0; -+ data++; -+ start = data; -+ continue; -+ } -+ len++; -+ data++; -+ } -+ -+ memset(val, 0, 128); -+ strncpy(val, start, len); -+ ast_log(LOG_DEBUG, "CIND IND %d set to %d [%s]\n", pos, atoi(val), val); -+ -+ -+ } -+ -+ return 0; -+} -+ -+/* -+ * handle an incoming call -+ */ -+static int -+ag_unsol_clip(blt_dev_t * dev, const char * data) -+{ -+ const char * orig = data; -+ char name[256]; -+ char number[64]; -+ int type; -+ -+ while (*(data) && *(data) == ' ') -+ data++; -+ -+ if (*(data) == 0) { -+ ast_log(LOG_WARNING, "Invalid value[1] for '+CLIP:%s'\n", orig); -+ return -1; -+ } -+ -+ parse_clip(data, number, sizeof(number)-1, name, sizeof(name)-1, &type); -+ ast_log(LOG_NOTICE, "Parsed '+CLIP: %s' number='%s' type='%d' name='%s'\n", data, number, type, name); -+ -+ blt_new(dev, AST_STATE_RING, dev->context, "s"); -+ -+ return 0; -+} -+ -+ -+ -+static blt_atcb_t -+atcmd_list[] = -+{ -+ { "A", NULL, NULL, atcmd_answer_execute, NULL, NULL }, -+ { "D", NULL, NULL, atcmd_dial_execute, NULL, NULL }, -+ { "+BRSF", atcmd_brsf_set, NULL, NULL, NULL, NULL }, -+ { "+BVRA", atcmd_bvra_set, NULL, NULL, NULL, NULL }, -+ { "+CCLK", NULL, atcmd_cclk_read, NULL, NULL, NULL }, -+ { "+CHUP", NULL, NULL, atcmd_chup_execute, NULL, NULL }, -+ { "+CIEV", NULL, NULL, NULL, NULL, ag_unsol_ciev }, -+ { "+CIND", NULL, atcmd_cind_read, NULL, atcmd_cind_test, ag_unsol_cind }, -+ { "*EAMI", NULL, NULL, atcmd_eami_execute, NULL, NULL}, -+ { "*EAII", NULL, NULL, atcmd_eaii_execute, NULL, NULL}, -+ -+ { "+CLAN", NULL, atcmd_clan_read, NULL, NULL, NULL }, -+ { "+CLIP", atcmd_clip_set, NULL, NULL, NULL, ag_unsol_clip }, -+ { "+COLP", atcmd_colp_set, NULL, NULL, NULL, NULL }, -+ { "+CMER", atcmd_cmer_set, NULL, NULL, NULL, NULL }, -+ { "+CPBR", atcmd_cpbr_set, NULL, NULL, NULL, NULL }, -+ { "+CPBS", atcmd_cpbs_set, NULL, NULL, NULL, NULL }, -+ { "+CSCS", atcmd_cscs_set, NULL, NULL, NULL, NULL }, -+ { "*EIPS", atcmd_eips_set, NULL, NULL, NULL, NULL }, -+ { "+VGS", atcmd_vgs_set, NULL, NULL, NULL, NULL }, -+ { "+BLDN", NULL, NULL, atcmd_bldn_execute, NULL, NULL }, -+}; -+ -+#define ATCMD_LIST_LEN (sizeof(atcmd_list) / sizeof(blt_atcb_t)) -+ -+/* ---------------------------------- */ -+ -+/* -- Handle negotiation when we're a HS -- */ -+ -+void -+ag_unknown_response(blt_dev_t * dev, char * cmd) -+{ -+ ast_log(LOG_DEBUG, "Got UNKN response: %s\n", cmd); -+ -+ // DELAYED -+ // NO CARRIER -+ -+} -+ -+void -+gui_easm_response(blt_dev_t * dev, char * cmd) -+{ -+ ast_log(LOG_NOTICE, "Menu displayed.\n"); -+} -+ -+void -+ag_cgmi_response(blt_dev_t * dev, char * cmd) -+{ -+ // CGMM - Phone Model -+ // CGMR - Phone Revision -+ // CGSN - IMEI -+ // AT* -+ // VTS - send tone -+ // CREG -+ // CBC - BATTERY -+ // CSQ - SIGANL -+ // CSMS - SMS STUFFS -+ // CMGL -+ // CMGR -+ // CMGS -+ // CSCA - sms CENTER NUMBER -+ // CNMI - SMS INDICATION -+ // ast_log(LOG_DEBUG, "Manufacturer: %s\n", cmd); -+ -+ if (dev->role == BLT_ROLE_GUI) { -+ ast_log(LOG_NOTICE, "Displaying Menu.\n"); -+ dev->cb = gui_easm_response; -+// send_atcmd(dev,"AT*EASM=\"SIP Menu\",1,1,3,\"Call Number\",\"Call Address\",\"More Options\",1"); -+ send_atcmd(dev,"AT*EASM=\"SIP Menu\",1,1,2,\"Call Number\",\"Call Address\",1"); -+ } else { -+ dev->cb = ag_unknown_response; -+ } -+} -+ -+void -+ag_cgmi_valid_response(blt_dev_t * dev, char * cmd) -+{ -+ // send_atcmd(dev, "AT+WS46?"); -+ // send_atcmd(dev, "AT+CRC=1"); -+ // send_atcmd(dev, "AT+CNUM"); -+ -+ if (strcmp(cmd, "OK") == 0) { -+ send_atcmd(dev, "AT+CGMI"); -+ dev->cb = ag_cgmi_response; -+ } else { -+ dev->cb = ag_unknown_response; -+ } -+} -+ -+void -+ag_clip_response(blt_dev_t * dev, char * cmd) -+{ -+ send_atcmd(dev, "AT+CGMI=?"); -+ dev->cb = ag_cgmi_valid_response; -+} -+ -+void -+ag_cmer_response(blt_dev_t * dev, char * cmd) -+{ -+ dev->cb = ag_clip_response; -+ dev->ready = 1; -+ dev->status = BLT_STATUS_READY; -+ send_atcmd(dev, "AT+CLIP=1"); -+} -+ -+void -+ag_cind_status_response(blt_dev_t * dev, char * cmd) -+{ -+ // XXX:T: Handle response. -+ dev->cb = ag_cmer_response; -+ send_atcmd(dev, "AT+CMER=3,0,0,1"); -+ // Initiliase SCO link! -+} -+ -+void -+ag_cind_response(blt_dev_t * dev, char * cmd) -+{ -+ dev->cb = ag_cind_status_response; -+ dev->cind = 1; -+ send_atcmd(dev, "AT+CIND?"); -+} -+ -+void -+ag_brsf_response(blt_dev_t * dev, char * cmd) -+{ -+ dev->cb = ag_cind_response; -+ ast_log(LOG_DEBUG, "Bluetooth features: %s\n", cmd); -+ dev->cind = 0; -+ send_atcmd(dev, "AT+CIND=?"); -+} -+ -+/* ---------------------------------- */ -+ -+static int -+sdp_register(sdp_session_t * session) -+{ -+ // XXX:T: Fix this horrible function so it makes some sense and is extensible! -+ sdp_list_t *svclass_id, *pfseq, *apseq, *root; -+ uuid_t root_uuid, svclass_uuid, ga_svclass_uuid, l2cap_uuid, rfcomm_uuid; -+ sdp_profile_desc_t profile; -+ sdp_list_t *aproto, *proto[2]; -+ sdp_record_t record; -+ uint8_t u8 = rfcomm_channel_ag; -+ uint8_t u8_hs = rfcomm_channel_hs; -+ sdp_data_t *channel; -+ int ret = 0; -+ -+ memset((void *)&record, 0, sizeof(sdp_record_t)); -+ record.handle = 0xffffffff; -+ sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP); -+ root = sdp_list_append(0, &root_uuid); -+ sdp_set_browse_groups(&record, root); -+ -+ // Register as an AG -+ -+ sdp_uuid16_create(&svclass_uuid, HANDSFREE_AUDIO_GW_SVCLASS_ID); -+ svclass_id = sdp_list_append(0, &svclass_uuid); -+ sdp_uuid16_create(&ga_svclass_uuid, GENERIC_AUDIO_SVCLASS_ID); -+ svclass_id = sdp_list_append(svclass_id, &ga_svclass_uuid); -+ sdp_set_service_classes(&record, svclass_id); -+ sdp_uuid16_create(&profile.uuid, 0x111f); -+ profile.version = 0x0100; -+ pfseq = sdp_list_append(0, &profile); -+ -+ sdp_set_profile_descs(&record, pfseq); -+ -+ sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID); -+ proto[0] = sdp_list_append(0, &l2cap_uuid); -+ apseq = sdp_list_append(0, proto[0]); -+ -+ sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID); -+ proto[1] = sdp_list_append(0, &rfcomm_uuid); -+ channel = sdp_data_alloc(SDP_UINT8, &u8); -+ proto[1] = sdp_list_append(proto[1], channel); -+ apseq = sdp_list_append(apseq, proto[1]); -+ -+ aproto = sdp_list_append(0, apseq); -+ sdp_set_access_protos(&record, aproto); -+ -+ sdp_set_info_attr(&record, "Voice Gateway", 0, 0); -+ -+ if (sdp_record_register(session, &record, SDP_RECORD_PERSIST) < 0) { -+ ast_log(LOG_ERROR, "Service Record registration failed\n"); -+ ret = -1; -+ goto end; -+ } -+ -+ sdp_record_ag = record.handle; -+ sdp_record_gui = record.handle; -+ -+ ast_log(LOG_NOTICE, "HeadsetAudioGateway service registered\n"); -+ -+ sdp_data_free(channel); -+ sdp_list_free(proto[0], 0); -+ sdp_list_free(proto[1], 0); -+ sdp_list_free(apseq, 0); -+ sdp_list_free(aproto, 0); -+ -+ // ------------- -+ -+ memset((void *)&record, 0, sizeof(sdp_record_t)); -+ record.handle = 0xffffffff; -+ sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP); -+ root = sdp_list_append(0, &root_uuid); -+ sdp_set_browse_groups(&record, root); -+ -+ // Register as an HS -+ -+ sdp_uuid16_create(&svclass_uuid, HANDSFREE_AUDIO_GW_SVCLASS_ID); -+ svclass_id = sdp_list_append(0, &svclass_uuid); -+ sdp_uuid16_create(&ga_svclass_uuid, GENERIC_AUDIO_SVCLASS_ID); -+ svclass_id = sdp_list_append(svclass_id, &ga_svclass_uuid); -+ sdp_set_service_classes(&record, svclass_id); -+ sdp_uuid16_create(&profile.uuid, 0x111e); -+ profile.version = 0x0100; -+ pfseq = sdp_list_append(0, &profile); -+ sdp_set_profile_descs(&record, pfseq); -+ -+ sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID); -+ proto[0] = sdp_list_append(0, &l2cap_uuid); -+ apseq = sdp_list_append(0, proto[0]); -+ -+ sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID); -+ proto[1] = sdp_list_append(0, &rfcomm_uuid); -+ channel = sdp_data_alloc(SDP_UINT8, &u8_hs); -+ proto[1] = sdp_list_append(proto[1], channel); -+ apseq = sdp_list_append(apseq, proto[1]); -+ -+ aproto = sdp_list_append(0, apseq); -+ sdp_set_access_protos(&record, aproto); -+ sdp_set_info_attr(&record, "Voice Gateway", 0, 0); -+ -+ if (sdp_record_register(session, &record, SDP_RECORD_PERSIST) < 0) { -+ ast_log(LOG_ERROR, "Service Record registration failed\n"); -+ ret = -1; -+ goto end; -+ } -+ -+ sdp_record_hs = record.handle; -+ -+ ast_log(LOG_NOTICE, "HeadsetAudioGateway service registered\n"); -+ -+end: -+ sdp_data_free(channel); -+ sdp_list_free(proto[0], 0); -+ sdp_list_free(proto[1], 0); -+ sdp_list_free(apseq, 0); -+ sdp_list_free(aproto, 0); -+ -+ return ret; -+} -+ -+static int -+rfcomm_listen(bdaddr_t * bdaddr, int channel) -+{ -+ -+ int sock = -1; -+ struct sockaddr_rc loc_addr; -+ int on = 1; -+ -+ if ((sock = socket(PF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM)) < 0) { -+ ast_log(LOG_ERROR, "Can't create socket: %s (errno: %d)\n", strerror(errno), errno); -+ return -1; -+ } -+ -+ loc_addr.rc_family = AF_BLUETOOTH; -+ -+ /* Local Interface Address */ -+ bacpy(&loc_addr.rc_bdaddr, bdaddr); -+ -+ /* Channel */ -+ loc_addr.rc_channel = channel; -+ -+ if (bind(sock, (struct sockaddr *)&loc_addr, sizeof(loc_addr)) < 0) { -+ ast_log(LOG_ERROR, "Can't bind socket: %s (errno: %d)\n", strerror(errno), errno); -+ close(sock); -+ return -1; -+ } -+ -+ if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) == -1) { -+ ast_log(LOG_ERROR, "Set socket SO_REUSEADDR option on failed: errno %d, %s", errno, strerror(errno)); -+ close(sock); -+ return -1; -+ } -+ -+ if (fcntl(sock, F_SETFL, O_RDWR|O_NONBLOCK) != 0) -+ ast_log(LOG_ERROR, "Can't set RFCOMM socket to NBIO\n"); -+ -+ if (listen(sock, 10) < 0) { -+ ast_log(LOG_ERROR,"Can not listen on the socket. %s(%d)\n", strerror(errno), errno); -+ close(sock); -+ return -1; -+ } -+ -+ ast_log(LOG_NOTICE, "Listening for RFCOMM channel %d connections on FD %d\n", channel, sock); -+ -+ return sock; -+} -+ -+ -+static int -+sco_listen(bdaddr_t * bdaddr) -+{ -+ int sock = -1; -+ int on = 1; -+ struct sockaddr_sco loc_addr; -+ -+ memset(&loc_addr, 0, sizeof(loc_addr)); -+ -+ if ((sock = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_SCO)) < 0) { -+ ast_log(LOG_ERROR, "Can't create SCO socket: %s (errno: %d)\n", strerror(errno), errno); -+ return -1; -+ } -+ -+ loc_addr.sco_family = AF_BLUETOOTH; -+ bacpy(&loc_addr.sco_bdaddr, BDADDR_ANY); -+ -+ if (bind(sock, (struct sockaddr *)&loc_addr, sizeof(loc_addr)) < 0) { -+ ast_log(LOG_ERROR, "Can't bind SCO socket: %s (errno: %d)\n", strerror(errno), errno); -+ close(sock); -+ return -1; -+ } -+ -+ if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) == -1) { -+ ast_log(LOG_ERROR, "Set SCO socket SO_REUSEADDR option on failed: errno %d, %s", errno, strerror(errno)); -+ close(sock); -+ return -1; -+ } -+ -+ if (fcntl(sock, F_SETFL, O_RDWR|O_NONBLOCK) != 0) -+ ast_log(LOG_ERROR, "Can't set SCO socket to NBIO\n"); -+ -+ if (listen(sock, 10) < 0) { -+ ast_log(LOG_ERROR,"Can not listen on SCO socket: %s(%d)\n", strerror(errno), errno); -+ close(sock); -+ return -1; -+ } -+ -+ ast_log(LOG_NOTICE, "Listening for SCO connections on FD %d\n", sock); -+ -+ return sock; -+} -+ -+static int -+rfcomm_connect(bdaddr_t * src, bdaddr_t * dst, int channel, int nbio) -+{ -+ struct sockaddr_rc addr; -+ int s; -+ -+ if ((s = socket(PF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM)) < 0) { -+ return -1; -+ } -+ -+ memset(&addr, 0, sizeof(addr)); -+ addr.rc_family = AF_BLUETOOTH; -+ bacpy(&addr.rc_bdaddr, src); -+ addr.rc_channel = 0; -+ -+ if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) { -+ close(s); -+ return -1; -+ } -+ -+ memset(&addr, 0, sizeof(addr)); -+ addr.rc_family = AF_BLUETOOTH; -+ bacpy(&addr.rc_bdaddr, dst); -+ addr.rc_channel = channel; -+ -+ if (nbio) { -+ if (fcntl(s, F_SETFL, O_RDWR|O_NONBLOCK) != 0) -+ ast_log(LOG_ERROR, "Can't set RFCOMM socket to NBIO\n"); -+ } -+ -+ if (connect(s, (struct sockaddr *)&addr, sizeof(addr)) < 0 && (nbio != 1 || (errno != EAGAIN))) { -+ close(s); -+ return -1; -+ } -+ -+ return s; -+} -+ -+/* Must be called with dev->lock held */ -+ -+static int -+sco_connect(blt_dev_t * dev) -+{ -+ struct sockaddr_sco addr; -+ // struct sco_conninfo conn; -+ // struct sco_options opts; -+ // int size; -+ // bdaddr_t * src = &local_bdaddr; -+ -+ int s; -+ bdaddr_t * dst = &(dev->bdaddr); -+ -+ if (dev->sco != -1) { -+ ast_log(LOG_ERROR, "SCO fd already open.\n"); -+ return -1; -+ } -+ -+ if ((s = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_SCO)) < 0) { -+ ast_log(LOG_ERROR, "Can't create SCO socket(): %s\n", strerror(errno)); -+ return -1; -+ } -+ -+ memset(&addr, 0, sizeof(addr)); -+ -+ addr.sco_family = AF_BLUETOOTH; -+ bacpy(&addr.sco_bdaddr, BDADDR_ANY); -+ -+ if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) { -+ ast_log(LOG_ERROR, "Can't bind() SCO socket: %s\n", strerror(errno)); -+ close(s); -+ return -1; -+ } -+ -+ memset(&addr, 0, sizeof(addr)); -+ addr.sco_family = AF_BLUETOOTH; -+ bacpy(&addr.sco_bdaddr, dst); -+ -+ if (fcntl(s, F_SETFL, O_RDWR|O_NONBLOCK) != 0) -+ ast_log(LOG_ERROR, "Can't set SCO socket to NBIO\n"); -+ -+ if ((connect(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) && (errno != EAGAIN)) { -+ ast_log(LOG_ERROR, "Can't connect() SCO socket: %s (errno %d)\n", strerror(errno), errno); -+ close(s); -+ return -1; -+ } -+ -+ //size = sizeof(conn); -+ -+ -+/* XXX:T: HERE, fix getting SCO conninfo. -+ -+ if (getsockopt(s, SOL_SCO, SCO_CONNINFO, &conn, &size) < 0) { -+ ast_log(LOG_ERROR, "Can't getsockopt SCO_CONNINFO on SCO socket: %s\n", strerror(errno)); -+ close(s); -+ return -1; -+ } -+ -+ size = sizeof(opts); -+ -+ if (getsockopt(s, SOL_SCO, SCO_OPTIONS, &opts, &size) < 0) { -+ ast_log(LOG_ERROR, "Can't getsockopt SCO_OPTIONS on SCO socket: %s\n", strerror(errno)); -+ close(s); -+ return -1; -+ } -+ -+ dev->sco_handle = conn.hci_handle; -+ dev->sco_mtu = opts.mtu; -+ -+*/ -+ -+ ast_log(LOG_DEBUG, "SCO: %d\n", s); -+ -+ dev->sco = s; -+ -+ return 0; -+} -+ -+ -+/* ---------------------------------- */ -+ -+/* Non blocking (async) outgoing bluetooth connection */ -+ -+static int -+try_connect(blt_dev_t * dev) -+{ -+ int fd; -+ ast_mutex_lock(&(dev->lock)); -+ -+ if (dev->status != BLT_STATUS_CONNECTING && dev->status != BLT_STATUS_DOWN) { -+ ast_mutex_unlock(&(dev->lock)); -+ return 0; -+ } -+ -+ if (dev->rd != -1) { -+ -+ int ret; -+ struct pollfd pfd; -+ -+ if (dev->status != BLT_STATUS_CONNECTING) { -+ ast_mutex_unlock(&(dev->lock)); -+ dev->outgoing_id = -1; -+ return 0; -+ } -+ -+ // ret = connect(dev->rd, (struct sockaddr *)&(dev->addr), sizeof(struct sockaddr_rc)); // -+ -+ pfd.fd = dev->rd; -+ pfd.events = POLLIN | POLLOUT; -+ -+ ret = poll(&pfd, 1, 0); -+ -+ if (ret == -1) { -+ close(dev->rd); -+ dev->rd = -1; -+ dev->status = BLT_STATUS_DOWN; -+ dev->outgoing_id = ast_sched_add(sched, 10000, AST_SCHED_CB(try_connect), dev); -+ ast_mutex_unlock(&(dev->lock)); -+ return 0; -+ } -+ -+ if (ret > 0) { -+ -+ int len = sizeof(ret); -+ getsockopt(dev->rd, SOL_SOCKET, SO_ERROR, &ret, &len); -+ -+ if (ret == 0) { -+ -+ ast_log(LOG_NOTICE, "Initialised bluetooth link to device %s\n", dev->name); -+ -+#if 0 -+ { -+ struct hci_conn_info_req * cr; -+ int dd; -+ char name[248]; -+ -+ cr = malloc(sizeof(*cr) + sizeof(struct hci_conn_info)); -+ dd = hci_open_dev(hcidev_id); -+ cr->type = ACL_LINK; -+ bacpy(&cr->bdaddr, &(dev->bdaddr)); -+ -+ if (ioctl(dd, HCIGETCONNINFO, (unsigned long)cr) < 0) { -+ ast_log(LOG_ERROR, "Failed to get connection info: %s\n", strerror(errno)); -+ } else { -+ ast_log(LOG_DEBUG, "HCI Handle: %d\n", cr->conn_info->handle); -+ } -+ -+ if (hci_read_remote_name(dd, &(dev->bdaddr), sizeof(name), name, 25000) == 0) -+ ast_log(LOG_DEBUG, "Remote Name: %s\n", name); -+ free(cr); -+ } -+#endif -+ -+ dev->status = BLT_STATUS_NEGOTIATING; -+ -+ /* If this device is an AG/GUI, we initiate the negotiation. */ -+ -+ if (dev->role == BLT_ROLE_AG || -+ dev->role == BLT_ROLE_GUI) { -+ dev->cb = ag_brsf_response; -+ send_atcmd(dev, "AT+BRSF=23"); -+ } -+ -+ dev->outgoing_id = -1; -+ ast_mutex_unlock(&(dev->lock)); -+ return 0; -+ -+ } else { -+ -+ if (ret != EHOSTDOWN) -+ ast_log(LOG_NOTICE, "Connect to device %s failed: %s (errno %d)\n", dev->name, strerror(ret), ret); -+ -+ close(dev->rd); -+ dev->rd = -1; -+ dev->status = BLT_STATUS_DOWN; -+ dev->outgoing_id = ast_sched_add(sched, (ret == EHOSTDOWN) ? 10000 : 2500, AST_SCHED_CB(try_connect), dev); -+ ast_mutex_unlock(&(dev->lock)); -+ return 0; -+ -+ } -+ -+ } -+ -+ dev->outgoing_id = ast_sched_add(sched, 100, AST_SCHED_CB(try_connect), dev); -+ ast_mutex_unlock(&(dev->lock)); -+ return 0; -+ } -+ -+ ast_log(LOG_NOTICE, "RFCOMM connect start.\n"); -+ fd = rfcomm_connect(&local_bdaddr, &(dev->bdaddr), dev->channel, 1); -+ ast_log(LOG_NOTICE, "RFCOMM connect done.\n"); -+ -+ if (fd == -1) { -+ ast_log(LOG_WARNING, "NBIO connect() to %s returned %d: %s\n", dev->name, errno, strerror(errno)); -+ dev->outgoing_id = ast_sched_add(sched, 5000, AST_SCHED_CB(try_connect), dev); -+ ast_mutex_unlock(&(dev->lock)); -+ return 0; -+ } -+ -+ dev->rd = fd; -+ dev->status = BLT_STATUS_CONNECTING; -+ dev->outgoing_id = ast_sched_add(sched, 100, AST_SCHED_CB(try_connect), dev); -+ ast_mutex_unlock(&(dev->lock)); -+ return 0; -+} -+ -+ -+/* Called whenever a new command is received while we're the AG */ -+ -+ -+static int -+process_rfcomm_cmd(blt_dev_t * dev, char * cmd) -+{ -+ int i; -+ char * fullcmd = cmd; -+ -+ if (option_verbose) -+ ast_verbose(VERBOSE_PREFIX_1 "[%s] %*s > %s\n", role2str(dev->role), 10, dev->name, cmd); -+ -+ /* Read the 'AT' from the start of the string */ -+ if (strncmp(cmd, "AT", 2)) { -+ ast_log(LOG_WARNING, "Unknown command without 'AT': %s\n", cmd); -+ send_atcmd_error(dev); -+ return 0; -+ } -+ -+ cmd += 2; -+ -+ // Don't forget 'AT' on its own is OK. -+ -+ if (strlen(cmd) == 0) { -+ send_atcmd_ok(dev, fullcmd); -+ return 0; -+ } -+ -+ for (i = 0 ; i < ATCMD_LIST_LEN ; i++) { -+ if (strncmp(atcmd_list[i].str, cmd, strlen(atcmd_list[i].str)) == 0) { -+ char * pos = (cmd + strlen(atcmd_list[i].str)); -+ if ((strncmp(pos, "=?", 2) == 0) && (strlen(pos) == 2)) { -+ /* TEST command */ -+ if (atcmd_list[i].test) { -+ if (atcmd_list[i].test(dev) == 0) -+ send_atcmd_ok(dev, fullcmd); -+ else -+ send_atcmd_error(dev); -+ } else { -+ send_atcmd_ok(dev, fullcmd); -+ } -+ } else if ((strncmp(pos, "?", 1) == 0) && (strlen(pos) == 1)) { -+ /* READ command */ -+ if (atcmd_list[i].read) { -+ if (atcmd_list[i].read(dev) == 0) -+ send_atcmd_ok(dev, fullcmd); -+ else -+ send_atcmd_error(dev); -+ } else { -+ ast_log(LOG_WARNING, "AT Command: '%s' missing READ function\n", fullcmd); -+ send_atcmd_error(dev); -+ } -+ } else if (strncmp(pos, "=", 1) == 0) { -+ /* SET command */ -+ if (atcmd_list[i].set) { -+ if (atcmd_list[i].set(dev, (pos + 1), (*(pos + 1)) ? strlen(pos + 1) : 0) == 0) -+ send_atcmd_ok(dev, fullcmd); -+ else -+ send_atcmd_error(dev); -+ } else { -+ ast_log(LOG_WARNING, "AT Command: '%s' missing SET function\n", fullcmd); -+ send_atcmd_error(dev); -+ } -+ } else { -+ /* EXECUTE command */ -+ if (atcmd_list[i].execute) { -+ if (atcmd_list[i].execute(dev, cmd + strlen(atcmd_list[i].str)) == 0) -+ send_atcmd_ok(dev, fullcmd); -+ else -+ send_atcmd_error(dev); -+ } else { -+ ast_log(LOG_WARNING, "AT Command: '%s' missing EXECUTE function\n", fullcmd); -+ send_atcmd_error(dev); -+ } -+ } -+ return 0; -+ } -+ } -+ -+ ast_log(LOG_NOTICE, "Unknown AT Command: '%s' (%s)\n", fullcmd, cmd); -+ send_atcmd_error(dev); -+ -+ return 0; -+} -+ -+/* Called when a socket is incoming */ -+ -+static void -+handle_incoming(int fd, blt_role_t role) -+{ -+ blt_dev_t * dev; -+ struct sockaddr_rc addr; -+ int len = sizeof(addr); -+ -+ // Got a new incoming socket. -+ ast_log(LOG_DEBUG, "Incoming RFCOMM socket\n"); -+ -+ ast_mutex_lock(&iface_lock); -+ -+ fd = accept(fd, (struct sockaddr*)&addr, &len); -+ -+ dev = iface_head; -+ while (dev) { -+ if (bacmp(&(dev->bdaddr), &addr.rc_bdaddr) == 0) { -+ ast_log(LOG_DEBUG, "Connect from %s\n", dev->name); -+ ast_mutex_lock(&(dev->lock)); -+ /* Kill any outstanding connect attempt. */ -+ if (dev->outgoing_id > -1) { -+ ast_sched_del(sched, dev->outgoing_id); -+ dev->outgoing_id = -1; -+ } -+ -+ rd_close(dev, 0, 0); -+ -+ dev->status = BLT_STATUS_NEGOTIATING; -+ dev->rd = fd; -+ -+ if (dev->role == BLT_ROLE_AG || -+ dev->role == BLT_ROLE_GUI) { -+ dev->cb = ag_brsf_response; -+ send_atcmd(dev, "AT+BRSF=23"); -+ } -+ ast_mutex_unlock(&(dev->lock)); -+ break; -+ } -+ dev = dev->next; -+ } -+ -+ if (dev == NULL) { -+ ast_log(LOG_WARNING, "Connect from unknown device\n"); -+ close(fd); -+ } -+ ast_mutex_unlock(&iface_lock); -+ -+ return; -+} -+ -+static void -+handle_incoming_sco(int master) -+{ -+ -+ blt_dev_t * dev; -+ struct sockaddr_sco addr; -+ struct sco_conninfo conn; -+ struct sco_options opts; -+ int len = sizeof(addr); -+ int fd; -+ -+ ast_log(LOG_DEBUG, "Incoming SCO socket\n"); -+ -+ fd = accept(master, (struct sockaddr*)&addr, &len); -+ -+ if (fcntl(fd, F_SETFL, O_RDWR|O_NONBLOCK) != 0) { -+ ast_log(LOG_ERROR, "Can't set SCO socket to NBIO\n"); -+ close(fd); -+ return; -+ } -+ -+ len = sizeof(conn); -+ -+ if (getsockopt(fd, SOL_SCO, SCO_CONNINFO, &conn, &len) < 0) { -+ ast_log(LOG_ERROR, "Can't getsockopt SCO_CONNINFO on SCO socket: %s\n", strerror(errno)); -+ close(fd); -+ return; -+ } -+ -+ len = sizeof(opts); -+ -+ if (getsockopt(fd, SOL_SCO, SCO_OPTIONS, &opts, &len) < 0) { -+ ast_log(LOG_ERROR, "Can't getsockopt SCO_OPTIONS on SCO socket: %s\n", strerror(errno)); -+ close(fd); -+ return; -+ } -+ -+ ast_mutex_lock(&iface_lock); -+ dev = iface_head; -+ while (dev) { -+ if (bacmp(&(dev->bdaddr), &addr.sco_bdaddr) == 0) { -+ ast_log(LOG_DEBUG, "SCO Connect from %s\n", dev->name); -+ ast_mutex_lock(&(dev->lock)); -+ if (dev->sco_running != -1) { -+ ast_log(LOG_ERROR, "Incoming SCO socket, but SCO thread already running.\n"); -+ } else { -+ sco_start(dev, fd); -+ } -+ ast_mutex_unlock(&(dev->lock)); -+ break; -+ } -+ dev = dev->next; -+ } -+ -+ ast_mutex_unlock(&iface_lock); -+ -+ if (dev == NULL) { -+ ast_log(LOG_WARNING, "SCO Connect from unknown device\n"); -+ close(fd); -+ } else { -+ // XXX:T: We need to handle the fact we might have an outgoing connection attempt in progress. -+ ast_log(LOG_DEBUG, "SCO: %d, HCIHandle=%d, MUT=%d\n", fd, conn.hci_handle, opts.mtu); -+ } -+ -+ -+ -+ return; -+} -+ -+/* Called when there is data waiting on a socket */ -+ -+static int -+handle_rd_data(blt_dev_t * dev) -+{ -+ char c; -+ int ret; -+ -+ while ((ret = read(dev->rd, &c, 1)) == 1) { -+ -+ // log_buf[i++] = c; -+ -+ if (dev->role == BLT_ROLE_HS) { -+ -+ if (c == '\r') { -+ ret = process_rfcomm_cmd(dev, dev->rd_buff); -+ dev->rd_buff_pos = 0; -+ memset(dev->rd_buff, 0, BLT_RDBUFF_MAX); -+ return ret; -+ } -+ -+ if (dev->rd_buff_pos >= BLT_RDBUFF_MAX) -+ return 0; -+ -+ dev->rd_buff[dev->rd_buff_pos++] = c; -+ -+ } else if (dev->role == BLT_ROLE_AG || -+ dev->role == BLT_ROLE_GUI) { -+ -+ //ast_log(LOG_ERROR, "%s: %c\n", dev->name, c); -+ -+ switch (dev->state) { -+ case BLT_STATE_WANT_R: -+ if (c == '\r' || c == 10) { -+ dev->state = BLT_STATE_WANT_N; -+ } else if (c == '+') { -+ dev->state = BLT_STATE_WANT_CMD; -+ dev->rd_buff[dev->rd_buff_pos++] = '+'; -+ } else { -+ ast_log(LOG_ERROR, "Device %s: Expected '\\r', got %d. state=BLT_STATE_WANT_R\n", dev->name, c); -+ return -1; -+ } -+ break; -+ -+ case BLT_STATE_WANT_N: -+ if (c == '\n' || c == 13) -+ dev->state = BLT_STATE_WANT_CMD; -+ else { -+ ast_log(LOG_ERROR, "Device %s: Expected '\\n', got %d. state=BLT_STATE_WANT_N\n", dev->name, c); -+ return -1; -+ } -+ break; -+ -+ case BLT_STATE_WANT_CMD: -+ if (c == '\r' || c == 10) -+ dev->state = BLT_STATE_WANT_N2; -+ else { -+ if (dev->rd_buff_pos >= BLT_RDBUFF_MAX) { -+ ast_log(LOG_ERROR, "Device %s: Buffer exceeded\n", dev->name); -+ return -1; -+ } -+ dev->rd_buff[dev->rd_buff_pos++] = c; -+ } -+ break; -+ -+ case BLT_STATE_WANT_N2: -+ if (c == '\n' || c == 13) { -+ -+ dev->state = BLT_STATE_WANT_R; -+ -+ if (dev->rd_buff[0] == '+') { -+ int i; -+ // find unsolicited -+ for (i = 0 ; i < ATCMD_LIST_LEN ; i++) { -+ if (strncmp(atcmd_list[i].str, dev->rd_buff, strlen(atcmd_list[i].str)) == 0) { -+ if (atcmd_list[i].unsolicited) -+ atcmd_list[i].unsolicited(dev, dev->rd_buff + strlen(atcmd_list[i].str) + 1); -+ else -+ ast_log(LOG_WARNING, "Device %s: Unhandled Unsolicited: %s\n", dev->name, dev->rd_buff); -+ break; -+ } -+ } -+ -+ if (option_verbose) -+ ast_verbose(VERBOSE_PREFIX_1 "[%s] %*s > %s\n", role2str(dev->role), 10, dev->name, dev->rd_buff); -+ -+ if (i == ATCMD_LIST_LEN) -+ ast_log(LOG_NOTICE, "Device %s: Got unsolicited message: %s\n", dev->name, dev->rd_buff); -+ -+ } else if (dev->rd_buff[0] == '*') { -+ if (option_verbose) -+ ast_verbose(VERBOSE_PREFIX_1 "[%s]* %*s > %s\n", role2str(dev->role), 9, dev->name, dev->rd_buff); -+ -+ int i; -+ // find execute -+ for (i = 0 ; i < ATCMD_LIST_LEN ; i++) { -+ if (strncmp(atcmd_list[i].str, dev->rd_buff, strlen(atcmd_list[i].str)) == 0) { -+ if (atcmd_list[i].execute) -+ atcmd_list[i].execute(dev, dev->rd_buff + strlen(atcmd_list[i].str) + 1); -+ else -+ ast_log(LOG_ERROR, "Device %s: Unhandled Execute: %s\n", dev->name, dev->rd_buff); -+ break; -+ } -+ } -+ -+ -+ } else { -+ -+ if ( -+ strcmp(dev->rd_buff, "OK") != 0 && -+ strcmp(dev->rd_buff, "CONNECT") != 0 && -+ strcmp(dev->rd_buff, "RING") != 0 && -+ strcmp(dev->rd_buff, "NO CARRIER") != 0 && -+ strcmp(dev->rd_buff, "ERROR") != 0 && -+ strcmp(dev->rd_buff, "NO DIALTONE") != 0 && -+ strcmp(dev->rd_buff, "BUSY") != 0 && -+ strcmp(dev->rd_buff, "NO ANSWER") != 0 && -+ strcmp(dev->rd_buff, "DELAYED") != 0 -+ ){ -+ // It must be a multiline error -+ strncpy(dev->last_err_cmd, dev->rd_buff, 1023); -+ if (option_verbose) -+ ast_verbose(VERBOSE_PREFIX_1 "[%s] %*s > %s\n", role2str(dev->role), 10, dev->name, dev->rd_buff); -+ } else if (dev->cb) { -+ if (option_verbose) -+ ast_verbose(VERBOSE_PREFIX_1 "[%s] %*s > %s\n", role2str(dev->role), 10, dev->name, dev->rd_buff); -+ dev->cb(dev, dev->rd_buff); -+ } else { -+ ast_log(LOG_ERROR, "Device %s: Data on socket in HS mode, but no callback\n", dev->name); -+ } -+ -+ } -+ -+ dev->rd_buff_pos = 0; -+ memset(dev->rd_buff, 0, BLT_RDBUFF_MAX); -+ } else { -+ -+ ast_log(LOG_ERROR, "Device %s: Expected '\\n' got %d. state = BLT_STATE_WANT_N2:\n", dev->name, c); -+ return -1; -+ -+ } -+ -+ break; -+ -+ default: -+ ast_log(LOG_ERROR, "Device %s: Unknown device state %d\n", dev->name, dev->state); -+ return -1; -+ -+ } -+ -+ } -+ -+ } -+ -+ return 0; -+} -+ -+/* Close the devices RFCOMM socket, and SCO if it exists. Must hold dev->lock */ -+ -+static void -+rd_close(blt_dev_t * dev, int reconnect, int e) -+{ -+ dev->ready = 0; -+ -+ if (dev->rd) -+ close(dev->rd); -+ -+ dev->rd = -1; -+ -+ dev->status = BLT_STATUS_DOWN; -+ -+ sco_stop(dev); -+ -+ if (dev->owner) { -+ ast_setstate(dev->owner, AST_STATE_DOWN); -+ ast_queue_control(dev->owner, AST_CONTROL_HANGUP); -+ } -+ -+ /* Schedule a reconnect */ -+ if (reconnect && dev->autoconnect) { -+ dev->outgoing_id = ast_sched_add(sched, 5000, AST_SCHED_CB(try_connect), dev); -+ -+ if (monitor_thread == pthread_self()) { -+ // Because we're not the monitor thread, we needd to inturrupt poll(). -+ pthread_kill(monitor_thread, SIGURG); -+ } -+ -+ if (e) -+ ast_log(LOG_NOTICE, "Device %s disconnected, scheduled reconnect in 5 seconds: %s (errno %d)\n", dev->name, strerror(e), e); -+ } else if (e) { -+ ast_log(LOG_NOTICE, "Device %s disconnected: %s (errno %d)\n", dev->name, strerror(e), e); -+ } -+ -+ return; -+} -+ -+/* -+ * Remember that we can only add to the scheduler from -+ * the do_monitor thread, as it calculates time to next one from -+ * this loop. -+ */ -+ -+static void * -+do_monitor(void * data) -+{ -+#define SRV_SOCK_CNT 4 -+ -+ int res = 0; -+ blt_dev_t * dev; -+ struct pollfd * pfds = malloc(sizeof(struct pollfd) * (ifcount + SRV_SOCK_CNT)); -+ -+ /* -- We start off by trying to connect all of our devices (non blocking) -- */ -+ -+ monitor_pid = getpid(); -+ -+ if (ast_mutex_lock(&iface_lock)) { -+ ast_log(LOG_ERROR, "Failed to get iface_lock.\n"); -+ return NULL; -+ } -+ -+ dev = iface_head; -+ while (dev) { -+ -+ if (socketpair(PF_UNIX, SOCK_STREAM, 0, dev->sco_pipe) != 0) { -+ ast_log(LOG_ERROR, "Failed to create socket pair: %s (errno %d)\n", strerror(errno), errno); -+ ast_mutex_unlock(&iface_lock); -+ return NULL; -+ } -+ -+ if (dev->autoconnect && dev->status == BLT_STATUS_DOWN) -+ dev->outgoing_id = ast_sched_add(sched, 1500, AST_SCHED_CB(try_connect), dev); -+ dev = dev->next; -+ } -+ ast_mutex_unlock(&iface_lock); -+ -+ /* -- Now, Scan all sockets, and service scheduler -- */ -+ -+ pfds[0].fd = rfcomm_sock_ag; -+ pfds[0].events = POLLIN; -+ -+ pfds[1].fd = rfcomm_sock_hs; -+ pfds[1].events = POLLIN; -+ -+ pfds[2].fd = rfcomm_sock_gui; -+ pfds[2].events = POLLIN; -+ -+ pfds[3].fd = sco_socket; -+ pfds[3].events = POLLIN; -+ -+ while (1) { -+ int cnt = SRV_SOCK_CNT; -+ int i; -+ -+ /* -- Build pfds -- */ -+ -+ if (ast_mutex_lock(&iface_lock)) { -+ ast_log(LOG_ERROR, "Failed to get iface_lock.\n"); -+ return NULL; -+ } -+ dev = iface_head; -+ while (dev) { -+ ast_mutex_lock(&(dev->lock)); -+ if (dev->rd > 0 && ((dev->status != BLT_STATUS_DOWN) && (dev->status != BLT_STATUS_CONNECTING))) { -+ pfds[cnt].fd = dev->rd; -+ pfds[cnt].events = POLLIN; -+ cnt++; -+ } -+ ast_mutex_unlock(&(dev->lock)); -+ dev = dev->next; -+ } -+ ast_mutex_unlock(&iface_lock); -+ -+ /* -- End Build pfds -- */ -+ -+ res = ast_sched_wait(sched); -+ res = poll(pfds, cnt, MAX(100, MIN(100, res))); -+ -+ if (res == 0) -+ ast_sched_runq(sched); -+ -+ if (pfds[0].revents) { -+ handle_incoming(rfcomm_sock_ag, BLT_ROLE_AG); -+ res--; -+ } -+ -+ if (pfds[1].revents) { -+ handle_incoming(rfcomm_sock_hs, BLT_ROLE_HS); -+ res--; -+ } -+ -+ if (pfds[2].revents) { -+ handle_incoming(rfcomm_sock_gui, BLT_ROLE_GUI); -+ res--; -+ } -+ -+ if (pfds[3].revents) { -+ handle_incoming_sco(sco_socket); -+ res--; -+ } -+ -+ if (res == 0) -+ continue; -+ -+ for (i = SRV_SOCK_CNT ; i < cnt ; i++) { -+ -+ /* Optimise a little bit */ -+ if (res == 0) -+ break; -+ else if (pfds[i].revents == 0) -+ continue; -+ -+ /* -- Find the socket that has activity -- */ -+ -+ if (ast_mutex_lock(&iface_lock)) { -+ ast_log(LOG_ERROR, "Failed to get iface_lock.\n"); -+ return NULL; -+ } -+ -+ dev = iface_head; -+ -+ while (dev) { -+ if (pfds[i].fd == dev->rd) { -+ ast_mutex_lock(&(dev->lock)); -+ if (pfds[i].revents & POLLIN) { -+ if (handle_rd_data(dev) == -1) { -+ rd_close(dev, 0, 0); -+ } -+ } else { -+ rd_close(dev, 1, sock_err(dev->rd)); -+ } -+ ast_mutex_unlock(&(dev->lock)); -+ res--; -+ break; -+ } -+ dev = dev->next; -+ } -+ -+ if (dev == NULL) { -+ ast_log(LOG_ERROR, "Unhandled fd from poll()\n"); -+ close(pfds[i].fd); -+ } -+ -+ ast_mutex_unlock(&iface_lock); -+ -+ /* -- End find socket with activity -- */ -+ -+ } -+ -+ } -+ -+ return NULL; -+} -+ -+static int -+restart_monitor(void) -+{ -+ -+ if (monitor_thread == AST_PTHREADT_STOP) -+ return 0; -+ -+ if (ast_mutex_lock(&monitor_lock)) { -+ ast_log(LOG_WARNING, "Unable to lock monitor\n"); -+ return -1; -+ } -+ -+ if (monitor_thread == pthread_self()) { -+ ast_mutex_unlock(&monitor_lock); -+ ast_log(LOG_WARNING, "Cannot kill myself\n"); -+ return -1; -+ } -+ -+ if (monitor_thread != AST_PTHREADT_NULL) { -+ -+ /* Just signal it to be sure it wakes up */ -+ pthread_cancel(monitor_thread); -+ pthread_kill(monitor_thread, SIGURG); -+ ast_log(LOG_DEBUG, "Waiting for monitor thread to join...\n"); -+ pthread_join(monitor_thread, NULL); -+ ast_log(LOG_DEBUG, "joined\n"); -+ -+ } else { -+ -+ /* Start a new monitor */ -+ if (ast_pthread_create(&monitor_thread, NULL, do_monitor, NULL) < 0) { -+ ast_mutex_unlock(&monitor_lock); -+ ast_log(LOG_ERROR, "Unable to start monitor thread.\n"); -+ return -1; -+ } -+ -+ } -+ -+ ast_mutex_unlock(&monitor_lock); -+ return 0; -+} -+ -+static int -+blt_parse_config(void) -+{ -+ struct ast_config * cfg; -+ struct ast_variable * v; -+ char * cat; -+ -+ cfg = ast_load(BLT_CONFIG_FILE); -+ -+ if (!cfg) { -+ ast_log(LOG_NOTICE, "Unable to load Bluetooth config: %s. Bluetooth disabled\n", BLT_CONFIG_FILE); -+ return -1; -+ } -+ -+ v = ast_variable_browse(cfg, "general"); -+ -+ while (v) { -+ if (!strcasecmp(v->name, "rfchannel_ag")) { -+ rfcomm_channel_ag = atoi(v->value); -+ } else if (!strcasecmp(v->name, "rfchannel_hs")) { -+ rfcomm_channel_hs = atoi(v->value); -+ } else if (!strcasecmp(v->name, "rfchannel_gui")) { -+ rfcomm_channel_gui = atoi(v->value); -+ } else if (!strcasecmp(v->name, "interface")) { -+ hcidev_id = atoi(v->value); -+ } else if (!strcasecmp(v->name, "gui_default_sip_number")) { -+ gui_default_sip_number = v->value; -+ } else if (!strcasecmp(v->name, "gui_default_sip_address")) { -+ gui_default_sip_address = v->value; -+ } else { -+ ast_log(LOG_WARNING, "Unknown config key '%s' in section [general]\n", v->name); -+ } -+ v = v->next; -+ } -+ cat = ast_category_browse(cfg, NULL); -+ -+ while(cat) { -+ -+ char * str; -+ -+ if (strcasecmp(cat, "general")) { -+ blt_dev_t * device = malloc(sizeof(blt_dev_t)); -+ memset(device, 0, sizeof(blt_dev_t)); -+ device->sco_running = -1; -+ device->sco = -1; -+ device->rd = -1; -+ device->outgoing_id = -1; -+ device->status = BLT_STATUS_DOWN; -+ str2ba(cat, &(device->bdaddr)); -+ device->name = ast_variable_retrieve(cfg, cat, "name"); -+ -+ str = ast_variable_retrieve(cfg, cat, "type"); -+ -+ if (str == NULL) { -+ ast_log(LOG_ERROR, "Device [%s] has no role. Specify type=\n", cat); -+ return -1; -+ } else if (strcasecmp(str, "HS") == 0) { -+ device->role = BLT_ROLE_HS; -+ } else if (strcasecmp(str, "AG") == 0) { -+ device->role = BLT_ROLE_AG; -+ } else if (strcasecmp(str, "GUI") == 0) { -+ device->role = BLT_ROLE_GUI; -+ } else { -+ ast_log(LOG_ERROR, "Device [%s] has invalid role '%s'\n", cat, str); -+ return -1; -+ } -+ -+ /* XXX:T: Find channel to use using SDP. -+ * However, this needs to be non blocking, and I can't see -+ * anything in sdp_lib.h that will allow non blocking calls. -+ */ -+ -+ device->channel = 1; -+ -+ if ((str = ast_variable_retrieve(cfg, cat, "channel")) != NULL) -+ device->channel = atoi(str); -+ -+ if ((str = ast_variable_retrieve(cfg, cat, "autoconnect")) != NULL) -+ device->autoconnect = (strcasecmp(str, "yes") == 0 || strcmp(str, "1") == 0) ? 1 : 0; -+ -+ if ((str = ast_variable_retrieve(cfg, cat, "context")) != NULL) -+ device->context = str; -+ else -+ device->context = "bluetooth"; -+ -+ device->next = iface_head; -+ iface_head = device; -+ ifcount++; -+ } -+ -+ cat = ast_category_browse(cfg, cat); -+ } -+ return 0; -+} -+ -+ -+static int -+blt_show_peers(int fd, int argc, char *argv[]) -+{ -+ blt_dev_t * dev; -+ -+ if (ast_mutex_lock(&iface_lock)) { -+ ast_log(LOG_ERROR, "Failed to get Iface lock\n"); -+ ast_cli(fd, "Failed to get iface lock\n"); -+ return RESULT_FAILURE; -+ } -+ -+ dev = iface_head; -+ -+ ast_cli(fd, "BDAddr Name Role Status A/C SCOCon/Fd/Th Sig\n"); -+ ast_cli(fd, "----------------- ---------- ---- ----------- --- ------------ ---\n"); -+ -+ while (dev) { -+ char b1[18]; -+ ba2str(&(dev->bdaddr), b1); -+ ast_cli(fd, "%s %-10s %-4s %-11s %-3s %2d/%02d/%-6ld %s\n", -+ b1, dev->name, -+// (dev->role == BLT_ROLE_HS) ? "HS" : "AG", -+ (dev->role == BLT_ROLE_HS) ? "HS" : (dev->role == BLT_ROLE_AG) ? "AG" : "GUI", -+ status2str(dev->status), -+ (dev->autoconnect) ? "Yes" : "No", -+ dev->sco_running, -+ dev->sco, -+ dev->sco_thread, -+ (dev->role == BLT_ROLE_AG) ? (dev->service) ? "Yes" : "No" : "N/A" -+ ); -+ dev = dev->next; -+ } -+ -+ ast_mutex_unlock(&iface_lock); -+ return RESULT_SUCCESS; -+} -+ -+static int -+blt_show_information(int fd, int argc, char *argv[]) -+{ -+ char b1[18]; -+ ba2str(&local_bdaddr, b1); -+ ast_cli(fd, "-------------------------------------------\n"); -+ ast_cli(fd, " Version : %s\n", BLT_SVN_REVISION); -+ ast_cli(fd, " Monitor PID : %d\n", monitor_pid); -+ ast_cli(fd, " RFCOMM AG : Channel %d, FD %d\n", rfcomm_channel_ag, rfcomm_sock_ag); -+ ast_cli(fd, " RFCOMM HS : Channel %d, FD %d\n", rfcomm_channel_hs, rfcomm_sock_hs); -+ ast_cli(fd, " RFCOMM GUI : Channel %d, FD %d\n", rfcomm_channel_gui, rfcomm_sock_gui); -+ ast_cli(fd, " Device : hci%d, MAC Address %s\n", hcidev_id, b1); -+ ast_cli(fd, "-------------------------------------------\n"); -+ return RESULT_SUCCESS; -+} -+ -+static int -+blt_ag_sendcmd(int fd, int argc, char *argv[]) -+{ -+ blt_dev_t * dev; -+ -+ if (argc != 4) -+ return RESULT_SHOWUSAGE; -+ -+ ast_mutex_lock(&iface_lock); -+ dev = iface_head; -+ while (dev) { -+ if (!strcasecmp(argv[2], dev->name)) -+ break; -+ dev = dev->next; -+ } -+ ast_mutex_unlock(&iface_lock); -+ -+ if (!dev) { -+ ast_cli(fd, "Device '%s' does not exist\n", argv[2]); -+ return RESULT_FAILURE; -+ } -+ -+ if ((dev->role != BLT_ROLE_AG) && (dev->role != BLT_ROLE_GUI)) { -+ ast_cli(fd, "Device '%s' is not an AG or GUI\n", argv[2]); -+ return RESULT_FAILURE; -+ } -+ -+ if (dev->status == BLT_STATUS_DOWN || dev->status == BLT_STATUS_NEGOTIATING) { -+ ast_cli(fd, "Device '%s' is not connected\n", argv[2]); -+ return RESULT_FAILURE; -+ } -+ -+ if (*(argv[3] + strlen(argv[3]) - 1) == '.') -+ *(argv[3] + strlen(argv[3]) - 1) = '?'; -+ -+ ast_cli(fd, "Sending AT command to %s: %s\n", dev->name, argv[3]); -+ -+ ast_mutex_lock(&(dev->lock)); -+ send_atcmd(dev, argv[3]); -+ ast_mutex_unlock(&(dev->lock)); -+ -+ return RESULT_SUCCESS; -+} -+ -+static char * -+complete_device(char * line, char * word, int pos, int state, int rpos, blt_role_t role) -+{ -+ blt_dev_t * dev; -+ int which = 0; -+ char *ret; -+ -+ if (pos != rpos) -+ return NULL; -+ -+ ast_mutex_lock(&iface_lock); -+ -+ dev = iface_head; -+ -+ while (dev) { -+ -+ if ((dev->role == role) && (!strncasecmp(word, dev->name, strlen(word)))) { -+ if (++which > state) -+ break; -+ } -+ -+ dev = dev->next; -+ } -+ -+ if (dev) -+ ret = strdup(dev->name); -+ else -+ ret = NULL; -+ -+ ast_mutex_unlock(&iface_lock); -+ -+ return ret; -+} -+ -+static char * -+complete_device_2_ag_gui(char * line, char * word, int pos, int state) -+{ -+ return complete_device(line, word, pos, state, 2, BLT_ROLE_AG); -+} -+ -+static char show_peers_usage[] = -+"Usage: bluetooth show peers\n" -+" List all bluetooth peers and their status\n"; -+ -+static struct ast_cli_entry -+cli_show_peers = -+ { { "bluetooth", "show", "peers", NULL }, blt_show_peers, "List Bluetooth Peers", show_peers_usage }; -+ -+ -+static char ag_sendcmd[] = -+"Usage: bluetooth sendcmd \n" -+" Sends a AT cmd over the RFCOMM link, and print result (AG only)\n"; -+ -+static struct ast_cli_entry -+cli_ag_sendcmd = -+ { { "bluetooth", "sendcmd", NULL }, blt_ag_sendcmd, "Send AG/GUI an AT command", ag_sendcmd, complete_device_2_ag_gui }; -+ -+static char show_information[] = -+"Usage: bluetooth show information\n" -+" Lists information about the bluetooth subsystem\n"; -+ -+static struct ast_cli_entry -+cli_show_information = -+ { { "bluetooth", "show", "information", NULL }, blt_show_information, "List Bluetooth Info", show_information }; -+ -+void -+remove_sdp_records(void) -+{ -+ -+ sdp_session_t * sdp; -+ sdp_list_t * attr; -+ sdp_record_t * rec; -+ int res = -1; -+ uint32_t range = 0x0000ffff; -+ -+ if (sdp_record_ag == -1 || sdp_record_gui == -1 || sdp_record_hs == -1) -+ return; -+ -+ ast_log(LOG_DEBUG, "Removing SDP records\n"); -+ -+ sdp = sdp_connect(BDADDR_ANY, BDADDR_LOCAL, SDP_RETRY_IF_BUSY); -+ -+ if (!sdp) -+ return; -+ -+ attr = sdp_list_append(0, &range); -+ rec = sdp_service_attr_req(sdp, sdp_record_ag, SDP_ATTR_REQ_RANGE, attr); -+ sdp_list_free(attr, 0); -+ -+ if (rec) -+ if (sdp_record_unregister(sdp, rec) == 0) -+ res = 0; -+ -+ rec = sdp_service_attr_req(sdp, sdp_record_gui, SDP_ATTR_REQ_RANGE, attr); -+ sdp_list_free(attr, 0); -+ -+ if (rec) -+ if (sdp_record_unregister(sdp, rec) == 0) -+ res = 0; -+ -+ attr = sdp_list_append(0, &range); -+ rec = sdp_service_attr_req(sdp, sdp_record_hs, SDP_ATTR_REQ_RANGE, attr); -+ sdp_list_free(attr, 0); -+ -+ if (rec) -+ if (sdp_record_unregister(sdp, rec) == 0) -+ res = 0; -+ -+ sdp_close(sdp); -+ -+ if (res == 0) -+ ast_log(LOG_NOTICE, "Removed SDP records\n"); -+ else -+ ast_log(LOG_ERROR, "Failed to remove SDP records\n"); -+ -+} -+ -+static int -+__unload_module(void) -+{ -+ -+#if ASTERISK_VERSION_NUM <= 010107 -+ ast_channel_unregister(BLT_CHAN_NAME); -+#else -+ ast_channel_unregister(&blt_tech); -+#endif -+ -+ if (monitor_thread != AST_PTHREADT_NULL) { -+ -+ if (ast_mutex_lock(&monitor_lock)) { -+ -+ if (monitor_thread && (monitor_thread != AST_PTHREADT_STOP) && (monitor_thread != AST_PTHREADT_NULL)) { -+ pthread_cancel(monitor_thread); -+ pthread_kill(monitor_thread, SIGURG); -+ fprintf(stderr, "Waiting for monitor thread to join...\n"); -+ pthread_join(monitor_thread, NULL); -+ fprintf(stderr, "joined\n"); -+ } -+ monitor_thread = AST_PTHREADT_STOP; -+ ast_mutex_unlock(&monitor_lock); -+ -+ } else { -+ -+ ast_log(LOG_WARNING, "Unable to lock the monitor\n"); -+ return -1; -+ -+ } -+ -+ } -+ -+ ast_unregister_atexit(remove_sdp_records); -+ remove_sdp_records(); -+ return 0; -+} -+ -+int -+load_module() -+{ -+ sdp_session_t * sess; -+ int dd; -+ uint16_t vs; -+ -+ hcidev_id = BLT_DEFAULT_HCI_DEV; -+ -+ if (blt_parse_config() != 0) { -+ ast_log(LOG_ERROR, "Bluetooth configuration error. Bluetooth Disabled\n"); -+ return unload_module(); -+ } -+ -+ dd = hci_open_dev(hcidev_id); -+ if (dd == -1) { -+ ast_log(LOG_ERROR, "Unable to open interface hci%d: %s.\n", hcidev_id, strerror(errno)); -+ return -1; -+ } -+ -+ hci_read_voice_setting(dd, &vs, 1000); -+ vs = htobs(vs); -+ close(dd); -+ -+ if (vs != 0x0060) { -+ ast_log(LOG_ERROR, "Bluetooth voice setting must be 0x0060, not 0x%04x\n", vs); -+ unload_module(); -+ return 0; -+ } -+ -+ if ((sched = sched_context_create()) == NULL) { -+ ast_log(LOG_WARNING, "Unable to create schedule context\n"); -+ return -1; -+ } -+ -+ memset(&local_bdaddr, 0, sizeof(local_bdaddr)); -+ -+ hci_devba(hcidev_id, &local_bdaddr); -+ -+ /* --- Add SDP record --- */ -+ -+ sess = sdp_connect(&local_bdaddr, BDADDR_LOCAL, SDP_RETRY_IF_BUSY); -+ -+ if ((rfcomm_sock_ag = rfcomm_listen(&local_bdaddr, rfcomm_channel_ag)) < 0) { -+ return -1; -+ } -+ -+ if ((rfcomm_sock_hs = rfcomm_listen(&local_bdaddr, rfcomm_channel_hs)) < 0) -+ return -1; -+ -+ if ((rfcomm_sock_gui = rfcomm_listen(&local_bdaddr, rfcomm_channel_gui)) < 0) -+ return -1; -+ -+ if ((sco_socket = sco_listen(&local_bdaddr)) < 0) -+ return -1; -+ -+ if (!sess) { -+ ast_log(LOG_ERROR, "Failed to connect to SDP server: %s\n", strerror(errno)); -+ return -1; -+ } -+ -+ if (sdp_register(sess) != 0) { -+ ast_log(LOG_ERROR, "Failed to register HeadsetAudioGateway in SDP\n"); -+ return -1; -+ } -+ -+ sdp_close(sess); -+ -+ if (restart_monitor() != 0) -+ return -1; -+ -+#if ASTERISK_VERSION_NUM <= 010107 -+ if (ast_channel_register(BLT_CHAN_NAME, "Bluetooth Driver", BLUETOOTH_FORMAT, blt_request)) { -+#else -+ if (ast_channel_register(&blt_tech)) { -+#endif -+ ast_log(LOG_ERROR, "Unable to register channel class BTL\n"); -+ __unload_module(); -+ return -1; -+ } -+ -+ ast_cli_register(&cli_show_information); -+ ast_cli_register(&cli_show_peers); -+ ast_cli_register(&cli_ag_sendcmd); -+ -+ ast_register_atexit(remove_sdp_records); -+ -+ ast_log(LOG_NOTICE, "Loaded Bluetooth support, %s\n", BLT_SVN_REVISION + 1); -+ -+ return 0; -+} -+ -+int -+unload_module(void) -+{ -+ ast_cli_unregister(&cli_ag_sendcmd); -+ ast_cli_unregister(&cli_show_peers); -+ ast_cli_unregister(&cli_show_information); -+ return __unload_module(); -+} -+ -+int -+usecount() -+{ -+ int res; -+ ast_mutex_lock(&usecnt_lock); -+ res = usecnt; -+ ast_mutex_unlock(&usecnt_lock); -+ return res; -+} -+ -+char *description() -+{ -+ return "Bluetooth Channel Driver"; -+} -+ -+char * -+key() -+{ -+ return ASTERISK_GPL_KEY; -+} -+ -+ -diff -ruN asterisk-1.0.9-old/configs/bluetooth.conf asterisk-1.0.9-new/configs/bluetooth.conf ---- asterisk-1.0.9-old/configs/bluetooth.conf 1970-01-01 01:00:00.000000000 +0100 -+++ asterisk-1.0.9-new/configs/bluetooth.conf 2005-09-06 22:51:38.000000000 +0200 -@@ -0,0 +1,46 @@ -+[general] -+; Channel we listen on as a HS (Headset) -+rfchannel_hs = 2 -+; Channel we listen on as an AG (AudioGateway) -+rfchannel_ag = 3 -+; Channel we listen on as GUI -+rfchannel_gui = 4 -+; hci interface to use (number - e.g '0') -+interface = 0 -+ -+; RFCOMM channel to connect to. For a HandsSet: -+; sdptool search --bdaddr xx:xx:xx:xx:xx:xx 0x111E -+; or,for an AudioGateway (Phone): -+; sdptool search --bdaddr xx:xx:xx:xx:xx:xx 0x111F -+; -+; Find the 'channel' value under RFCOMM. -+; -+;channel = 6 -+; Automatically connect? -+;autoconnect = yes -+ -+;example for a SonyEricsson mobile as a GUI device -+[00:0F:DE:6E:77:6B] -+name = T610 -+type = GUI -+channel = 6 -+;channel = 1 -+autoconnect = yes -+ -+;[00:0E:6D:1A:3D:86] -+;name = Nokia -+;type = AG -+;channel = 13 -+;autoconnect = yes -+ -+[00:0E:A1:01:49:AE] -+name = AutoBlue -+type = HS -+channel = 2 -+autoconnect = yes -+ -+;[00:0A:D9:EB:FD:D8] -+;name = P900 -+;type = AG -+;channel = 8 -+;autoconnect = no diff --git a/net/asterisk/patches/asterisk-1.2.0-Makefile-apps.patch b/net/asterisk/patches/asterisk-1.2.0-Makefile-apps.patch deleted file mode 100644 index 7df38f764..000000000 --- a/net/asterisk/patches/asterisk-1.2.0-Makefile-apps.patch +++ /dev/null @@ -1,34 +0,0 @@ -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/net/asterisk/patches/asterisk-1.2.0-Makefile-cdr.patch b/net/asterisk/patches/asterisk-1.2.0-Makefile-cdr.patch deleted file mode 100644 index 6f28394cd..000000000 --- a/net/asterisk/patches/asterisk-1.2.0-Makefile-cdr.patch +++ /dev/null @@ -1,37 +0,0 @@ -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_mysql.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/net/asterisk/patches/asterisk-1.2.0-Makefile-channels.patch b/net/asterisk/patches/asterisk-1.2.0-Makefile-channels.patch deleted file mode 100644 index d5ac6ad7a..000000000 --- a/net/asterisk/patches/asterisk-1.2.0-Makefile-channels.patch +++ /dev/null @@ -1,22 +0,0 @@ -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/net/asterisk/patches/asterisk-1.2.0-Makefile-codecs-gsm.patch b/net/asterisk/patches/asterisk-1.2.0-Makefile-codecs-gsm.patch deleted file mode 100644 index 372d6970e..000000000 --- a/net/asterisk/patches/asterisk-1.2.0-Makefile-codecs-gsm.patch +++ /dev/null @@ -1,39 +0,0 @@ -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,8 @@ - ifneq ($(shell uname -m),armv4l) - ifneq ($(shell uname -m),sparc64) - ifneq (${PROC},arm) -+ifneq (${PROC},mipsel) -+ifneq (${PROC},mips) - GSM_SOURCES+= $(SRC)/k6opt.s - endif - endif -@@ -246,6 +247,8 @@ - endif - endif - endif -+endif -+endif - - TOAST_SOURCES = $(SRC)/toast.c \ - $(SRC)/toast_lin.c \ -@@ -299,6 +301,8 @@ - ifneq ($(shell uname -m), alpha) - ifneq ($(shell uname -m), sparc64) - ifneq ($(shell uname -m), armv4l) -+ifneq (${PROC}, mipsel) -+ifneq (${PROC}, mips) - GSM_OBJECTS+= $(SRC)/k6opt.o - endif - endif -@@ -308,6 +311,8 @@ - endif - endif - endif -+endif -+endif - - TOAST_OBJECTS = $(SRC)/toast.o \ - $(SRC)/toast_lin.o \ diff --git a/net/asterisk/patches/asterisk-1.2.0-Makefile-codecs.patch b/net/asterisk/patches/asterisk-1.2.0-Makefile-codecs.patch deleted file mode 100644 index f59c24c5d..000000000 --- a/net/asterisk/patches/asterisk-1.2.0-Makefile-codecs.patch +++ /dev/null @@ -1,13 +0,0 @@ -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/net/asterisk/patches/asterisk-1.2.0-Makefile-pbx.patch b/net/asterisk/patches/asterisk-1.2.0-Makefile-pbx.patch deleted file mode 100644 index f1d2a6331..000000000 --- a/net/asterisk/patches/asterisk-1.2.0-Makefile-pbx.patch +++ /dev/null @@ -1,22 +0,0 @@ -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/net/asterisk/patches/asterisk-1.2.0-Makefile-res.patch b/net/asterisk/patches/asterisk-1.2.0-Makefile-res.patch deleted file mode 100644 index 2f782cb1d..000000000 --- a/net/asterisk/patches/asterisk-1.2.0-Makefile-res.patch +++ /dev/null @@ -1,26 +0,0 @@ -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/net/asterisk/patches/asterisk-1.2.0-Makefile.patch b/net/asterisk/patches/asterisk-1.2.0-Makefile.patch deleted file mode 100644 index 2b4afa26e..000000000 --- a/net/asterisk/patches/asterisk-1.2.0-Makefile.patch +++ /dev/null @@ -1,54 +0,0 @@ -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/net/asterisk/patches/asterisk-1.2.0-app_mysql.patch b/net/asterisk/patches/asterisk-1.2.0-app_mysql.patch deleted file mode 100644 index 6f02e75a5..000000000 --- a/net/asterisk/patches/asterisk-1.2.0-app_mysql.patch +++ /dev/null @@ -1,449 +0,0 @@ -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 -+ * Constantine Filin -+ * -+ * This program is free software, distributed under the terms of -+ * the GNU General Public License -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#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 -+ * -+ * Modified August 2003 -+ * Tilghman Lesher -+ * -+ * Modified August 6, 2005 -+ * Joseph Benden -+ * 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 -+ -+#include -+#include -+ -+#include -+#include -+#include -+ -+#include -+#include -+ -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#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/net/asterisk/patches/asterisk-1.2.0-chan_bluetooth.patch b/net/asterisk/patches/asterisk-1.2.0-chan_bluetooth.patch deleted file mode 100644 index 6ffe30e82..000000000 --- a/net/asterisk/patches/asterisk-1.2.0-chan_bluetooth.patch +++ /dev/null @@ -1,20 +0,0 @@ -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 - #include - #include -+#include - #include - #include - #include -@@ -3133,7 +3133,7 @@ - struct ast_variable * v; - char * cat; - -- cfg = ast_load(BLT_CONFIG_FILE); -+ cfg = ast_config_load(BLT_CONFIG_FILE); - - if (!cfg) { - ast_log(LOG_NOTICE, "Unable to load Bluetooth config: %s. Bluetooth disabled\n", BLT_CONFIG_FILE); diff --git a/net/asterisk/patches/asterisk-1.2.0-compat-getloadavg.patch b/net/asterisk/patches/asterisk-1.2.0-compat-getloadavg.patch deleted file mode 100644 index a909513b1..000000000 --- a/net/asterisk/patches/asterisk-1.2.0-compat-getloadavg.patch +++ /dev/null @@ -1,13 +0,0 @@ -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/net/asterisk/patches/asterisk-1.2.0-res_mysql.patch b/net/asterisk/patches/asterisk-1.2.0-res_mysql.patch deleted file mode 100644 index 5de810741..000000000 --- a/net/asterisk/patches/asterisk-1.2.0-res_mysql.patch +++ /dev/null @@ -1,698 +0,0 @@ -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 - Asterisk Author -+ * Matthew Boehm - MySQL RealTime Driver Author -+ * -+ * res_config_mysql.c -+ * -+ * 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 -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+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/net/asterisk/patches/asterisk-1.2.1-Makefile-codecs-ilbc.patch b/net/asterisk/patches/asterisk-1.2.1-Makefile-codecs-ilbc.patch deleted file mode 100644 index 875f26fa0..000000000 --- a/net/asterisk/patches/asterisk-1.2.1-Makefile-codecs-ilbc.patch +++ /dev/null @@ -1,21 +0,0 @@ -diff -ruN asterisk-1.2.1-old/codecs/ilbc/Makefile asterisk-1.2.1-new/codecs/ilbc/Makefile ---- asterisk-1.2.1-old/codecs/ilbc/Makefile 2005-11-29 19:24:39.000000000 +0100 -+++ asterisk-1.2.1-new/codecs/ilbc/Makefile 2005-12-16 19:24:36.000000000 +0100 -@@ -1,5 +1,5 @@ - ARCH=$(PROC) --CFLAGS+=-Wall -O3 -funroll-loops -+CFLAGS+=-Wall $(OPTIMIZE) -funroll-loops - ifneq (${OSARCH},CYGWIN) - CFLAGS += -fPIC - endif -@@ -15,8 +15,8 @@ - - - $(LIB): $(OBJS) -- ar cr $(LIB) $(OBJS) -- ranlib $(LIB) -+ $(AR) cr $(LIB) $(OBJS) -+ $(RANLIB) $(LIB) - - clean: - rm -f $(LIB) *.o diff --git a/net/asterisk/patches/asterisk-1.2.1-Makefile-versionnum.patch b/net/asterisk/patches/asterisk-1.2.1-Makefile-versionnum.patch deleted file mode 100644 index 230764205..000000000 --- a/net/asterisk/patches/asterisk-1.2.1-Makefile-versionnum.patch +++ /dev/null @@ -1,11 +0,0 @@ ---- 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/net/asterisk/patches/asterisk-1.2.1-chan_h323.patch b/net/asterisk/patches/asterisk-1.2.1-chan_h323.patch deleted file mode 100644 index 10760de0b..000000000 --- a/net/asterisk/patches/asterisk-1.2.1-chan_h323.patch +++ /dev/null @@ -1,32 +0,0 @@ -diff -ruN asterisk-1.2.1-old/channels/Makefile asterisk-1.2.1-new/channels/Makefile ---- asterisk-1.2.1-old/channels/Makefile 2006-05-07 13:06:06.000000000 +0200 -+++ asterisk-1.2.1-new/channels/Makefile 2006-05-07 15:26:00.000000000 +0200 -@@ -15,6 +15,7 @@ - # - - CHANNEL_LIBS=chan_sip.so chan_agent.so chan_mgcp.so chan_iax2.so chan_local.so chan_skinny.so chan_features.so -+CXXLIBS=-lstdc++ - - ifneq (${OSARCH},CYGWIN) - # if you really, really want to use these drivers, uncomment the line below -@@ -230,7 +231,7 @@ - - ifeq (${OSARCH},Linux) - chan_h323.so: chan_h323.o h323/libchanh323.a h323/Makefile.ast -- $(CC) $(SOLINK) $(H323LDFLAGS) -o $@ $< h323/libchanh323.a $(H323LDLIBS) -lstdc++ -+ $(CC) $(SOLINK) $(H323LDFLAGS) -o $@ $< h323/libchanh323.a $(H323LDLIBS) $(CXXLIBS) - else - chan_h323.so: chan_h323.o h323/libchanh323.a - $(CC) $(SOLINK) -o $@ $< h323/libchanh323.a $(CHANH323LIB) -L$(PWLIBDIR)/lib $(PTLIB) -L$(OPENH323DIR)/lib $(H323LIB) -L/usr/lib -lcrypto -lssl -lexpat -diff -ruN asterisk-1.2.1-old/channels/h323/Makefile asterisk-1.2.1-new/channels/h323/Makefile ---- asterisk-1.2.1-old/channels/h323/Makefile 2005-11-29 19:24:39.000000000 +0100 -+++ asterisk-1.2.1-new/channels/h323/Makefile 2006-05-07 13:18:46.000000000 +0200 -@@ -30,7 +30,7 @@ - touch $(SOURCES) - - libchanh323.a: $(OBJS) -- ar crv $@ $(OBJS) -+ $(AR) crv $@ $(OBJS) - - Makefile.ast: FORCE - @echo H323CFLAGS = $(STDCCFLAGS) $(OPTCCFLAGS) $(CFLAGS) >$@.tmp