Revision
14544
Author
gmaruzz
Date
2009-08-17 04:17:09 -0500 (Mon, 17 Aug 2009)

Log Message

celliax: added mod_celliax skeleton directory, with files from the celliax for asterisk distribution

Added Paths

Diff

Added: freeswitch/branches/gmaruzz/mod_celliax/Makefile (0 => 14544)


--- freeswitch/branches/gmaruzz/mod_celliax/Makefile	                        (rev 0)
+++ freeswitch/branches/gmaruzz/mod_celliax/Makefile	2009-08-17 09:17:09 UTC (rev 14544)
@@ -0,0 +1,6 @@
+MODNAME=mod_skypiax
+SVNDEF := -D'SKYPIAX_SVN_VERSION="$(shell svnversion -n .)"'
+LOCAL_CFLAGS += $(SVNDEF)
+LOCAL_LDFLAGS=-lX11
+LOCAL_OBJS=skypiax_protocol.o
+include ../../../../build/modmake.rules

Added: freeswitch/branches/gmaruzz/mod_celliax/README (0 => 14544)


--- freeswitch/branches/gmaruzz/mod_celliax/README	                        (rev 0)
+++ freeswitch/branches/gmaruzz/mod_celliax/README	2009-08-17 09:17:09 UTC (rev 14544)
@@ -0,0 +1,9 @@
+Skypiax, Skype Endpoint and Trunk
+
+All documentation on compiling, using, configuring, 
+tricks and tweaks, possible problems at: 
+
+http://wiki.freeswitch.org/wiki/Skypiax_Skype_Endpoint_and_Trunk
+
+< gmaruzz at gmail dot com >
+

Added: freeswitch/branches/gmaruzz/mod_celliax/celliax.h (0 => 14544)


--- freeswitch/branches/gmaruzz/mod_celliax/celliax.h	                        (rev 0)
+++ freeswitch/branches/gmaruzz/mod_celliax/celliax.h	2009-08-17 09:17:09 UTC (rev 14544)
@@ -0,0 +1,291 @@
+/*
+ * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ * Copyright (C) 2005/2006, Anthony Minessale II <anthmct@yahoo.com>
+ *
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ *
+ * The Initial Developer of the Original Code is
+ * Anthony Minessale II <anthmct@yahoo.com>
+ * Portions created by the Initial Developer are Copyright (C)
+ * the Initial Developer. All Rights Reserved.
+ *
+ * This module (mod_skypiax) has been contributed by:
+ *
+ * Giovanni Maruzzelli (gmaruzz@gmail.com)
+ *
+ *
+ * Further Contributors:
+ *
+ *
+ *
+ * mod_skypiax.c -- Skype compatible Endpoint Module
+ *
+ */
+
+#include <switch.h>
+#include <switch_version.h>
+
+#ifndef WIN32
+#include <sys/time.h>
+#include <X11/Xlib.h>
+#include <X11/Xlibint.h>
+#include <X11/Xatom.h>
+#endif //WIN32
+
+#ifdef _MSC_VER
+//Windows macro  for FD_SET includes a warning C4127: conditional expression is constant
+#pragma warning(push)
+#pragma warning(disable:4127)
+#endif
+
+#define SAMPLERATE_SKYPIAX 16000
+#define SAMPLES_PER_FRAME SAMPLERATE_SKYPIAX/50
+
+#ifndef SKYPIAX_SVN_VERSION
+#define SKYPIAX_SVN_VERSION SWITCH_VERSION_REVISION
+#endif /* SKYPIAX_SVN_VERSION */
+
+typedef enum {
+	TFLAG_IO = (1 << 0),
+	TFLAG_INBOUND = (1 << 1),
+	TFLAG_OUTBOUND = (1 << 2),
+	TFLAG_DTMF = (1 << 3),
+	TFLAG_VOICE = (1 << 4),
+	TFLAG_HANGUP = (1 << 5),
+	TFLAG_LINEAR = (1 << 6),
+	TFLAG_CODEC = (1 << 7),
+	TFLAG_BREAK = (1 << 8)
+} TFLAGS;
+
+typedef enum {
+	GFLAG_MY_CODEC_PREFS = (1 << 0)
+} GFLAGS;
+
+#define DEBUGA_SKYPE(...)  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, 		"rev "SKYPIAX_SVN_VERSION "[%p|%-7lx][DEBUG_SKYPE  %-5d][%-10s][%2d,%2d,%2d] " __VA_ARGS__ );
+#define DEBUGA_CALL(...)  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, 		"rev "SKYPIAX_SVN_VERSION "[%p|%-7lx][DEBUG_CALL  %-5d][%-10s][%2d,%2d,%2d] " __VA_ARGS__ );
+#define DEBUGA_PBX(...)  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, 		"rev "SKYPIAX_SVN_VERSION "[%p|%-7lx][DEBUG_PBX  %-5d][%-10s][%2d,%2d,%2d] " __VA_ARGS__ );
+#define ERRORA(...)  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, 		"rev "SKYPIAX_SVN_VERSION "[%p|%-7lx][ERRORA  %-5d][%-10s][%2d,%2d,%2d] " __VA_ARGS__ );
+#define WARNINGA(...)  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, 		"rev "SKYPIAX_SVN_VERSION "[%p|%-7lx][WARNINGA  %-5d][%-10s][%2d,%2d,%2d] " __VA_ARGS__ );
+#define NOTICA(...)  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, 		"rev "SKYPIAX_SVN_VERSION "[%p|%-7lx][NOTICA  %-5d][%-10s][%2d,%2d,%2d] " __VA_ARGS__ );
+
+#define SKYPIAX_P_LOG NULL, (unsigned long)55, __LINE__, tech_pvt ? tech_pvt->name ? tech_pvt->name : "none" : "none", -1, tech_pvt ? tech_pvt->interface_state : -1, tech_pvt ? tech_pvt->skype_callflow : -1
+
+/*********************************/
+#define SKYPIAX_CAUSE_NORMAL		1
+/*********************************/
+#define SKYPIAX_FRAME_DTMF			1
+/*********************************/
+#define SKYPIAX_CONTROL_RINGING		1
+#define SKYPIAX_CONTROL_ANSWER		2
+
+/*********************************/
+#define		SKYPIAX_STATE_IDLE					0
+#define		SKYPIAX_STATE_DOWN					1
+#define		SKYPIAX_STATE_RING					2
+#define		SKYPIAX_STATE_DIALING				3
+#define		SKYPIAX_STATE_BUSY					4
+#define		SKYPIAX_STATE_UP					5
+#define		SKYPIAX_STATE_RINGING				6
+#define		SKYPIAX_STATE_PRERING				7
+#define		SKYPIAX_STATE_ERROR_DOUBLE_CALL		8
+#define		SKYPIAX_STATE_SELECTED				9
+#define 	SKYPIAX_STATE_HANGUP_REQUESTED		10
+#define		SKYPIAX_STATE_PREANSWER				11
+/*********************************/
+/* call flow from the device */
+#define 	CALLFLOW_CALL_IDLE					0
+#define 	CALLFLOW_CALL_DOWN					1
+#define 	CALLFLOW_INCOMING_RING				2
+#define 	CALLFLOW_CALL_DIALING				3
+#define 	CALLFLOW_CALL_LINEBUSY				4
+#define 	CALLFLOW_CALL_ACTIVE				5
+#define 	CALLFLOW_INCOMING_HANGUP			6
+#define 	CALLFLOW_CALL_RELEASED				7
+#define 	CALLFLOW_CALL_NOCARRIER				8
+#define 	CALLFLOW_CALL_INFLUX				9
+#define 	CALLFLOW_CALL_INCOMING				10
+#define 	CALLFLOW_CALL_FAILED				11
+#define 	CALLFLOW_CALL_NOSERVICE				12
+#define 	CALLFLOW_CALL_OUTGOINGRESTRICTED	13
+#define 	CALLFLOW_CALL_SECURITYFAIL			14
+#define 	CALLFLOW_CALL_NOANSWER				15
+#define 	CALLFLOW_STATUS_FINISHED			16
+#define 	CALLFLOW_STATUS_CANCELLED			17
+#define 	CALLFLOW_STATUS_FAILED				18
+#define 	CALLFLOW_STATUS_REFUSED				19
+#define 	CALLFLOW_STATUS_RINGING				20
+#define 	CALLFLOW_STATUS_INPROGRESS			21
+#define 	CALLFLOW_STATUS_UNPLACED			22
+#define 	CALLFLOW_STATUS_ROUTING				23
+#define 	CALLFLOW_STATUS_EARLYMEDIA			24
+#define 	CALLFLOW_INCOMING_CALLID			25
+#define 	CALLFLOW_STATUS_REMOTEHOLD			26
+
+/*********************************/
+
+#define SKYPIAX_MAX_INTERFACES 64
+
+#ifndef WIN32
+struct SkypiaxHandles {
+	Window skype_win;
+	Display *disp;
+	Window win;
+	int currentuserhandle;
+	int api_connected;
+	int fdesc[2];
+};
+#else //WIN32
+
+struct SkypiaxHandles {
+	HWND win32_hInit_MainWindowHandle;
+	HWND win32_hGlobal_SkypeAPIWindowHandle;
+	HINSTANCE win32_hInit_ProcessHandle;
+	char win32_acInit_WindowClassName[128];
+	UINT win32_uiGlobal_MsgID_SkypeControlAPIAttach;
+	UINT win32_uiGlobal_MsgID_SkypeControlAPIDiscover;
+	int currentuserhandle;
+	int api_connected;
+	switch_file_t *fdesc[2];
+};
+
+#endif //WIN32
+
+struct private_object {
+	unsigned int flags;
+	switch_codec_t read_codec;
+	switch_codec_t write_codec;
+	switch_frame_t read_frame;
+	unsigned char databuf[SWITCH_RECOMMENDED_BUFFER_SIZE];
+	char session_uuid_str[SWITCH_UUID_FORMATTED_LENGTH + 1];
+	switch_caller_profile_t *caller_profile;
+	switch_mutex_t *mutex;
+	switch_mutex_t *flag_mutex;
+
+	char interface_id[80];
+	char name[80];
+	char dialplan[80];
+	char context[80];
+	char dial_regex[256];
+	char fail_dial_regex[256];
+	char hold_music[256];
+	char type[256];
+	char X11_display[256];
+#ifdef WIN32
+	unsigned short tcp_cli_port;
+	unsigned short tcp_srv_port;
+#else
+	int tcp_cli_port;
+	int tcp_srv_port;
+#endif
+	struct SkypiaxHandles SkypiaxHandles;
+
+	int interface_state;		/*!< \brief 'state' of the interface (channel) */
+	char language[80];			/*!< \brief default Asterisk dialplan language for this interface */
+	char exten[80];				/*!< \brief default Asterisk dialplan extension for this interface */
+	int skypiax_sound_rate;		/*!< \brief rate of the sound device, in Hz, eg: 8000 */
+	char callid_name[50];
+	char callid_number[50];
+	double playback_boost;
+	double capture_boost;
+	int stripmsd;
+	char skype_call_id[512];
+	int skype_call_ongoing;
+	char skype_friends[4096];
+	char skype_fullname[512];
+	char skype_displayname[512];
+	int skype_callflow;			/*!< \brief 'callflow' of the skype interface (as opposed to phone interface) */
+	int skype;					/*!< \brief config flag, bool, Skype support on this interface (0 if false, -1 if true) */
+	int control_to_send;
+#ifdef WIN32
+	switch_file_t *audiopipe[2];
+	switch_file_t *audioskypepipe[2];
+	switch_file_t *skypiax_sound_capt_fd;	/*!< \brief file descriptor for sound capture dev */
+#else							/* WIN32 */
+	int audiopipe[2];
+	int audioskypepipe[2];
+	int skypiax_sound_capt_fd;	/*!< \brief file descriptor for sound capture dev */
+#endif							/* WIN32 */
+	switch_thread_t *tcp_srv_thread;
+	switch_thread_t *tcp_cli_thread;
+	switch_thread_t *skypiax_signaling_thread;
+	switch_thread_t *skypiax_api_thread;
+	short audiobuf[SAMPLES_PER_FRAME];
+	int audiobuf_is_loaded;
+
+	//int phonebook_listing;
+	//int phonebook_querying;
+	//int phonebook_listing_received_calls;
+
+	//int phonebook_first_entry;
+	//int phonebook_last_entry;
+	//int phonebook_number_lenght;
+	//int phonebook_text_lenght;
+	FILE *phonebook_writing_fp;
+	int skypiax_dir_entry_extension_prefix;
+	char skype_user[256];
+	char skype_password[256];
+	char destination[256];
+	struct timeval answer_time;
+
+	struct timeval transfer_time;
+	char transfer_callid_number[50];
+	char skype_transfer_call_id[512];
+	int running;
+	unsigned long ib_calls;
+	unsigned long ob_calls;
+	unsigned long ib_failed_calls;
+	unsigned long ob_failed_calls;
+};
+
+typedef struct private_object private_t;
+
+void *SWITCH_THREAD_FUNC skypiax_api_thread_func(switch_thread_t * thread, void *obj);
+int skypiax_audio_read(private_t * tech_pvt);
+int skypiax_audio_init(private_t * tech_pvt);
+int skypiax_signaling_write(private_t * tech_pvt, char *msg_to_skype);
+int skypiax_signaling_read(private_t * tech_pvt);
+
+int skypiax_call(private_t * tech_pvt, char *idest, int timeout);
+int skypiax_senddigit(private_t * tech_pvt, char digit);
+
+void *skypiax_do_tcp_srv_thread_func(void *obj);
+void *SWITCH_THREAD_FUNC skypiax_do_tcp_srv_thread(switch_thread_t * thread, void *obj);
+
+void *skypiax_do_tcp_cli_thread_func(void *obj);
+void *SWITCH_THREAD_FUNC skypiax_do_tcp_cli_thread(switch_thread_t * thread, void *obj);
+
+void *skypiax_do_skypeapi_thread_func(void *obj);
+void *SWITCH_THREAD_FUNC skypiax_do_skypeapi_thread(switch_thread_t * thread, void *obj);
+int dtmf_received(private_t * tech_pvt, char *value);
+int start_audio_threads(private_t * tech_pvt);
+int new_inbound_channel(private_t * tech_pvt);
+int outbound_channel_answered(private_t * tech_pvt);
+int skypiax_signaling_write(private_t * tech_pvt, char *msg_to_skype);
+#if defined(WIN32) && !defined(__CYGWIN__)
+int skypiax_pipe_read(switch_file_t * pipe, short *buf, int howmany);
+int skypiax_pipe_write(switch_file_t * pipe, short *buf, int howmany);
+/* Visual C do not have strsep ? */
+char *strsep(char **stringp, const char *delim);
+#else
+int skypiax_pipe_read(int pipe, short *buf, int howmany);
+int skypiax_pipe_write(int pipe, short *buf, int howmany);
+#endif /* WIN32 */
+int skypiax_close_socket(unsigned int fd);
+private_t *find_available_skypiax_interface_rr(private_t * tech_pvt_calling);
+int remote_party_is_ringing(private_t * tech_pvt);
+int remote_party_is_early_media(private_t * tech_pvt);
+int skypiax_answer(private_t * tech_pvt, char *id, char *value);
+int skypiax_transfer(private_t * tech_pvt, char *id, char *value);
+int skypiax_socket_create_and_bind(private_t * tech_pvt, int *which_port);

Added: freeswitch/branches/gmaruzz/mod_celliax/celliax_protocol.c (0 => 14544)


--- freeswitch/branches/gmaruzz/mod_celliax/celliax_protocol.c	                        (rev 0)
+++ freeswitch/branches/gmaruzz/mod_celliax/celliax_protocol.c	2009-08-17 09:17:09 UTC (rev 14544)
@@ -0,0 +1,1548 @@
+#include "skypiax.h"
+
+#ifdef ASTERISK
+#define skypiax_sleep usleep
+#define skypiax_strncpy strncpy
+#define tech_pvt p
+extern int skypiax_debug;
+extern char *skypiax_console_active;
+#else /* FREESWITCH */
+#define skypiax_sleep switch_sleep
+#define skypiax_strncpy switch_copy_string
+extern switch_memory_pool_t *skypiax_module_pool;
+extern switch_endpoint_interface_t *skypiax_endpoint_interface;
+#endif /* ASTERISK */
+int samplerate_skypiax = SAMPLERATE_SKYPIAX;
+
+extern int running;
+
+/*************************************/
+/* suspicious globals FIXME */
+#ifdef WIN32
+DWORD win32_dwThreadId;
+#else
+XErrorHandler old_handler = 0;
+int xerror = 0;
+#endif /* WIN32 */
+/*************************************/
+
+int skypiax_socket_create_and_bind(private_t * tech_pvt, int *which_port)
+{
+	int s = -1;
+	struct sockaddr_in my_addr;
+	int start_port = 6001;
+
+	memset(&my_addr, 0, sizeof(my_addr));
+	my_addr.sin_family = AF_INET;
+	my_addr.sin_addr.s_addr = htonl(0x7f000001);	/* use the localhost */
+
+	if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+		ERRORA("socket Error\n", SKYPIAX_P_LOG);
+		return -1;
+	}
+
+	if (*which_port != 0)
+		start_port = *which_port;
+
+	my_addr.sin_port = htons(start_port);
+	//tech_pvt->tcp_cli_port = start_port;
+	*which_port = start_port;
+	while (bind(s, (struct sockaddr *) &my_addr, sizeof(struct sockaddr)) < 0) {
+		DEBUGA_SKYPE("*which_port=%d, tech_pvt->tcp_cli_port=%d, tech_pvt->tcp_srv_port=%d\n", SKYPIAX_P_LOG, *which_port, tech_pvt->tcp_cli_port,
+					 tech_pvt->tcp_srv_port);
+		DEBUGA_SKYPE("bind errno=%d, error: %s\n", SKYPIAX_P_LOG, errno, strerror(errno));
+		start_port++;
+		my_addr.sin_port = htons(start_port);
+		*which_port = start_port;
+		DEBUGA_SKYPE("*which_port=%d, tech_pvt->tcp_cli_port=%d, tech_pvt->tcp_srv_port=%d\n", SKYPIAX_P_LOG, *which_port, tech_pvt->tcp_cli_port,
+					 tech_pvt->tcp_srv_port);
+
+		if (start_port > 65000) {
+			ERRORA("NO MORE PORTS! *which_port=%d, tech_pvt->tcp_cli_port=%d, tech_pvt->tcp_srv_port=%d\n", SKYPIAX_P_LOG, *which_port,
+				   tech_pvt->tcp_cli_port, tech_pvt->tcp_srv_port);
+			return -1;
+		}
+	}
+
+	DEBUGA_SKYPE("SUCCESS! *which_port=%d, tech_pvt->tcp_cli_port=%d, tech_pvt->tcp_srv_port=%d\n", SKYPIAX_P_LOG, *which_port, tech_pvt->tcp_cli_port,
+				 tech_pvt->tcp_srv_port);
+	return s;
+}
+
+int skypiax_signaling_read(private_t * tech_pvt)
+{
+	char read_from_pipe[4096];
+	char message[4096];
+	char message_2[4096];
+	char *buf, obj[512] = "", id[512] = "", prop[512] = "", value[512] = "", *where;
+	char **stringp = NULL;
+	int a;
+	unsigned int howmany;
+	unsigned int i;
+
+	memset(read_from_pipe, 0, 4096);
+	memset(message, 0, 4096);
+	memset(message_2, 0, 4096);
+
+	howmany = skypiax_pipe_read(tech_pvt->SkypiaxHandles.fdesc[0], (short *) read_from_pipe, sizeof(read_from_pipe));
+
+	a = 0;
+	for (i = 0; i < howmany; i++) {
+		message[a] = read_from_pipe[i];
+		a++;
+
+		if (read_from_pipe[i] == '\0') {
+
+			//if (!strstr(message, "DURATION")) {
+			DEBUGA_SKYPE("READING: |||%s||| \n", SKYPIAX_P_LOG, message);
+			//}
+
+			if (!strcasecmp(message, "ERROR 68")) {
+				DEBUGA_SKYPE
+					("If I don't connect immediately, please give the Skype client authorization to be connected by Skypiax (and to not ask you again)\n",
+					 SKYPIAX_P_LOG);
+				skypiax_sleep(1000000);
+				skypiax_signaling_write(tech_pvt, "PROTOCOL 7");
+				skypiax_sleep(10000);
+				return 0;
+			}
+			if (!strncasecmp(message, "ERROR 92 CALL", 12)) {
+				ERRORA("Skype got ERROR: |||%s|||, the (skypeout) number we called was not recognized as valid\n", SKYPIAX_P_LOG, message);
+				tech_pvt->skype_callflow = CALLFLOW_STATUS_FINISHED;
+				DEBUGA_SKYPE("skype_call now is DOWN\n", SKYPIAX_P_LOG);
+				tech_pvt->skype_call_id[0] = '\0';
+
+				if (tech_pvt->interface_state != SKYPIAX_STATE_HANGUP_REQUESTED) {
+					tech_pvt->interface_state = SKYPIAX_STATE_DOWN;
+					return CALLFLOW_INCOMING_HANGUP;
+				} else {
+					tech_pvt->interface_state = SKYPIAX_STATE_DOWN;
+				}
+			}
+
+			if (!strncasecmp(message, "ERROR", 4)) {
+				if (!strncasecmp(message, "ERROR 96 CALL", 12)) {
+					DEBUGA_SKYPE
+						("Skype got ERROR: |||%s|||, we are trying to use this interface to make or receive a call, but another call is half-active on this interface. Let's the previous one to continue.\n",
+						 SKYPIAX_P_LOG, message);
+				} else if (!strncasecmp(message, "ERROR 99 CALL", 12)) {
+					ERRORA("Skype got ERROR: |||%s|||, another call is active on this interface\n\n\n", SKYPIAX_P_LOG, message);
+					tech_pvt->interface_state = SKYPIAX_STATE_ERROR_DOUBLE_CALL;
+				} else if (!strncasecmp(message, "ERROR 592 ALTER CALL", 19)) {
+					ERRORA("Skype got ERROR about TRANSFERRING, no problem: |||%s|||\n", SKYPIAX_P_LOG, message);
+				} else if (!strncasecmp(message, "ERROR 559 CALL", 13)) {
+					DEBUGA_SKYPE("Skype got ERROR about a failed action (probably TRYING to HANGUP A CALL), no problem: |||%s|||\n", SKYPIAX_P_LOG,
+								 message);
+				} else {
+					ERRORA("Skype got ERROR: |||%s|||\n", SKYPIAX_P_LOG, message);
+					tech_pvt->skype_callflow = CALLFLOW_STATUS_FINISHED;
+					ERRORA("skype_call now is DOWN\n", SKYPIAX_P_LOG);
+					tech_pvt->skype_call_id[0] = '\0';
+
+					if (tech_pvt->interface_state != SKYPIAX_STATE_HANGUP_REQUESTED) {
+						tech_pvt->interface_state = SKYPIAX_STATE_DOWN;
+						return CALLFLOW_INCOMING_HANGUP;
+					} else {
+						tech_pvt->interface_state = SKYPIAX_STATE_DOWN;
+					}
+				}
+			}
+
+
+
+
+			skypiax_strncpy(message_2, message, sizeof(message) - 1);
+			buf = message;
+			stringp = &buf;
+			where = strsep(stringp, " ");
+			if (!where) {
+				WARNINGA("Skype MSG without spaces: %s\n", SKYPIAX_P_LOG, message);
+			}
+
+
+
+
+
+
+
+
+			if (!strcasecmp(message, "CURRENTUSERHANDLE")) {
+				skypiax_strncpy(obj, where, sizeof(obj) - 1);
+				where = strsep(stringp, " ");
+				skypiax_strncpy(id, where, sizeof(id) - 1);
+				if (!strcasecmp(id, tech_pvt->skype_user)) {
+					tech_pvt->SkypiaxHandles.currentuserhandle = 1;
+					DEBUGA_SKYPE
+						("Skype MSG: message: %s, currentuserhandle: %s, cuh: %s, skype_user: %s!\n",
+						 SKYPIAX_P_LOG, message, obj, id, tech_pvt->skype_user);
+				}
+			}
+			if (!strcasecmp(message, "USER")) {
+				skypiax_strncpy(obj, where, sizeof(obj) - 1);
+				where = strsep(stringp, " ");
+				skypiax_strncpy(id, where, sizeof(id) - 1);
+				where = strsep(stringp, " ");
+				skypiax_strncpy(prop, where, sizeof(prop) - 1);
+				if (!strcasecmp(prop, "RECEIVEDAUTHREQUEST")) {
+					char msg_to_skype[256];
+					DEBUGA_SKYPE("Skype MSG: message: %s, obj: %s, id: %s, prop: %s!\n", SKYPIAX_P_LOG, message, obj, id, prop);
+					//TODO: allow authorization based on config param
+					sprintf(msg_to_skype, "SET USER %s ISAUTHORIZED TRUE", id);
+					skypiax_signaling_write(tech_pvt, msg_to_skype);
+				}
+			}
+			if (!strcasecmp(message, "MESSAGE")) {
+				skypiax_strncpy(obj, where, sizeof(obj) - 1);
+				where = strsep(stringp, " ");
+				skypiax_strncpy(id, where, sizeof(id) - 1);
+				where = strsep(stringp, " ");
+				skypiax_strncpy(prop, where, sizeof(prop) - 1);
+				if (!strcasecmp(prop, "STATUS")) {
+					where = strsep(stringp, " ");
+					skypiax_strncpy(value, where, sizeof(value) - 1);
+					if (!strcasecmp(value, "RECEIVED")) {
+						char msg_to_skype[256];
+						DEBUGA_SKYPE("Skype MSG: message: %s, obj: %s, id: %s, prop: %s value: %s!\n", SKYPIAX_P_LOG, message, obj, id, prop, value);
+						//TODO: authomatically flag messages as read based on config param
+						sprintf(msg_to_skype, "SET MESSAGE %s SEEN", id);
+						skypiax_signaling_write(tech_pvt, msg_to_skype);
+					}
+				} else if (!strcasecmp(prop, "BODY")) {
+					char msg_to_skype[256];
+					DEBUGA_SKYPE("Skype MSG: message: %s, obj: %s, id: %s, prop: %s!\n", SKYPIAX_P_LOG, message, obj, id, prop);
+					//TODO: authomatically flag messages as read based on config param
+					sprintf(msg_to_skype, "SET MESSAGE %s SEEN", id);
+					skypiax_signaling_write(tech_pvt, msg_to_skype);
+				}
+			}
+			if (!strcasecmp(message, "CALL")) {
+				skypiax_strncpy(obj, where, sizeof(obj) - 1);
+				where = strsep(stringp, " ");
+				skypiax_strncpy(id, where, sizeof(id) - 1);
+				where = strsep(stringp, " ");
+				skypiax_strncpy(prop, where, sizeof(prop) - 1);
+				where = strsep(stringp, " ");
+				skypiax_strncpy(value, where, sizeof(value) - 1);
+				where = strsep(stringp, " ");
+
+				//DEBUGA_SKYPE
+				//("Skype MSG: message: %s, obj: %s, id: %s, prop: %s, value: %s,where: %s!\n",
+				//SKYPIAX_P_LOG, message, obj, id, prop, value, where ? where : "NULL");
+
+				if (!strcasecmp(prop, "PARTNER_HANDLE")) {
+					if (tech_pvt->interface_state != SKYPIAX_STATE_SELECTED && (!strlen(tech_pvt->skype_call_id) || !strlen(tech_pvt->session_uuid_str))) {
+						//if (!strlen(tech_pvt->skype_call_id)) {
+						/* we are NOT inside an active call */
+						DEBUGA_SKYPE("Call %s TRY ANSWER\n", SKYPIAX_P_LOG, id);
+						skypiax_answer(tech_pvt, id, value);
+					} else {
+						/* we are inside an active call */
+						if (!strcasecmp(tech_pvt->skype_call_id, id)) {
+							/* this is the call in which we are calling out */
+							DEBUGA_SKYPE("Call %s DO NOTHING\n", SKYPIAX_P_LOG, id);
+						} else {
+							skypiax_sleep(400000);	//0.4 seconds
+							DEBUGA_SKYPE("Call %s TRY TRANSFER\n", SKYPIAX_P_LOG, id);
+							skypiax_transfer(tech_pvt, id, value);
+						}
+					}
+				}
+				if (!strcasecmp(prop, "PARTNER_DISPNAME")) {
+					snprintf(tech_pvt->callid_name, sizeof(tech_pvt->callid_name) - 1, "%s%s%s", value, where ? " " : "", where ? where : "");
+					//DEBUGA_SKYPE
+					//("the skype_call %s caller PARTNER_DISPNAME (tech_pvt->callid_name) is: %s\n",
+					//SKYPIAX_P_LOG, id, tech_pvt->callid_name);
+				}
+				if (!strcasecmp(prop, "CONF_ID") && !strcasecmp(value, "0")) {
+					//DEBUGA_SKYPE("the skype_call %s is NOT a conference call\n", SKYPIAX_P_LOG, id);
+					//if (tech_pvt->interface_state == SKYPIAX_STATE_DOWN)
+					//tech_pvt->interface_state = SKYPIAX_STATE_PRERING;
+				}
+				if (!strcasecmp(prop, "CONF_ID") && strcasecmp(value, "0")) {
+					DEBUGA_SKYPE("the skype_call %s is a conference call\n", SKYPIAX_P_LOG, id);
+					//if (tech_pvt->interface_state == SKYPIAX_STATE_DOWN)
+					//tech_pvt->interface_state = SKYPIAX_STATE_PRERING;
+				}
+				if (!strcasecmp(prop, "DTMF")) {
+					DEBUGA_SKYPE("Call %s received a DTMF: %s\n", SKYPIAX_P_LOG, id, value);
+					dtmf_received(tech_pvt, value);
+				}
+				if (!strcasecmp(prop, "FAILUREREASON")) {
+					DEBUGA_SKYPE("Skype FAILED on skype_call %s. Let's wait for the FAILED message.\n", SKYPIAX_P_LOG, id);
+				}
+				if (!strcasecmp(prop, "DURATION") && (!strcasecmp(value, "1"))) {
+					if (strcasecmp(id, tech_pvt->skype_call_id)) {
+						skypiax_strncpy(tech_pvt->skype_call_id, id, sizeof(tech_pvt->skype_call_id) - 1);
+						DEBUGA_SKYPE("We called a Skype contact and he answered us on skype_call: %s.\n", SKYPIAX_P_LOG, id);
+					}
+				}
+
+				if (!strcasecmp(prop, "DURATION") && (tech_pvt->interface_state == SKYPIAX_STATE_ERROR_DOUBLE_CALL)) {
+					char msg_to_skype[1024];
+					skypiax_strncpy(tech_pvt->skype_call_id, id, sizeof(tech_pvt->skype_call_id) - 1);
+					ERRORA("We are in a double call situation, trying to get out hanging up call id: %s.\n", SKYPIAX_P_LOG, id);
+					sprintf(msg_to_skype, "ALTER CALL %s HANGUP", id);
+					skypiax_signaling_write(tech_pvt, msg_to_skype);
+					skypiax_sleep(10000);
+					//return CALLFLOW_INCOMING_HANGUP;
+				}
+
+				if (!strcasecmp(prop, "STATUS")) {
+
+					if (!strcasecmp(value, "RINGING")) {
+						char msg_to_skype[1024];
+						if ((tech_pvt->interface_state != SKYPIAX_STATE_SELECTED && tech_pvt->interface_state != SKYPIAX_STATE_DIALING)
+							&& (!strlen(tech_pvt->skype_call_id) || !strlen(tech_pvt->session_uuid_str))) {
+							/* we are NOT inside an active call */
+
+							DEBUGA_SKYPE("NO ACTIVE calls in this moment, skype_call %s is RINGING, to ask PARTNER_HANDLE\n", SKYPIAX_P_LOG, id);
+							sprintf(msg_to_skype, "GET CALL %s PARTNER_HANDLE", id);
+							skypiax_signaling_write(tech_pvt, msg_to_skype);
+							skypiax_sleep(10000);
+						} else {
+							/* we are inside an active call */
+							if (!strcasecmp(tech_pvt->skype_call_id, id)) {
+								/* this is the call in which we are calling out */
+								tech_pvt->skype_callflow = CALLFLOW_STATUS_RINGING;
+								tech_pvt->interface_state = SKYPIAX_STATE_RINGING;
+								skypiax_strncpy(tech_pvt->skype_call_id, id, sizeof(tech_pvt->skype_call_id) - 1);
+								DEBUGA_SKYPE("Our remote party in skype_call %s is RINGING\n", SKYPIAX_P_LOG, id);
+								remote_party_is_ringing(tech_pvt);
+							} else {
+								DEBUGA_SKYPE
+									("We are in another call, but skype_call %s is RINGING on us, let's ask PARTNER_HANDLE, so maybe we'll TRANSFER\n",
+									 SKYPIAX_P_LOG, id);
+								sprintf(msg_to_skype, "GET CALL %s PARTNER_HANDLE", id);
+								skypiax_signaling_write(tech_pvt, msg_to_skype);
+								skypiax_sleep(10000);
+							}
+						}
+					} else if (!strcasecmp(value, "EARLYMEDIA")) {
+						char msg_to_skype[1024];
+						tech_pvt->skype_callflow = CALLFLOW_STATUS_EARLYMEDIA;
+						tech_pvt->interface_state = SKYPIAX_STATE_DIALING;
+						DEBUGA_SKYPE("Our remote party in skype_call %s is EARLYMEDIA\n", SKYPIAX_P_LOG, id);
+						if (start_audio_threads(tech_pvt)) {
+							ERRORA("start_audio_threads FAILED\n", SKYPIAX_P_LOG);
+							return CALLFLOW_INCOMING_HANGUP;
+						}
+						skypiax_sleep(1000);
+						sprintf(msg_to_skype, "ALTER CALL %s SET_INPUT PORT=\"%d\"", id, tech_pvt->tcp_cli_port);
+						skypiax_signaling_write(tech_pvt, msg_to_skype);
+						sprintf(msg_to_skype, "#output ALTER CALL %s SET_OUTPUT PORT=\"%d\"", id, tech_pvt->tcp_srv_port);
+						skypiax_signaling_write(tech_pvt, msg_to_skype);
+
+						remote_party_is_early_media(tech_pvt);
+					} else if (!strcasecmp(value, "MISSED")) {
+						DEBUGA_SKYPE("We missed skype_call %s\n", SKYPIAX_P_LOG, id);
+					} else if (!strcasecmp(value, "FINISHED")) {
+						//DEBUGA_SKYPE("skype_call %s now is DOWN\n", SKYPIAX_P_LOG, id);
+						if (!strcasecmp(tech_pvt->skype_call_id, id)) {
+							//tech_pvt->skype_callflow = CALLFLOW_STATUS_FINISHED;
+							DEBUGA_SKYPE("skype_call %s is MY call, now I'm going DOWN\n", SKYPIAX_P_LOG, id);
+							//tech_pvt->skype_call_id[0] = '\0';
+							if (tech_pvt->interface_state != SKYPIAX_STATE_HANGUP_REQUESTED) {
+								//tech_pvt->interface_state = SKYPIAX_STATE_DOWN;
+								return CALLFLOW_INCOMING_HANGUP;
+							} else {
+								tech_pvt->interface_state = SKYPIAX_STATE_DOWN;
+							}
+						} else {
+							DEBUGA_SKYPE("skype_call %s is NOT MY call, ignoring\n", SKYPIAX_P_LOG, id);
+						}
+
+					} else if (!strcasecmp(value, "CANCELLED")) {
+						tech_pvt->skype_callflow = CALLFLOW_STATUS_CANCELLED;
+						DEBUGA_SKYPE("we tried to call Skype on skype_call %s and Skype has now CANCELLED\n", SKYPIAX_P_LOG, id);
+						tech_pvt->skype_call_id[0] = '\0';
+						if (tech_pvt->interface_state != SKYPIAX_STATE_HANGUP_REQUESTED) {
+							tech_pvt->interface_state = SKYPIAX_STATE_DOWN;
+							return CALLFLOW_INCOMING_HANGUP;
+						} else {
+							tech_pvt->interface_state = SKYPIAX_STATE_DOWN;
+						}
+					} else if (!strcasecmp(value, "FAILED")) {
+						tech_pvt->skype_callflow = CALLFLOW_STATUS_FAILED;
+						DEBUGA_SKYPE("we tried to call Skype on skype_call %s and Skype has now FAILED\n", SKYPIAX_P_LOG, id);
+						tech_pvt->skype_call_id[0] = '\0';
+						skypiax_strncpy(tech_pvt->skype_call_id, id, sizeof(tech_pvt->skype_call_id) - 1);
+						tech_pvt->interface_state = SKYPIAX_STATE_DOWN;
+						return CALLFLOW_INCOMING_HANGUP;
+					} else if (!strcasecmp(value, "REFUSED")) {
+						if (!strcasecmp(id, tech_pvt->skype_call_id)) {
+							/* this is the id of the call we are in, probably we generated it */
+							tech_pvt->skype_callflow = CALLFLOW_STATUS_REFUSED;
+							DEBUGA_SKYPE("we tried to call Skype on skype_call %s and Skype has now REFUSED\n", SKYPIAX_P_LOG, id);
+							skypiax_strncpy(tech_pvt->skype_call_id, id, sizeof(tech_pvt->skype_call_id) - 1);
+							tech_pvt->interface_state = SKYPIAX_STATE_DOWN;
+							tech_pvt->skype_call_id[0] = '\0';
+							return CALLFLOW_INCOMING_HANGUP;
+						} else {
+							/* we're here because were us that refused an incoming call */
+							DEBUGA_SKYPE("we REFUSED skype_call %s\n", SKYPIAX_P_LOG, id);
+						}
+					} else if (!strcasecmp(value, "TRANSFERRING")) {
+						DEBUGA_SKYPE("skype_call %s is transferring\n", SKYPIAX_P_LOG, id);
+					} else if (!strcasecmp(value, "TRANSFERRED")) {
+						DEBUGA_SKYPE("skype_call %s has been transferred\n", SKYPIAX_P_LOG, id);
+					} else if (!strcasecmp(value, "ROUTING")) {
+						tech_pvt->skype_callflow = CALLFLOW_STATUS_ROUTING;
+						tech_pvt->interface_state = SKYPIAX_STATE_DIALING;
+						skypiax_strncpy(tech_pvt->skype_call_id, id, sizeof(tech_pvt->skype_call_id) - 1);
+						DEBUGA_SKYPE("skype_call: %s is now ROUTING\n", SKYPIAX_P_LOG, id);
+					} else if (!strcasecmp(value, "UNPLACED")) {
+						tech_pvt->skype_callflow = CALLFLOW_STATUS_UNPLACED;
+						tech_pvt->interface_state = SKYPIAX_STATE_DIALING;
+						skypiax_strncpy(tech_pvt->skype_call_id, id, sizeof(tech_pvt->skype_call_id) - 1);
+						DEBUGA_SKYPE("skype_call: %s is now UNPLACED\n", SKYPIAX_P_LOG, id);
+					} else if (!strcasecmp(value, "INPROGRESS")) {
+						char msg_to_skype[1024];
+
+						if (!strlen(tech_pvt->session_uuid_str)) {
+							DEBUGA_SKYPE("no tech_pvt->session_uuid_str\n", SKYPIAX_P_LOG);
+						}
+						if (tech_pvt->skype_callflow != CALLFLOW_STATUS_REMOTEHOLD) {
+							if (!strlen(tech_pvt->session_uuid_str) || !strlen(tech_pvt->skype_call_id)
+								|| !strcasecmp(tech_pvt->skype_call_id, id)) {
+								skypiax_strncpy(tech_pvt->skype_call_id, id, sizeof(tech_pvt->skype_call_id) - 1);
+								DEBUGA_SKYPE("skype_call: %s is now active\n", SKYPIAX_P_LOG, id);
+
+								if (tech_pvt->skype_callflow != CALLFLOW_STATUS_EARLYMEDIA) {
+									tech_pvt->skype_callflow = CALLFLOW_STATUS_INPROGRESS;
+									tech_pvt->interface_state = SKYPIAX_STATE_UP;
+
+									if (start_audio_threads(tech_pvt)) {
+										ERRORA("start_audio_threads FAILED\n", SKYPIAX_P_LOG);
+										return CALLFLOW_INCOMING_HANGUP;
+									}
+									skypiax_sleep(1000);	//FIXME
+									sprintf(msg_to_skype, "ALTER CALL %s SET_INPUT PORT=\"%d\"", id, tech_pvt->tcp_cli_port);
+									skypiax_signaling_write(tech_pvt, msg_to_skype);
+									skypiax_sleep(1000);	//FIXME
+									sprintf(msg_to_skype, "#output ALTER CALL %s SET_OUTPUT PORT=\"%d\"", id, tech_pvt->tcp_srv_port);
+									skypiax_signaling_write(tech_pvt, msg_to_skype);
+								}
+								tech_pvt->skype_callflow = SKYPIAX_STATE_UP;
+								if (!strlen(tech_pvt->session_uuid_str)) {
+									DEBUGA_SKYPE("New Inbound Channel!\n\n\n\n", SKYPIAX_P_LOG);
+									new_inbound_channel(tech_pvt);
+								} else {
+									DEBUGA_SKYPE("Outbound Channel Answered! session_uuid_str=%s\n", SKYPIAX_P_LOG, tech_pvt->session_uuid_str);
+									outbound_channel_answered(tech_pvt);
+								}
+							} else {
+								DEBUGA_SKYPE("I'm on %s, skype_call %s is NOT MY call, ignoring\n", SKYPIAX_P_LOG, tech_pvt->skype_call_id, id);
+							}
+						} else {
+							tech_pvt->skype_callflow = CALLFLOW_STATUS_INPROGRESS;
+							DEBUGA_SKYPE("Back from REMOTEHOLD!\n", SKYPIAX_P_LOG);
+						}
+
+					} else if (!strcasecmp(value, "REMOTEHOLD")) {
+						tech_pvt->skype_callflow = CALLFLOW_STATUS_REMOTEHOLD;
+						DEBUGA_SKYPE("skype_call: %s is now REMOTEHOLD\n", SKYPIAX_P_LOG, id);
+
+					} else if (!strcasecmp(value, "BUSY")) {
+						tech_pvt->skype_callflow = CALLFLOW_STATUS_FAILED;
+						DEBUGA_SKYPE
+							("we tried to call Skype on skype_call %s and remote party (destination) was BUSY. Our outbound call has failed\n",
+							 SKYPIAX_P_LOG, id);
+						skypiax_strncpy(tech_pvt->skype_call_id, id, sizeof(tech_pvt->skype_call_id) - 1);
+						tech_pvt->interface_state = SKYPIAX_STATE_DOWN;
+						tech_pvt->skype_call_id[0] = '\0';
+						skypiax_sleep(1000);
+						return CALLFLOW_INCOMING_HANGUP;
+					} else if (!strcasecmp(value, "WAITING_REDIAL_COMMAND")) {
+						tech_pvt->skype_callflow = CALLFLOW_STATUS_FAILED;
+						DEBUGA_SKYPE
+							("we tried to call Skype on skype_call %s and remote party (destination) has rejected us (WAITING_REDIAL_COMMAND). Our outbound call has failed\n",
+							 SKYPIAX_P_LOG, id);
+						skypiax_strncpy(tech_pvt->skype_call_id, id, sizeof(tech_pvt->skype_call_id) - 1);
+						tech_pvt->interface_state = SKYPIAX_STATE_DOWN;
+						tech_pvt->skype_call_id[0] = '\0';
+						skypiax_sleep(1000);
+						return CALLFLOW_INCOMING_HANGUP;
+					} else {
+						WARNINGA("skype_call: %s, STATUS: %s is not recognized\n", SKYPIAX_P_LOG, id, value);
+					}
+				}				//STATUS
+			}					//CALL
+			/* the "numbered" messages that follows are used by the directory application, not yet ported */
+			if (!strcasecmp(message, "#333")) {
+				/* DEBUGA_SKYPE("Skype MSG: message_2: %s, message2[11]: %s\n", SKYPIAX_P_LOG,
+				 * message_2, &message_2[11]); */
+				memset(tech_pvt->skype_friends, 0, 4096);
+				skypiax_strncpy(tech_pvt->skype_friends, &message_2[11], 4095);
+			}
+			if (!strcasecmp(message, "#222")) {
+				/* DEBUGA_SKYPE("Skype MSG: message_2: %s, message2[10]: %s\n", SKYPIAX_P_LOG,
+				 * message_2, &message_2[10]); */
+				memset(tech_pvt->skype_fullname, 0, 512);
+				skypiax_strncpy(tech_pvt->skype_fullname, &message_2[10], 511);
+			}
+			if (!strcasecmp(message, "#765")) {
+				/* DEBUGA_SKYPE("Skype MSG: message_2: %s, message2[10]: %s\n", SKYPIAX_P_LOG,
+				 * message_2, &message_2[10]); */
+				memset(tech_pvt->skype_displayname, 0, 512);
+				skypiax_strncpy(tech_pvt->skype_displayname, &message_2[10], 511);
+			}
+			a = 0;
+		}						//message end
+	}							//read_from_pipe
+	return 0;
+}
+
+void *skypiax_do_tcp_srv_thread_func(void *obj)
+{
+	private_t *tech_pvt = obj;
+	int s;
+	unsigned int len;
+	unsigned int i;
+	unsigned int a;
+#if defined(WIN32) && !defined(__CYGWIN__)
+	int sin_size;
+#else /* WIN32 */
+	unsigned int sin_size;
+#endif /* WIN32 */
+	unsigned int fd;
+	short srv_in[SAMPLES_PER_FRAME];
+	short srv_out[SAMPLES_PER_FRAME / 2];
+	//struct sockaddr_in my_addr;
+	struct sockaddr_in remote_addr;
+	//int exit = 0;
+	unsigned int kill_cli_size;
+	short kill_cli_buff[SAMPLES_PER_FRAME];
+	short totalbuf[SAMPLES_PER_FRAME];
+
+	s = skypiax_socket_create_and_bind(tech_pvt, &tech_pvt->tcp_srv_port);
+	if (s < 0) {
+		ERRORA("skypiax_socket_create_and_bind error!\n", SKYPIAX_P_LOG);
+		return NULL;
+	}
+	DEBUGA_SKYPE("started tcp_srv_thread thread.\n", SKYPIAX_P_LOG);
+
+	listen(s, 6);
+
+	sin_size = sizeof(remote_addr);
+
+  /****************************/
+	while (tech_pvt->interface_state != SKYPIAX_STATE_DOWN
+		   && (tech_pvt->skype_callflow == CALLFLOW_STATUS_INPROGRESS
+			   || tech_pvt->skype_callflow == CALLFLOW_STATUS_EARLYMEDIA
+			   || tech_pvt->skype_callflow == CALLFLOW_STATUS_REMOTEHOLD || tech_pvt->skype_callflow == SKYPIAX_STATE_UP)) {
+
+		unsigned int fdselectgio;
+		int rtgio;
+		fd_set fsgio;
+		struct timeval togio;
+
+		if (!(running && tech_pvt->running))
+			break;
+		FD_ZERO(&fsgio);
+		togio.tv_usec = 20000;	//20msec
+		togio.tv_sec = 0;
+		fdselectgio = s;
+		FD_SET(fdselectgio, &fsgio);
+
+		rtgio = select(fdselectgio + 1, &fsgio, NULL, NULL, &togio);
+
+		if (rtgio) {
+
+  /****************************/
+
+			while ((fd = accept(s, (struct sockaddr *) &remote_addr, &sin_size)) > 0) {
+				DEBUGA_SKYPE("ACCEPTED here I send you %d\n", SKYPIAX_P_LOG, tech_pvt->tcp_srv_port);
+				if (!(running && tech_pvt->running))
+					break;
+				while (tech_pvt->interface_state != SKYPIAX_STATE_DOWN
+					   && (tech_pvt->skype_callflow == CALLFLOW_STATUS_INPROGRESS
+						   || tech_pvt->skype_callflow == CALLFLOW_STATUS_EARLYMEDIA
+						   || tech_pvt->skype_callflow == CALLFLOW_STATUS_REMOTEHOLD || tech_pvt->skype_callflow == SKYPIAX_STATE_UP)) {
+
+					unsigned int fdselect;
+					int rt;
+					fd_set fs;
+					struct timeval to;
+
+					if (!(running && tech_pvt->running))
+						break;
+					//exit = 1;
+
+					fdselect = fd;
+					FD_ZERO(&fs);
+					FD_SET(fdselect, &fs);
+					//to.tv_usec = 2000000;     //2000 msec
+					to.tv_usec = 60000;	//60 msec
+					to.tv_sec = 0;
+
+					rt = select(fdselect + 1, &fs, NULL, NULL, &to);
+					if (rt > 0) {
+
+						if (tech_pvt->skype_callflow != CALLFLOW_STATUS_REMOTEHOLD) {
+							len = recv(fd, (char *) srv_in, 320, 0);	//seems that Skype only sends 320 bytes at time
+						} else {
+							len = 0;
+						}
+
+						if (len == 320) {
+							unsigned int howmany;
+
+							if (samplerate_skypiax == 8000) {
+								/* we're downsampling from 16khz to 8khz, srv_out will contain each other sample from srv_in */
+								a = 0;
+								for (i = 0; i < len / sizeof(short); i++) {
+									srv_out[a] = srv_in[i];
+									i++;
+									a++;
+								}
+							} else if (samplerate_skypiax == 16000) {
+								/* we're NOT downsampling, srv_out will contain ALL samples from srv_in */
+								for (i = 0; i < len / sizeof(short); i++) {
+									srv_out[i] = srv_in[i];
+								}
+							} else {
+								ERRORA("SAMPLERATE_SKYPIAX can only be 8000 or 16000\n", SKYPIAX_P_LOG);
+							}
+							/* if not yet done, let's store the half incoming frame */
+							if (!tech_pvt->audiobuf_is_loaded) {
+								for (i = 0; i < SAMPLES_PER_FRAME / 2; i++) {
+									tech_pvt->audiobuf[i] = srv_out[i];
+								}
+								tech_pvt->audiobuf_is_loaded = 1;
+							} else {
+								/* we got a stored half frame, build a complete frame in totalbuf using the stored half frame and the current half frame */
+								for (i = 0; i < SAMPLES_PER_FRAME / 2; i++) {
+									totalbuf[i] = tech_pvt->audiobuf[i];
+								}
+								for (a = 0; a < SAMPLES_PER_FRAME / 2; a++) {
+									totalbuf[i] = srv_out[a];
+									i++;
+								}
+								/* send the complete frame through the pipe to our code waiting for incoming audio */
+								howmany = skypiax_pipe_write(tech_pvt->audiopipe[1], totalbuf, SAMPLES_PER_FRAME * sizeof(short));
+								if (howmany != SAMPLES_PER_FRAME * sizeof(short)) {
+									ERRORA("howmany is %d, but was expected to be %d\n", SKYPIAX_P_LOG,
+										   howmany, (int) (SAMPLES_PER_FRAME * sizeof(short)));
+								}
+								/* done with the stored half frame */
+								tech_pvt->audiobuf_is_loaded = 0;
+							}
+
+						} else if (len == 0) {
+							skypiax_sleep(1000);
+						} else {
+							DEBUGA_SKYPE("len=%d, expected 320\n", SKYPIAX_P_LOG, len);
+						}
+
+					} else {
+						if (rt)
+							ERRORA("SRV rt=%d\n", SKYPIAX_P_LOG, rt);
+						skypiax_sleep(10000);
+					}
+
+				}
+
+				/* let's send some frame in the pipes, so both tcp_cli and tcp_srv will have an occasion to die */
+				kill_cli_size = SAMPLES_PER_FRAME * sizeof(short);
+				len = skypiax_pipe_write(tech_pvt->audiopipe[1], kill_cli_buff, kill_cli_size);
+				kill_cli_size = SAMPLES_PER_FRAME * sizeof(short);
+				len = skypiax_pipe_write(tech_pvt->audioskypepipe[1], kill_cli_buff, kill_cli_size);
+				tech_pvt->interface_state = SKYPIAX_STATE_DOWN;
+				kill_cli_size = SAMPLES_PER_FRAME * sizeof(short);
+				len = skypiax_pipe_write(tech_pvt->audiopipe[1], kill_cli_buff, kill_cli_size);
+				kill_cli_size = SAMPLES_PER_FRAME * sizeof(short);
+				len = skypiax_pipe_write(tech_pvt->audioskypepipe[1], kill_cli_buff, kill_cli_size);
+
+				DEBUGA_SKYPE("Skype incoming audio GONE\n", SKYPIAX_P_LOG);
+				skypiax_close_socket(fd);
+				//if (exit)
+				break;
+			}
+		}
+	}
+
+	DEBUGA_SKYPE("incoming audio server (I am it) EXITING\n", SKYPIAX_P_LOG);
+	skypiax_close_socket(s);
+	tech_pvt->tcp_srv_thread = NULL;
+	return NULL;
+}
+
+void *skypiax_do_tcp_cli_thread_func(void *obj)
+{
+	private_t *tech_pvt = obj;
+	int s;
+	//struct sockaddr_in my_addr;
+	struct sockaddr_in remote_addr;
+	unsigned int got;
+	unsigned int len;
+	unsigned int i;
+	unsigned int a;
+	unsigned int fd;
+	short cli_out[SAMPLES_PER_FRAME * 2];
+	short cli_in[SAMPLES_PER_FRAME];
+#ifdef WIN32
+	int sin_size;
+#else
+	unsigned int sin_size;
+#endif /* WIN32 */
+
+	s = skypiax_socket_create_and_bind(tech_pvt, &tech_pvt->tcp_cli_port);
+	if (s < 0) {
+		ERRORA("skypiax_socket_create_and_bind error!\n", SKYPIAX_P_LOG);
+		return NULL;
+	}
+
+
+
+	DEBUGA_SKYPE("started tcp_cli_thread thread.\n", SKYPIAX_P_LOG);
+
+	listen(s, 6);
+
+	sin_size = sizeof(remote_addr);
+
+  /****************************/
+	while (tech_pvt->interface_state != SKYPIAX_STATE_DOWN
+		   && (tech_pvt->skype_callflow == CALLFLOW_STATUS_INPROGRESS
+			   || tech_pvt->skype_callflow == CALLFLOW_STATUS_EARLYMEDIA
+			   || tech_pvt->skype_callflow == CALLFLOW_STATUS_REMOTEHOLD || tech_pvt->skype_callflow == SKYPIAX_STATE_UP)) {
+
+		unsigned int fdselectgio;
+		int rtgio;
+		fd_set fsgio;
+		struct timeval togio;
+
+		if (!(running && tech_pvt->running))
+			break;
+		FD_ZERO(&fsgio);
+		togio.tv_usec = 20000;	//20msec
+		togio.tv_sec = 0;
+		fdselectgio = s;
+		FD_SET(fdselectgio, &fsgio);
+
+		rtgio = select(fdselectgio + 1, &fsgio, NULL, NULL, &togio);
+
+		if (rtgio) {
+
+  /****************************/
+
+			while ((fd = accept(s, (struct sockaddr *) &remote_addr, &sin_size)) > 0) {
+				DEBUGA_SKYPE("ACCEPTED here you send me %d\n", SKYPIAX_P_LOG, tech_pvt->tcp_cli_port);
+#ifndef WIN32
+				fcntl(tech_pvt->audioskypepipe[0], F_SETFL, O_NONBLOCK);
+				fcntl(tech_pvt->audioskypepipe[1], F_SETFL, O_NONBLOCK);
+#endif //WIN32
+
+				if (!(running && tech_pvt->running))
+					break;
+				while (tech_pvt->interface_state != SKYPIAX_STATE_DOWN
+					   && (tech_pvt->skype_callflow == CALLFLOW_STATUS_INPROGRESS
+						   || tech_pvt->skype_callflow == CALLFLOW_STATUS_EARLYMEDIA
+						   || tech_pvt->skype_callflow == CALLFLOW_STATUS_REMOTEHOLD || tech_pvt->skype_callflow == SKYPIAX_STATE_UP)) {
+					unsigned int fdselect;
+					int rt;
+					fd_set fs;
+					struct timeval to;
+
+					if (!(running && tech_pvt->running))
+						break;
+					FD_ZERO(&fs);
+					to.tv_usec = 120000;	//120msec
+					to.tv_sec = 0;
+#if defined(WIN32) && !defined(__CYGWIN__)
+/* on win32 we cannot select from the apr "pipe", so we select on socket writability */
+					fdselect = fd;
+					FD_SET(fdselect, &fs);
+
+					rt = select(fdselect + 1, NULL, &fs, NULL, &to);
+#else
+/* on *unix and cygwin we select from the real pipe */
+					fdselect = tech_pvt->audioskypepipe[0];
+					FD_SET(fdselect, &fs);
+
+					rt = select(fdselect + 1, &fs, NULL, NULL, &to);
+#endif
+
+					if (rt > 0) {
+						int counter;
+
+						/* until we drained the pipe to empty */
+						for (counter = 0; counter < 10; counter++) {
+							/* read from the pipe the audio frame we are supposed to send out */
+							got = skypiax_pipe_read(tech_pvt->audioskypepipe[0], cli_in, SAMPLES_PER_FRAME * sizeof(short));
+							if (got == -1)
+								break;
+
+							if (got != SAMPLES_PER_FRAME * sizeof(short)) {
+								WARNINGA("got is %d, but was expected to be %d\n", SKYPIAX_P_LOG, got, (int) (SAMPLES_PER_FRAME * sizeof(short)));
+							}
+
+							if (got == SAMPLES_PER_FRAME * sizeof(short)) {
+								if (samplerate_skypiax == 8000) {
+
+									/* we're upsampling from 8khz to 16khz, cli_out will contain two times each sample from cli_in */
+									a = 0;
+									for (i = 0; i < got / sizeof(short); i++) {
+										cli_out[a] = cli_in[i];
+										a++;
+										cli_out[a] = cli_in[i];
+										a++;
+									}
+									got = got * 2;
+								} else if (samplerate_skypiax == 16000) {
+									/* we're NOT upsampling, cli_out will contain just ALL samples from cli_in */
+									for (i = 0; i < got / sizeof(short); i++) {
+										cli_out[i] = cli_in[i];
+									}
+								} else {
+									ERRORA("SAMPLERATE_SKYPIAX can only be 8000 or 16000\n", SKYPIAX_P_LOG);
+								}
+
+								/* send the 16khz frame to the Skype client waiting for incoming audio to be sent to the remote party */
+								if (tech_pvt->skype_callflow != CALLFLOW_STATUS_REMOTEHOLD) {
+									len = send(fd, (char *) cli_out, got, 0);
+									skypiax_sleep(5000);	//5 msec
+
+									if (len == -1) {
+										break;
+									} else if (len != got) {
+										ERRORA("len=%d\n", SKYPIAX_P_LOG, len);
+										skypiax_sleep(1000);
+										break;
+									}
+								}
+
+							} else {
+
+								WARNINGA("got is %d, but was expected to be %d\n", SKYPIAX_P_LOG, got, (int) (SAMPLES_PER_FRAME * sizeof(short)));
+							}
+						}
+					} else {
+						if (rt)
+							ERRORA("CLI rt=%d\n", SKYPIAX_P_LOG, rt);
+						memset(cli_out, 0, sizeof(cli_out));
+						if (tech_pvt->skype_callflow != CALLFLOW_STATUS_REMOTEHOLD) {
+							len = send(fd, (char *) cli_out, sizeof(cli_out), 0);
+							len = send(fd, (char *) cli_out, sizeof(cli_out) / 2, 0);
+							//WARNINGA("sent %d of zeros to keep the Skype client socket busy\n", SKYPIAX_P_LOG, sizeof(cli_out) + sizeof(cli_out)/2);
+						} else {
+							/*
+							   XXX do nothing 
+							 */
+							//WARNINGA("we don't send it\n", SKYPIAX_P_LOG);
+						}
+						skypiax_sleep(1000);
+					}
+
+				}
+				DEBUGA_SKYPE("Skype outbound audio GONE\n", SKYPIAX_P_LOG);
+				skypiax_close_socket(fd);
+				break;
+			}
+		}
+	}
+
+	DEBUGA_SKYPE("outbound audio server (I am it) EXITING\n", SKYPIAX_P_LOG);
+	skypiax_close_socket(s);
+	tech_pvt->tcp_cli_thread = NULL;
+	return NULL;
+}
+
+int skypiax_audio_read(private_t * tech_pvt)
+{
+	unsigned int samples;
+
+	samples = skypiax_pipe_read(tech_pvt->audiopipe[0], tech_pvt->read_frame.data, SAMPLES_PER_FRAME * sizeof(short));
+
+	if (samples != SAMPLES_PER_FRAME * sizeof(short)) {
+		if (samples)
+			WARNINGA("read samples=%u expected=%u\n", SKYPIAX_P_LOG, samples, (int) (SAMPLES_PER_FRAME * sizeof(short)));
+		return 0;
+	} else {
+		/* A real frame */
+		tech_pvt->read_frame.datalen = samples;
+	}
+	return 1;
+}
+
+int skypiax_senddigit(private_t * tech_pvt, char digit)
+{
+	char msg_to_skype[1024];
+
+	DEBUGA_SKYPE("DIGIT received: %c\n", SKYPIAX_P_LOG, digit);
+	sprintf(msg_to_skype, "SET CALL %s DTMF %c", tech_pvt->skype_call_id, digit);
+	skypiax_signaling_write(tech_pvt, msg_to_skype);
+
+	return 0;
+}
+
+int skypiax_call(private_t * tech_pvt, char *rdest, int timeout)
+{
+	char msg_to_skype[1024];
+
+	//skypiax_sleep(5000);
+	DEBUGA_SKYPE("Calling Skype, rdest is: %s\n", SKYPIAX_P_LOG, rdest);
+	//skypiax_signaling_write(tech_pvt, "SET AGC OFF");
+	//skypiax_sleep(10000);
+	//skypiax_signaling_write(tech_pvt, "SET AEC OFF");
+	//skypiax_sleep(10000);
+
+	sprintf(msg_to_skype, "CALL %s", rdest);
+	if (skypiax_signaling_write(tech_pvt, msg_to_skype) < 0) {
+		ERRORA("failed to communicate with Skype client, now exit\n", SKYPIAX_P_LOG);
+		return -1;
+	}
+	return 0;
+}
+
+/***************************/
+/* PLATFORM SPECIFIC */
+/***************************/
+#if defined(WIN32) && !defined(__CYGWIN__)
+int skypiax_pipe_read(switch_file_t * pipe, short *buf, int howmany)
+{
+	switch_size_t quantity;
+
+	quantity = howmany;
+
+	switch_file_read(pipe, buf, &quantity);
+
+	howmany = quantity;
+
+	return howmany;
+}
+
+int skypiax_pipe_write(switch_file_t * pipe, short *buf, int howmany)
+{
+	switch_size_t quantity;
+
+	quantity = howmany;
+
+	switch_file_write(pipe, buf, &quantity);
+
+	howmany = quantity;
+
+	return howmany;
+}
+
+int skypiax_close_socket(unsigned int fd)
+{
+	int res;
+
+	res = closesocket(fd);
+
+	return res;
+}
+
+int skypiax_audio_init(private_t * tech_pvt)
+{
+	switch_status_t rv;
+	rv = switch_file_pipe_create(&tech_pvt->audiopipe[0], &tech_pvt->audiopipe[1], skypiax_module_pool);
+	rv = switch_file_pipe_create(&tech_pvt->audioskypepipe[0], &tech_pvt->audioskypepipe[1], skypiax_module_pool);
+	return 0;
+}
+#else /* WIN32 */
+int skypiax_pipe_read(int pipe, short *buf, int howmany)
+{
+	howmany = read(pipe, buf, howmany);
+	return howmany;
+}
+
+int skypiax_pipe_write(int pipe, short *buf, int howmany)
+{
+	howmany = write(pipe, buf, howmany);
+	return howmany;
+}
+
+int skypiax_close_socket(unsigned int fd)
+{
+	int res;
+
+	res = close(fd);
+
+	return res;
+}
+
+int skypiax_audio_init(private_t * tech_pvt)
+{
+	if (pipe(tech_pvt->audiopipe)) {
+		fcntl(tech_pvt->audiopipe[0], F_SETFL, O_NONBLOCK);
+		fcntl(tech_pvt->audiopipe[1], F_SETFL, O_NONBLOCK);
+	}
+	if (pipe(tech_pvt->audioskypepipe)) {
+		fcntl(tech_pvt->audioskypepipe[0], F_SETFL, O_NONBLOCK);
+		fcntl(tech_pvt->audioskypepipe[1], F_SETFL, O_NONBLOCK);
+	}
+
+/* this pipe is the audio fd for asterisk to poll on during a call. FS do not use it */
+	tech_pvt->skypiax_sound_capt_fd = tech_pvt->audiopipe[0];
+
+	return 0;
+}
+#endif /* WIN32 */
+
+#ifdef WIN32
+
+enum {
+	SKYPECONTROLAPI_ATTACH_SUCCESS = 0,	/*  Client is successfully 
+										   attached and API window handle can be found
+										   in wParam parameter */
+	SKYPECONTROLAPI_ATTACH_PENDING_AUTHORIZATION = 1,	/*  Skype has acknowledged
+														   connection request and is waiting
+														   for confirmation from the user. */
+	/*  The client is not yet attached 
+	 * and should wait for SKYPECONTROLAPI_ATTACH_SUCCESS message */
+	SKYPECONTROLAPI_ATTACH_REFUSED = 2,	/*  User has explicitly
+										   denied access to client */
+	SKYPECONTROLAPI_ATTACH_NOT_AVAILABLE = 3,	/*  API is not available
+												   at the moment.
+												   For example, this happens when no user
+												   is currently logged in. */
+	/*  Client should wait for 
+	 * SKYPECONTROLAPI_ATTACH_API_AVAILABLE 
+	 * broadcast before making any further */
+	/*  connection attempts. */
+	SKYPECONTROLAPI_ATTACH_API_AVAILABLE = 0x8001
+};
+
+/* Visual C do not have strsep? */
+char
+    *strsep(char **stringp, const char *delim)
+{
+	char *res;
+
+	if (!stringp || !*stringp || !**stringp)
+		return (char *) 0;
+
+	res = *stringp;
+	while (**stringp && !strchr(delim, **stringp))
+		++(*stringp);
+
+	if (**stringp) {
+		**stringp = '\0';
+		++(*stringp);
+	}
+
+	return res;
+}
+
+int skypiax_signaling_write(private_t * tech_pvt, char *msg_to_skype)
+{
+	static char acInputRow[1024];
+	COPYDATASTRUCT oCopyData;
+
+	DEBUGA_SKYPE("SENDING: |||%s||||\n", SKYPIAX_P_LOG, msg_to_skype);
+
+	sprintf(acInputRow, "%s", msg_to_skype);
+	DEBUGA_SKYPE("acInputRow: |||%s||||\n", SKYPIAX_P_LOG, acInputRow);
+	/*  send command to skype */
+	oCopyData.dwData = 0;
+	oCopyData.lpData = acInputRow;
+	oCopyData.cbData = strlen(acInputRow) + 1;
+	if (oCopyData.cbData != 1) {
+		if (SendMessage
+			(tech_pvt->SkypiaxHandles.win32_hGlobal_SkypeAPIWindowHandle, WM_COPYDATA,
+			 (WPARAM) tech_pvt->SkypiaxHandles.win32_hInit_MainWindowHandle, (LPARAM) & oCopyData) == FALSE) {
+			ERRORA("Sending message failed - probably Skype crashed.\n\nPlease shutdown Skypiax, then launch Skypiax and try again.\n", SKYPIAX_P_LOG);
+			return -1;
+		}
+	}
+
+	return 0;
+
+}
+
+LRESULT APIENTRY skypiax_present(HWND hWindow, UINT uiMessage, WPARAM uiParam, LPARAM ulParam)
+{
+	LRESULT lReturnCode;
+	int fIssueDefProc;
+	private_t *tech_pvt = NULL;
+
+	lReturnCode = 0;
+	fIssueDefProc = 0;
+	tech_pvt = (private_t *) GetWindowLong(hWindow, GWL_USERDATA);
+	if (!running)
+		return lReturnCode;
+	switch (uiMessage) {
+	case WM_CREATE:
+		tech_pvt = (private_t *) ((LPCREATESTRUCT) ulParam)->lpCreateParams;
+		SetWindowLong(hWindow, GWL_USERDATA, (LONG) tech_pvt);
+		DEBUGA_SKYPE("got CREATE\n", SKYPIAX_P_LOG);
+		break;
+	case WM_DESTROY:
+		DEBUGA_SKYPE("got DESTROY\n", SKYPIAX_P_LOG);
+		tech_pvt->SkypiaxHandles.win32_hInit_MainWindowHandle = NULL;
+		PostQuitMessage(0);
+		break;
+	case WM_COPYDATA:
+		if (tech_pvt->SkypiaxHandles.win32_hGlobal_SkypeAPIWindowHandle == (HWND) uiParam) {
+			unsigned int howmany;
+			char msg_from_skype[2048];
+
+			PCOPYDATASTRUCT poCopyData = (PCOPYDATASTRUCT) ulParam;
+
+			memset(msg_from_skype, '\0', sizeof(msg_from_skype));
+			skypiax_strncpy(msg_from_skype, (const char *) poCopyData->lpData, sizeof(msg_from_skype) - 2);
+
+			howmany = strlen(msg_from_skype) + 1;
+			howmany = skypiax_pipe_write(tech_pvt->SkypiaxHandles.fdesc[1], (short *) msg_from_skype, howmany);
+			//DEBUGA_SKYPE("From Skype API: %s\n", SKYPIAX_P_LOG, msg_from_skype);
+			lReturnCode = 1;
+		}
+		break;
+	default:
+		if (tech_pvt && tech_pvt->SkypiaxHandles.win32_uiGlobal_MsgID_SkypeControlAPIAttach) {
+			if (uiMessage == tech_pvt->SkypiaxHandles.win32_uiGlobal_MsgID_SkypeControlAPIAttach) {
+				switch (ulParam) {
+				case SKYPECONTROLAPI_ATTACH_SUCCESS:
+					if (!tech_pvt->SkypiaxHandles.currentuserhandle) {
+						//DEBUGA_SKYPE("\n\n\tConnected to Skype API!\n", SKYPIAX_P_LOG);
+						tech_pvt->SkypiaxHandles.api_connected = 1;
+						tech_pvt->SkypiaxHandles.win32_hGlobal_SkypeAPIWindowHandle = (HWND) uiParam;
+						tech_pvt->SkypiaxHandles.win32_hGlobal_SkypeAPIWindowHandle = tech_pvt->SkypiaxHandles.win32_hGlobal_SkypeAPIWindowHandle;
+					}
+					break;
+				case SKYPECONTROLAPI_ATTACH_PENDING_AUTHORIZATION:
+					//DEBUGA_SKYPE ("\n\n\tIf I do not (almost) immediately connect to Skype API,\n\tplease give the Skype client authorization to be connected \n\tby Asterisk and to not ask you again.\n\n", SKYPIAX_P_LOG);
+					skypiax_sleep(5000);
+#if 0
+					if (!tech_pvt->SkypiaxHandles.currentuserhandle) {
+						SendMessage(HWND_BROADCAST,
+									tech_pvt->SkypiaxHandles.
+									win32_uiGlobal_MsgID_SkypeControlAPIDiscover, (WPARAM) tech_pvt->SkypiaxHandles.win32_hInit_MainWindowHandle, 0);
+					}
+#endif
+					break;
+				case SKYPECONTROLAPI_ATTACH_REFUSED:
+					ERRORA("Skype client refused to be connected by Skypiax!\n", SKYPIAX_P_LOG);
+					break;
+				case SKYPECONTROLAPI_ATTACH_NOT_AVAILABLE:
+					ERRORA("Skype API not (yet?) available\n", SKYPIAX_P_LOG);
+					break;
+				case SKYPECONTROLAPI_ATTACH_API_AVAILABLE:
+					DEBUGA_SKYPE("Skype API available\n", SKYPIAX_P_LOG);
+					skypiax_sleep(5000);
+#if 0
+					if (!tech_pvt->SkypiaxHandles.currentuserhandle) {
+						SendMessage(HWND_BROADCAST,
+									tech_pvt->SkypiaxHandles.
+									win32_uiGlobal_MsgID_SkypeControlAPIDiscover, (WPARAM) tech_pvt->SkypiaxHandles.win32_hInit_MainWindowHandle, 0);
+					}
+#endif
+					break;
+				default:
+					WARNINGA("GOT AN UNKNOWN SKYPE WINDOWS MSG\n", SKYPIAX_P_LOG);
+				}
+				lReturnCode = 1;
+				break;
+			}
+		}
+		fIssueDefProc = 1;
+		break;
+	}
+	if (fIssueDefProc)
+		lReturnCode = DefWindowProc(hWindow, uiMessage, uiParam, ulParam);
+	return (lReturnCode);
+}
+
+int win32_Initialize_CreateWindowClass(private_t * tech_pvt)
+{
+	unsigned char *paucUUIDString;
+	RPC_STATUS lUUIDResult;
+	int fReturnStatus;
+	UUID oUUID;
+
+	fReturnStatus = 0;
+	lUUIDResult = UuidCreate(&oUUID);
+	tech_pvt->SkypiaxHandles.win32_hInit_ProcessHandle = (HINSTANCE) OpenProcess(PROCESS_DUP_HANDLE, FALSE, GetCurrentProcessId());
+	if (tech_pvt->SkypiaxHandles.win32_hInit_ProcessHandle != NULL && (lUUIDResult == RPC_S_OK || lUUIDResult == RPC_S_UUID_LOCAL_ONLY)) {
+		if (UuidToString(&oUUID, &paucUUIDString) == RPC_S_OK) {
+			WNDCLASS oWindowClass;
+
+			strcpy(tech_pvt->SkypiaxHandles.win32_acInit_WindowClassName, "Skype-API-Skypiax-");
+			strcat(tech_pvt->SkypiaxHandles.win32_acInit_WindowClassName, (char *) paucUUIDString);
+
+			oWindowClass.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
+			oWindowClass.lpfnWndProc = (WNDPROC) & skypiax_present;
+			oWindowClass.cbClsExtra = 0;
+			oWindowClass.cbWndExtra = 0;
+			oWindowClass.hInstance = tech_pvt->SkypiaxHandles.win32_hInit_ProcessHandle;
+			oWindowClass.hIcon = NULL;
+			oWindowClass.hCursor = NULL;
+			oWindowClass.hbrBackground = NULL;
+			oWindowClass.lpszMenuName = NULL;
+			oWindowClass.lpszClassName = tech_pvt->SkypiaxHandles.win32_acInit_WindowClassName;
+
+			if (RegisterClass(&oWindowClass) != 0)
+				fReturnStatus = 1;
+
+			RpcStringFree(&paucUUIDString);
+		}
+	}
+	if (fReturnStatus == 0)
+		CloseHandle(tech_pvt->SkypiaxHandles.win32_hInit_ProcessHandle);
+	tech_pvt->SkypiaxHandles.win32_hInit_ProcessHandle = NULL;
+	return (fReturnStatus);
+}
+
+void win32_DeInitialize_DestroyWindowClass(private_t * tech_pvt)
+{
+	UnregisterClass(tech_pvt->SkypiaxHandles.win32_acInit_WindowClassName, tech_pvt->SkypiaxHandles.win32_hInit_ProcessHandle);
+	CloseHandle(tech_pvt->SkypiaxHandles.win32_hInit_ProcessHandle);
+	tech_pvt->SkypiaxHandles.win32_hInit_ProcessHandle = NULL;
+}
+
+int win32_Initialize_CreateMainWindow(private_t * tech_pvt)
+{
+	tech_pvt->SkypiaxHandles.win32_hInit_MainWindowHandle =
+		CreateWindowEx(WS_EX_APPWINDOW | WS_EX_WINDOWEDGE,
+					   tech_pvt->SkypiaxHandles.win32_acInit_WindowClassName, "",
+					   WS_BORDER | WS_SYSMENU | WS_MINIMIZEBOX, CW_USEDEFAULT, CW_USEDEFAULT,
+					   128, 128, NULL, 0, tech_pvt->SkypiaxHandles.win32_hInit_ProcessHandle, tech_pvt);
+	return (tech_pvt->SkypiaxHandles.win32_hInit_MainWindowHandle != NULL ? 1 : 0);
+}
+
+void win32_DeInitialize_DestroyMainWindow(private_t * tech_pvt)
+{
+	if (tech_pvt->SkypiaxHandles.win32_hInit_MainWindowHandle != NULL)
+		DestroyWindow(tech_pvt->SkypiaxHandles.win32_hInit_MainWindowHandle), tech_pvt->SkypiaxHandles.win32_hInit_MainWindowHandle = NULL;
+}
+
+void *skypiax_do_skypeapi_thread_func(void *obj)
+{
+	private_t *tech_pvt = obj;
+#if defined(WIN32) && !defined(__CYGWIN__)
+	switch_status_t rv;
+
+	switch_file_pipe_create(&tech_pvt->SkypiaxHandles.fdesc[0], &tech_pvt->SkypiaxHandles.fdesc[1], skypiax_module_pool);
+	rv = switch_file_pipe_create(&tech_pvt->SkypiaxHandles.fdesc[0], &tech_pvt->SkypiaxHandles.fdesc[1], skypiax_module_pool);
+#else /* WIN32 */
+	if (pipe(tech_pvt->SkypiaxHandles.fdesc)) {
+		fcntl(tech_pvt->SkypiaxHandles.fdesc[0], F_SETFL, O_NONBLOCK);
+		fcntl(tech_pvt->SkypiaxHandles.fdesc[1], F_SETFL, O_NONBLOCK);
+	}
+#endif /* WIN32 */
+
+	tech_pvt->SkypiaxHandles.win32_uiGlobal_MsgID_SkypeControlAPIAttach = RegisterWindowMessage("SkypeControlAPIAttach");
+	tech_pvt->SkypiaxHandles.win32_uiGlobal_MsgID_SkypeControlAPIDiscover = RegisterWindowMessage("SkypeControlAPIDiscover");
+
+	skypiax_sleep(200000);		//0,2 sec
+
+	if (tech_pvt->SkypiaxHandles.win32_uiGlobal_MsgID_SkypeControlAPIAttach != 0
+		&& tech_pvt->SkypiaxHandles.win32_uiGlobal_MsgID_SkypeControlAPIDiscover != 0) {
+		if (win32_Initialize_CreateWindowClass(tech_pvt)) {
+			if (win32_Initialize_CreateMainWindow(tech_pvt)) {
+				if (SendMessage
+					(HWND_BROADCAST,
+					 tech_pvt->SkypiaxHandles.win32_uiGlobal_MsgID_SkypeControlAPIDiscover,
+					 (WPARAM) tech_pvt->SkypiaxHandles.win32_hInit_MainWindowHandle, 0) != 0) {
+					tech_pvt->SkypiaxHandles.win32_hInit_MainWindowHandle = tech_pvt->SkypiaxHandles.win32_hInit_MainWindowHandle;
+					while (running && tech_pvt->running) {
+						MSG oMessage;
+						if (!(running && tech_pvt->running))
+							break;
+						while (GetMessage(&oMessage, 0, 0, 0)) {
+							TranslateMessage(&oMessage);
+							DispatchMessage(&oMessage);
+						}
+					}
+				}
+				win32_DeInitialize_DestroyMainWindow(tech_pvt);
+			}
+			win32_DeInitialize_DestroyWindowClass(tech_pvt);
+		}
+	}
+
+	return NULL;
+}
+
+#else /* NOT WIN32 */
+int X11_errors_handler(Display * dpy, XErrorEvent * err)
+{
+	(void) dpy;
+	private_t *tech_pvt = NULL;
+
+	xerror = err->error_code;
+	ERRORA("Received error code %d from X Server\n\n", SKYPIAX_P_LOG, xerror);	///FIXME why crash the entire skypiax? just crash the interface, instead
+	running = 0;
+	return 0;					/*  ignore the error */
+}
+
+static void X11_errors_trap(void)
+{
+	xerror = 0;
+	old_handler = XSetErrorHandler(X11_errors_handler);
+}
+
+static int X11_errors_untrap(void)
+{
+	XSetErrorHandler(old_handler);
+	return (xerror != BadValue) && (xerror != BadWindow);
+}
+
+int skypiax_send_message(struct SkypiaxHandles *SkypiaxHandles, const char *message_P)
+{
+
+	Window w_P;
+	Display *disp;
+	Window handle_P;
+	int ok;
+	private_t *tech_pvt = NULL;
+
+	w_P = SkypiaxHandles->skype_win;
+	disp = SkypiaxHandles->disp;
+	handle_P = SkypiaxHandles->win;
+
+	Atom atom1 = XInternAtom(disp, "SKYPECONTROLAPI_MESSAGE_BEGIN", False);
+	Atom atom2 = XInternAtom(disp, "SKYPECONTROLAPI_MESSAGE", False);
+	unsigned int pos = 0;
+	unsigned int len = strlen(message_P);
+	XEvent e;
+
+	memset(&e, 0, sizeof(e));
+	e.xclient.type = ClientMessage;
+	e.xclient.message_type = atom1;	/*  leading message */
+	e.xclient.display = disp;
+	e.xclient.window = handle_P;
+	e.xclient.format = 8;
+
+	X11_errors_trap();
+	//XLockDisplay(disp);
+	do {
+		unsigned int i;
+		for (i = 0; i < 20 && i + pos <= len; ++i)
+			e.xclient.data.b[i] = message_P[i + pos];
+		XSendEvent(disp, w_P, False, 0, &e);
+
+		e.xclient.message_type = atom2;	/*  following messages */
+		pos += i;
+	} while (pos <= len);
+
+	XSync(disp, False);
+	ok = X11_errors_untrap();
+
+	if (!ok)
+		ERRORA("Sending message failed with status %d\n", SKYPIAX_P_LOG, xerror);
+	//XUnlockDisplay(disp);
+
+	return 1;
+}
+
+int skypiax_signaling_write(private_t * tech_pvt, char *msg_to_skype)
+{
+	struct SkypiaxHandles *SkypiaxHandles;
+
+	DEBUGA_SKYPE("SENDING: |||%s||||\n", SKYPIAX_P_LOG, msg_to_skype);
+
+	SkypiaxHandles = &tech_pvt->SkypiaxHandles;
+
+	if (!skypiax_send_message(SkypiaxHandles, msg_to_skype)) {
+		ERRORA
+			("Sending message failed - probably Skype crashed.\n\nPlease shutdown Skypiax, then restart Skype, then launch Skypiax and try again.\n",
+			 SKYPIAX_P_LOG);
+		return -1;
+	}
+
+	return 0;
+
+}
+
+int skypiax_present(struct SkypiaxHandles *SkypiaxHandles)
+{
+	Atom skype_inst = XInternAtom(SkypiaxHandles->disp, "_SKYPE_INSTANCE", True);
+
+	Atom type_ret;
+	int format_ret;
+	unsigned long nitems_ret;
+	unsigned long bytes_after_ret;
+	unsigned char *prop;
+	int status;
+	private_t *tech_pvt = NULL;
+
+	X11_errors_trap();
+	//XLockDisplay(disp);
+	status =
+		XGetWindowProperty(SkypiaxHandles->disp, DefaultRootWindow(SkypiaxHandles->disp),
+						   skype_inst, 0, 1, False, XA_WINDOW, &type_ret, &format_ret, &nitems_ret, &bytes_after_ret, &prop);
+	//XUnlockDisplay(disp);
+	X11_errors_untrap();
+
+	/*  sanity check */
+	if (status != Success || format_ret != 32 || nitems_ret != 1) {
+		SkypiaxHandles->skype_win = (Window) - 1;
+		DEBUGA_SKYPE("Skype instance not found\n", SKYPIAX_P_LOG);
+		running = 0;
+		SkypiaxHandles->api_connected = 0;
+		return 0;
+	}
+
+	SkypiaxHandles->skype_win = *(const unsigned long *) prop & 0xffffffff;
+	DEBUGA_SKYPE("Skype instance found with id #%d\n", SKYPIAX_P_LOG, (unsigned int) SkypiaxHandles->skype_win);
+	SkypiaxHandles->api_connected = 1;
+	return 1;
+}
+
+void skypiax_clean_disp(void *data)
+{
+
+	int *dispptr;
+	int disp;
+	private_t *tech_pvt = NULL;
+
+	dispptr = data;
+	disp = *dispptr;
+
+	if (disp) {
+		DEBUGA_SKYPE("to be destroyed disp %d\n", SKYPIAX_P_LOG, disp);
+		close(disp);
+		DEBUGA_SKYPE("destroyed disp\n", SKYPIAX_P_LOG);
+	} else {
+		DEBUGA_SKYPE("NOT destroyed disp\n", SKYPIAX_P_LOG);
+	}
+	DEBUGA_SKYPE("OUT destroyed disp\n", SKYPIAX_P_LOG);
+	skypiax_sleep(1000);
+}
+
+void *skypiax_do_skypeapi_thread_func(void *obj)
+{
+
+	private_t *tech_pvt = obj;
+	struct SkypiaxHandles *SkypiaxHandles;
+	char buf[512];
+	Display *disp = NULL;
+	Window root = -1;
+	Window win = -1;
+
+	if (!strlen(tech_pvt->X11_display))
+		strcpy(tech_pvt->X11_display, getenv("DISPLAY"));
+
+	if (!tech_pvt->tcp_srv_port)
+		tech_pvt->tcp_srv_port = 10160;
+
+	if (!tech_pvt->tcp_cli_port)
+		tech_pvt->tcp_cli_port = 10161;
+
+	if (pipe(tech_pvt->SkypiaxHandles.fdesc)) {
+		fcntl(tech_pvt->SkypiaxHandles.fdesc[0], F_SETFL, O_NONBLOCK);
+		fcntl(tech_pvt->SkypiaxHandles.fdesc[1], F_SETFL, O_NONBLOCK);
+	}
+	SkypiaxHandles = &tech_pvt->SkypiaxHandles;
+	disp = XOpenDisplay(tech_pvt->X11_display);
+	if (!disp) {
+		ERRORA("Cannot open X Display '%s', exiting skype thread\n", SKYPIAX_P_LOG, tech_pvt->X11_display);
+		running = 0;
+		return NULL;
+	} else {
+		DEBUGA_SKYPE("X Display '%s' opened\n", SKYPIAX_P_LOG, tech_pvt->X11_display);
+	}
+
+	int xfd;
+	xfd = XConnectionNumber(disp);
+	fcntl(xfd, F_SETFD, FD_CLOEXEC);
+
+	SkypiaxHandles->disp = disp;
+
+	if (skypiax_present(SkypiaxHandles)) {
+		root = DefaultRootWindow(disp);
+		win = XCreateSimpleWindow(disp, root, 0, 0, 1, 1, 0, BlackPixel(disp, DefaultScreen(disp)), BlackPixel(disp, DefaultScreen(disp)));
+
+		SkypiaxHandles->win = win;
+
+		snprintf(buf, 512, "NAME skypiax");
+
+		if (!skypiax_send_message(SkypiaxHandles, buf)) {
+			ERRORA("Sending message failed - probably Skype crashed. Please run/restart Skype manually and launch Skypiax again\n", SKYPIAX_P_LOG);
+			running = 0;
+			return NULL;
+		}
+
+		snprintf(buf, 512, "PROTOCOL 7");
+		if (!skypiax_send_message(SkypiaxHandles, buf)) {
+			ERRORA("Sending message failed - probably Skype crashed. Please run/restart Skype manually and launch Skypiax again\n", SKYPIAX_P_LOG);
+			running = 0;
+			return NULL;
+		}
+
+		/* perform an events loop */
+		XEvent an_event;
+		char buf[21];			/*  can't be longer */
+		char buffer[17000];
+		char *b;
+		int i;
+		int continue_is_broken = 0;
+		Atom atom_begin = XInternAtom(disp, "SKYPECONTROLAPI_MESSAGE_BEGIN", False);
+		Atom atom_continue = XInternAtom(disp, "SKYPECONTROLAPI_MESSAGE", False);
+
+		b = buffer;
+
+		while (1) {
+			XNextEvent(disp, &an_event);
+			if (!(running && tech_pvt->running))
+				break;
+			switch (an_event.type) {
+			case ClientMessage:
+
+				if (an_event.xclient.format != 8)
+					break;
+
+				for (i = 0; i < 20 && an_event.xclient.data.b[i] != '\0'; ++i)
+					buf[i] = an_event.xclient.data.b[i];
+
+				buf[i] = '\0';
+
+				//DEBUGA_SKYPE ("BUF=|||%s|||\n", SKYPIAX_P_LOG, buf);
+
+				if (an_event.xclient.message_type == atom_begin) {
+
+					if (strlen(buffer)) {
+						unsigned int howmany;
+						howmany = strlen(b) + 1;
+						howmany = write(SkypiaxHandles->fdesc[1], b, howmany);
+						DEBUGA_SKYPE("RECEIVED2=|||%s|||\n", SKYPIAX_P_LOG, buffer);
+						memset(buffer, '\0', 17000);
+					}
+				}
+				if (an_event.xclient.message_type == atom_continue) {
+
+					if (!strlen(buffer)) {
+						DEBUGA_SKYPE
+							("Got a 'continue' XAtom without a previous 'begin'. It's value (between vertical bars) is=|||%s|||\n", SKYPIAX_P_LOG, buf);
+						continue_is_broken = 1;
+						if (!strncmp(buf, "ognised identity", 15)) {
+							WARNINGA
+								("Got a 'continue' XAtom without a previous 'begin'. It's value (between vertical bars) is=|||%s|||. Let's introduce a 1 second delay.\n",
+								 SKYPIAX_P_LOG, buf);
+							skypiax_sleep(1000000);	//1 sec
+						}
+						break;
+					}
+				}
+
+				strcat(buffer, buf);
+
+				if (i < 20 || continue_is_broken) {	/* last fragment */
+					unsigned int howmany;
+
+					howmany = strlen(b) + 1;
+
+					howmany = write(SkypiaxHandles->fdesc[1], b, howmany);
+					//DEBUGA_SKYPE ("RECEIVED=|||%s|||\n", SKYPIAX_P_LOG, buffer);
+					memset(buffer, '\0', 17000);
+					XFlush(disp);
+					continue_is_broken = 0;
+				}
+
+				break;
+			default:
+				break;
+			}
+		}
+	} else {
+		ERRORA("Skype is not running, maybe crashed. Please run/restart Skype and relaunch Skypiax\n", SKYPIAX_P_LOG);
+		running = 0;
+		return NULL;
+	}
+	//running = 0;
+	return NULL;
+
+}
+#endif // WIN32

Added: freeswitch/branches/gmaruzz/mod_celliax/mod_celliax.c (0 => 14544)


--- freeswitch/branches/gmaruzz/mod_celliax/mod_celliax.c	                        (rev 0)
+++ freeswitch/branches/gmaruzz/mod_celliax/mod_celliax.c	2009-08-17 09:17:09 UTC (rev 14544)
@@ -0,0 +1,2110 @@
+/*
+ * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ * Copyright (C) 2005/2006, Anthony Minessale II <anthmct@yahoo.com>
+ *
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ *
+ * The Initial Developer of the Original Code is
+ * Anthony Minessale II <anthmct@yahoo.com>
+ * Portions created by the Initial Developer are Copyright (C)
+ * the Initial Developer. All Rights Reserved.
+ *
+ * This module (mod_skypiax) has been contributed by:
+ *
+ * Giovanni Maruzzelli (gmaruzz@gmail.com)
+ *
+ *
+ * Further Contributors:
+ *
+ *
+ *
+ * mod_skypiax.c -- Skype compatible Endpoint Module
+ *
+ */
+
+#include "skypiax.h"
+
+#ifdef WIN32
+/***************/
+// from http://www.openasthra.com/c-tidbits/gettimeofday-function-for-windows/
+
+#include <time.h>
+
+#if defined(_MSC_VER) || defined(_MSC_EXTENSIONS)
+#define DELTA_EPOCH_IN_MICROSECS  11644473600000000Ui64
+#else /*  */
+#define DELTA_EPOCH_IN_MICROSECS  11644473600000000ULL
+#endif /*  */
+struct sk_timezone {
+	int tz_minuteswest;			/* minutes W of Greenwich */
+	int tz_dsttime;				/* type of dst correction */
+};
+int gettimeofday(struct timeval *tv, struct sk_timezone *tz)
+{
+	FILETIME ft;
+	unsigned __int64 tmpres = 0;
+	static int tzflag;
+	if (NULL != tv) {
+		GetSystemTimeAsFileTime(&ft);
+		tmpres |= ft.dwHighDateTime;
+		tmpres <<= 32;
+		tmpres |= ft.dwLowDateTime;
+
+		/*converting file time to unix epoch */
+		tmpres /= 10;			/*convert into microseconds */
+		tmpres -= DELTA_EPOCH_IN_MICROSECS;
+		tv->tv_sec = (long) (tmpres / 1000000UL);
+		tv->tv_usec = (long) (tmpres % 1000000UL);
+	}
+	if (NULL != tz) {
+		if (!tzflag) {
+			_tzset();
+			tzflag++;
+		}
+		tz->tz_minuteswest = _timezone / 60;
+		tz->tz_dsttime = _daylight;
+	}
+	return 0;
+}
+
+/***************/
+#endif /* WIN32 */
+SWITCH_MODULE_LOAD_FUNCTION(mod_skypiax_load);
+SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_skypiax_shutdown);
+SWITCH_MODULE_DEFINITION(mod_skypiax, mod_skypiax_load, mod_skypiax_shutdown, NULL);
+SWITCH_STANDARD_API(sk_function);
+/* BEGIN: Changes here */
+#define SK_SYNTAX "list [full] || console || skype_API_msg || remove < skypeusername | #interface_name | #interface_id > || reload"
+/* END: Changes heres */
+SWITCH_STANDARD_API(skypiax_function);
+#define SKYPIAX_SYNTAX "interface_name skype_API_msg"
+
+/* BEGIN: Changes here */
+#define FULL_RELOAD 0
+#define SOFT_RELOAD 1
+/* END: Changes heres */
+
+char *interface_status[] = {	/* should match SKYPIAX_STATE_xxx in skypiax.h */
+	"IDLE",
+	"DOWN",
+	"RING",
+	"DIALING",
+	"BUSY",
+	"UP",
+	"RINGING",
+	"PRERING",
+	"DOUBLE",
+	"SELECTD",
+	"HANG_RQ",
+	"PREANSW"
+};
+char *skype_callflow[] = {		/* should match CALLFLOW_XXX in skypiax.h */
+	"CALL_IDLE",
+	"CALL_DOWN",
+	"INCOMING_RNG",
+	"CALL_DIALING",
+	"CALL_LINEBUSY",
+	"CALL_ACTIVE",
+	"INCOMING_HNG",
+	"CALL_RLEASD",
+	"CALL_NOCARR",
+	"CALL_INFLUX",
+	"CALL_INCOMING",
+	"CALL_FAILED",
+	"CALL_NOSRVC",
+	"CALL_OUTRESTR",
+	"CALL_SECFAIL",
+	"CALL_NOANSWER",
+	"STATUS_FNSHED",
+	"STATUS_CANCLED",
+	"STATUS_FAILED",
+	"STATUS_REFUSED",
+	"STATUS_RINGING",
+	"STATUS_INPROGRS",
+	"STATUS_UNPLACD",
+	"STATUS_ROUTING",
+	"STATUS_EARLYMD",
+	"INCOMING_CLID",
+	"STATUS_RMTEHOLD"
+};
+
+
+static struct {
+	int debug;
+	char *ip;
+	int port;
+	char *dialplan;
+	char *destination;
+	char *context;
+	char *codec_string;
+	char *codec_order[SWITCH_MAX_CODECS];
+	int codec_order_last;
+	char *codec_rates_string;
+	char *codec_rates[SWITCH_MAX_CODECS];
+	int codec_rates_last;
+	unsigned int flags;
+	int fd;
+	int calls;
+	int real_interfaces;
+	int next_interface;
+	char hold_music[256];
+	private_t SKYPIAX_INTERFACES[SKYPIAX_MAX_INTERFACES];
+	switch_mutex_t *mutex;
+	private_t *sk_console;
+} globals;
+
+switch_endpoint_interface_t *skypiax_endpoint_interface;
+switch_memory_pool_t *skypiax_module_pool = NULL;
+int running = 0;
+
+SWITCH_DECLARE_GLOBAL_STRING_FUNC(set_global_dialplan, globals.dialplan);
+SWITCH_DECLARE_GLOBAL_STRING_FUNC(set_global_context, globals.context);
+SWITCH_DECLARE_GLOBAL_STRING_FUNC(set_global_destination, globals.destination);
+SWITCH_DECLARE_GLOBAL_STRING_FUNC(set_global_codec_string, globals.codec_string);
+SWITCH_DECLARE_GLOBAL_STRING_FUNC(set_global_codec_rates_string, globals.codec_rates_string);
+
+/* BEGIN: Changes here */
+static switch_status_t interface_exists(char *the_interface);
+static switch_status_t remove_interface(char *the_interface);
+/* END: Changes here */
+
+static switch_status_t channel_on_init(switch_core_session_t *session);
+static switch_status_t channel_on_hangup(switch_core_session_t *session);
+static switch_status_t channel_on_destroy(switch_core_session_t *session);
+static switch_status_t channel_on_routing(switch_core_session_t *session);
+static switch_status_t channel_on_exchange_media(switch_core_session_t *session);
+static switch_status_t channel_on_consume_media(switch_core_session_t *session);
+static switch_status_t channel_on_soft_execute(switch_core_session_t *session);
+static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *session,
+													switch_event_t *var_event,
+													switch_caller_profile_t *outbound_profile,
+													switch_core_session_t **new_session, switch_memory_pool_t **pool, switch_originate_flag_t flags);
+static switch_status_t channel_read_frame(switch_core_session_t *session, switch_frame_t **frame, switch_io_flag_t flags, int stream_id);
+static switch_status_t channel_write_frame(switch_core_session_t *session, switch_frame_t *frame, switch_io_flag_t flags, int stream_id);
+static switch_status_t channel_kill_channel(switch_core_session_t *session, int sig);
+static switch_status_t skypiax_tech_init(private_t * tech_pvt, switch_core_session_t *session);
+
+static switch_status_t skypiax_codec(private_t * tech_pvt, int sample_rate, int codec_ms)
+{
+	switch_core_session_t *session = NULL;
+
+	if (switch_core_codec_init
+		(&tech_pvt->read_codec, "L16", NULL, sample_rate, codec_ms, 1,
+		 SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE, NULL, NULL) != SWITCH_STATUS_SUCCESS) {
+		ERRORA("Can't load codec?\n", SKYPIAX_P_LOG);
+		return SWITCH_STATUS_FALSE;
+	}
+
+	if (switch_core_codec_init
+		(&tech_pvt->write_codec, "L16", NULL, sample_rate, codec_ms, 1,
+		 SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE, NULL, NULL) != SWITCH_STATUS_SUCCESS) {
+		ERRORA("Can't load codec?\n", SKYPIAX_P_LOG);
+		switch_core_codec_destroy(&tech_pvt->read_codec);
+		return SWITCH_STATUS_FALSE;
+	}
+
+	tech_pvt->read_frame.rate = sample_rate;
+	tech_pvt->read_frame.codec = &tech_pvt->read_codec;
+
+	session = switch_core_session_locate(tech_pvt->session_uuid_str);
+
+	if (session) {
+		switch_core_session_set_read_codec(session, &tech_pvt->read_codec);
+		switch_core_session_set_write_codec(session, &tech_pvt->write_codec);
+		switch_core_session_rwunlock(session);
+	} else {
+		ERRORA("no session\n", SKYPIAX_P_LOG);
+		return SWITCH_STATUS_FALSE;
+	}
+
+	return SWITCH_STATUS_SUCCESS;
+
+}
+
+switch_status_t skypiax_tech_init(private_t * tech_pvt, switch_core_session_t *session)
+{
+
+	switch_assert(tech_pvt != NULL);
+	switch_assert(session != NULL);
+	tech_pvt->read_frame.data = tech_pvt->databuf;
+	tech_pvt->read_frame.buflen = sizeof(tech_pvt->databuf);
+	switch_mutex_init(&tech_pvt->mutex, SWITCH_MUTEX_NESTED, switch_core_session_get_pool(session));
+	switch_mutex_init(&tech_pvt->flag_mutex, SWITCH_MUTEX_NESTED, switch_core_session_get_pool(session));
+	switch_core_session_set_private(session, tech_pvt);
+	switch_copy_string(tech_pvt->session_uuid_str, switch_core_session_get_uuid(session), sizeof(tech_pvt->session_uuid_str));
+	if (!strlen(tech_pvt->session_uuid_str)) {
+		ERRORA("no tech_pvt->session_uuid_str\n", SKYPIAX_P_LOG);
+		return SWITCH_STATUS_FALSE;
+	}
+	if (skypiax_codec(tech_pvt, SAMPLERATE_SKYPIAX, 20) != SWITCH_STATUS_SUCCESS) {
+		ERRORA("skypiax_codec FAILED\n", SKYPIAX_P_LOG);
+		return SWITCH_STATUS_FALSE;
+	}
+	DEBUGA_SKYPE("skypiax_codec SUCCESS\n", SKYPIAX_P_LOG);
+	return SWITCH_STATUS_SUCCESS;
+}
+
+/* BEGIN: Changes here */
+static switch_status_t interface_exists(char *the_interface)
+{
+	int i;
+	int interface_id;
+
+	if (*the_interface == '#') {	/* look by interface id or interface name */
+		the_interface++;
+		switch_assert(the_interface);
+		interface_id = atoi(the_interface);
+
+		/* take a number as interface id */
+		if (interface_id > 0 || (interface_id == 0 && strcmp(the_interface, "0") == 0)) {
+			if (strlen(globals.SKYPIAX_INTERFACES[interface_id].name)) {
+				return SWITCH_STATUS_SUCCESS;
+			}
+		} else {
+			/* interface name */
+			for (interface_id = 0; interface_id < SKYPIAX_MAX_INTERFACES; interface_id++) {
+				if (strcmp(globals.SKYPIAX_INTERFACES[interface_id].name, the_interface) == 0) {
+					return SWITCH_STATUS_SUCCESS;
+					break;
+				}
+			}
+		}
+	} else {					/* look by skype_user */
+
+
+		for (i = 0; i < SKYPIAX_MAX_INTERFACES; i++) {
+			if (strlen(globals.SKYPIAX_INTERFACES[i].skype_user)) {
+				if (strcmp(globals.SKYPIAX_INTERFACES[i].skype_user, the_interface) == 0) {
+					return SWITCH_STATUS_SUCCESS;
+				}
+			}
+		}
+	}
+	return SWITCH_STATUS_FALSE;
+}
+
+static switch_status_t remove_interface(char *the_interface)
+{
+	int x = 10;
+	unsigned int howmany = 8;
+	int interface_id = -1;
+	private_t *tech_pvt = NULL;
+	switch_status_t status;
+
+	//running = 0;
+
+
+	if (*the_interface == '#') {	/* remove by interface id or interface name */
+		the_interface++;
+		switch_assert(the_interface);
+		interface_id = atoi(the_interface);
+
+		if (interface_id > 0 || (interface_id == 0 && strcmp(the_interface, "0") == 0)) {
+			/* take a number as interface id */
+			tech_pvt = &globals.SKYPIAX_INTERFACES[interface_id];
+		} else {
+
+			for (interface_id = 0; interface_id < SKYPIAX_MAX_INTERFACES; interface_id++) {
+				if (strcmp(globals.SKYPIAX_INTERFACES[interface_id].name, the_interface) == 0) {
+					tech_pvt = &globals.SKYPIAX_INTERFACES[interface_id];
+					break;
+				}
+			}
+		}
+	} else {					/* remove by skype_user */
+		for (interface_id = 0; interface_id < SKYPIAX_MAX_INTERFACES; interface_id++) {
+			if (strcmp(globals.SKYPIAX_INTERFACES[interface_id].skype_user, the_interface) == 0) {
+				tech_pvt = &globals.SKYPIAX_INTERFACES[interface_id];
+				break;
+			}
+		}
+	}
+
+	if (!tech_pvt) {
+		DEBUGA_SKYPE("interface '%s' does not exist\n", SKYPIAX_P_LOG, the_interface);
+		goto end;
+	}
+
+	if (strlen(globals.SKYPIAX_INTERFACES[interface_id].session_uuid_str)) {
+		DEBUGA_SKYPE("interface '%s' is busy\n", SKYPIAX_P_LOG, the_interface);
+		goto end;
+	}
+
+	globals.SKYPIAX_INTERFACES[interface_id].running = 0;
+
+	if (globals.SKYPIAX_INTERFACES[interface_id].skypiax_signaling_thread) {
+#ifdef WIN32
+		switch_file_write(tech_pvt->SkypiaxHandles.fdesc[1], "sciutati", &howmany);	// let's the controldev_thread die
+#else /* WIN32 */
+		howmany = write(tech_pvt->SkypiaxHandles.fdesc[1], "sciutati", howmany);
+#endif /* WIN32 */
+	}
+
+	if (globals.SKYPIAX_INTERFACES[interface_id].skypiax_api_thread) {
+#ifdef WIN32
+		if (SendMessage(tech_pvt->SkypiaxHandles.win32_hInit_MainWindowHandle, WM_DESTROY, 0, 0) == FALSE) {	// let's the skypiax_api_thread_func die
+			DEBUGA_SKYPE("got FALSE here, thread probably was already dead. GetLastError returned: %d\n", SKYPIAX_P_LOG, GetLastError());
+			globals.SKYPIAX_INTERFACES[interface_id].skypiax_api_thread = NULL;
+		}
+#else
+		XEvent e;
+		Atom atom1 = XInternAtom(tech_pvt->SkypiaxHandles.disp, "SKYPECONTROLAPI_MESSAGE_BEGIN", False);
+		memset(&e, 0, sizeof(e));
+		e.xclient.type = ClientMessage;
+		e.xclient.message_type = atom1;	/*  leading message */
+		e.xclient.display = tech_pvt->SkypiaxHandles.disp;
+		e.xclient.window = tech_pvt->SkypiaxHandles.skype_win;
+		e.xclient.format = 8;
+
+		XSendEvent(tech_pvt->SkypiaxHandles.disp, tech_pvt->SkypiaxHandles.win, False, 0, &e);
+		XSync(tech_pvt->SkypiaxHandles.disp, False);
+#endif
+	}
+
+	while (x) {
+		x--;
+		switch_yield(50000);
+	}
+
+	if (globals.SKYPIAX_INTERFACES[interface_id].skypiax_signaling_thread) {
+		switch_thread_join(&status, globals.SKYPIAX_INTERFACES[interface_id].skypiax_signaling_thread);
+	}
+
+	if (globals.SKYPIAX_INTERFACES[interface_id].skypiax_api_thread) {
+		switch_thread_join(&status, globals.SKYPIAX_INTERFACES[interface_id].skypiax_api_thread);
+	}
+
+	switch_mutex_lock(globals.mutex);
+	if (globals.sk_console == &globals.SKYPIAX_INTERFACES[interface_id]) {
+		DEBUGA_SKYPE("interface '%s' no more console\n", SKYPIAX_P_LOG, the_interface);
+		globals.sk_console = NULL;
+	} else {
+		DEBUGA_SKYPE("interface '%s' STILL console\n", SKYPIAX_P_LOG, the_interface);
+	}
+	memset(&globals.SKYPIAX_INTERFACES[interface_id], '\0', sizeof(private_t));
+	globals.real_interfaces--;
+	switch_mutex_unlock(globals.mutex);
+
+	DEBUGA_SKYPE("interface '%s' deleted successfully\n", SKYPIAX_P_LOG, the_interface);
+	globals.SKYPIAX_INTERFACES[interface_id].running = 1;
+  end:
+	//running = 1;
+	return SWITCH_STATUS_SUCCESS;
+}
+
+/* END: Changes here */
+
+/* 
+   State methods they get called when the state changes to the specific state 
+   returning SWITCH_STATUS_SUCCESS tells the core to execute the standard state method next
+   so if you fully implement the state you can return SWITCH_STATUS_FALSE to skip it.
+*/
+static switch_status_t channel_on_init(switch_core_session_t *session)
+{
+	switch_channel_t *channel;
+	private_t *tech_pvt = NULL;
+
+	tech_pvt = switch_core_session_get_private(session);
+	switch_assert(tech_pvt != NULL);
+
+	channel = switch_core_session_get_channel(session);
+	switch_assert(channel != NULL);
+	//ERRORA("%s CHANNEL INIT\n", SKYPIAX_P_LOG, tech_pvt->name);
+	switch_set_flag(tech_pvt, TFLAG_IO);
+
+	/* Move channel's state machine to ROUTING. This means the call is trying
+	   to get from the initial start where the call because, to the point
+	   where a destination has been identified. If the channel is simply
+	   left in the initial state, nothing will happen. */
+	switch_channel_set_state(channel, CS_ROUTING);
+	switch_mutex_lock(globals.mutex);
+	globals.calls++;
+
+	switch_mutex_unlock(globals.mutex);
+	DEBUGA_SKYPE("%s CHANNEL INIT %s\n", SKYPIAX_P_LOG, tech_pvt->name, switch_core_session_get_uuid(session));
+
+	return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status_t channel_on_destroy(switch_core_session_t *session)
+{
+	private_t *tech_pvt = NULL;
+
+	tech_pvt = switch_core_session_get_private(session);
+
+
+	if (tech_pvt) {
+		DEBUGA_SKYPE("%s CHANNEL DESTROY %s\n", SKYPIAX_P_LOG, tech_pvt->name, switch_core_session_get_uuid(session));
+
+		if (switch_core_codec_ready(&tech_pvt->read_codec)) {
+			switch_core_codec_destroy(&tech_pvt->read_codec);
+		}
+
+		if (switch_core_codec_ready(&tech_pvt->write_codec)) {
+			switch_core_codec_destroy(&tech_pvt->write_codec);
+		}
+		*tech_pvt->session_uuid_str = '\0';
+		tech_pvt->interface_state = SKYPIAX_STATE_IDLE;
+		if (tech_pvt->skype_callflow == CALLFLOW_STATUS_FINISHED) {
+			tech_pvt->skype_callflow = CALLFLOW_CALL_IDLE;
+		}
+		switch_core_session_set_private(session, NULL);
+	} else {
+		DEBUGA_SKYPE("!!!!!!NO tech_pvt!!!! CHANNEL DESTROY %s\n", SKYPIAX_P_LOG, switch_core_session_get_uuid(session));
+	}
+
+	return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status_t channel_on_hangup(switch_core_session_t *session)
+{
+	switch_channel_t *channel = NULL;
+	private_t *tech_pvt = NULL;
+	char msg_to_skype[256];
+
+
+	channel = switch_core_session_get_channel(session);
+	switch_assert(channel != NULL);
+
+	tech_pvt = switch_core_session_get_private(session);
+	switch_assert(tech_pvt != NULL);
+
+	if (!switch_channel_test_flag(channel, CF_ANSWERED)) {
+		if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND) {
+			tech_pvt->ob_failed_calls++;
+		} else {
+			tech_pvt->ib_failed_calls++;
+		}
+	}
+
+	switch_clear_flag(tech_pvt, TFLAG_IO);
+	switch_clear_flag(tech_pvt, TFLAG_VOICE);
+	//switch_set_flag(tech_pvt, TFLAG_HANGUP);
+
+	if (strlen(tech_pvt->skype_call_id)) {
+		//switch_thread_cond_signal(tech_pvt->cond);
+		DEBUGA_SKYPE("hanging up skype call: %s\n", SKYPIAX_P_LOG, tech_pvt->skype_call_id);
+		sprintf(msg_to_skype, "ALTER CALL %s HANGUP", tech_pvt->skype_call_id);
+		skypiax_signaling_write(tech_pvt, msg_to_skype);
+	}
+	//memset(tech_pvt->session_uuid_str, '\0', sizeof(tech_pvt->session_uuid_str));
+	//*tech_pvt->session_uuid_str = '\0';
+	DEBUGA_SKYPE("%s CHANNEL HANGUP\n", SKYPIAX_P_LOG, tech_pvt->name);
+	switch_mutex_lock(globals.mutex);
+	globals.calls--;
+	if (globals.calls < 0) {
+		globals.calls = 0;
+	}
+
+	tech_pvt->interface_state = SKYPIAX_STATE_IDLE;
+	if (tech_pvt->skype_callflow == CALLFLOW_STATUS_FINISHED) {
+		tech_pvt->skype_callflow = CALLFLOW_CALL_IDLE;
+	}
+	switch_mutex_unlock(globals.mutex);
+
+	return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status_t channel_on_routing(switch_core_session_t *session)
+{
+	switch_channel_t *channel = NULL;
+	private_t *tech_pvt = NULL;
+
+	channel = switch_core_session_get_channel(session);
+	switch_assert(channel != NULL);
+
+	tech_pvt = switch_core_session_get_private(session);
+	switch_assert(tech_pvt != NULL);
+
+	DEBUGA_SKYPE("%s CHANNEL ROUTING\n", SKYPIAX_P_LOG, tech_pvt->name);
+
+	return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status_t channel_on_execute(switch_core_session_t *session)
+{
+
+	switch_channel_t *channel = NULL;
+	private_t *tech_pvt = NULL;
+
+	channel = switch_core_session_get_channel(session);
+	switch_assert(channel != NULL);
+
+	tech_pvt = switch_core_session_get_private(session);
+	switch_assert(tech_pvt != NULL);
+
+	DEBUGA_SKYPE("%s CHANNEL EXECUTE\n", SKYPIAX_P_LOG, tech_pvt->name);
+
+	return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status_t channel_kill_channel(switch_core_session_t *session, int sig)
+{
+	switch_channel_t *channel = NULL;
+	private_t *tech_pvt = NULL;
+
+	channel = switch_core_session_get_channel(session);
+	switch_assert(channel != NULL);
+
+	tech_pvt = switch_core_session_get_private(session);
+	switch_assert(tech_pvt != NULL);
+
+	DEBUGA_SKYPE("%s CHANNEL KILL_CHANNEL\n", SKYPIAX_P_LOG, tech_pvt->name);
+	switch (sig) {
+	case SWITCH_SIG_KILL:
+		DEBUGA_SKYPE("%s CHANNEL got SWITCH_SIG_KILL\n", SKYPIAX_P_LOG, switch_channel_get_name(channel));
+		//switch_mutex_lock(tech_pvt->flag_mutex);
+		switch_clear_flag(tech_pvt, TFLAG_IO);
+		switch_clear_flag(tech_pvt, TFLAG_VOICE);
+		switch_set_flag(tech_pvt, TFLAG_HANGUP);
+		//switch_mutex_unlock(tech_pvt->flag_mutex);
+		break;
+	case SWITCH_SIG_BREAK:
+		DEBUGA_SKYPE("%s CHANNEL got SWITCH_SIG_BREAK\n", SKYPIAX_P_LOG, switch_channel_get_name(channel));
+		//switch_set_flag(tech_pvt, TFLAG_BREAK);
+		//switch_mutex_lock(tech_pvt->flag_mutex);
+		switch_set_flag(tech_pvt, TFLAG_BREAK);
+		//switch_mutex_unlock(tech_pvt->flag_mutex);
+		break;
+	default:
+		break;
+	}
+
+	return SWITCH_STATUS_SUCCESS;
+}
+static switch_status_t channel_on_consume_media(switch_core_session_t *session)
+{
+	private_t *tech_pvt = NULL;
+
+	tech_pvt = switch_core_session_get_private(session);
+
+	DEBUGA_SKYPE("%s CHANNEL CONSUME_MEDIA\n", SKYPIAX_P_LOG, tech_pvt->name);
+	return SWITCH_STATUS_SUCCESS;
+}
+
+
+static switch_status_t channel_on_exchange_media(switch_core_session_t *session)
+{
+	private_t *tech_pvt = NULL;
+	tech_pvt = switch_core_session_get_private(session);
+	DEBUGA_SKYPE("%s CHANNEL EXCHANGE_MEDIA\n", SKYPIAX_P_LOG, tech_pvt->name);
+	return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status_t channel_on_soft_execute(switch_core_session_t *session)
+{
+	private_t *tech_pvt = NULL;
+	tech_pvt = switch_core_session_get_private(session);
+	DEBUGA_SKYPE("%s CHANNEL SOFT_EXECUTE\n", SKYPIAX_P_LOG, tech_pvt->name);
+	return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status_t channel_send_dtmf(switch_core_session_t *session, const switch_dtmf_t *dtmf)
+{
+	private_t *tech_pvt = switch_core_session_get_private(session);
+	switch_assert(tech_pvt != NULL);
+
+	DEBUGA_SKYPE("%s CHANNEL SEND_DTMF\n", SKYPIAX_P_LOG, tech_pvt->name);
+	DEBUGA_SKYPE("DTMF: %c\n", SKYPIAX_P_LOG, dtmf->digit);
+
+	skypiax_senddigit(tech_pvt, dtmf->digit);
+
+	return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status_t channel_read_frame(switch_core_session_t *session, switch_frame_t **frame, switch_io_flag_t flags, int stream_id)
+{
+	switch_channel_t *channel = NULL;
+	private_t *tech_pvt = NULL;
+	switch_byte_t *data;
+
+	channel = switch_core_session_get_channel(session);
+	switch_assert(channel != NULL);
+
+	tech_pvt = switch_core_session_get_private(session);
+	switch_assert(tech_pvt != NULL);
+
+	if (!switch_channel_ready(channel) || !switch_test_flag(tech_pvt, TFLAG_IO)) {
+		ERRORA("channel not ready \n", SKYPIAX_P_LOG);
+		//TODO: kill the bastard
+		return SWITCH_STATUS_FALSE;
+	}
+
+	tech_pvt->read_frame.flags = SFF_NONE;
+	*frame = NULL;
+
+	if (!skypiax_audio_read(tech_pvt)) {
+
+		ERRORA("skypiax_audio_read ERROR\n", SKYPIAX_P_LOG);
+
+	} else {
+		switch_set_flag(tech_pvt, TFLAG_VOICE);
+	}
+
+	while (switch_test_flag(tech_pvt, TFLAG_IO)) {
+		if (switch_test_flag(tech_pvt, TFLAG_BREAK)) {
+			switch_clear_flag(tech_pvt, TFLAG_BREAK);
+			DEBUGA_SKYPE("CHANNEL READ FRAME goto CNG\n", SKYPIAX_P_LOG);
+			goto cng;
+		}
+
+		if (!switch_test_flag(tech_pvt, TFLAG_IO)) {
+			DEBUGA_SKYPE("CHANNEL READ FRAME not IO\n", SKYPIAX_P_LOG);
+			return SWITCH_STATUS_FALSE;
+		}
+
+		if (switch_test_flag(tech_pvt, TFLAG_IO) && switch_test_flag(tech_pvt, TFLAG_VOICE)) {
+			switch_clear_flag(tech_pvt, TFLAG_VOICE);
+			if (!tech_pvt->read_frame.datalen) {
+				DEBUGA_SKYPE("CHANNEL READ CONTINUE\n", SKYPIAX_P_LOG);
+				continue;
+			}
+			*frame = &tech_pvt->read_frame;
+#ifdef BIGENDIAN
+			if (switch_test_flag(tech_pvt, TFLAG_LINEAR)) {
+				switch_swap_linear((*frame)->data, (int) (*frame)->datalen / 2);
+			}
+#endif
+			return SWITCH_STATUS_SUCCESS;
+		}
+
+		DEBUGA_SKYPE("CHANNEL READ no TFLAG_IO\n", SKYPIAX_P_LOG);
+		return SWITCH_STATUS_FALSE;
+
+	}
+
+	DEBUGA_SKYPE("CHANNEL READ FALSE\n", SKYPIAX_P_LOG);
+	return SWITCH_STATUS_FALSE;
+
+  cng:
+	data = (switch_byte_t *) tech_pvt->read_frame.data;
+	data[0] = 65;
+	data[1] = 0;
+	tech_pvt->read_frame.datalen = 2;
+	tech_pvt->read_frame.flags = SFF_CNG;
+	*frame = &tech_pvt->read_frame;
+	return SWITCH_STATUS_SUCCESS;
+
+}
+
+static switch_status_t channel_write_frame(switch_core_session_t *session, switch_frame_t *frame, switch_io_flag_t flags, int stream_id)
+{
+	switch_channel_t *channel = NULL;
+	private_t *tech_pvt = NULL;
+	unsigned int sent;
+
+	channel = switch_core_session_get_channel(session);
+	switch_assert(channel != NULL);
+
+	tech_pvt = switch_core_session_get_private(session);
+	switch_assert(tech_pvt != NULL);
+
+	if (!switch_channel_ready(channel) || !switch_test_flag(tech_pvt, TFLAG_IO)) {
+		ERRORA("channel not ready \n", SKYPIAX_P_LOG);
+		//TODO: kill the bastard
+		return SWITCH_STATUS_FALSE;
+	}
+#ifdef BIGENDIAN
+	if (switch_test_flag(tech_pvt, TFLAG_LINEAR)) {
+		switch_swap_linear(frame->data, (int) frame->datalen / 2);
+	}
+#endif
+
+	sent = frame->datalen;
+#ifdef WIN32
+	switch_file_write(tech_pvt->audioskypepipe[1], frame->data, &sent);
+#else /* WIN32 */
+	sent = write(tech_pvt->audioskypepipe[1], frame->data, sent);
+#endif /* WIN32 */
+	if (sent != frame->datalen && sent != -1) {
+		DEBUGA_SKYPE("CLI PIPE write %d\n", SKYPIAX_P_LOG, sent);
+	}
+
+	return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status_t channel_answer_channel(switch_core_session_t *session)
+{
+	private_t *tech_pvt;
+	switch_channel_t *channel = NULL;
+
+	channel = switch_core_session_get_channel(session);
+	switch_assert(channel != NULL);
+
+	tech_pvt = switch_core_session_get_private(session);
+	switch_assert(tech_pvt != NULL);
+
+	DEBUGA_SKYPE("ANSWERED! \n", SKYPIAX_P_LOG);
+
+	return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status_t channel_receive_message(switch_core_session_t *session, switch_core_session_message_t *msg)
+{
+	switch_channel_t *channel;
+	private_t *tech_pvt;
+
+	channel = switch_core_session_get_channel(session);
+	switch_assert(channel != NULL);
+
+	tech_pvt = (private_t *) switch_core_session_get_private(session);
+	switch_assert(tech_pvt != NULL);
+
+	switch (msg->message_id) {
+	case SWITCH_MESSAGE_INDICATE_ANSWER:
+		{
+			DEBUGA_SKYPE("MSG_ID=%d, TO BE ANSWERED!\n", SKYPIAX_P_LOG, msg->message_id);
+			channel_answer_channel(session);
+		}
+		break;
+	default:
+		{
+			DEBUGA_SKYPE("MSG_ID=%d\n", SKYPIAX_P_LOG, msg->message_id);
+		}
+		break;
+	}
+
+	return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status_t channel_receive_event(switch_core_session_t *session, switch_event_t *event)
+{
+	struct private_object *tech_pvt = switch_core_session_get_private(session);
+	char *body = switch_event_get_body(event);
+	switch_assert(tech_pvt != NULL);
+
+	if (!body) {
+		body = "";
+	}
+
+	WARNINGA("event: |||%s|||\n", SKYPIAX_P_LOG, body);
+
+	return SWITCH_STATUS_SUCCESS;
+}
+
+switch_state_handler_table_t skypiax_state_handlers = {
+	/*.on_init */ channel_on_init,
+	/*.on_routing */ channel_on_routing,
+	/*.on_execute */ channel_on_execute,
+	/*.on_hangup */ channel_on_hangup,
+	/*.on_exchange_media */ channel_on_exchange_media,
+	/*.on_soft_execute */ channel_on_soft_execute,
+	/*.on_consume_media */ channel_on_consume_media,
+	/*.on_hibernate */ NULL,
+	/*.on_reset */ NULL,
+	/*.on_park */ NULL,
+	/*.on_reporting */ NULL,
+	/*.on_destroy */ channel_on_destroy
+};
+
+switch_io_routines_t skypiax_io_routines = {
+	/*.outgoing_channel */ channel_outgoing_channel,
+	/*.read_frame */ channel_read_frame,
+	/*.write_frame */ channel_write_frame,
+	/*.kill_channel */ channel_kill_channel,
+	/*.send_dtmf */ channel_send_dtmf,
+	/*.receive_message */ channel_receive_message,
+	/*.receive_event */ channel_receive_event
+};
+
+static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *session,
+													switch_event_t *var_event,
+													switch_caller_profile_t *outbound_profile,
+													switch_core_session_t **new_session, switch_memory_pool_t **pool, switch_originate_flag_t flags)
+{
+	private_t *tech_pvt = NULL;
+	if ((*new_session = switch_core_session_request(skypiax_endpoint_interface, SWITCH_CALL_DIRECTION_OUTBOUND, pool)) != 0) {
+		switch_channel_t *channel = NULL;
+		switch_caller_profile_t *caller_profile;
+		char *rdest;
+		int found = 0;
+		char interface_name[256];
+
+		DEBUGA_SKYPE("1 SESSION_REQUEST %s\n", SKYPIAX_P_LOG, switch_core_session_get_uuid(*new_session));
+		switch_core_session_add_stream(*new_session, NULL);
+
+
+		if (!switch_strlen_zero(outbound_profile->destination_number)) {
+			int i;
+			char *slash;
+
+			switch_copy_string(interface_name, outbound_profile->destination_number, 255);
+			slash = strrchr(interface_name, '/');
+			*slash = '\0';
+
+			switch_mutex_lock(globals.mutex);
+			if (strncmp("ANY", interface_name, strlen(interface_name)) == 0 || strncmp("RR", interface_name, strlen(interface_name)) == 0) {
+				/* we've been asked for the "ANY" interface, let's find the first idle interface */
+				//DEBUGA_SKYPE("Finding one available skype interface\n", SKYPIAX_P_LOG);
+				//tech_pvt = find_available_skypiax_interface(NULL);
+				//if (tech_pvt)
+				//found = 1;
+				//} else if (strncmp("RR", interface_name, strlen(interface_name)) == 0) {
+				/* Find the first idle interface using Round Robin */
+				DEBUGA_SKYPE("Finding one available skype interface RR\n", SKYPIAX_P_LOG);
+				tech_pvt = find_available_skypiax_interface_rr(NULL);
+				if (tech_pvt)
+					found = 1;
+			}
+
+			for (i = 0; !found && i < SKYPIAX_MAX_INTERFACES; i++) {
+				/* we've been asked for a normal interface name, or we have not found idle interfaces to serve as the "ANY" interface */
+				if (strlen(globals.SKYPIAX_INTERFACES[i].name)
+					&& (strncmp(globals.SKYPIAX_INTERFACES[i].name, interface_name, strlen(interface_name)) == 0)) {
+					if (strlen(globals.SKYPIAX_INTERFACES[i].session_uuid_str)) {
+						DEBUGA_SKYPE
+							("globals.SKYPIAX_INTERFACES[%d].name=|||%s||| session_uuid_str=|||%s||| is BUSY\n",
+							 SKYPIAX_P_LOG, i, globals.SKYPIAX_INTERFACES[i].name, globals.SKYPIAX_INTERFACES[i].session_uuid_str);
+						DEBUGA_SKYPE("1 SESSION_DESTROY %s\n", SKYPIAX_P_LOG, switch_core_session_get_uuid(*new_session));
+						switch_core_session_destroy(new_session);
+						switch_mutex_unlock(globals.mutex);
+						return SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER;
+					}
+
+					DEBUGA_SKYPE("globals.SKYPIAX_INTERFACES[%d].name=|||%s|||?\n", SKYPIAX_P_LOG, i, globals.SKYPIAX_INTERFACES[i].name);
+					tech_pvt = &globals.SKYPIAX_INTERFACES[i];
+					found = 1;
+					break;
+				}
+
+			}
+
+		} else {
+			ERRORA("Doh! no destination number?\n", SKYPIAX_P_LOG);
+			switch_core_session_destroy(new_session);
+			return SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER;
+		}
+
+		if (!found) {
+			DEBUGA_SKYPE("Doh! no available interface for |||%s|||?\n", SKYPIAX_P_LOG, interface_name);
+			DEBUGA_SKYPE("2 SESSION_DESTROY %s\n", SKYPIAX_P_LOG, switch_core_session_get_uuid(*new_session));
+			switch_core_session_destroy(new_session);
+			switch_mutex_unlock(globals.mutex);
+			//return SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER;
+			return SWITCH_CAUSE_NORMAL_CIRCUIT_CONGESTION;
+		}
+
+		channel = switch_core_session_get_channel(*new_session);
+		if (!channel) {
+			ERRORA("Doh! no channel?\n", SKYPIAX_P_LOG);
+			switch_core_session_destroy(new_session);
+			switch_mutex_unlock(globals.mutex);
+			return SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER;
+		}
+		if (skypiax_tech_init(tech_pvt, *new_session) != SWITCH_STATUS_SUCCESS) {
+			ERRORA("Doh! no tech_init?\n", SKYPIAX_P_LOG);
+			switch_core_session_destroy(new_session);
+			switch_mutex_unlock(globals.mutex);
+			return SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER;
+		}
+
+
+		if (outbound_profile) {
+			char name[128];
+
+			snprintf(name, sizeof(name), "skypiax/%s", outbound_profile->destination_number);
+			//snprintf(name, sizeof(name), "skypiax/%s", tech_pvt->name);
+			switch_channel_set_name(channel, name);
+			caller_profile = switch_caller_profile_clone(*new_session, outbound_profile);
+			switch_channel_set_caller_profile(channel, caller_profile);
+			tech_pvt->caller_profile = caller_profile;
+		} else {
+			ERRORA("Doh! no caller profile\n", SKYPIAX_P_LOG);
+			switch_core_session_destroy(new_session);
+			switch_mutex_unlock(globals.mutex);
+			return SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER;
+		}
+
+		tech_pvt->ob_calls++;
+
+		rdest = strchr(caller_profile->destination_number, '/');
+		*rdest++ = '\0';
+
+		//skypiax_call(tech_pvt, rdest, 30);
+
+		switch_copy_string(tech_pvt->session_uuid_str, switch_core_session_get_uuid(*new_session), sizeof(tech_pvt->session_uuid_str));
+		caller_profile = tech_pvt->caller_profile;
+		caller_profile->destination_number = rdest;
+
+		switch_channel_set_flag(channel, CF_OUTBOUND);
+		switch_set_flag(tech_pvt, TFLAG_OUTBOUND);
+		switch_channel_set_state(channel, CS_INIT);
+		skypiax_call(tech_pvt, rdest, 30);
+		switch_mutex_unlock(globals.mutex);
+		return SWITCH_CAUSE_SUCCESS;
+	}
+
+	ERRORA("Doh! no new_session\n", SKYPIAX_P_LOG);
+	return SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER;
+}
+
+/*!
+ * \brief This thread runs during a call, and monitor the interface for signaling, like hangup, caller id, etc most of signaling is handled inside the skypiax_signaling_read function
+ *
+ */
+static void *SWITCH_THREAD_FUNC skypiax_signaling_thread_func(switch_thread_t * thread, void *obj)
+{
+	private_t *tech_pvt = obj;
+	int res;
+	int forever = 1;
+
+	if (!tech_pvt)
+		return NULL;
+
+	DEBUGA_SKYPE("In skypiax_signaling_thread_func: started, p=%p\n", SKYPIAX_P_LOG, (void *) tech_pvt);
+
+	while (forever) {
+		if (!(running && tech_pvt->running))
+			break;
+		res = skypiax_signaling_read(tech_pvt);
+		if (res == CALLFLOW_INCOMING_HANGUP) {
+			switch_core_session_t *session = NULL;
+			switch_channel_t *channel = NULL;
+			//private_t *tech_pvt = NULL;
+			DEBUGA_SKYPE("skype call ended\n", SKYPIAX_P_LOG);
+
+			if (tech_pvt) {
+				session = switch_core_session_locate(tech_pvt->session_uuid_str);
+				if (session) {
+					channel = switch_core_session_get_channel(session);
+					if (channel) {
+						switch_channel_state_t state = switch_channel_get_state(channel);
+						if (state < CS_EXECUTE) {
+							switch_sleep(10000);	//10 msec, let the state evolve from CS_NEW
+						}
+						switch_channel_hangup(channel, SWITCH_CAUSE_NORMAL_CLEARING);
+					} else {
+						ERRORA("no channel?\n", SKYPIAX_P_LOG);
+					}
+					switch_core_session_rwunlock(session);
+				} else {
+					DEBUGA_SKYPE("no session\n", SKYPIAX_P_LOG);
+				}
+				switch_mutex_lock(globals.mutex);
+				tech_pvt->interface_state = SKYPIAX_STATE_DOWN;
+				*tech_pvt->session_uuid_str = '\0';
+				*tech_pvt->skype_call_id = '\0';
+				switch_mutex_unlock(globals.mutex);
+
+				//ERRORA("LET'S WAIT\n", SKYPIAX_P_LOG);
+				switch_sleep(300000);	//0.3 sec
+				//ERRORA("WAIT'S OVER\n", SKYPIAX_P_LOG);
+				//tech_pvt->skype_callflow = CALLFLOW_STATUS_FINISHED;
+				//usleep(30000);    //0.03 sec
+				switch_mutex_lock(globals.mutex);
+				tech_pvt->skype_callflow = CALLFLOW_CALL_IDLE;
+				tech_pvt->interface_state = SKYPIAX_STATE_IDLE;
+				switch_mutex_unlock(globals.mutex);
+			} else {
+				ERRORA("no tech_pvt?\n", SKYPIAX_P_LOG);
+			}
+		}
+	}
+	return NULL;
+}
+
+/* BEGIN: Changes heres */
+static switch_status_t load_config(int reload_type)
+/* END: Changes heres */
+{
+	char *cf = "skypiax.conf";
+	switch_xml_t cfg, xml, global_settings, param, interfaces, myinterface;
+	private_t *tech_pvt = NULL;
+
+	switch_mutex_init(&globals.mutex, SWITCH_MUTEX_NESTED, skypiax_module_pool);
+	if (!(xml = switch_xml_open_cfg(cf, &cfg, NULL))) {
+		ERRORA("open of %s failed\n", SKYPIAX_P_LOG, cf);
+		running = 0;
+		switch_xml_free(xml);
+		return SWITCH_STATUS_TERM;
+	}
+
+	switch_mutex_lock(globals.mutex);
+	if ((global_settings = switch_xml_child(cfg, "global_settings"))) {
+		for (param = switch_xml_child(global_settings, "param"); param; param = param->next) {
+			char *var = (char *) switch_xml_attr_soft(param, "name");
+			char *val = (char *) switch_xml_attr_soft(param, "value");
+
+			if (!strcasecmp(var, "debug")) {
+				DEBUGA_SKYPE("globals.debug=%d\n", SKYPIAX_P_LOG, globals.debug);
+				globals.debug = atoi(val);
+				DEBUGA_SKYPE("globals.debug=%d\n", SKYPIAX_P_LOG, globals.debug);
+			} else if (!strcasecmp(var, "hold-music")) {
+				switch_set_string(globals.hold_music, val);
+				DEBUGA_SKYPE("globals.hold_music=%s\n", SKYPIAX_P_LOG, globals.hold_music);
+			} else if (!strcmp(var, "port")) {
+				globals.port = atoi(val);
+				DEBUGA_SKYPE("globals.port=%d\n", SKYPIAX_P_LOG, globals.port);
+			} else if (!strcmp(var, "codec-master")) {
+				if (!strcasecmp(val, "us")) {
+					switch_set_flag(&globals, GFLAG_MY_CODEC_PREFS);
+				}
+				DEBUGA_SKYPE("codec-master globals.debug=%d\n", SKYPIAX_P_LOG, globals.debug);
+			} else if (!strcmp(var, "dialplan")) {
+				set_global_dialplan(val);
+				DEBUGA_SKYPE("globals.dialplan=%s\n", SKYPIAX_P_LOG, globals.dialplan);
+			} else if (!strcmp(var, "destination")) {
+				set_global_destination(val);
+				DEBUGA_SKYPE("globals.destination=%s\n", SKYPIAX_P_LOG, globals.destination);
+			} else if (!strcmp(var, "context")) {
+				set_global_context(val);
+				DEBUGA_SKYPE("globals.context=%s\n", SKYPIAX_P_LOG, globals.context);
+			} else if (!strcmp(var, "codec-prefs")) {
+				set_global_codec_string(val);
+				DEBUGA_SKYPE("globals.codec_string=%s\n", SKYPIAX_P_LOG, globals.codec_string);
+				globals.codec_order_last = switch_separate_string(globals.codec_string, ',', globals.codec_order, SWITCH_MAX_CODECS);
+			} else if (!strcmp(var, "codec-rates")) {
+				set_global_codec_rates_string(val);
+				DEBUGA_SKYPE("globals.codec_rates_string=%s\n", SKYPIAX_P_LOG, globals.codec_rates_string);
+				globals.codec_rates_last = switch_separate_string(globals.codec_rates_string, ',', globals.codec_rates, SWITCH_MAX_CODECS);
+			}
+
+		}
+	}
+
+	if ((interfaces = switch_xml_child(cfg, "per_interface_settings"))) {
+		int i = 0;
+
+		for (myinterface = switch_xml_child(interfaces, "interface"); myinterface; myinterface = myinterface->next) {
+			char *id = (char *) switch_xml_attr(myinterface, "id");
+			char *name = (char *) switch_xml_attr(myinterface, "name");
+			char *context = "default";
+			char *dialplan = "XML";
+			char *destination = "5000";
+			char *tonegroup = NULL;
+			char *digit_timeout = NULL;
+			char *max_digits = NULL;
+			char *hotline = NULL;
+			char *dial_regex = NULL;
+			char *hold_music = NULL;
+			char *fail_dial_regex = NULL;
+			char *enable_callerid = "true";
+			char *X11_display = NULL;
+			char *tcp_cli_port = NULL;
+			char *tcp_srv_port = NULL;
+			char *skype_user = NULL;
+
+			uint32_t interface_id = 0, to = 0, max = 0;
+
+			tech_pvt = NULL;
+
+			for (param = switch_xml_child(myinterface, "param"); param; param = param->next) {
+				char *var = (char *) switch_xml_attr_soft(param, "name");
+				char *val = (char *) switch_xml_attr_soft(param, "value");
+
+				if (!strcasecmp(var, "tonegroup")) {
+					tonegroup = val;
+				} else if (!strcasecmp(var, "digit_timeout") || !strcasecmp(var, "digit-timeout")) {
+					digit_timeout = val;
+				} else if (!strcasecmp(var, "context")) {
+					context = val;
+				} else if (!strcasecmp(var, "dialplan")) {
+					dialplan = val;
+				} else if (!strcasecmp(var, "destination")) {
+					destination = val;
+				} else if (!strcasecmp(var, "dial-regex")) {
+					dial_regex = val;
+				} else if (!strcasecmp(var, "enable-callerid")) {
+					enable_callerid = val;
+				} else if (!strcasecmp(var, "fail-dial-regex")) {
+					fail_dial_regex = val;
+				} else if (!strcasecmp(var, "hold-music")) {
+					hold_music = val;
+				} else if (!strcasecmp(var, "skype_user")) {
+					skype_user = val;
+				} else if (!strcasecmp(var, "tcp_cli_port")) {
+					tcp_cli_port = val;
+				} else if (!strcasecmp(var, "tcp_srv_port")) {
+					tcp_srv_port = val;
+				} else if (!strcasecmp(var, "X11-display") || !strcasecmp(var, "X11_display")) {
+					X11_display = val;
+				} else if (!strcasecmp(var, "max_digits") || !strcasecmp(var, "max-digits")) {
+					max_digits = val;
+				} else if (!strcasecmp(var, "hotline")) {
+					hotline = val;
+				}
+
+			}
+			if (!skype_user) {
+				ERRORA("interface missing REQUIRED param 'skype_user'\n", SKYPIAX_P_LOG);
+				continue;
+			}
+
+			/* BEGIN: Changes here */
+			if (reload_type == SOFT_RELOAD) {
+				char the_interface[256];
+				sprintf(the_interface, "#%s", name);
+
+				if (interface_exists(the_interface) == SWITCH_STATUS_SUCCESS) {
+					continue;
+				}
+			}
+			/* END: Changes here */
+
+			if (!X11_display) {
+				ERRORA("interface missing REQUIRED param 'X11_display'\n", SKYPIAX_P_LOG);
+				continue;
+			}
+			if (!tcp_cli_port) {
+				ERRORA("interface missing REQUIRED param 'tcp_cli_port'\n", SKYPIAX_P_LOG);
+				continue;
+			}
+
+			if (!tcp_srv_port) {
+				ERRORA("interface missing REQUIRED param 'tcp_srv_port'\n", SKYPIAX_P_LOG);
+				continue;
+			}
+			if (!id) {
+				ERRORA("interface missing REQUIRED param 'id'\n", SKYPIAX_P_LOG);
+				continue;
+			}
+			if (switch_is_number(id)) {
+				interface_id = atoi(id);
+				DEBUGA_SKYPE("interface_id=%d\n", SKYPIAX_P_LOG, interface_id);
+			} else {
+				ERRORA("interface param 'id' MUST be a number, now id='%s'\n", SKYPIAX_P_LOG, id);
+				continue;
+			}
+
+			if (!name) {
+				WARNINGA("interface missing param 'name', not nice, but works\n", SKYPIAX_P_LOG);
+			}
+
+			if (!tonegroup) {
+				tonegroup = "us";
+			}
+
+			if (digit_timeout) {
+				to = atoi(digit_timeout);
+			}
+
+			if (max_digits) {
+				max = atoi(max_digits);
+			}
+
+			if (name) {
+				DEBUGA_SKYPE("name=%s\n", SKYPIAX_P_LOG, name);
+			}
+#ifndef WIN32
+			if (!XInitThreads()) {
+				ERRORA("Not initialized XInitThreads!\n", SKYPIAX_P_LOG);
+			} else {
+				DEBUGA_SKYPE("Initialized XInitThreads!\n", SKYPIAX_P_LOG);
+			}
+			switch_sleep(100);
+#endif /* WIN32 */
+
+			if (interface_id && interface_id < SKYPIAX_MAX_INTERFACES) {
+				private_t newconf;
+				switch_threadattr_t *skypiax_api_thread_attr = NULL;
+				switch_threadattr_t *skypiax_signaling_thread_attr = NULL;
+
+				memset(&newconf, '\0', sizeof(newconf));
+				globals.SKYPIAX_INTERFACES[interface_id] = newconf;
+				globals.SKYPIAX_INTERFACES[interface_id].running = 1;
+
+
+				tech_pvt = &globals.SKYPIAX_INTERFACES[interface_id];
+
+				switch_set_string(globals.SKYPIAX_INTERFACES[interface_id].interface_id, id);
+				if (name) {
+					switch_set_string(globals.SKYPIAX_INTERFACES[interface_id].name, name);
+				} else {
+					switch_set_string(globals.SKYPIAX_INTERFACES[interface_id].name, "N/A");
+				}
+				DEBUGA_SKYPE("CONFIGURING interface_id=%d\n", SKYPIAX_P_LOG, interface_id);
+#ifdef WIN32
+				globals.SKYPIAX_INTERFACES[interface_id].tcp_cli_port = (unsigned short) atoi(tcp_cli_port);
+				globals.SKYPIAX_INTERFACES[interface_id].tcp_srv_port = (unsigned short) atoi(tcp_srv_port);
+#else /* WIN32 */
+				globals.SKYPIAX_INTERFACES[interface_id].tcp_cli_port = atoi(tcp_cli_port);
+				globals.SKYPIAX_INTERFACES[interface_id].tcp_srv_port = atoi(tcp_srv_port);
+#endif /* WIN32 */
+				switch_set_string(globals.SKYPIAX_INTERFACES[interface_id].X11_display, X11_display);
+				switch_set_string(globals.SKYPIAX_INTERFACES[interface_id].skype_user, skype_user);
+				switch_set_string(globals.SKYPIAX_INTERFACES[interface_id].context, context);
+				switch_set_string(globals.SKYPIAX_INTERFACES[interface_id].dialplan, dialplan);
+				switch_set_string(globals.SKYPIAX_INTERFACES[interface_id].destination, destination);
+				switch_set_string(globals.SKYPIAX_INTERFACES[interface_id].context, context);
+
+				DEBUGA_SKYPE
+					("interface_id=%d globals.SKYPIAX_INTERFACES[interface_id].X11_display=%s\n",
+					 SKYPIAX_P_LOG, interface_id, globals.SKYPIAX_INTERFACES[interface_id].X11_display);
+				DEBUGA_SKYPE
+					("interface_id=%d globals.SKYPIAX_INTERFACES[interface_id].skype_user=%s\n",
+					 SKYPIAX_P_LOG, interface_id, globals.SKYPIAX_INTERFACES[interface_id].skype_user);
+				DEBUGA_SKYPE
+					("interface_id=%d globals.SKYPIAX_INTERFACES[interface_id].tcp_cli_port=%d\n",
+					 SKYPIAX_P_LOG, interface_id, globals.SKYPIAX_INTERFACES[interface_id].tcp_cli_port);
+				DEBUGA_SKYPE
+					("interface_id=%d globals.SKYPIAX_INTERFACES[interface_id].tcp_srv_port=%d\n",
+					 SKYPIAX_P_LOG, interface_id, globals.SKYPIAX_INTERFACES[interface_id].tcp_srv_port);
+				DEBUGA_SKYPE("interface_id=%d globals.SKYPIAX_INTERFACES[interface_id].name=%s\n",
+							 SKYPIAX_P_LOG, interface_id, globals.SKYPIAX_INTERFACES[interface_id].name);
+				DEBUGA_SKYPE
+					("interface_id=%d globals.SKYPIAX_INTERFACES[interface_id].context=%s\n",
+					 SKYPIAX_P_LOG, interface_id, globals.SKYPIAX_INTERFACES[interface_id].context);
+				DEBUGA_SKYPE
+					("interface_id=%d globals.SKYPIAX_INTERFACES[interface_id].dialplan=%s\n",
+					 SKYPIAX_P_LOG, interface_id, globals.SKYPIAX_INTERFACES[interface_id].dialplan);
+				DEBUGA_SKYPE
+					("interface_id=%d globals.SKYPIAX_INTERFACES[interface_id].destination=%s\n",
+					 SKYPIAX_P_LOG, interface_id, globals.SKYPIAX_INTERFACES[interface_id].destination);
+				DEBUGA_SKYPE
+					("interface_id=%d globals.SKYPIAX_INTERFACES[interface_id].context=%s\n",
+					 SKYPIAX_P_LOG, interface_id, globals.SKYPIAX_INTERFACES[interface_id].context);
+				WARNINGA("STARTING interface_id=%d\n", SKYPIAX_P_LOG, interface_id);
+
+				switch_threadattr_create(&skypiax_api_thread_attr, skypiax_module_pool);
+				switch_threadattr_stacksize_set(skypiax_api_thread_attr, SWITCH_THREAD_STACKSIZE);
+				switch_thread_create(&globals.SKYPIAX_INTERFACES[interface_id].skypiax_api_thread,
+									 skypiax_api_thread_attr, skypiax_do_skypeapi_thread, &globals.SKYPIAX_INTERFACES[interface_id], skypiax_module_pool);
+
+				switch_sleep(100000);
+
+				switch_threadattr_create(&skypiax_signaling_thread_attr, skypiax_module_pool);
+				switch_threadattr_stacksize_set(skypiax_signaling_thread_attr, SWITCH_THREAD_STACKSIZE);
+				switch_thread_create(&globals.SKYPIAX_INTERFACES[interface_id].
+									 skypiax_signaling_thread, skypiax_signaling_thread_attr,
+									 skypiax_signaling_thread_func, &globals.SKYPIAX_INTERFACES[interface_id], skypiax_module_pool);
+
+				switch_sleep(100000);
+
+				skypiax_audio_init(&globals.SKYPIAX_INTERFACES[interface_id]);
+
+				NOTICA
+					("WAITING roughly 10 seconds to find a running Skype client and connect to its SKYPE API for interface_id=%d\n",
+					 SKYPIAX_P_LOG, interface_id);
+				i = 0;
+				while (globals.SKYPIAX_INTERFACES[interface_id].SkypiaxHandles.api_connected == 0 && running && i < 200) {	// 10 seconds! thanks Jeff Lenk
+					switch_sleep(50000);
+					i++;
+				}
+				if (globals.SKYPIAX_INTERFACES[interface_id].SkypiaxHandles.api_connected) {
+					NOTICA
+						("Found a running Skype client, connected to its SKYPE API for interface_id=%d, waiting 60 seconds for CURRENTUSERHANDLE==%s\n",
+						 SKYPIAX_P_LOG, interface_id, globals.SKYPIAX_INTERFACES[interface_id].skype_user);
+				} else {
+					ERRORA
+						("Failed to connect to a SKYPE API for interface_id=%d, no SKYPE client running, please (re)start Skype client. Skypiax exiting\n",
+						 SKYPIAX_P_LOG, interface_id);
+					running = 0;
+					switch_mutex_unlock(globals.mutex);
+					switch_xml_free(xml);
+					return SWITCH_STATUS_FALSE;
+				}
+
+				i = 0;
+				while (globals.SKYPIAX_INTERFACES[interface_id].SkypiaxHandles.currentuserhandle == 0 && running && i < 1200) {	// 60 seconds! thanks Jeff Lenk
+					switch_sleep(50000);
+					i++;
+				}
+				if (globals.SKYPIAX_INTERFACES[interface_id].SkypiaxHandles.currentuserhandle) {
+					WARNINGA
+						("Interface_id=%d is now STARTED, the Skype client to which we are connected gave us the correct CURRENTUSERHANDLE (%s)\n",
+						 SKYPIAX_P_LOG, interface_id, globals.SKYPIAX_INTERFACES[interface_id].skype_user);
+
+					skypiax_signaling_write(&globals.SKYPIAX_INTERFACES[interface_id], "SET AUTOAWAY OFF");
+				} else {
+					ERRORA
+						("The Skype client to which we are connected FAILED to gave us CURRENTUSERHANDLE=%s, interface_id=%d FAILED to start. No Skype client logged in as '%s' has been found. Please (re)launch a Skype client logged in as '%s'. Skypiax exiting now\n",
+						 SKYPIAX_P_LOG, globals.SKYPIAX_INTERFACES[interface_id].skype_user,
+						 interface_id, globals.SKYPIAX_INTERFACES[interface_id].skype_user, globals.SKYPIAX_INTERFACES[interface_id].skype_user);
+					running = 0;
+					switch_mutex_unlock(globals.mutex);
+					switch_xml_free(xml);
+					return SWITCH_STATUS_FALSE;
+				}
+
+			} else {
+				ERRORA("interface id %d is higher than SKYPIAX_MAX_INTERFACES (%d)\n", SKYPIAX_P_LOG, interface_id, SKYPIAX_MAX_INTERFACES);
+				continue;
+			}
+
+		}
+
+		for (i = 0; i < SKYPIAX_MAX_INTERFACES; i++) {
+			if (strlen(globals.SKYPIAX_INTERFACES[i].name)) {
+				/* How many real intterfaces */
+				globals.real_interfaces = i + 1;
+
+				tech_pvt = &globals.SKYPIAX_INTERFACES[i];
+
+				DEBUGA_SKYPE("i=%d globals.SKYPIAX_INTERFACES[%d].interface_id=%s\n", SKYPIAX_P_LOG, i, i, globals.SKYPIAX_INTERFACES[i].interface_id);
+				DEBUGA_SKYPE("i=%d globals.SKYPIAX_INTERFACES[%d].X11_display=%s\n", SKYPIAX_P_LOG, i, i, globals.SKYPIAX_INTERFACES[i].X11_display);
+				DEBUGA_SKYPE("i=%d globals.SKYPIAX_INTERFACES[%d].name=%s\n", SKYPIAX_P_LOG, i, i, globals.SKYPIAX_INTERFACES[i].name);
+				DEBUGA_SKYPE("i=%d globals.SKYPIAX_INTERFACES[%d].context=%s\n", SKYPIAX_P_LOG, i, i, globals.SKYPIAX_INTERFACES[i].context);
+				DEBUGA_SKYPE("i=%d globals.SKYPIAX_INTERFACES[%d].dialplan=%s\n", SKYPIAX_P_LOG, i, i, globals.SKYPIAX_INTERFACES[i].dialplan);
+				DEBUGA_SKYPE("i=%d globals.SKYPIAX_INTERFACES[%d].destination=%s\n", SKYPIAX_P_LOG, i, i, globals.SKYPIAX_INTERFACES[i].destination);
+				DEBUGA_SKYPE("i=%d globals.SKYPIAX_INTERFACES[%d].context=%s\n", SKYPIAX_P_LOG, i, i, globals.SKYPIAX_INTERFACES[i].context);
+			}
+		}
+	}
+
+	switch_mutex_unlock(globals.mutex);
+	switch_xml_free(xml);
+
+	return SWITCH_STATUS_SUCCESS;
+}
+
+SWITCH_MODULE_LOAD_FUNCTION(mod_skypiax_load)
+{
+	switch_api_interface_t *commands_api_interface;
+
+	skypiax_module_pool = pool;
+	memset(&globals, '\0', sizeof(globals));
+
+	running = 1;
+
+	if (load_config(FULL_RELOAD) != SWITCH_STATUS_SUCCESS) {
+		running = 0;
+		return SWITCH_STATUS_FALSE;
+	}
+
+	*module_interface = switch_loadable_module_create_module_interface(pool, modname);
+	skypiax_endpoint_interface = switch_loadable_module_create_interface(*module_interface, SWITCH_ENDPOINT_INTERFACE);
+	skypiax_endpoint_interface->interface_name = "skypiax";
+	skypiax_endpoint_interface->io_routines = &skypiax_io_routines;
+	skypiax_endpoint_interface->state_handler = &skypiax_state_handlers;
+
+	if (running) {
+
+		SWITCH_ADD_API(commands_api_interface, "sk", "Skypiax console commands", sk_function, SK_SYNTAX);
+		SWITCH_ADD_API(commands_api_interface, "skypiax", "Skypiax interface commands", skypiax_function, SKYPIAX_SYNTAX);
+
+		/* indicate that the module should continue to be loaded */
+		return SWITCH_STATUS_SUCCESS;
+	} else
+		return SWITCH_STATUS_FALSE;
+}
+
+SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_skypiax_shutdown)
+{
+	int x;
+	private_t *tech_pvt = NULL;
+	switch_status_t status;
+	unsigned int howmany = 8;
+	int interface_id;
+
+	running = 0;
+
+	for (interface_id = 0; interface_id < SKYPIAX_MAX_INTERFACES; interface_id++) {
+		tech_pvt = &globals.SKYPIAX_INTERFACES[interface_id];
+
+		if (strlen(globals.SKYPIAX_INTERFACES[interface_id].name)) {
+			if (globals.SKYPIAX_INTERFACES[interface_id].skypiax_signaling_thread) {
+#ifdef WIN32
+				switch_file_write(tech_pvt->SkypiaxHandles.fdesc[1], "sciutati", &howmany);	// let's the controldev_thread die
+#else /* WIN32 */
+				howmany = write(tech_pvt->SkypiaxHandles.fdesc[1], "sciutati", howmany);
+#endif /* WIN32 */
+			}
+
+			if (globals.SKYPIAX_INTERFACES[interface_id].skypiax_api_thread) {
+#ifdef WIN32
+				if (SendMessage(tech_pvt->SkypiaxHandles.win32_hInit_MainWindowHandle, WM_DESTROY, 0, 0) == FALSE) {	// let's the skypiax_api_thread_func die
+					DEBUGA_SKYPE("got FALSE here, thread probably was already dead. GetLastError returned: %d\n", SKYPIAX_P_LOG, GetLastError());
+					globals.SKYPIAX_INTERFACES[interface_id].skypiax_api_thread = NULL;
+				}
+#else
+				XEvent e;
+				Atom atom1 = XInternAtom(tech_pvt->SkypiaxHandles.disp, "SKYPECONTROLAPI_MESSAGE_BEGIN",
+										 False);
+				memset(&e, 0, sizeof(e));
+				e.xclient.type = ClientMessage;
+				e.xclient.message_type = atom1;	/*  leading message */
+				e.xclient.display = tech_pvt->SkypiaxHandles.disp;
+				e.xclient.window = tech_pvt->SkypiaxHandles.skype_win;
+				e.xclient.format = 8;
+
+				XSendEvent(tech_pvt->SkypiaxHandles.disp, tech_pvt->SkypiaxHandles.win, False, 0, &e);
+				XSync(tech_pvt->SkypiaxHandles.disp, False);
+#endif
+			}
+			x = 10;
+			while (x) {			//FIXME 0.5 seconds?
+				x--;
+				switch_yield(50000);
+			}
+			if (globals.SKYPIAX_INTERFACES[interface_id].skypiax_signaling_thread) {
+				switch_thread_join(&status, globals.SKYPIAX_INTERFACES[interface_id].skypiax_signaling_thread);
+			}
+			if (globals.SKYPIAX_INTERFACES[interface_id].skypiax_api_thread) {
+				switch_thread_join(&status, globals.SKYPIAX_INTERFACES[interface_id].skypiax_api_thread);
+			}
+#ifndef WIN32
+			WARNINGA("SHUTDOWN interface_id=%d\n", SKYPIAX_P_LOG, interface_id);
+			shutdown(tech_pvt->audioskypepipe[0], 2);
+			close(tech_pvt->audioskypepipe[0]);
+			shutdown(tech_pvt->audioskypepipe[1], 2);
+			close(tech_pvt->audioskypepipe[1]);
+			shutdown(tech_pvt->audiopipe[0], 2);
+			close(tech_pvt->audiopipe[0]);
+			shutdown(tech_pvt->audiopipe[1], 2);
+			close(tech_pvt->audiopipe[1]);
+			shutdown(tech_pvt->SkypiaxHandles.fdesc[0], 2);
+			close(tech_pvt->SkypiaxHandles.fdesc[0]);
+			shutdown(tech_pvt->SkypiaxHandles.fdesc[1], 2);
+			close(tech_pvt->SkypiaxHandles.fdesc[1]);
+#endif /* WIN32 */
+		}
+
+	}
+	switch_safe_free(globals.dialplan);
+	switch_safe_free(globals.context);
+	switch_safe_free(globals.destination);
+	switch_safe_free(globals.codec_string);
+	switch_safe_free(globals.codec_rates_string);
+
+	return SWITCH_STATUS_SUCCESS;
+}
+
+void *SWITCH_THREAD_FUNC skypiax_do_tcp_srv_thread(switch_thread_t * thread, void *obj)
+{
+	return skypiax_do_tcp_srv_thread_func(obj);
+}
+
+void *SWITCH_THREAD_FUNC skypiax_do_tcp_cli_thread(switch_thread_t * thread, void *obj)
+{
+	return skypiax_do_tcp_cli_thread_func(obj);
+}
+
+void *SWITCH_THREAD_FUNC skypiax_do_skypeapi_thread(switch_thread_t * thread, void *obj)
+{
+	return skypiax_do_skypeapi_thread_func(obj);
+}
+
+int dtmf_received(private_t * tech_pvt, char *value)
+{
+	switch_core_session_t *session = NULL;
+	switch_channel_t *channel = NULL;
+
+	session = switch_core_session_locate(tech_pvt->session_uuid_str);
+	channel = switch_core_session_get_channel(session);
+
+	if (channel) {
+
+		if (!switch_channel_test_flag(channel, CF_BRIDGED)) {
+
+			switch_dtmf_t dtmf = { (char) value[0], switch_core_default_dtmf_duration(0) };
+			DEBUGA_SKYPE("received DTMF %c on channel %s\n", SKYPIAX_P_LOG, dtmf.digit, switch_channel_get_name(channel));
+			switch_mutex_lock(tech_pvt->flag_mutex);
+			//FIXME: why sometimes DTMFs from here do not seems to be get by FS?
+			switch_channel_queue_dtmf(channel, &dtmf);
+			switch_set_flag(tech_pvt, TFLAG_DTMF);
+			switch_mutex_unlock(tech_pvt->flag_mutex);
+		} else {
+			DEBUGA_SKYPE
+				("received a DTMF on channel %s, but we're BRIDGED, so let's NOT relay it out of band\n", SKYPIAX_P_LOG, switch_channel_get_name(channel));
+		}
+	} else {
+		WARNINGA("received %c DTMF, but no channel?\n", SKYPIAX_P_LOG, value[0]);
+	}
+	switch_core_session_rwunlock(session);
+
+	return 0;
+}
+
+int start_audio_threads(private_t * tech_pvt)
+{
+	switch_threadattr_t *thd_attr = NULL;
+
+	switch_threadattr_create(&thd_attr, skypiax_module_pool);
+	switch_threadattr_detach_set(thd_attr, 1);
+	switch_threadattr_stacksize_set(thd_attr, SWITCH_THREAD_STACKSIZE);
+	if (switch_thread_create(&tech_pvt->tcp_srv_thread, thd_attr, skypiax_do_tcp_srv_thread, tech_pvt, skypiax_module_pool) == SWITCH_STATUS_SUCCESS) {
+		DEBUGA_SKYPE("started tcp_srv_thread thread.\n", SKYPIAX_P_LOG);
+	} else {
+		ERRORA("failed to start tcp_srv_thread thread.\n", SKYPIAX_P_LOG);
+		return -1;
+	}
+
+	switch_threadattr_create(&thd_attr, skypiax_module_pool);
+	switch_threadattr_detach_set(thd_attr, 1);
+	switch_threadattr_stacksize_set(thd_attr, SWITCH_THREAD_STACKSIZE);
+	if (switch_thread_create(&tech_pvt->tcp_cli_thread, thd_attr, skypiax_do_tcp_cli_thread, tech_pvt, skypiax_module_pool) == SWITCH_STATUS_SUCCESS) {
+		DEBUGA_SKYPE("started tcp_cli_thread thread.\n", SKYPIAX_P_LOG);
+	} else {
+		ERRORA("failed to start tcp_cli_thread thread.\n", SKYPIAX_P_LOG);
+		return -1;
+	}
+	switch_sleep(100000);
+
+	if (tech_pvt->tcp_cli_thread == NULL || tech_pvt->tcp_srv_thread == NULL) {
+		ERRORA("tcp_cli_thread or tcp_srv_thread exited\n", SKYPIAX_P_LOG);
+		return -1;
+	}
+
+	return 0;
+}
+
+int new_inbound_channel(private_t * tech_pvt)
+{
+	switch_core_session_t *session = NULL;
+	switch_channel_t *channel = NULL;
+
+	if ((session = switch_core_session_request(skypiax_endpoint_interface, SWITCH_CALL_DIRECTION_INBOUND, NULL)) != 0) {
+		DEBUGA_SKYPE("2 SESSION_REQUEST %s\n", SKYPIAX_P_LOG, switch_core_session_get_uuid(session));
+		switch_core_session_add_stream(session, NULL);
+		channel = switch_core_session_get_channel(session);
+		if (!channel) {
+			ERRORA("Doh! no channel?\n", SKYPIAX_P_LOG);
+			switch_core_session_destroy(&session);
+			return 0;
+		}
+		if (skypiax_tech_init(tech_pvt, session) != SWITCH_STATUS_SUCCESS) {
+			ERRORA("Doh! no tech_init?\n", SKYPIAX_P_LOG);
+			switch_core_session_destroy(&session);
+			return 0;
+		}
+
+		if ((tech_pvt->caller_profile =
+			 switch_caller_profile_new(switch_core_session_get_pool(session), "skypiax",
+									   tech_pvt->dialplan, tech_pvt->callid_name,
+									   tech_pvt->callid_number, NULL, NULL, NULL, NULL, "mod_skypiax", tech_pvt->context, tech_pvt->destination)) != 0) {
+			char name[128];
+			//switch_snprintf(name, sizeof(name), "skypiax/%s/%s", tech_pvt->name, tech_pvt->caller_profile->destination_number);
+			switch_snprintf(name, sizeof(name), "skypiax/%s", tech_pvt->name);
+			switch_channel_set_name(channel, name);
+			switch_channel_set_caller_profile(channel, tech_pvt->caller_profile);
+		}
+		switch_channel_set_state(channel, CS_INIT);
+		if (switch_core_session_thread_launch(session) != SWITCH_STATUS_SUCCESS) {
+			ERRORA("Error spawning thread\n", SKYPIAX_P_LOG);
+			switch_core_session_destroy(&session);
+			return 0;
+		}
+	}
+	if (channel) {
+		switch_channel_mark_answered(channel);
+	}
+
+	DEBUGA_SKYPE("new_inbound_channel\n", SKYPIAX_P_LOG);
+
+	return 0;
+}
+
+int remote_party_is_ringing(private_t * tech_pvt)
+{
+	switch_core_session_t *session = NULL;
+	switch_channel_t *channel = NULL;
+
+	if (!switch_strlen_zero(tech_pvt->session_uuid_str)) {
+		session = switch_core_session_locate(tech_pvt->session_uuid_str);
+	} else {
+		ERRORA("No session???\n", SKYPIAX_P_LOG);
+		goto done;
+	}
+	if (session) {
+		channel = switch_core_session_get_channel(session);
+	} else {
+		ERRORA("No session???\n", SKYPIAX_P_LOG);
+		goto done;
+	}
+	if (channel) {
+		switch_channel_mark_ring_ready(channel);
+		DEBUGA_SKYPE("skype_call: REMOTE PARTY RINGING\n", SKYPIAX_P_LOG);
+	} else {
+		ERRORA("No channel???\n", SKYPIAX_P_LOG);
+	}
+
+	switch_core_session_rwunlock(session);
+
+  done:
+	return 0;
+}
+
+int remote_party_is_early_media(private_t * tech_pvt)
+{
+	switch_core_session_t *session = NULL;
+	switch_channel_t *channel = NULL;
+
+	if (!switch_strlen_zero(tech_pvt->session_uuid_str)) {
+		session = switch_core_session_locate(tech_pvt->session_uuid_str);
+	} else {
+		ERRORA("No session???\n\n\n", SKYPIAX_P_LOG);
+		//TODO: kill the bastard
+		goto done;
+	}
+	if (session) {
+		channel = switch_core_session_get_channel(session);
+		switch_core_session_add_stream(session, NULL);
+	} else {
+		ERRORA("No session???\n", SKYPIAX_P_LOG);
+		//TODO: kill the bastard
+		goto done;
+	}
+	if (channel) {
+		switch_channel_mark_pre_answered(channel);
+		DEBUGA_SKYPE("skype_call: REMOTE PARTY EARLY MEDIA\n", SKYPIAX_P_LOG);
+	} else {
+		ERRORA("No channel???\n", SKYPIAX_P_LOG);
+		//TODO: kill the bastard
+	}
+
+	switch_core_session_rwunlock(session);
+
+  done:
+	return 0;
+}
+
+int outbound_channel_answered(private_t * tech_pvt)
+{
+	switch_core_session_t *session = NULL;
+	switch_channel_t *channel = NULL;
+
+	if (!switch_strlen_zero(tech_pvt->session_uuid_str)) {
+		session = switch_core_session_locate(tech_pvt->session_uuid_str);
+	} else {
+		ERRORA("No session???\n", SKYPIAX_P_LOG);
+		goto done;
+	}
+	if (session) {
+		channel = switch_core_session_get_channel(session);
+	} else {
+		ERRORA("No channel???\n", SKYPIAX_P_LOG);
+		goto done;
+	}
+	if (channel) {
+		switch_channel_mark_answered(channel);
+		//DEBUGA_SKYPE("skype_call: %s, answered\n", SKYPIAX_P_LOG, id);
+	} else {
+		ERRORA("No channel???\n", SKYPIAX_P_LOG);
+	}
+
+	switch_core_session_rwunlock(session);
+
+  done:
+	DEBUGA_SKYPE("outbound_channel_answered!\n", SKYPIAX_P_LOG);
+
+	return 0;
+}
+
+private_t *find_available_skypiax_interface_rr(private_t * tech_pvt_calling)
+{
+	private_t *tech_pvt = NULL;
+	int i;
+	//int num_interfaces = SKYPIAX_MAX_INTERFACES; 
+	//int num_interfaces = globals.real_interfaces;
+
+	switch_mutex_lock(globals.mutex);
+
+	/* Fact is the real interface start from 1 */
+	//XXX no, is just a convention, but you can have it start from 0. I do not, for aestetic reasons :-)  
+	//if (globals.next_interface == 0) globals.next_interface = 1;
+
+	for (i = 0; i < SKYPIAX_MAX_INTERFACES; i++) {
+		int interface_id;
+
+		interface_id = globals.next_interface;
+		//interface_id = interface_id < SKYPIAX_MAX_INTERFACES ? interface_id : interface_id - SKYPIAX_MAX_INTERFACES + 1;
+		globals.next_interface = interface_id + 1 < SKYPIAX_MAX_INTERFACES ? interface_id + 1 : 0;
+
+		if (strlen(globals.SKYPIAX_INTERFACES[interface_id].name)) {
+			int skype_state = 0;
+
+			tech_pvt = &globals.SKYPIAX_INTERFACES[interface_id];
+			skype_state = tech_pvt->interface_state;
+			//DEBUGA_SKYPE("skype interface: %d, name: %s, state: %d\n", SKYPIAX_P_LOG, interface_id, globals.SKYPIAX_INTERFACES[interface_id].name, skype_state);
+			if ((tech_pvt_calling ? strcmp(tech_pvt->skype_user, tech_pvt_calling->skype_user) : 1)
+				&& (SKYPIAX_STATE_DOWN == skype_state || 0 == skype_state) && (tech_pvt->skype_callflow == CALLFLOW_STATUS_FINISHED
+																			   || 0 == tech_pvt->skype_callflow)) {
+				DEBUGA_SKYPE("returning as available skype interface name: %s, state: %d callflow: %d\n", SKYPIAX_P_LOG, tech_pvt->name, skype_state,
+							 tech_pvt->skype_callflow);
+				/*set to Dialing state to avoid other thread fint it, don't know if it is safe */
+				//XXX no, it's not safe 
+				if (tech_pvt_calling == NULL) {
+					tech_pvt->interface_state = SKYPIAX_STATE_SELECTED;
+				}
+
+				switch_mutex_unlock(globals.mutex);
+				return tech_pvt;
+			}
+		}						// else {
+		//DEBUGA_SKYPE("Skype interface: %d blank!! A hole here means we cannot hunt the last interface.\n", SKYPIAX_P_LOG, interface_id);
+		//}
+	}
+
+	switch_mutex_unlock(globals.mutex);
+	return NULL;
+}
+
+SWITCH_STANDARD_API(sk_function)
+{
+	char *mycmd = NULL, *argv[10] = { 0 };
+	int argc = 0;
+
+	if (globals.sk_console)
+		stream->write_function(stream, "sk console is: |||%s|||\n", globals.sk_console->name);
+	else
+		stream->write_function(stream, "sk console is NOT yet assigned\n");
+
+	if (!switch_strlen_zero(cmd) && (mycmd = strdup(cmd))) {
+		argc = switch_separate_string(mycmd, ' ', argv, (sizeof(argv) / sizeof(argv[0])));
+	}
+
+	if (!argc || !argv[0]) {
+		stream->write_function(stream, "%s", SK_SYNTAX);
+		goto end;
+	}
+
+	if (!strcasecmp(argv[0], "list")) {
+		int i;
+		char next_flag_char = ' ';
+
+		stream->write_function(stream, "F ID\t    Name    \tIB (F/T)    OB (F/T)\tState\tCallFlw\t\tUUID\n");
+		stream->write_function(stream, "= ====\t  ========  \t=======     =======\t======\t============\t======\n");
+
+		for (i = 0; i < SKYPIAX_MAX_INTERFACES; i++) {
+			next_flag_char = i == globals.next_interface ? '*' : ' ';
+
+			if (strlen(globals.SKYPIAX_INTERFACES[i].name)) {
+				stream->write_function(stream,
+									   "%c %d\t[%s]\t%3ld/%ld\t%6ld/%ld\t%s\t%s\t%s\n",
+									   next_flag_char,
+									   i, globals.SKYPIAX_INTERFACES[i].name,
+									   globals.SKYPIAX_INTERFACES[i].ib_failed_calls,
+									   globals.SKYPIAX_INTERFACES[i].ib_calls,
+									   globals.SKYPIAX_INTERFACES[i].ob_failed_calls,
+									   globals.SKYPIAX_INTERFACES[i].ob_calls,
+									   interface_status[globals.SKYPIAX_INTERFACES[i].interface_state],
+									   skype_callflow[globals.SKYPIAX_INTERFACES[i].skype_callflow], globals.SKYPIAX_INTERFACES[i].session_uuid_str);
+			} else if (argc > 1 && !strcasecmp(argv[1], "full")) {
+				stream->write_function(stream, "%c\t%d\n", next_flag_char, i);
+			}
+
+		}
+		stream->write_function(stream, "\nTotal: %d\n", globals.real_interfaces - 1);
+
+	} else if (!strcasecmp(argv[0], "console")) {
+		int i;
+		int found = 0;
+
+		if (argc == 2) {
+			for (i = 0; !found && i < SKYPIAX_MAX_INTERFACES; i++) {
+				/* we've been asked for a normal interface name, or we have not found idle interfaces to serve as the "ANY" interface */
+				if (strlen(globals.SKYPIAX_INTERFACES[i].name)
+					&& (strncmp(globals.SKYPIAX_INTERFACES[i].name, argv[1], strlen(argv[1])) == 0)) {
+					globals.sk_console = &globals.SKYPIAX_INTERFACES[i];
+					stream->write_function(stream,
+										   "sk console is now: globals.SKYPIAX_INTERFACES[%d].name=|||%s|||\n", i, globals.SKYPIAX_INTERFACES[i].name);
+					stream->write_function(stream, "sk console is: |||%s|||\n", globals.sk_console->name);
+					found = 1;
+					break;
+				}
+
+			}
+			if (!found)
+				stream->write_function(stream, "ERROR: A Skypiax interface with name='%s' was not found\n", argv[1]);
+		} else {
+
+			stream->write_function(stream, "-ERR Usage: sk console interface_name\n");
+			goto end;
+		}
+
+	} else if (!strcasecmp(argv[0], "ciapalino")) {
+
+/* BEGIN: Changes heres */
+	} else if (!strcasecmp(argv[0], "reload")) {
+		if (load_config(SOFT_RELOAD) != SWITCH_STATUS_SUCCESS) {
+			stream->write_function(stream, "sk reload failed\n");
+		} else {
+			stream->write_function(stream, "sk reload success\n");
+		}
+	} else if (!strcasecmp(argv[0], "remove")) {
+		if (argc == 2) {
+			if (remove_interface(argv[1]) == SWITCH_STATUS_SUCCESS) {
+				if (interface_exists(argv[1]) == SWITCH_STATUS_SUCCESS) {
+					stream->write_function(stream, "sk remove '%s' failed\n", argv[1]);
+				} else {
+					stream->write_function(stream, "sk remove '%s' success\n", argv[1]);
+				}
+			}
+		} else {
+			stream->write_function(stream, "-ERR Usage: sk remove interface_name\n");
+			goto end;
+		}
+/* END: Changes heres */
+
+	} else {
+		if (globals.sk_console)
+			skypiax_signaling_write(globals.sk_console, (char *) cmd);
+		else
+			stream->write_function(stream, "sk console is NOT yet assigned\n");
+	}
+  end:
+	switch_safe_free(mycmd);
+
+	return SWITCH_STATUS_SUCCESS;
+}
+
+SWITCH_STANDARD_API(skypiax_function)
+{
+	char *mycmd = NULL, *argv[10] = { 0 };
+	int argc = 0;
+	private_t *tech_pvt = NULL;
+
+	if (!switch_strlen_zero(cmd) && (mycmd = strdup(cmd))) {
+		argc = switch_separate_string(mycmd, ' ', argv, (sizeof(argv) / sizeof(argv[0])));
+	}
+
+	if (!argc) {
+		stream->write_function(stream, "ERROR, usage: %s", SKYPIAX_SYNTAX);
+		goto end;
+	}
+
+	if (argc < 2) {
+		stream->write_function(stream, "ERROR, usage: %s", SKYPIAX_SYNTAX);
+		goto end;
+	}
+
+	if (argv[0]) {
+		int i;
+		int found = 0;
+
+		for (i = 0; !found && i < SKYPIAX_MAX_INTERFACES; i++) {
+			/* we've been asked for a normal interface name, or we have not found idle interfaces to serve as the "ANY" interface */
+			if (strlen(globals.SKYPIAX_INTERFACES[i].name)
+				&& (strncmp(globals.SKYPIAX_INTERFACES[i].name, argv[0], strlen(argv[0])) == 0)) {
+				tech_pvt = &globals.SKYPIAX_INTERFACES[i];
+				stream->write_function(stream, "Using interface: globals.SKYPIAX_INTERFACES[%d].name=|||%s|||\n", i, globals.SKYPIAX_INTERFACES[i].name);
+				found = 1;
+				break;
+			}
+
+		}
+		if (!found) {
+			stream->write_function(stream, "ERROR: A Skypiax interface with name='%s' was not found\n", argv[0]);
+			switch_safe_free(mycmd);
+
+			return SWITCH_STATUS_SUCCESS;
+		} else {
+			skypiax_signaling_write(tech_pvt, (char *) &cmd[strlen(argv[0]) + 1]);
+		}
+	} else {
+		stream->write_function(stream, "ERROR, usage: %s", SKYPIAX_SYNTAX);
+	}
+  end:
+	switch_safe_free(mycmd);
+
+	return SWITCH_STATUS_SUCCESS;
+}
+
+int skypiax_answer(private_t * tech_pvt, char *id, char *value)
+{
+	char msg_to_skype[1024];
+	int i;
+	int found = 0;
+	private_t *giovatech;
+	struct timeval timenow;
+
+	switch_mutex_lock(globals.mutex);
+
+	gettimeofday(&timenow, NULL);
+	for (i = 0; !found && i < SKYPIAX_MAX_INTERFACES; i++) {
+		if (strlen(globals.SKYPIAX_INTERFACES[i].name)) {
+
+			giovatech = &globals.SKYPIAX_INTERFACES[i];
+			//NOTICA("skype interface: %d, name: %s, state: %d, value=%s, giovatech->callid_number=%s, giovatech->skype_user=%s\n", SKYPIAX_P_LOG, i, giovatech->name, giovatech->interface_state, value, giovatech->callid_number, giovatech->skype_user);
+			//FIXME check a timestamp here
+			if (strlen(giovatech->skype_call_id) && (giovatech->interface_state != SKYPIAX_STATE_DOWN) && (!strcmp(giovatech->skype_user, tech_pvt->skype_user)) && (!strcmp(giovatech->callid_number, value)) && ((((timenow.tv_sec - giovatech->answer_time.tv_sec) * 1000000) + (timenow.tv_usec - giovatech->answer_time.tv_usec)) < 500000)) {	//0.5sec
+				found = 1;
+				DEBUGA_SKYPE
+					("FOUND  (name=%s, giovatech->interface_state=%d != SKYPIAX_STATE_DOWN) && (giovatech->skype_user=%s == tech_pvt->skype_user=%s) && (giovatech->callid_number=%s == value=%s)\n",
+					 SKYPIAX_P_LOG, giovatech->name, giovatech->interface_state,
+					 giovatech->skype_user, tech_pvt->skype_user, giovatech->callid_number, value)
+					if (tech_pvt->interface_state == SKYPIAX_STATE_PRERING) {
+					tech_pvt->interface_state = SKYPIAX_STATE_DOWN;
+				} else if (tech_pvt->interface_state != 0 && tech_pvt->interface_state != SKYPIAX_STATE_DOWN) {
+					WARNINGA("Why an interface_state %d HERE?\n", SKYPIAX_P_LOG, tech_pvt->interface_state);
+					tech_pvt->interface_state = SKYPIAX_STATE_DOWN;
+				}
+
+				break;
+			}
+		}
+	}
+
+	if (found) {
+		//tech_pvt->callid_number[0]='\0';
+		//sprintf(msg_to_skype, "ALTER CALL %s END HANGUP", id);
+		//skypiax_signaling_write(tech_pvt, msg_to_skype);
+		switch_mutex_unlock(globals.mutex);
+		return 0;
+	}
+	DEBUGA_SKYPE("NOT FOUND\n", SKYPIAX_P_LOG);
+
+	if (tech_pvt && tech_pvt->skype_call_id && !strlen(tech_pvt->skype_call_id)) {
+		/* we are not inside an active call */
+
+		tech_pvt->ib_calls++;
+
+		sprintf(msg_to_skype, "GET CALL %s PARTNER_DISPNAME", id);
+		skypiax_signaling_write(tech_pvt, msg_to_skype);
+		switch_sleep(10000);
+		tech_pvt->interface_state = SKYPIAX_STATE_PREANSWER;
+		sprintf(msg_to_skype, "ALTER CALL %s ANSWER", id);
+		skypiax_signaling_write(tech_pvt, msg_to_skype);
+		DEBUGA_SKYPE("We answered a Skype RING on skype_call %s\n", SKYPIAX_P_LOG, id);
+		//FIXME write a timestamp here
+		gettimeofday(&tech_pvt->answer_time, NULL);
+		switch_copy_string(tech_pvt->skype_call_id, id, sizeof(tech_pvt->skype_call_id) - 1);
+
+		switch_copy_string(tech_pvt->callid_number, value, sizeof(tech_pvt->callid_number) - 1);
+
+		DEBUGA_SKYPE
+			("NEW!  name: %s, state: %d, value=%s, tech_pvt->callid_number=%s, tech_pvt->skype_user=%s\n",
+			 SKYPIAX_P_LOG, tech_pvt->name, tech_pvt->interface_state, value, tech_pvt->callid_number, tech_pvt->skype_user);
+	} else if (!tech_pvt || !tech_pvt->skype_call_id) {
+		ERRORA("No Call ID?\n", SKYPIAX_P_LOG);
+	} else {
+		DEBUGA_SKYPE("We're in a call now (%s), let's refuse this one (%s)\n", SKYPIAX_P_LOG, tech_pvt->skype_call_id, id);
+		sprintf(msg_to_skype, "ALTER CALL %s END HANGUP", id);
+		skypiax_signaling_write(tech_pvt, msg_to_skype);
+	}
+
+	switch_mutex_unlock(globals.mutex);
+	return 0;
+}
+int skypiax_transfer(private_t * tech_pvt, char *id, char *value)
+{
+	char msg_to_skype[1024];
+	int i;
+	int found = 0;
+	private_t *giovatech;
+	struct timeval timenow;
+
+	switch_mutex_lock(globals.mutex);
+
+	gettimeofday(&timenow, NULL);
+	for (i = 0; !found && i < SKYPIAX_MAX_INTERFACES; i++) {
+		if (strlen(globals.SKYPIAX_INTERFACES[i].name)) {
+
+			giovatech = &globals.SKYPIAX_INTERFACES[i];
+			//NOTICA("skype interface: %d, name: %s, state: %d, value=%s, giovatech->callid_number=%s, giovatech->skype_user=%s\n", SKYPIAX_P_LOG, i, giovatech->name, giovatech->interface_state, value, giovatech->callid_number, giovatech->skype_user);
+			//FIXME check a timestamp here
+			if (strlen(giovatech->skype_call_id) && (giovatech->interface_state != SKYPIAX_STATE_DOWN) && (!strcmp(giovatech->skype_user, tech_pvt->skype_user)) && (!strcmp(giovatech->callid_number, value)) && ((((timenow.tv_sec - giovatech->answer_time.tv_sec) * 1000000) + (timenow.tv_usec - giovatech->answer_time.tv_usec)) < 500000)) {	//0.5sec
+				found = 1;
+				DEBUGA_SKYPE
+					("FOUND  (name=%s, giovatech->interface_state=%d != SKYPIAX_STATE_DOWN) && (giovatech->skype_user=%s == tech_pvt->skype_user=%s) && (giovatech->callid_number=%s == value=%s)\n",
+					 SKYPIAX_P_LOG, giovatech->name, giovatech->interface_state,
+					 giovatech->skype_user, tech_pvt->skype_user, giovatech->callid_number, value)
+					break;
+			}
+		}
+	}
+
+	if (found) {
+		//tech_pvt->callid_number[0]='\0';
+		//sprintf(msg_to_skype, "ALTER CALL %s END HANGUP", id);
+		//skypiax_signaling_write(tech_pvt, msg_to_skype);
+		switch_mutex_unlock(globals.mutex);
+		return 0;
+	}
+	DEBUGA_SKYPE("NOT FOUND\n", SKYPIAX_P_LOG);
+
+	if (!tech_pvt || !tech_pvt->skype_call_id || !strlen(tech_pvt->skype_call_id)) {
+		/* we are not inside an active call */
+		DEBUGA_SKYPE("We're NO MORE in a call now %s\n", SKYPIAX_P_LOG, (tech_pvt && tech_pvt->skype_call_id) ? tech_pvt->skype_call_id : "");
+		switch_mutex_unlock(globals.mutex);
+
+	} else {
+
+		/* we're owned, we're in a call, let's try to transfer */
+		/************************** TODO
+		  Checking here if it is possible to transfer this call to Test2
+		  -> GET CALL 288 CAN_TRANSFER Test2
+		  <- CALL 288 CAN_TRANSFER test2 TRUE
+		 **********************************/
+
+		private_t *available_skypiax_interface = NULL;
+
+		gettimeofday(&timenow, NULL);
+		for (i = 0; !found && i < SKYPIAX_MAX_INTERFACES; i++) {
+			if (strlen(globals.SKYPIAX_INTERFACES[i].name)) {
+
+				giovatech = &globals.SKYPIAX_INTERFACES[i];
+				//NOTICA("skype interface: %d, name: %s, state: %d, value=%s, giovatech->callid_number=%s, giovatech->skype_user=%s\n", SKYPIAX_P_LOG, i, giovatech->name, giovatech->interface_state, value, giovatech->callid_number, giovatech->skype_user);
+				//FIXME check a timestamp here
+				if (strlen(giovatech->skype_transfer_call_id) && (giovatech->interface_state != SKYPIAX_STATE_DOWN) && (!strcmp(giovatech->skype_user, tech_pvt->skype_user)) && (!strcmp(giovatech->transfer_callid_number, value)) && ((((timenow.tv_sec - giovatech->transfer_time.tv_sec) * 1000000) + (timenow.tv_usec - giovatech->transfer_time.tv_usec)) < 1000000)) {	//1.0 sec
+					found = 1;
+					DEBUGA_SKYPE
+						("FOUND  (name=%s, giovatech->interface_state=%d != SKYPIAX_STATE_DOWN) && (giovatech->skype_user=%s == tech_pvt->skype_user=%s) && (giovatech->transfer_callid_number=%s == value=%s)\n",
+						 SKYPIAX_P_LOG, giovatech->name, giovatech->interface_state,
+						 giovatech->skype_user, tech_pvt->skype_user, giovatech->transfer_callid_number, value)
+						break;
+				}
+			}
+		}
+
+		if (found) {
+			//tech_pvt->callid_number[0]='\0';
+			//sprintf(msg_to_skype, "ALTER CALL %s END HANGUP", id);
+			//skypiax_signaling_write(tech_pvt, msg_to_skype);
+			switch_mutex_unlock(globals.mutex);
+			return 0;
+		}
+		DEBUGA_SKYPE("NOT FOUND\n", SKYPIAX_P_LOG);
+
+		available_skypiax_interface = find_available_skypiax_interface_rr(tech_pvt);
+		if (available_skypiax_interface) {
+			/* there is a skypiax interface idle, let's transfer the call to it */
+
+			//FIXME write a timestamp here
+			gettimeofday(&tech_pvt->transfer_time, NULL);
+			switch_copy_string(tech_pvt->skype_transfer_call_id, id, sizeof(tech_pvt->skype_transfer_call_id) - 1);
+
+			switch_copy_string(tech_pvt->transfer_callid_number, value, sizeof(tech_pvt->transfer_callid_number) - 1);
+
+			DEBUGA_SKYPE
+				("Let's transfer the skype_call %s to %s interface (with skype_user: %s), because we are already in a skypiax call(%s)\n",
+				 SKYPIAX_P_LOG, tech_pvt->skype_call_id, available_skypiax_interface->name, available_skypiax_interface->skype_user, id);
+
+			//FIXME why this? the inbound call will come, eventually, on that other interface
+			//available_skypiax_interface->ib_calls++;
+
+			sprintf(msg_to_skype, "ALTER CALL %s TRANSFER %s", id, available_skypiax_interface->skype_user);
+			skypiax_signaling_write(tech_pvt, msg_to_skype);
+			if (tech_pvt->interface_state == SKYPIAX_STATE_SELECTED) {
+				tech_pvt->interface_state = SKYPIAX_STATE_IDLE;	//we marked it SKYPIAX_STATE_SELECTED just in case it has to make an outbound call
+			}
+		} else {
+			/* no skypiax interfaces idle, do nothing */
+			DEBUGA_SKYPE
+				("Not answering the skype_call %s, because we are already in a skypiax call(%s) and not transferring, because no other skypiax interfaces are available\n",
+				 SKYPIAX_P_LOG, id, tech_pvt->skype_call_id);
+			sprintf(msg_to_skype, "ALTER CALL %s END HANGUP", id);
+			skypiax_signaling_write(tech_pvt, msg_to_skype);
+		}
+		switch_sleep(10000);
+		DEBUGA_SKYPE
+			("We have NOT answered a Skype RING from skype_call %s, because we are already in a skypiax call (%s)\n",
+			 SKYPIAX_P_LOG, id, tech_pvt->skype_call_id);
+
+		switch_mutex_unlock(globals.mutex);
+	}
+	return 0;
+}
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4 expandtab:
+ */

Added: freeswitch/branches/gmaruzz/mod_celliax/mod_skypiax.2008.vcproj (0 => 14544)


--- freeswitch/branches/gmaruzz/mod_celliax/mod_skypiax.2008.vcproj	                        (rev 0)
+++ freeswitch/branches/gmaruzz/mod_celliax/mod_skypiax.2008.vcproj	2009-08-17 09:17:09 UTC (rev 14544)
@@ -0,0 +1,164 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+	ProjectType="Visual C++"
+	Version="9.00"
+	Name="mod_skypiax"
+	ProjectGUID="{C6E78A4C-DB1E-47F4-9B63-4DC27D86343F}"
+	RootNamespace="mod_skypiax"
+	Keyword="Win32Proj"
+	TargetFrameworkVersion="131072"
+	>
+	<Platforms>
+		<Platform
+			Name="Win32"
+		/>
+	</Platforms>
+	<ToolFiles>
+	</ToolFiles>
+	<Configurations>
+		<Configuration
+			Name="Debug|Win32"
+			ConfigurationType="2"
+			InheritedPropertySheets="..\..\..\..\w32\module_debug.vsprops"
+			CharacterSet="2"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				UsePrecompiledHeader="0"
+				WarningLevel="4"
+				WarnAsError="false"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalOptions="rpcrt4.lib "
+				RandomizedBaseAddress="1"
+				DataExecutionPrevention="0"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Release|Win32"
+			ConfigurationType="2"
+			InheritedPropertySheets="..\..\..\..\w32\module_release.vsprops"
+			CharacterSet="2"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				UsePrecompiledHeader="0"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalOptions="rpcrt4.lib "
+				RandomizedBaseAddress="1"
+				DataExecutionPrevention="0"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+	</Configurations>
+	<References>
+	</References>
+	<Files>
+		<File
+			RelativePath="..\mod_skypiax\mod_skypiax.c"
+			>
+		</File>
+		<File
+			RelativePath=".\skypiax.h"
+			>
+		</File>
+		<File
+			RelativePath=".\skypiax_protocol.c"
+			>
+		</File>
+	</Files>
+	<Globals>
+	</Globals>
+</VisualStudioProject>

Added: freeswitch/branches/gmaruzz/mod_celliax/mod_skypiax.c (0 => 14544)


--- freeswitch/branches/gmaruzz/mod_celliax/mod_skypiax.c	                        (rev 0)
+++ freeswitch/branches/gmaruzz/mod_celliax/mod_skypiax.c	2009-08-17 09:17:09 UTC (rev 14544)
@@ -0,0 +1,2110 @@
+/*
+ * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ * Copyright (C) 2005/2006, Anthony Minessale II <anthmct@yahoo.com>
+ *
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ *
+ * The Initial Developer of the Original Code is
+ * Anthony Minessale II <anthmct@yahoo.com>
+ * Portions created by the Initial Developer are Copyright (C)
+ * the Initial Developer. All Rights Reserved.
+ *
+ * This module (mod_skypiax) has been contributed by:
+ *
+ * Giovanni Maruzzelli (gmaruzz@gmail.com)
+ *
+ *
+ * Further Contributors:
+ *
+ *
+ *
+ * mod_skypiax.c -- Skype compatible Endpoint Module
+ *
+ */
+
+#include "skypiax.h"
+
+#ifdef WIN32
+/***************/
+// from http://www.openasthra.com/c-tidbits/gettimeofday-function-for-windows/
+
+#include <time.h>
+
+#if defined(_MSC_VER) || defined(_MSC_EXTENSIONS)
+#define DELTA_EPOCH_IN_MICROSECS  11644473600000000Ui64
+#else /*  */
+#define DELTA_EPOCH_IN_MICROSECS  11644473600000000ULL
+#endif /*  */
+struct sk_timezone {
+	int tz_minuteswest;			/* minutes W of Greenwich */
+	int tz_dsttime;				/* type of dst correction */
+};
+int gettimeofday(struct timeval *tv, struct sk_timezone *tz)
+{
+	FILETIME ft;
+	unsigned __int64 tmpres = 0;
+	static int tzflag;
+	if (NULL != tv) {
+		GetSystemTimeAsFileTime(&ft);
+		tmpres |= ft.dwHighDateTime;
+		tmpres <<= 32;
+		tmpres |= ft.dwLowDateTime;
+
+		/*converting file time to unix epoch */
+		tmpres /= 10;			/*convert into microseconds */
+		tmpres -= DELTA_EPOCH_IN_MICROSECS;
+		tv->tv_sec = (long) (tmpres / 1000000UL);
+		tv->tv_usec = (long) (tmpres % 1000000UL);
+	}
+	if (NULL != tz) {
+		if (!tzflag) {
+			_tzset();
+			tzflag++;
+		}
+		tz->tz_minuteswest = _timezone / 60;
+		tz->tz_dsttime = _daylight;
+	}
+	return 0;
+}
+
+/***************/
+#endif /* WIN32 */
+SWITCH_MODULE_LOAD_FUNCTION(mod_skypiax_load);
+SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_skypiax_shutdown);
+SWITCH_MODULE_DEFINITION(mod_skypiax, mod_skypiax_load, mod_skypiax_shutdown, NULL);
+SWITCH_STANDARD_API(sk_function);
+/* BEGIN: Changes here */
+#define SK_SYNTAX "list [full] || console || skype_API_msg || remove < skypeusername | #interface_name | #interface_id > || reload"
+/* END: Changes heres */
+SWITCH_STANDARD_API(skypiax_function);
+#define SKYPIAX_SYNTAX "interface_name skype_API_msg"
+
+/* BEGIN: Changes here */
+#define FULL_RELOAD 0
+#define SOFT_RELOAD 1
+/* END: Changes heres */
+
+char *interface_status[] = {	/* should match SKYPIAX_STATE_xxx in skypiax.h */
+	"IDLE",
+	"DOWN",
+	"RING",
+	"DIALING",
+	"BUSY",
+	"UP",
+	"RINGING",
+	"PRERING",
+	"DOUBLE",
+	"SELECTD",
+	"HANG_RQ",
+	"PREANSW"
+};
+char *skype_callflow[] = {		/* should match CALLFLOW_XXX in skypiax.h */
+	"CALL_IDLE",
+	"CALL_DOWN",
+	"INCOMING_RNG",
+	"CALL_DIALING",
+	"CALL_LINEBUSY",
+	"CALL_ACTIVE",
+	"INCOMING_HNG",
+	"CALL_RLEASD",
+	"CALL_NOCARR",
+	"CALL_INFLUX",
+	"CALL_INCOMING",
+	"CALL_FAILED",
+	"CALL_NOSRVC",
+	"CALL_OUTRESTR",
+	"CALL_SECFAIL",
+	"CALL_NOANSWER",
+	"STATUS_FNSHED",
+	"STATUS_CANCLED",
+	"STATUS_FAILED",
+	"STATUS_REFUSED",
+	"STATUS_RINGING",
+	"STATUS_INPROGRS",
+	"STATUS_UNPLACD",
+	"STATUS_ROUTING",
+	"STATUS_EARLYMD",
+	"INCOMING_CLID",
+	"STATUS_RMTEHOLD"
+};
+
+
+static struct {
+	int debug;
+	char *ip;
+	int port;
+	char *dialplan;
+	char *destination;
+	char *context;
+	char *codec_string;
+	char *codec_order[SWITCH_MAX_CODECS];
+	int codec_order_last;
+	char *codec_rates_string;
+	char *codec_rates[SWITCH_MAX_CODECS];
+	int codec_rates_last;
+	unsigned int flags;
+	int fd;
+	int calls;
+	int real_interfaces;
+	int next_interface;
+	char hold_music[256];
+	private_t SKYPIAX_INTERFACES[SKYPIAX_MAX_INTERFACES];
+	switch_mutex_t *mutex;
+	private_t *sk_console;
+} globals;
+
+switch_endpoint_interface_t *skypiax_endpoint_interface;
+switch_memory_pool_t *skypiax_module_pool = NULL;
+int running = 0;
+
+SWITCH_DECLARE_GLOBAL_STRING_FUNC(set_global_dialplan, globals.dialplan);
+SWITCH_DECLARE_GLOBAL_STRING_FUNC(set_global_context, globals.context);
+SWITCH_DECLARE_GLOBAL_STRING_FUNC(set_global_destination, globals.destination);
+SWITCH_DECLARE_GLOBAL_STRING_FUNC(set_global_codec_string, globals.codec_string);
+SWITCH_DECLARE_GLOBAL_STRING_FUNC(set_global_codec_rates_string, globals.codec_rates_string);
+
+/* BEGIN: Changes here */
+static switch_status_t interface_exists(char *the_interface);
+static switch_status_t remove_interface(char *the_interface);
+/* END: Changes here */
+
+static switch_status_t channel_on_init(switch_core_session_t *session);
+static switch_status_t channel_on_hangup(switch_core_session_t *session);
+static switch_status_t channel_on_destroy(switch_core_session_t *session);
+static switch_status_t channel_on_routing(switch_core_session_t *session);
+static switch_status_t channel_on_exchange_media(switch_core_session_t *session);
+static switch_status_t channel_on_consume_media(switch_core_session_t *session);
+static switch_status_t channel_on_soft_execute(switch_core_session_t *session);
+static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *session,
+													switch_event_t *var_event,
+													switch_caller_profile_t *outbound_profile,
+													switch_core_session_t **new_session, switch_memory_pool_t **pool, switch_originate_flag_t flags);
+static switch_status_t channel_read_frame(switch_core_session_t *session, switch_frame_t **frame, switch_io_flag_t flags, int stream_id);
+static switch_status_t channel_write_frame(switch_core_session_t *session, switch_frame_t *frame, switch_io_flag_t flags, int stream_id);
+static switch_status_t channel_kill_channel(switch_core_session_t *session, int sig);
+static switch_status_t skypiax_tech_init(private_t * tech_pvt, switch_core_session_t *session);
+
+static switch_status_t skypiax_codec(private_t * tech_pvt, int sample_rate, int codec_ms)
+{
+	switch_core_session_t *session = NULL;
+
+	if (switch_core_codec_init
+		(&tech_pvt->read_codec, "L16", NULL, sample_rate, codec_ms, 1,
+		 SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE, NULL, NULL) != SWITCH_STATUS_SUCCESS) {
+		ERRORA("Can't load codec?\n", SKYPIAX_P_LOG);
+		return SWITCH_STATUS_FALSE;
+	}
+
+	if (switch_core_codec_init
+		(&tech_pvt->write_codec, "L16", NULL, sample_rate, codec_ms, 1,
+		 SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE, NULL, NULL) != SWITCH_STATUS_SUCCESS) {
+		ERRORA("Can't load codec?\n", SKYPIAX_P_LOG);
+		switch_core_codec_destroy(&tech_pvt->read_codec);
+		return SWITCH_STATUS_FALSE;
+	}
+
+	tech_pvt->read_frame.rate = sample_rate;
+	tech_pvt->read_frame.codec = &tech_pvt->read_codec;
+
+	session = switch_core_session_locate(tech_pvt->session_uuid_str);
+
+	if (session) {
+		switch_core_session_set_read_codec(session, &tech_pvt->read_codec);
+		switch_core_session_set_write_codec(session, &tech_pvt->write_codec);
+		switch_core_session_rwunlock(session);
+	} else {
+		ERRORA("no session\n", SKYPIAX_P_LOG);
+		return SWITCH_STATUS_FALSE;
+	}
+
+	return SWITCH_STATUS_SUCCESS;
+
+}
+
+switch_status_t skypiax_tech_init(private_t * tech_pvt, switch_core_session_t *session)
+{
+
+	switch_assert(tech_pvt != NULL);
+	switch_assert(session != NULL);
+	tech_pvt->read_frame.data = tech_pvt->databuf;
+	tech_pvt->read_frame.buflen = sizeof(tech_pvt->databuf);
+	switch_mutex_init(&tech_pvt->mutex, SWITCH_MUTEX_NESTED, switch_core_session_get_pool(session));
+	switch_mutex_init(&tech_pvt->flag_mutex, SWITCH_MUTEX_NESTED, switch_core_session_get_pool(session));
+	switch_core_session_set_private(session, tech_pvt);
+	switch_copy_string(tech_pvt->session_uuid_str, switch_core_session_get_uuid(session), sizeof(tech_pvt->session_uuid_str));
+	if (!strlen(tech_pvt->session_uuid_str)) {
+		ERRORA("no tech_pvt->session_uuid_str\n", SKYPIAX_P_LOG);
+		return SWITCH_STATUS_FALSE;
+	}
+	if (skypiax_codec(tech_pvt, SAMPLERATE_SKYPIAX, 20) != SWITCH_STATUS_SUCCESS) {
+		ERRORA("skypiax_codec FAILED\n", SKYPIAX_P_LOG);
+		return SWITCH_STATUS_FALSE;
+	}
+	DEBUGA_SKYPE("skypiax_codec SUCCESS\n", SKYPIAX_P_LOG);
+	return SWITCH_STATUS_SUCCESS;
+}
+
+/* BEGIN: Changes here */
+static switch_status_t interface_exists(char *the_interface)
+{
+	int i;
+	int interface_id;
+
+	if (*the_interface == '#') {	/* look by interface id or interface name */
+		the_interface++;
+		switch_assert(the_interface);
+		interface_id = atoi(the_interface);
+
+		/* take a number as interface id */
+		if (interface_id > 0 || (interface_id == 0 && strcmp(the_interface, "0") == 0)) {
+			if (strlen(globals.SKYPIAX_INTERFACES[interface_id].name)) {
+				return SWITCH_STATUS_SUCCESS;
+			}
+		} else {
+			/* interface name */
+			for (interface_id = 0; interface_id < SKYPIAX_MAX_INTERFACES; interface_id++) {
+				if (strcmp(globals.SKYPIAX_INTERFACES[interface_id].name, the_interface) == 0) {
+					return SWITCH_STATUS_SUCCESS;
+					break;
+				}
+			}
+		}
+	} else {					/* look by skype_user */
+
+
+		for (i = 0; i < SKYPIAX_MAX_INTERFACES; i++) {
+			if (strlen(globals.SKYPIAX_INTERFACES[i].skype_user)) {
+				if (strcmp(globals.SKYPIAX_INTERFACES[i].skype_user, the_interface) == 0) {
+					return SWITCH_STATUS_SUCCESS;
+				}
+			}
+		}
+	}
+	return SWITCH_STATUS_FALSE;
+}
+
+static switch_status_t remove_interface(char *the_interface)
+{
+	int x = 10;
+	unsigned int howmany = 8;
+	int interface_id = -1;
+	private_t *tech_pvt = NULL;
+	switch_status_t status;
+
+	//running = 0;
+
+
+	if (*the_interface == '#') {	/* remove by interface id or interface name */
+		the_interface++;
+		switch_assert(the_interface);
+		interface_id = atoi(the_interface);
+
+		if (interface_id > 0 || (interface_id == 0 && strcmp(the_interface, "0") == 0)) {
+			/* take a number as interface id */
+			tech_pvt = &globals.SKYPIAX_INTERFACES[interface_id];
+		} else {
+
+			for (interface_id = 0; interface_id < SKYPIAX_MAX_INTERFACES; interface_id++) {
+				if (strcmp(globals.SKYPIAX_INTERFACES[interface_id].name, the_interface) == 0) {
+					tech_pvt = &globals.SKYPIAX_INTERFACES[interface_id];
+					break;
+				}
+			}
+		}
+	} else {					/* remove by skype_user */
+		for (interface_id = 0; interface_id < SKYPIAX_MAX_INTERFACES; interface_id++) {
+			if (strcmp(globals.SKYPIAX_INTERFACES[interface_id].skype_user, the_interface) == 0) {
+				tech_pvt = &globals.SKYPIAX_INTERFACES[interface_id];
+				break;
+			}
+		}
+	}
+
+	if (!tech_pvt) {
+		DEBUGA_SKYPE("interface '%s' does not exist\n", SKYPIAX_P_LOG, the_interface);
+		goto end;
+	}
+
+	if (strlen(globals.SKYPIAX_INTERFACES[interface_id].session_uuid_str)) {
+		DEBUGA_SKYPE("interface '%s' is busy\n", SKYPIAX_P_LOG, the_interface);
+		goto end;
+	}
+
+	globals.SKYPIAX_INTERFACES[interface_id].running = 0;
+
+	if (globals.SKYPIAX_INTERFACES[interface_id].skypiax_signaling_thread) {
+#ifdef WIN32
+		switch_file_write(tech_pvt->SkypiaxHandles.fdesc[1], "sciutati", &howmany);	// let's the controldev_thread die
+#else /* WIN32 */
+		howmany = write(tech_pvt->SkypiaxHandles.fdesc[1], "sciutati", howmany);
+#endif /* WIN32 */
+	}
+
+	if (globals.SKYPIAX_INTERFACES[interface_id].skypiax_api_thread) {
+#ifdef WIN32
+		if (SendMessage(tech_pvt->SkypiaxHandles.win32_hInit_MainWindowHandle, WM_DESTROY, 0, 0) == FALSE) {	// let's the skypiax_api_thread_func die
+			DEBUGA_SKYPE("got FALSE here, thread probably was already dead. GetLastError returned: %d\n", SKYPIAX_P_LOG, GetLastError());
+			globals.SKYPIAX_INTERFACES[interface_id].skypiax_api_thread = NULL;
+		}
+#else
+		XEvent e;
+		Atom atom1 = XInternAtom(tech_pvt->SkypiaxHandles.disp, "SKYPECONTROLAPI_MESSAGE_BEGIN", False);
+		memset(&e, 0, sizeof(e));
+		e.xclient.type = ClientMessage;
+		e.xclient.message_type = atom1;	/*  leading message */
+		e.xclient.display = tech_pvt->SkypiaxHandles.disp;
+		e.xclient.window = tech_pvt->SkypiaxHandles.skype_win;
+		e.xclient.format = 8;
+
+		XSendEvent(tech_pvt->SkypiaxHandles.disp, tech_pvt->SkypiaxHandles.win, False, 0, &e);
+		XSync(tech_pvt->SkypiaxHandles.disp, False);
+#endif
+	}
+
+	while (x) {
+		x--;
+		switch_yield(50000);
+	}
+
+	if (globals.SKYPIAX_INTERFACES[interface_id].skypiax_signaling_thread) {
+		switch_thread_join(&status, globals.SKYPIAX_INTERFACES[interface_id].skypiax_signaling_thread);
+	}
+
+	if (globals.SKYPIAX_INTERFACES[interface_id].skypiax_api_thread) {
+		switch_thread_join(&status, globals.SKYPIAX_INTERFACES[interface_id].skypiax_api_thread);
+	}
+
+	switch_mutex_lock(globals.mutex);
+	if (globals.sk_console == &globals.SKYPIAX_INTERFACES[interface_id]) {
+		DEBUGA_SKYPE("interface '%s' no more console\n", SKYPIAX_P_LOG, the_interface);
+		globals.sk_console = NULL;
+	} else {
+		DEBUGA_SKYPE("interface '%s' STILL console\n", SKYPIAX_P_LOG, the_interface);
+	}
+	memset(&globals.SKYPIAX_INTERFACES[interface_id], '\0', sizeof(private_t));
+	globals.real_interfaces--;
+	switch_mutex_unlock(globals.mutex);
+
+	DEBUGA_SKYPE("interface '%s' deleted successfully\n", SKYPIAX_P_LOG, the_interface);
+	globals.SKYPIAX_INTERFACES[interface_id].running = 1;
+  end:
+	//running = 1;
+	return SWITCH_STATUS_SUCCESS;
+}
+
+/* END: Changes here */
+
+/* 
+   State methods they get called when the state changes to the specific state 
+   returning SWITCH_STATUS_SUCCESS tells the core to execute the standard state method next
+   so if you fully implement the state you can return SWITCH_STATUS_FALSE to skip it.
+*/
+static switch_status_t channel_on_init(switch_core_session_t *session)
+{
+	switch_channel_t *channel;
+	private_t *tech_pvt = NULL;
+
+	tech_pvt = switch_core_session_get_private(session);
+	switch_assert(tech_pvt != NULL);
+
+	channel = switch_core_session_get_channel(session);
+	switch_assert(channel != NULL);
+	//ERRORA("%s CHANNEL INIT\n", SKYPIAX_P_LOG, tech_pvt->name);
+	switch_set_flag(tech_pvt, TFLAG_IO);
+
+	/* Move channel's state machine to ROUTING. This means the call is trying
+	   to get from the initial start where the call because, to the point
+	   where a destination has been identified. If the channel is simply
+	   left in the initial state, nothing will happen. */
+	switch_channel_set_state(channel, CS_ROUTING);
+	switch_mutex_lock(globals.mutex);
+	globals.calls++;
+
+	switch_mutex_unlock(globals.mutex);
+	DEBUGA_SKYPE("%s CHANNEL INIT %s\n", SKYPIAX_P_LOG, tech_pvt->name, switch_core_session_get_uuid(session));
+
+	return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status_t channel_on_destroy(switch_core_session_t *session)
+{
+	private_t *tech_pvt = NULL;
+
+	tech_pvt = switch_core_session_get_private(session);
+
+
+	if (tech_pvt) {
+		DEBUGA_SKYPE("%s CHANNEL DESTROY %s\n", SKYPIAX_P_LOG, tech_pvt->name, switch_core_session_get_uuid(session));
+
+		if (switch_core_codec_ready(&tech_pvt->read_codec)) {
+			switch_core_codec_destroy(&tech_pvt->read_codec);
+		}
+
+		if (switch_core_codec_ready(&tech_pvt->write_codec)) {
+			switch_core_codec_destroy(&tech_pvt->write_codec);
+		}
+		*tech_pvt->session_uuid_str = '\0';
+		tech_pvt->interface_state = SKYPIAX_STATE_IDLE;
+		if (tech_pvt->skype_callflow == CALLFLOW_STATUS_FINISHED) {
+			tech_pvt->skype_callflow = CALLFLOW_CALL_IDLE;
+		}
+		switch_core_session_set_private(session, NULL);
+	} else {
+		DEBUGA_SKYPE("!!!!!!NO tech_pvt!!!! CHANNEL DESTROY %s\n", SKYPIAX_P_LOG, switch_core_session_get_uuid(session));
+	}
+
+	return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status_t channel_on_hangup(switch_core_session_t *session)
+{
+	switch_channel_t *channel = NULL;
+	private_t *tech_pvt = NULL;
+	char msg_to_skype[256];
+
+
+	channel = switch_core_session_get_channel(session);
+	switch_assert(channel != NULL);
+
+	tech_pvt = switch_core_session_get_private(session);
+	switch_assert(tech_pvt != NULL);
+
+	if (!switch_channel_test_flag(channel, CF_ANSWERED)) {
+		if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND) {
+			tech_pvt->ob_failed_calls++;
+		} else {
+			tech_pvt->ib_failed_calls++;
+		}
+	}
+
+	switch_clear_flag(tech_pvt, TFLAG_IO);
+	switch_clear_flag(tech_pvt, TFLAG_VOICE);
+	//switch_set_flag(tech_pvt, TFLAG_HANGUP);
+
+	if (strlen(tech_pvt->skype_call_id)) {
+		//switch_thread_cond_signal(tech_pvt->cond);
+		DEBUGA_SKYPE("hanging up skype call: %s\n", SKYPIAX_P_LOG, tech_pvt->skype_call_id);
+		sprintf(msg_to_skype, "ALTER CALL %s HANGUP", tech_pvt->skype_call_id);
+		skypiax_signaling_write(tech_pvt, msg_to_skype);
+	}
+	//memset(tech_pvt->session_uuid_str, '\0', sizeof(tech_pvt->session_uuid_str));
+	//*tech_pvt->session_uuid_str = '\0';
+	DEBUGA_SKYPE("%s CHANNEL HANGUP\n", SKYPIAX_P_LOG, tech_pvt->name);
+	switch_mutex_lock(globals.mutex);
+	globals.calls--;
+	if (globals.calls < 0) {
+		globals.calls = 0;
+	}
+
+	tech_pvt->interface_state = SKYPIAX_STATE_IDLE;
+	if (tech_pvt->skype_callflow == CALLFLOW_STATUS_FINISHED) {
+		tech_pvt->skype_callflow = CALLFLOW_CALL_IDLE;
+	}
+	switch_mutex_unlock(globals.mutex);
+
+	return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status_t channel_on_routing(switch_core_session_t *session)
+{
+	switch_channel_t *channel = NULL;
+	private_t *tech_pvt = NULL;
+
+	channel = switch_core_session_get_channel(session);
+	switch_assert(channel != NULL);
+
+	tech_pvt = switch_core_session_get_private(session);
+	switch_assert(tech_pvt != NULL);
+
+	DEBUGA_SKYPE("%s CHANNEL ROUTING\n", SKYPIAX_P_LOG, tech_pvt->name);
+
+	return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status_t channel_on_execute(switch_core_session_t *session)
+{
+
+	switch_channel_t *channel = NULL;
+	private_t *tech_pvt = NULL;
+
+	channel = switch_core_session_get_channel(session);
+	switch_assert(channel != NULL);
+
+	tech_pvt = switch_core_session_get_private(session);
+	switch_assert(tech_pvt != NULL);
+
+	DEBUGA_SKYPE("%s CHANNEL EXECUTE\n", SKYPIAX_P_LOG, tech_pvt->name);
+
+	return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status_t channel_kill_channel(switch_core_session_t *session, int sig)
+{
+	switch_channel_t *channel = NULL;
+	private_t *tech_pvt = NULL;
+
+	channel = switch_core_session_get_channel(session);
+	switch_assert(channel != NULL);
+
+	tech_pvt = switch_core_session_get_private(session);
+	switch_assert(tech_pvt != NULL);
+
+	DEBUGA_SKYPE("%s CHANNEL KILL_CHANNEL\n", SKYPIAX_P_LOG, tech_pvt->name);
+	switch (sig) {
+	case SWITCH_SIG_KILL:
+		DEBUGA_SKYPE("%s CHANNEL got SWITCH_SIG_KILL\n", SKYPIAX_P_LOG, switch_channel_get_name(channel));
+		//switch_mutex_lock(tech_pvt->flag_mutex);
+		switch_clear_flag(tech_pvt, TFLAG_IO);
+		switch_clear_flag(tech_pvt, TFLAG_VOICE);
+		switch_set_flag(tech_pvt, TFLAG_HANGUP);
+		//switch_mutex_unlock(tech_pvt->flag_mutex);
+		break;
+	case SWITCH_SIG_BREAK:
+		DEBUGA_SKYPE("%s CHANNEL got SWITCH_SIG_BREAK\n", SKYPIAX_P_LOG, switch_channel_get_name(channel));
+		//switch_set_flag(tech_pvt, TFLAG_BREAK);
+		//switch_mutex_lock(tech_pvt->flag_mutex);
+		switch_set_flag(tech_pvt, TFLAG_BREAK);
+		//switch_mutex_unlock(tech_pvt->flag_mutex);
+		break;
+	default:
+		break;
+	}
+
+	return SWITCH_STATUS_SUCCESS;
+}
+static switch_status_t channel_on_consume_media(switch_core_session_t *session)
+{
+	private_t *tech_pvt = NULL;
+
+	tech_pvt = switch_core_session_get_private(session);
+
+	DEBUGA_SKYPE("%s CHANNEL CONSUME_MEDIA\n", SKYPIAX_P_LOG, tech_pvt->name);
+	return SWITCH_STATUS_SUCCESS;
+}
+
+
+static switch_status_t channel_on_exchange_media(switch_core_session_t *session)
+{
+	private_t *tech_pvt = NULL;
+	tech_pvt = switch_core_session_get_private(session);
+	DEBUGA_SKYPE("%s CHANNEL EXCHANGE_MEDIA\n", SKYPIAX_P_LOG, tech_pvt->name);
+	return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status_t channel_on_soft_execute(switch_core_session_t *session)
+{
+	private_t *tech_pvt = NULL;
+	tech_pvt = switch_core_session_get_private(session);
+	DEBUGA_SKYPE("%s CHANNEL SOFT_EXECUTE\n", SKYPIAX_P_LOG, tech_pvt->name);
+	return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status_t channel_send_dtmf(switch_core_session_t *session, const switch_dtmf_t *dtmf)
+{
+	private_t *tech_pvt = switch_core_session_get_private(session);
+	switch_assert(tech_pvt != NULL);
+
+	DEBUGA_SKYPE("%s CHANNEL SEND_DTMF\n", SKYPIAX_P_LOG, tech_pvt->name);
+	DEBUGA_SKYPE("DTMF: %c\n", SKYPIAX_P_LOG, dtmf->digit);
+
+	skypiax_senddigit(tech_pvt, dtmf->digit);
+
+	return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status_t channel_read_frame(switch_core_session_t *session, switch_frame_t **frame, switch_io_flag_t flags, int stream_id)
+{
+	switch_channel_t *channel = NULL;
+	private_t *tech_pvt = NULL;
+	switch_byte_t *data;
+
+	channel = switch_core_session_get_channel(session);
+	switch_assert(channel != NULL);
+
+	tech_pvt = switch_core_session_get_private(session);
+	switch_assert(tech_pvt != NULL);
+
+	if (!switch_channel_ready(channel) || !switch_test_flag(tech_pvt, TFLAG_IO)) {
+		ERRORA("channel not ready \n", SKYPIAX_P_LOG);
+		//TODO: kill the bastard
+		return SWITCH_STATUS_FALSE;
+	}
+
+	tech_pvt->read_frame.flags = SFF_NONE;
+	*frame = NULL;
+
+	if (!skypiax_audio_read(tech_pvt)) {
+
+		ERRORA("skypiax_audio_read ERROR\n", SKYPIAX_P_LOG);
+
+	} else {
+		switch_set_flag(tech_pvt, TFLAG_VOICE);
+	}
+
+	while (switch_test_flag(tech_pvt, TFLAG_IO)) {
+		if (switch_test_flag(tech_pvt, TFLAG_BREAK)) {
+			switch_clear_flag(tech_pvt, TFLAG_BREAK);
+			DEBUGA_SKYPE("CHANNEL READ FRAME goto CNG\n", SKYPIAX_P_LOG);
+			goto cng;
+		}
+
+		if (!switch_test_flag(tech_pvt, TFLAG_IO)) {
+			DEBUGA_SKYPE("CHANNEL READ FRAME not IO\n", SKYPIAX_P_LOG);
+			return SWITCH_STATUS_FALSE;
+		}
+
+		if (switch_test_flag(tech_pvt, TFLAG_IO) && switch_test_flag(tech_pvt, TFLAG_VOICE)) {
+			switch_clear_flag(tech_pvt, TFLAG_VOICE);
+			if (!tech_pvt->read_frame.datalen) {
+				DEBUGA_SKYPE("CHANNEL READ CONTINUE\n", SKYPIAX_P_LOG);
+				continue;
+			}
+			*frame = &tech_pvt->read_frame;
+#ifdef BIGENDIAN
+			if (switch_test_flag(tech_pvt, TFLAG_LINEAR)) {
+				switch_swap_linear((*frame)->data, (int) (*frame)->datalen / 2);
+			}
+#endif
+			return SWITCH_STATUS_SUCCESS;
+		}
+
+		DEBUGA_SKYPE("CHANNEL READ no TFLAG_IO\n", SKYPIAX_P_LOG);
+		return SWITCH_STATUS_FALSE;
+
+	}
+
+	DEBUGA_SKYPE("CHANNEL READ FALSE\n", SKYPIAX_P_LOG);
+	return SWITCH_STATUS_FALSE;
+
+  cng:
+	data = (switch_byte_t *) tech_pvt->read_frame.data;
+	data[0] = 65;
+	data[1] = 0;
+	tech_pvt->read_frame.datalen = 2;
+	tech_pvt->read_frame.flags = SFF_CNG;
+	*frame = &tech_pvt->read_frame;
+	return SWITCH_STATUS_SUCCESS;
+
+}
+
+static switch_status_t channel_write_frame(switch_core_session_t *session, switch_frame_t *frame, switch_io_flag_t flags, int stream_id)
+{
+	switch_channel_t *channel = NULL;
+	private_t *tech_pvt = NULL;
+	unsigned int sent;
+
+	channel = switch_core_session_get_channel(session);
+	switch_assert(channel != NULL);
+
+	tech_pvt = switch_core_session_get_private(session);
+	switch_assert(tech_pvt != NULL);
+
+	if (!switch_channel_ready(channel) || !switch_test_flag(tech_pvt, TFLAG_IO)) {
+		ERRORA("channel not ready \n", SKYPIAX_P_LOG);
+		//TODO: kill the bastard
+		return SWITCH_STATUS_FALSE;
+	}
+#ifdef BIGENDIAN
+	if (switch_test_flag(tech_pvt, TFLAG_LINEAR)) {
+		switch_swap_linear(frame->data, (int) frame->datalen / 2);
+	}
+#endif
+
+	sent = frame->datalen;
+#ifdef WIN32
+	switch_file_write(tech_pvt->audioskypepipe[1], frame->data, &sent);
+#else /* WIN32 */
+	sent = write(tech_pvt->audioskypepipe[1], frame->data, sent);
+#endif /* WIN32 */
+	if (sent != frame->datalen && sent != -1) {
+		DEBUGA_SKYPE("CLI PIPE write %d\n", SKYPIAX_P_LOG, sent);
+	}
+
+	return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status_t channel_answer_channel(switch_core_session_t *session)
+{
+	private_t *tech_pvt;
+	switch_channel_t *channel = NULL;
+
+	channel = switch_core_session_get_channel(session);
+	switch_assert(channel != NULL);
+
+	tech_pvt = switch_core_session_get_private(session);
+	switch_assert(tech_pvt != NULL);
+
+	DEBUGA_SKYPE("ANSWERED! \n", SKYPIAX_P_LOG);
+
+	return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status_t channel_receive_message(switch_core_session_t *session, switch_core_session_message_t *msg)
+{
+	switch_channel_t *channel;
+	private_t *tech_pvt;
+
+	channel = switch_core_session_get_channel(session);
+	switch_assert(channel != NULL);
+
+	tech_pvt = (private_t *) switch_core_session_get_private(session);
+	switch_assert(tech_pvt != NULL);
+
+	switch (msg->message_id) {
+	case SWITCH_MESSAGE_INDICATE_ANSWER:
+		{
+			DEBUGA_SKYPE("MSG_ID=%d, TO BE ANSWERED!\n", SKYPIAX_P_LOG, msg->message_id);
+			channel_answer_channel(session);
+		}
+		break;
+	default:
+		{
+			DEBUGA_SKYPE("MSG_ID=%d\n", SKYPIAX_P_LOG, msg->message_id);
+		}
+		break;
+	}
+
+	return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status_t channel_receive_event(switch_core_session_t *session, switch_event_t *event)
+{
+	struct private_object *tech_pvt = switch_core_session_get_private(session);
+	char *body = switch_event_get_body(event);
+	switch_assert(tech_pvt != NULL);
+
+	if (!body) {
+		body = "";
+	}
+
+	WARNINGA("event: |||%s|||\n", SKYPIAX_P_LOG, body);
+
+	return SWITCH_STATUS_SUCCESS;
+}
+
+switch_state_handler_table_t skypiax_state_handlers = {
+	/*.on_init */ channel_on_init,
+	/*.on_routing */ channel_on_routing,
+	/*.on_execute */ channel_on_execute,
+	/*.on_hangup */ channel_on_hangup,
+	/*.on_exchange_media */ channel_on_exchange_media,
+	/*.on_soft_execute */ channel_on_soft_execute,
+	/*.on_consume_media */ channel_on_consume_media,
+	/*.on_hibernate */ NULL,
+	/*.on_reset */ NULL,
+	/*.on_park */ NULL,
+	/*.on_reporting */ NULL,
+	/*.on_destroy */ channel_on_destroy
+};
+
+switch_io_routines_t skypiax_io_routines = {
+	/*.outgoing_channel */ channel_outgoing_channel,
+	/*.read_frame */ channel_read_frame,
+	/*.write_frame */ channel_write_frame,
+	/*.kill_channel */ channel_kill_channel,
+	/*.send_dtmf */ channel_send_dtmf,
+	/*.receive_message */ channel_receive_message,
+	/*.receive_event */ channel_receive_event
+};
+
+static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *session,
+													switch_event_t *var_event,
+													switch_caller_profile_t *outbound_profile,
+													switch_core_session_t **new_session, switch_memory_pool_t **pool, switch_originate_flag_t flags)
+{
+	private_t *tech_pvt = NULL;
+	if ((*new_session = switch_core_session_request(skypiax_endpoint_interface, SWITCH_CALL_DIRECTION_OUTBOUND, pool)) != 0) {
+		switch_channel_t *channel = NULL;
+		switch_caller_profile_t *caller_profile;
+		char *rdest;
+		int found = 0;
+		char interface_name[256];
+
+		DEBUGA_SKYPE("1 SESSION_REQUEST %s\n", SKYPIAX_P_LOG, switch_core_session_get_uuid(*new_session));
+		switch_core_session_add_stream(*new_session, NULL);
+
+
+		if (!switch_strlen_zero(outbound_profile->destination_number)) {
+			int i;
+			char *slash;
+
+			switch_copy_string(interface_name, outbound_profile->destination_number, 255);
+			slash = strrchr(interface_name, '/');
+			*slash = '\0';
+
+			switch_mutex_lock(globals.mutex);
+			if (strncmp("ANY", interface_name, strlen(interface_name)) == 0 || strncmp("RR", interface_name, strlen(interface_name)) == 0) {
+				/* we've been asked for the "ANY" interface, let's find the first idle interface */
+				//DEBUGA_SKYPE("Finding one available skype interface\n", SKYPIAX_P_LOG);
+				//tech_pvt = find_available_skypiax_interface(NULL);
+				//if (tech_pvt)
+				//found = 1;
+				//} else if (strncmp("RR", interface_name, strlen(interface_name)) == 0) {
+				/* Find the first idle interface using Round Robin */
+				DEBUGA_SKYPE("Finding one available skype interface RR\n", SKYPIAX_P_LOG);
+				tech_pvt = find_available_skypiax_interface_rr(NULL);
+				if (tech_pvt)
+					found = 1;
+			}
+
+			for (i = 0; !found && i < SKYPIAX_MAX_INTERFACES; i++) {
+				/* we've been asked for a normal interface name, or we have not found idle interfaces to serve as the "ANY" interface */
+				if (strlen(globals.SKYPIAX_INTERFACES[i].name)
+					&& (strncmp(globals.SKYPIAX_INTERFACES[i].name, interface_name, strlen(interface_name)) == 0)) {
+					if (strlen(globals.SKYPIAX_INTERFACES[i].session_uuid_str)) {
+						DEBUGA_SKYPE
+							("globals.SKYPIAX_INTERFACES[%d].name=|||%s||| session_uuid_str=|||%s||| is BUSY\n",
+							 SKYPIAX_P_LOG, i, globals.SKYPIAX_INTERFACES[i].name, globals.SKYPIAX_INTERFACES[i].session_uuid_str);
+						DEBUGA_SKYPE("1 SESSION_DESTROY %s\n", SKYPIAX_P_LOG, switch_core_session_get_uuid(*new_session));
+						switch_core_session_destroy(new_session);
+						switch_mutex_unlock(globals.mutex);
+						return SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER;
+					}
+
+					DEBUGA_SKYPE("globals.SKYPIAX_INTERFACES[%d].name=|||%s|||?\n", SKYPIAX_P_LOG, i, globals.SKYPIAX_INTERFACES[i].name);
+					tech_pvt = &globals.SKYPIAX_INTERFACES[i];
+					found = 1;
+					break;
+				}
+
+			}
+
+		} else {
+			ERRORA("Doh! no destination number?\n", SKYPIAX_P_LOG);
+			switch_core_session_destroy(new_session);
+			return SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER;
+		}
+
+		if (!found) {
+			DEBUGA_SKYPE("Doh! no available interface for |||%s|||?\n", SKYPIAX_P_LOG, interface_name);
+			DEBUGA_SKYPE("2 SESSION_DESTROY %s\n", SKYPIAX_P_LOG, switch_core_session_get_uuid(*new_session));
+			switch_core_session_destroy(new_session);
+			switch_mutex_unlock(globals.mutex);
+			//return SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER;
+			return SWITCH_CAUSE_NORMAL_CIRCUIT_CONGESTION;
+		}
+
+		channel = switch_core_session_get_channel(*new_session);
+		if (!channel) {
+			ERRORA("Doh! no channel?\n", SKYPIAX_P_LOG);
+			switch_core_session_destroy(new_session);
+			switch_mutex_unlock(globals.mutex);
+			return SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER;
+		}
+		if (skypiax_tech_init(tech_pvt, *new_session) != SWITCH_STATUS_SUCCESS) {
+			ERRORA("Doh! no tech_init?\n", SKYPIAX_P_LOG);
+			switch_core_session_destroy(new_session);
+			switch_mutex_unlock(globals.mutex);
+			return SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER;
+		}
+
+
+		if (outbound_profile) {
+			char name[128];
+
+			snprintf(name, sizeof(name), "skypiax/%s", outbound_profile->destination_number);
+			//snprintf(name, sizeof(name), "skypiax/%s", tech_pvt->name);
+			switch_channel_set_name(channel, name);
+			caller_profile = switch_caller_profile_clone(*new_session, outbound_profile);
+			switch_channel_set_caller_profile(channel, caller_profile);
+			tech_pvt->caller_profile = caller_profile;
+		} else {
+			ERRORA("Doh! no caller profile\n", SKYPIAX_P_LOG);
+			switch_core_session_destroy(new_session);
+			switch_mutex_unlock(globals.mutex);
+			return SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER;
+		}
+
+		tech_pvt->ob_calls++;
+
+		rdest = strchr(caller_profile->destination_number, '/');
+		*rdest++ = '\0';
+
+		//skypiax_call(tech_pvt, rdest, 30);
+
+		switch_copy_string(tech_pvt->session_uuid_str, switch_core_session_get_uuid(*new_session), sizeof(tech_pvt->session_uuid_str));
+		caller_profile = tech_pvt->caller_profile;
+		caller_profile->destination_number = rdest;
+
+		switch_channel_set_flag(channel, CF_OUTBOUND);
+		switch_set_flag(tech_pvt, TFLAG_OUTBOUND);
+		switch_channel_set_state(channel, CS_INIT);
+		skypiax_call(tech_pvt, rdest, 30);
+		switch_mutex_unlock(globals.mutex);
+		return SWITCH_CAUSE_SUCCESS;
+	}
+
+	ERRORA("Doh! no new_session\n", SKYPIAX_P_LOG);
+	return SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER;
+}
+
+/*!
+ * \brief This thread runs during a call, and monitor the interface for signaling, like hangup, caller id, etc most of signaling is handled inside the skypiax_signaling_read function
+ *
+ */
+static void *SWITCH_THREAD_FUNC skypiax_signaling_thread_func(switch_thread_t * thread, void *obj)
+{
+	private_t *tech_pvt = obj;
+	int res;
+	int forever = 1;
+
+	if (!tech_pvt)
+		return NULL;
+
+	DEBUGA_SKYPE("In skypiax_signaling_thread_func: started, p=%p\n", SKYPIAX_P_LOG, (void *) tech_pvt);
+
+	while (forever) {
+		if (!(running && tech_pvt->running))
+			break;
+		res = skypiax_signaling_read(tech_pvt);
+		if (res == CALLFLOW_INCOMING_HANGUP) {
+			switch_core_session_t *session = NULL;
+			switch_channel_t *channel = NULL;
+			//private_t *tech_pvt = NULL;
+			DEBUGA_SKYPE("skype call ended\n", SKYPIAX_P_LOG);
+
+			if (tech_pvt) {
+				session = switch_core_session_locate(tech_pvt->session_uuid_str);
+				if (session) {
+					channel = switch_core_session_get_channel(session);
+					if (channel) {
+						switch_channel_state_t state = switch_channel_get_state(channel);
+						if (state < CS_EXECUTE) {
+							switch_sleep(10000);	//10 msec, let the state evolve from CS_NEW
+						}
+						switch_channel_hangup(channel, SWITCH_CAUSE_NORMAL_CLEARING);
+					} else {
+						ERRORA("no channel?\n", SKYPIAX_P_LOG);
+					}
+					switch_core_session_rwunlock(session);
+				} else {
+					DEBUGA_SKYPE("no session\n", SKYPIAX_P_LOG);
+				}
+				switch_mutex_lock(globals.mutex);
+				tech_pvt->interface_state = SKYPIAX_STATE_DOWN;
+				*tech_pvt->session_uuid_str = '\0';
+				*tech_pvt->skype_call_id = '\0';
+				switch_mutex_unlock(globals.mutex);
+
+				//ERRORA("LET'S WAIT\n", SKYPIAX_P_LOG);
+				switch_sleep(300000);	//0.3 sec
+				//ERRORA("WAIT'S OVER\n", SKYPIAX_P_LOG);
+				//tech_pvt->skype_callflow = CALLFLOW_STATUS_FINISHED;
+				//usleep(30000);    //0.03 sec
+				switch_mutex_lock(globals.mutex);
+				tech_pvt->skype_callflow = CALLFLOW_CALL_IDLE;
+				tech_pvt->interface_state = SKYPIAX_STATE_IDLE;
+				switch_mutex_unlock(globals.mutex);
+			} else {
+				ERRORA("no tech_pvt?\n", SKYPIAX_P_LOG);
+			}
+		}
+	}
+	return NULL;
+}
+
+/* BEGIN: Changes heres */
+static switch_status_t load_config(int reload_type)
+/* END: Changes heres */
+{
+	char *cf = "skypiax.conf";
+	switch_xml_t cfg, xml, global_settings, param, interfaces, myinterface;
+	private_t *tech_pvt = NULL;
+
+	switch_mutex_init(&globals.mutex, SWITCH_MUTEX_NESTED, skypiax_module_pool);
+	if (!(xml = switch_xml_open_cfg(cf, &cfg, NULL))) {
+		ERRORA("open of %s failed\n", SKYPIAX_P_LOG, cf);
+		running = 0;
+		switch_xml_free(xml);
+		return SWITCH_STATUS_TERM;
+	}
+
+	switch_mutex_lock(globals.mutex);
+	if ((global_settings = switch_xml_child(cfg, "global_settings"))) {
+		for (param = switch_xml_child(global_settings, "param"); param; param = param->next) {
+			char *var = (char *) switch_xml_attr_soft(param, "name");
+			char *val = (char *) switch_xml_attr_soft(param, "value");
+
+			if (!strcasecmp(var, "debug")) {
+				DEBUGA_SKYPE("globals.debug=%d\n", SKYPIAX_P_LOG, globals.debug);
+				globals.debug = atoi(val);
+				DEBUGA_SKYPE("globals.debug=%d\n", SKYPIAX_P_LOG, globals.debug);
+			} else if (!strcasecmp(var, "hold-music")) {
+				switch_set_string(globals.hold_music, val);
+				DEBUGA_SKYPE("globals.hold_music=%s\n", SKYPIAX_P_LOG, globals.hold_music);
+			} else if (!strcmp(var, "port")) {
+				globals.port = atoi(val);
+				DEBUGA_SKYPE("globals.port=%d\n", SKYPIAX_P_LOG, globals.port);
+			} else if (!strcmp(var, "codec-master")) {
+				if (!strcasecmp(val, "us")) {
+					switch_set_flag(&globals, GFLAG_MY_CODEC_PREFS);
+				}
+				DEBUGA_SKYPE("codec-master globals.debug=%d\n", SKYPIAX_P_LOG, globals.debug);
+			} else if (!strcmp(var, "dialplan")) {
+				set_global_dialplan(val);
+				DEBUGA_SKYPE("globals.dialplan=%s\n", SKYPIAX_P_LOG, globals.dialplan);
+			} else if (!strcmp(var, "destination")) {
+				set_global_destination(val);
+				DEBUGA_SKYPE("globals.destination=%s\n", SKYPIAX_P_LOG, globals.destination);
+			} else if (!strcmp(var, "context")) {
+				set_global_context(val);
+				DEBUGA_SKYPE("globals.context=%s\n", SKYPIAX_P_LOG, globals.context);
+			} else if (!strcmp(var, "codec-prefs")) {
+				set_global_codec_string(val);
+				DEBUGA_SKYPE("globals.codec_string=%s\n", SKYPIAX_P_LOG, globals.codec_string);
+				globals.codec_order_last = switch_separate_string(globals.codec_string, ',', globals.codec_order, SWITCH_MAX_CODECS);
+			} else if (!strcmp(var, "codec-rates")) {
+				set_global_codec_rates_string(val);
+				DEBUGA_SKYPE("globals.codec_rates_string=%s\n", SKYPIAX_P_LOG, globals.codec_rates_string);
+				globals.codec_rates_last = switch_separate_string(globals.codec_rates_string, ',', globals.codec_rates, SWITCH_MAX_CODECS);
+			}
+
+		}
+	}
+
+	if ((interfaces = switch_xml_child(cfg, "per_interface_settings"))) {
+		int i = 0;
+
+		for (myinterface = switch_xml_child(interfaces, "interface"); myinterface; myinterface = myinterface->next) {
+			char *id = (char *) switch_xml_attr(myinterface, "id");
+			char *name = (char *) switch_xml_attr(myinterface, "name");
+			char *context = "default";
+			char *dialplan = "XML";
+			char *destination = "5000";
+			char *tonegroup = NULL;
+			char *digit_timeout = NULL;
+			char *max_digits = NULL;
+			char *hotline = NULL;
+			char *dial_regex = NULL;
+			char *hold_music = NULL;
+			char *fail_dial_regex = NULL;
+			char *enable_callerid = "true";
+			char *X11_display = NULL;
+			char *tcp_cli_port = NULL;
+			char *tcp_srv_port = NULL;
+			char *skype_user = NULL;
+
+			uint32_t interface_id = 0, to = 0, max = 0;
+
+			tech_pvt = NULL;
+
+			for (param = switch_xml_child(myinterface, "param"); param; param = param->next) {
+				char *var = (char *) switch_xml_attr_soft(param, "name");
+				char *val = (char *) switch_xml_attr_soft(param, "value");
+
+				if (!strcasecmp(var, "tonegroup")) {
+					tonegroup = val;
+				} else if (!strcasecmp(var, "digit_timeout") || !strcasecmp(var, "digit-timeout")) {
+					digit_timeout = val;
+				} else if (!strcasecmp(var, "context")) {
+					context = val;
+				} else if (!strcasecmp(var, "dialplan")) {
+					dialplan = val;
+				} else if (!strcasecmp(var, "destination")) {
+					destination = val;
+				} else if (!strcasecmp(var, "dial-regex")) {
+					dial_regex = val;
+				} else if (!strcasecmp(var, "enable-callerid")) {
+					enable_callerid = val;
+				} else if (!strcasecmp(var, "fail-dial-regex")) {
+					fail_dial_regex = val;
+				} else if (!strcasecmp(var, "hold-music")) {
+					hold_music = val;
+				} else if (!strcasecmp(var, "skype_user")) {
+					skype_user = val;
+				} else if (!strcasecmp(var, "tcp_cli_port")) {
+					tcp_cli_port = val;
+				} else if (!strcasecmp(var, "tcp_srv_port")) {
+					tcp_srv_port = val;
+				} else if (!strcasecmp(var, "X11-display") || !strcasecmp(var, "X11_display")) {
+					X11_display = val;
+				} else if (!strcasecmp(var, "max_digits") || !strcasecmp(var, "max-digits")) {
+					max_digits = val;
+				} else if (!strcasecmp(var, "hotline")) {
+					hotline = val;
+				}
+
+			}
+			if (!skype_user) {
+				ERRORA("interface missing REQUIRED param 'skype_user'\n", SKYPIAX_P_LOG);
+				continue;
+			}
+
+			/* BEGIN: Changes here */
+			if (reload_type == SOFT_RELOAD) {
+				char the_interface[256];
+				sprintf(the_interface, "#%s", name);
+
+				if (interface_exists(the_interface) == SWITCH_STATUS_SUCCESS) {
+					continue;
+				}
+			}
+			/* END: Changes here */
+
+			if (!X11_display) {
+				ERRORA("interface missing REQUIRED param 'X11_display'\n", SKYPIAX_P_LOG);
+				continue;
+			}
+			if (!tcp_cli_port) {
+				ERRORA("interface missing REQUIRED param 'tcp_cli_port'\n", SKYPIAX_P_LOG);
+				continue;
+			}
+
+			if (!tcp_srv_port) {
+				ERRORA("interface missing REQUIRED param 'tcp_srv_port'\n", SKYPIAX_P_LOG);
+				continue;
+			}
+			if (!id) {
+				ERRORA("interface missing REQUIRED param 'id'\n", SKYPIAX_P_LOG);
+				continue;
+			}
+			if (switch_is_number(id)) {
+				interface_id = atoi(id);
+				DEBUGA_SKYPE("interface_id=%d\n", SKYPIAX_P_LOG, interface_id);
+			} else {
+				ERRORA("interface param 'id' MUST be a number, now id='%s'\n", SKYPIAX_P_LOG, id);
+				continue;
+			}
+
+			if (!name) {
+				WARNINGA("interface missing param 'name', not nice, but works\n", SKYPIAX_P_LOG);
+			}
+
+			if (!tonegroup) {
+				tonegroup = "us";
+			}
+
+			if (digit_timeout) {
+				to = atoi(digit_timeout);
+			}
+
+			if (max_digits) {
+				max = atoi(max_digits);
+			}
+
+			if (name) {
+				DEBUGA_SKYPE("name=%s\n", SKYPIAX_P_LOG, name);
+			}
+#ifndef WIN32
+			if (!XInitThreads()) {
+				ERRORA("Not initialized XInitThreads!\n", SKYPIAX_P_LOG);
+			} else {
+				DEBUGA_SKYPE("Initialized XInitThreads!\n", SKYPIAX_P_LOG);
+			}
+			switch_sleep(100);
+#endif /* WIN32 */
+
+			if (interface_id && interface_id < SKYPIAX_MAX_INTERFACES) {
+				private_t newconf;
+				switch_threadattr_t *skypiax_api_thread_attr = NULL;
+				switch_threadattr_t *skypiax_signaling_thread_attr = NULL;
+
+				memset(&newconf, '\0', sizeof(newconf));
+				globals.SKYPIAX_INTERFACES[interface_id] = newconf;
+				globals.SKYPIAX_INTERFACES[interface_id].running = 1;
+
+
+				tech_pvt = &globals.SKYPIAX_INTERFACES[interface_id];
+
+				switch_set_string(globals.SKYPIAX_INTERFACES[interface_id].interface_id, id);
+				if (name) {
+					switch_set_string(globals.SKYPIAX_INTERFACES[interface_id].name, name);
+				} else {
+					switch_set_string(globals.SKYPIAX_INTERFACES[interface_id].name, "N/A");
+				}
+				DEBUGA_SKYPE("CONFIGURING interface_id=%d\n", SKYPIAX_P_LOG, interface_id);
+#ifdef WIN32
+				globals.SKYPIAX_INTERFACES[interface_id].tcp_cli_port = (unsigned short) atoi(tcp_cli_port);
+				globals.SKYPIAX_INTERFACES[interface_id].tcp_srv_port = (unsigned short) atoi(tcp_srv_port);
+#else /* WIN32 */
+				globals.SKYPIAX_INTERFACES[interface_id].tcp_cli_port = atoi(tcp_cli_port);
+				globals.SKYPIAX_INTERFACES[interface_id].tcp_srv_port = atoi(tcp_srv_port);
+#endif /* WIN32 */
+				switch_set_string(globals.SKYPIAX_INTERFACES[interface_id].X11_display, X11_display);
+				switch_set_string(globals.SKYPIAX_INTERFACES[interface_id].skype_user, skype_user);
+				switch_set_string(globals.SKYPIAX_INTERFACES[interface_id].context, context);
+				switch_set_string(globals.SKYPIAX_INTERFACES[interface_id].dialplan, dialplan);
+				switch_set_string(globals.SKYPIAX_INTERFACES[interface_id].destination, destination);
+				switch_set_string(globals.SKYPIAX_INTERFACES[interface_id].context, context);
+
+				DEBUGA_SKYPE
+					("interface_id=%d globals.SKYPIAX_INTERFACES[interface_id].X11_display=%s\n",
+					 SKYPIAX_P_LOG, interface_id, globals.SKYPIAX_INTERFACES[interface_id].X11_display);
+				DEBUGA_SKYPE
+					("interface_id=%d globals.SKYPIAX_INTERFACES[interface_id].skype_user=%s\n",
+					 SKYPIAX_P_LOG, interface_id, globals.SKYPIAX_INTERFACES[interface_id].skype_user);
+				DEBUGA_SKYPE
+					("interface_id=%d globals.SKYPIAX_INTERFACES[interface_id].tcp_cli_port=%d\n",
+					 SKYPIAX_P_LOG, interface_id, globals.SKYPIAX_INTERFACES[interface_id].tcp_cli_port);
+				DEBUGA_SKYPE
+					("interface_id=%d globals.SKYPIAX_INTERFACES[interface_id].tcp_srv_port=%d\n",
+					 SKYPIAX_P_LOG, interface_id, globals.SKYPIAX_INTERFACES[interface_id].tcp_srv_port);
+				DEBUGA_SKYPE("interface_id=%d globals.SKYPIAX_INTERFACES[interface_id].name=%s\n",
+							 SKYPIAX_P_LOG, interface_id, globals.SKYPIAX_INTERFACES[interface_id].name);
+				DEBUGA_SKYPE
+					("interface_id=%d globals.SKYPIAX_INTERFACES[interface_id].context=%s\n",
+					 SKYPIAX_P_LOG, interface_id, globals.SKYPIAX_INTERFACES[interface_id].context);
+				DEBUGA_SKYPE
+					("interface_id=%d globals.SKYPIAX_INTERFACES[interface_id].dialplan=%s\n",
+					 SKYPIAX_P_LOG, interface_id, globals.SKYPIAX_INTERFACES[interface_id].dialplan);
+				DEBUGA_SKYPE
+					("interface_id=%d globals.SKYPIAX_INTERFACES[interface_id].destination=%s\n",
+					 SKYPIAX_P_LOG, interface_id, globals.SKYPIAX_INTERFACES[interface_id].destination);
+				DEBUGA_SKYPE
+					("interface_id=%d globals.SKYPIAX_INTERFACES[interface_id].context=%s\n",
+					 SKYPIAX_P_LOG, interface_id, globals.SKYPIAX_INTERFACES[interface_id].context);
+				WARNINGA("STARTING interface_id=%d\n", SKYPIAX_P_LOG, interface_id);
+
+				switch_threadattr_create(&skypiax_api_thread_attr, skypiax_module_pool);
+				switch_threadattr_stacksize_set(skypiax_api_thread_attr, SWITCH_THREAD_STACKSIZE);
+				switch_thread_create(&globals.SKYPIAX_INTERFACES[interface_id].skypiax_api_thread,
+									 skypiax_api_thread_attr, skypiax_do_skypeapi_thread, &globals.SKYPIAX_INTERFACES[interface_id], skypiax_module_pool);
+
+				switch_sleep(100000);
+
+				switch_threadattr_create(&skypiax_signaling_thread_attr, skypiax_module_pool);
+				switch_threadattr_stacksize_set(skypiax_signaling_thread_attr, SWITCH_THREAD_STACKSIZE);
+				switch_thread_create(&globals.SKYPIAX_INTERFACES[interface_id].
+									 skypiax_signaling_thread, skypiax_signaling_thread_attr,
+									 skypiax_signaling_thread_func, &globals.SKYPIAX_INTERFACES[interface_id], skypiax_module_pool);
+
+				switch_sleep(100000);
+
+				skypiax_audio_init(&globals.SKYPIAX_INTERFACES[interface_id]);
+
+				NOTICA
+					("WAITING roughly 10 seconds to find a running Skype client and connect to its SKYPE API for interface_id=%d\n",
+					 SKYPIAX_P_LOG, interface_id);
+				i = 0;
+				while (globals.SKYPIAX_INTERFACES[interface_id].SkypiaxHandles.api_connected == 0 && running && i < 200) {	// 10 seconds! thanks Jeff Lenk
+					switch_sleep(50000);
+					i++;
+				}
+				if (globals.SKYPIAX_INTERFACES[interface_id].SkypiaxHandles.api_connected) {
+					NOTICA
+						("Found a running Skype client, connected to its SKYPE API for interface_id=%d, waiting 60 seconds for CURRENTUSERHANDLE==%s\n",
+						 SKYPIAX_P_LOG, interface_id, globals.SKYPIAX_INTERFACES[interface_id].skype_user);
+				} else {
+					ERRORA
+						("Failed to connect to a SKYPE API for interface_id=%d, no SKYPE client running, please (re)start Skype client. Skypiax exiting\n",
+						 SKYPIAX_P_LOG, interface_id);
+					running = 0;
+					switch_mutex_unlock(globals.mutex);
+					switch_xml_free(xml);
+					return SWITCH_STATUS_FALSE;
+				}
+
+				i = 0;
+				while (globals.SKYPIAX_INTERFACES[interface_id].SkypiaxHandles.currentuserhandle == 0 && running && i < 1200) {	// 60 seconds! thanks Jeff Lenk
+					switch_sleep(50000);
+					i++;
+				}
+				if (globals.SKYPIAX_INTERFACES[interface_id].SkypiaxHandles.currentuserhandle) {
+					WARNINGA
+						("Interface_id=%d is now STARTED, the Skype client to which we are connected gave us the correct CURRENTUSERHANDLE (%s)\n",
+						 SKYPIAX_P_LOG, interface_id, globals.SKYPIAX_INTERFACES[interface_id].skype_user);
+
+					skypiax_signaling_write(&globals.SKYPIAX_INTERFACES[interface_id], "SET AUTOAWAY OFF");
+				} else {
+					ERRORA
+						("The Skype client to which we are connected FAILED to gave us CURRENTUSERHANDLE=%s, interface_id=%d FAILED to start. No Skype client logged in as '%s' has been found. Please (re)launch a Skype client logged in as '%s'. Skypiax exiting now\n",
+						 SKYPIAX_P_LOG, globals.SKYPIAX_INTERFACES[interface_id].skype_user,
+						 interface_id, globals.SKYPIAX_INTERFACES[interface_id].skype_user, globals.SKYPIAX_INTERFACES[interface_id].skype_user);
+					running = 0;
+					switch_mutex_unlock(globals.mutex);
+					switch_xml_free(xml);
+					return SWITCH_STATUS_FALSE;
+				}
+
+			} else {
+				ERRORA("interface id %d is higher than SKYPIAX_MAX_INTERFACES (%d)\n", SKYPIAX_P_LOG, interface_id, SKYPIAX_MAX_INTERFACES);
+				continue;
+			}
+
+		}
+
+		for (i = 0; i < SKYPIAX_MAX_INTERFACES; i++) {
+			if (strlen(globals.SKYPIAX_INTERFACES[i].name)) {
+				/* How many real intterfaces */
+				globals.real_interfaces = i + 1;
+
+				tech_pvt = &globals.SKYPIAX_INTERFACES[i];
+
+				DEBUGA_SKYPE("i=%d globals.SKYPIAX_INTERFACES[%d].interface_id=%s\n", SKYPIAX_P_LOG, i, i, globals.SKYPIAX_INTERFACES[i].interface_id);
+				DEBUGA_SKYPE("i=%d globals.SKYPIAX_INTERFACES[%d].X11_display=%s\n", SKYPIAX_P_LOG, i, i, globals.SKYPIAX_INTERFACES[i].X11_display);
+				DEBUGA_SKYPE("i=%d globals.SKYPIAX_INTERFACES[%d].name=%s\n", SKYPIAX_P_LOG, i, i, globals.SKYPIAX_INTERFACES[i].name);
+				DEBUGA_SKYPE("i=%d globals.SKYPIAX_INTERFACES[%d].context=%s\n", SKYPIAX_P_LOG, i, i, globals.SKYPIAX_INTERFACES[i].context);
+				DEBUGA_SKYPE("i=%d globals.SKYPIAX_INTERFACES[%d].dialplan=%s\n", SKYPIAX_P_LOG, i, i, globals.SKYPIAX_INTERFACES[i].dialplan);
+				DEBUGA_SKYPE("i=%d globals.SKYPIAX_INTERFACES[%d].destination=%s\n", SKYPIAX_P_LOG, i, i, globals.SKYPIAX_INTERFACES[i].destination);
+				DEBUGA_SKYPE("i=%d globals.SKYPIAX_INTERFACES[%d].context=%s\n", SKYPIAX_P_LOG, i, i, globals.SKYPIAX_INTERFACES[i].context);
+			}
+		}
+	}
+
+	switch_mutex_unlock(globals.mutex);
+	switch_xml_free(xml);
+
+	return SWITCH_STATUS_SUCCESS;
+}
+
+SWITCH_MODULE_LOAD_FUNCTION(mod_skypiax_load)
+{
+	switch_api_interface_t *commands_api_interface;
+
+	skypiax_module_pool = pool;
+	memset(&globals, '\0', sizeof(globals));
+
+	running = 1;
+
+	if (load_config(FULL_RELOAD) != SWITCH_STATUS_SUCCESS) {
+		running = 0;
+		return SWITCH_STATUS_FALSE;
+	}
+
+	*module_interface = switch_loadable_module_create_module_interface(pool, modname);
+	skypiax_endpoint_interface = switch_loadable_module_create_interface(*module_interface, SWITCH_ENDPOINT_INTERFACE);
+	skypiax_endpoint_interface->interface_name = "skypiax";
+	skypiax_endpoint_interface->io_routines = &skypiax_io_routines;
+	skypiax_endpoint_interface->state_handler = &skypiax_state_handlers;
+
+	if (running) {
+
+		SWITCH_ADD_API(commands_api_interface, "sk", "Skypiax console commands", sk_function, SK_SYNTAX);
+		SWITCH_ADD_API(commands_api_interface, "skypiax", "Skypiax interface commands", skypiax_function, SKYPIAX_SYNTAX);
+
+		/* indicate that the module should continue to be loaded */
+		return SWITCH_STATUS_SUCCESS;
+	} else
+		return SWITCH_STATUS_FALSE;
+}
+
+SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_skypiax_shutdown)
+{
+	int x;
+	private_t *tech_pvt = NULL;
+	switch_status_t status;
+	unsigned int howmany = 8;
+	int interface_id;
+
+	running = 0;
+
+	for (interface_id = 0; interface_id < SKYPIAX_MAX_INTERFACES; interface_id++) {
+		tech_pvt = &globals.SKYPIAX_INTERFACES[interface_id];
+
+		if (strlen(globals.SKYPIAX_INTERFACES[interface_id].name)) {
+			if (globals.SKYPIAX_INTERFACES[interface_id].skypiax_signaling_thread) {
+#ifdef WIN32
+				switch_file_write(tech_pvt->SkypiaxHandles.fdesc[1], "sciutati", &howmany);	// let's the controldev_thread die
+#else /* WIN32 */
+				howmany = write(tech_pvt->SkypiaxHandles.fdesc[1], "sciutati", howmany);
+#endif /* WIN32 */
+			}
+
+			if (globals.SKYPIAX_INTERFACES[interface_id].skypiax_api_thread) {
+#ifdef WIN32
+				if (SendMessage(tech_pvt->SkypiaxHandles.win32_hInit_MainWindowHandle, WM_DESTROY, 0, 0) == FALSE) {	// let's the skypiax_api_thread_func die
+					DEBUGA_SKYPE("got FALSE here, thread probably was already dead. GetLastError returned: %d\n", SKYPIAX_P_LOG, GetLastError());
+					globals.SKYPIAX_INTERFACES[interface_id].skypiax_api_thread = NULL;
+				}
+#else
+				XEvent e;
+				Atom atom1 = XInternAtom(tech_pvt->SkypiaxHandles.disp, "SKYPECONTROLAPI_MESSAGE_BEGIN",
+										 False);
+				memset(&e, 0, sizeof(e));
+				e.xclient.type = ClientMessage;
+				e.xclient.message_type = atom1;	/*  leading message */
+				e.xclient.display = tech_pvt->SkypiaxHandles.disp;
+				e.xclient.window = tech_pvt->SkypiaxHandles.skype_win;
+				e.xclient.format = 8;
+
+				XSendEvent(tech_pvt->SkypiaxHandles.disp, tech_pvt->SkypiaxHandles.win, False, 0, &e);
+				XSync(tech_pvt->SkypiaxHandles.disp, False);
+#endif
+			}
+			x = 10;
+			while (x) {			//FIXME 0.5 seconds?
+				x--;
+				switch_yield(50000);
+			}
+			if (globals.SKYPIAX_INTERFACES[interface_id].skypiax_signaling_thread) {
+				switch_thread_join(&status, globals.SKYPIAX_INTERFACES[interface_id].skypiax_signaling_thread);
+			}
+			if (globals.SKYPIAX_INTERFACES[interface_id].skypiax_api_thread) {
+				switch_thread_join(&status, globals.SKYPIAX_INTERFACES[interface_id].skypiax_api_thread);
+			}
+#ifndef WIN32
+			WARNINGA("SHUTDOWN interface_id=%d\n", SKYPIAX_P_LOG, interface_id);
+			shutdown(tech_pvt->audioskypepipe[0], 2);
+			close(tech_pvt->audioskypepipe[0]);
+			shutdown(tech_pvt->audioskypepipe[1], 2);
+			close(tech_pvt->audioskypepipe[1]);
+			shutdown(tech_pvt->audiopipe[0], 2);
+			close(tech_pvt->audiopipe[0]);
+			shutdown(tech_pvt->audiopipe[1], 2);
+			close(tech_pvt->audiopipe[1]);
+			shutdown(tech_pvt->SkypiaxHandles.fdesc[0], 2);
+			close(tech_pvt->SkypiaxHandles.fdesc[0]);
+			shutdown(tech_pvt->SkypiaxHandles.fdesc[1], 2);
+			close(tech_pvt->SkypiaxHandles.fdesc[1]);
+#endif /* WIN32 */
+		}
+
+	}
+	switch_safe_free(globals.dialplan);
+	switch_safe_free(globals.context);
+	switch_safe_free(globals.destination);
+	switch_safe_free(globals.codec_string);
+	switch_safe_free(globals.codec_rates_string);
+
+	return SWITCH_STATUS_SUCCESS;
+}
+
+void *SWITCH_THREAD_FUNC skypiax_do_tcp_srv_thread(switch_thread_t * thread, void *obj)
+{
+	return skypiax_do_tcp_srv_thread_func(obj);
+}
+
+void *SWITCH_THREAD_FUNC skypiax_do_tcp_cli_thread(switch_thread_t * thread, void *obj)
+{
+	return skypiax_do_tcp_cli_thread_func(obj);
+}
+
+void *SWITCH_THREAD_FUNC skypiax_do_skypeapi_thread(switch_thread_t * thread, void *obj)
+{
+	return skypiax_do_skypeapi_thread_func(obj);
+}
+
+int dtmf_received(private_t * tech_pvt, char *value)
+{
+	switch_core_session_t *session = NULL;
+	switch_channel_t *channel = NULL;
+
+	session = switch_core_session_locate(tech_pvt->session_uuid_str);
+	channel = switch_core_session_get_channel(session);
+
+	if (channel) {
+
+		if (!switch_channel_test_flag(channel, CF_BRIDGED)) {
+
+			switch_dtmf_t dtmf = { (char) value[0], switch_core_default_dtmf_duration(0) };
+			DEBUGA_SKYPE("received DTMF %c on channel %s\n", SKYPIAX_P_LOG, dtmf.digit, switch_channel_get_name(channel));
+			switch_mutex_lock(tech_pvt->flag_mutex);
+			//FIXME: why sometimes DTMFs from here do not seems to be get by FS?
+			switch_channel_queue_dtmf(channel, &dtmf);
+			switch_set_flag(tech_pvt, TFLAG_DTMF);
+			switch_mutex_unlock(tech_pvt->flag_mutex);
+		} else {
+			DEBUGA_SKYPE
+				("received a DTMF on channel %s, but we're BRIDGED, so let's NOT relay it out of band\n", SKYPIAX_P_LOG, switch_channel_get_name(channel));
+		}
+	} else {
+		WARNINGA("received %c DTMF, but no channel?\n", SKYPIAX_P_LOG, value[0]);
+	}
+	switch_core_session_rwunlock(session);
+
+	return 0;
+}
+
+int start_audio_threads(private_t * tech_pvt)
+{
+	switch_threadattr_t *thd_attr = NULL;
+
+	switch_threadattr_create(&thd_attr, skypiax_module_pool);
+	switch_threadattr_detach_set(thd_attr, 1);
+	switch_threadattr_stacksize_set(thd_attr, SWITCH_THREAD_STACKSIZE);
+	if (switch_thread_create(&tech_pvt->tcp_srv_thread, thd_attr, skypiax_do_tcp_srv_thread, tech_pvt, skypiax_module_pool) == SWITCH_STATUS_SUCCESS) {
+		DEBUGA_SKYPE("started tcp_srv_thread thread.\n", SKYPIAX_P_LOG);
+	} else {
+		ERRORA("failed to start tcp_srv_thread thread.\n", SKYPIAX_P_LOG);
+		return -1;
+	}
+
+	switch_threadattr_create(&thd_attr, skypiax_module_pool);
+	switch_threadattr_detach_set(thd_attr, 1);
+	switch_threadattr_stacksize_set(thd_attr, SWITCH_THREAD_STACKSIZE);
+	if (switch_thread_create(&tech_pvt->tcp_cli_thread, thd_attr, skypiax_do_tcp_cli_thread, tech_pvt, skypiax_module_pool) == SWITCH_STATUS_SUCCESS) {
+		DEBUGA_SKYPE("started tcp_cli_thread thread.\n", SKYPIAX_P_LOG);
+	} else {
+		ERRORA("failed to start tcp_cli_thread thread.\n", SKYPIAX_P_LOG);
+		return -1;
+	}
+	switch_sleep(100000);
+
+	if (tech_pvt->tcp_cli_thread == NULL || tech_pvt->tcp_srv_thread == NULL) {
+		ERRORA("tcp_cli_thread or tcp_srv_thread exited\n", SKYPIAX_P_LOG);
+		return -1;
+	}
+
+	return 0;
+}
+
+int new_inbound_channel(private_t * tech_pvt)
+{
+	switch_core_session_t *session = NULL;
+	switch_channel_t *channel = NULL;
+
+	if ((session = switch_core_session_request(skypiax_endpoint_interface, SWITCH_CALL_DIRECTION_INBOUND, NULL)) != 0) {
+		DEBUGA_SKYPE("2 SESSION_REQUEST %s\n", SKYPIAX_P_LOG, switch_core_session_get_uuid(session));
+		switch_core_session_add_stream(session, NULL);
+		channel = switch_core_session_get_channel(session);
+		if (!channel) {
+			ERRORA("Doh! no channel?\n", SKYPIAX_P_LOG);
+			switch_core_session_destroy(&session);
+			return 0;
+		}
+		if (skypiax_tech_init(tech_pvt, session) != SWITCH_STATUS_SUCCESS) {
+			ERRORA("Doh! no tech_init?\n", SKYPIAX_P_LOG);
+			switch_core_session_destroy(&session);
+			return 0;
+		}
+
+		if ((tech_pvt->caller_profile =
+			 switch_caller_profile_new(switch_core_session_get_pool(session), "skypiax",
+									   tech_pvt->dialplan, tech_pvt->callid_name,
+									   tech_pvt->callid_number, NULL, NULL, NULL, NULL, "mod_skypiax", tech_pvt->context, tech_pvt->destination)) != 0) {
+			char name[128];
+			//switch_snprintf(name, sizeof(name), "skypiax/%s/%s", tech_pvt->name, tech_pvt->caller_profile->destination_number);
+			switch_snprintf(name, sizeof(name), "skypiax/%s", tech_pvt->name);
+			switch_channel_set_name(channel, name);
+			switch_channel_set_caller_profile(channel, tech_pvt->caller_profile);
+		}
+		switch_channel_set_state(channel, CS_INIT);
+		if (switch_core_session_thread_launch(session) != SWITCH_STATUS_SUCCESS) {
+			ERRORA("Error spawning thread\n", SKYPIAX_P_LOG);
+			switch_core_session_destroy(&session);
+			return 0;
+		}
+	}
+	if (channel) {
+		switch_channel_mark_answered(channel);
+	}
+
+	DEBUGA_SKYPE("new_inbound_channel\n", SKYPIAX_P_LOG);
+
+	return 0;
+}
+
+int remote_party_is_ringing(private_t * tech_pvt)
+{
+	switch_core_session_t *session = NULL;
+	switch_channel_t *channel = NULL;
+
+	if (!switch_strlen_zero(tech_pvt->session_uuid_str)) {
+		session = switch_core_session_locate(tech_pvt->session_uuid_str);
+	} else {
+		ERRORA("No session???\n", SKYPIAX_P_LOG);
+		goto done;
+	}
+	if (session) {
+		channel = switch_core_session_get_channel(session);
+	} else {
+		ERRORA("No session???\n", SKYPIAX_P_LOG);
+		goto done;
+	}
+	if (channel) {
+		switch_channel_mark_ring_ready(channel);
+		DEBUGA_SKYPE("skype_call: REMOTE PARTY RINGING\n", SKYPIAX_P_LOG);
+	} else {
+		ERRORA("No channel???\n", SKYPIAX_P_LOG);
+	}
+
+	switch_core_session_rwunlock(session);
+
+  done:
+	return 0;
+}
+
+int remote_party_is_early_media(private_t * tech_pvt)
+{
+	switch_core_session_t *session = NULL;
+	switch_channel_t *channel = NULL;
+
+	if (!switch_strlen_zero(tech_pvt->session_uuid_str)) {
+		session = switch_core_session_locate(tech_pvt->session_uuid_str);
+	} else {
+		ERRORA("No session???\n\n\n", SKYPIAX_P_LOG);
+		//TODO: kill the bastard
+		goto done;
+	}
+	if (session) {
+		channel = switch_core_session_get_channel(session);
+		switch_core_session_add_stream(session, NULL);
+	} else {
+		ERRORA("No session???\n", SKYPIAX_P_LOG);
+		//TODO: kill the bastard
+		goto done;
+	}
+	if (channel) {
+		switch_channel_mark_pre_answered(channel);
+		DEBUGA_SKYPE("skype_call: REMOTE PARTY EARLY MEDIA\n", SKYPIAX_P_LOG);
+	} else {
+		ERRORA("No channel???\n", SKYPIAX_P_LOG);
+		//TODO: kill the bastard
+	}
+
+	switch_core_session_rwunlock(session);
+
+  done:
+	return 0;
+}
+
+int outbound_channel_answered(private_t * tech_pvt)
+{
+	switch_core_session_t *session = NULL;
+	switch_channel_t *channel = NULL;
+
+	if (!switch_strlen_zero(tech_pvt->session_uuid_str)) {
+		session = switch_core_session_locate(tech_pvt->session_uuid_str);
+	} else {
+		ERRORA("No session???\n", SKYPIAX_P_LOG);
+		goto done;
+	}
+	if (session) {
+		channel = switch_core_session_get_channel(session);
+	} else {
+		ERRORA("No channel???\n", SKYPIAX_P_LOG);
+		goto done;
+	}
+	if (channel) {
+		switch_channel_mark_answered(channel);
+		//DEBUGA_SKYPE("skype_call: %s, answered\n", SKYPIAX_P_LOG, id);
+	} else {
+		ERRORA("No channel???\n", SKYPIAX_P_LOG);
+	}
+
+	switch_core_session_rwunlock(session);
+
+  done:
+	DEBUGA_SKYPE("outbound_channel_answered!\n", SKYPIAX_P_LOG);
+
+	return 0;
+}
+
+private_t *find_available_skypiax_interface_rr(private_t * tech_pvt_calling)
+{
+	private_t *tech_pvt = NULL;
+	int i;
+	//int num_interfaces = SKYPIAX_MAX_INTERFACES; 
+	//int num_interfaces = globals.real_interfaces;
+
+	switch_mutex_lock(globals.mutex);
+
+	/* Fact is the real interface start from 1 */
+	//XXX no, is just a convention, but you can have it start from 0. I do not, for aestetic reasons :-)  
+	//if (globals.next_interface == 0) globals.next_interface = 1;
+
+	for (i = 0; i < SKYPIAX_MAX_INTERFACES; i++) {
+		int interface_id;
+
+		interface_id = globals.next_interface;
+		//interface_id = interface_id < SKYPIAX_MAX_INTERFACES ? interface_id : interface_id - SKYPIAX_MAX_INTERFACES + 1;
+		globals.next_interface = interface_id + 1 < SKYPIAX_MAX_INTERFACES ? interface_id + 1 : 0;
+
+		if (strlen(globals.SKYPIAX_INTERFACES[interface_id].name)) {
+			int skype_state = 0;
+
+			tech_pvt = &globals.SKYPIAX_INTERFACES[interface_id];
+			skype_state = tech_pvt->interface_state;
+			//DEBUGA_SKYPE("skype interface: %d, name: %s, state: %d\n", SKYPIAX_P_LOG, interface_id, globals.SKYPIAX_INTERFACES[interface_id].name, skype_state);
+			if ((tech_pvt_calling ? strcmp(tech_pvt->skype_user, tech_pvt_calling->skype_user) : 1)
+				&& (SKYPIAX_STATE_DOWN == skype_state || 0 == skype_state) && (tech_pvt->skype_callflow == CALLFLOW_STATUS_FINISHED
+																			   || 0 == tech_pvt->skype_callflow)) {
+				DEBUGA_SKYPE("returning as available skype interface name: %s, state: %d callflow: %d\n", SKYPIAX_P_LOG, tech_pvt->name, skype_state,
+							 tech_pvt->skype_callflow);
+				/*set to Dialing state to avoid other thread fint it, don't know if it is safe */
+				//XXX no, it's not safe 
+				if (tech_pvt_calling == NULL) {
+					tech_pvt->interface_state = SKYPIAX_STATE_SELECTED;
+				}
+
+				switch_mutex_unlock(globals.mutex);
+				return tech_pvt;
+			}
+		}						// else {
+		//DEBUGA_SKYPE("Skype interface: %d blank!! A hole here means we cannot hunt the last interface.\n", SKYPIAX_P_LOG, interface_id);
+		//}
+	}
+
+	switch_mutex_unlock(globals.mutex);
+	return NULL;
+}
+
+SWITCH_STANDARD_API(sk_function)
+{
+	char *mycmd = NULL, *argv[10] = { 0 };
+	int argc = 0;
+
+	if (globals.sk_console)
+		stream->write_function(stream, "sk console is: |||%s|||\n", globals.sk_console->name);
+	else
+		stream->write_function(stream, "sk console is NOT yet assigned\n");
+
+	if (!switch_strlen_zero(cmd) && (mycmd = strdup(cmd))) {
+		argc = switch_separate_string(mycmd, ' ', argv, (sizeof(argv) / sizeof(argv[0])));
+	}
+
+	if (!argc || !argv[0]) {
+		stream->write_function(stream, "%s", SK_SYNTAX);
+		goto end;
+	}
+
+	if (!strcasecmp(argv[0], "list")) {
+		int i;
+		char next_flag_char = ' ';
+
+		stream->write_function(stream, "F ID\t    Name    \tIB (F/T)    OB (F/T)\tState\tCallFlw\t\tUUID\n");
+		stream->write_function(stream, "= ====\t  ========  \t=======     =======\t======\t============\t======\n");
+
+		for (i = 0; i < SKYPIAX_MAX_INTERFACES; i++) {
+			next_flag_char = i == globals.next_interface ? '*' : ' ';
+
+			if (strlen(globals.SKYPIAX_INTERFACES[i].name)) {
+				stream->write_function(stream,
+									   "%c %d\t[%s]\t%3ld/%ld\t%6ld/%ld\t%s\t%s\t%s\n",
+									   next_flag_char,
+									   i, globals.SKYPIAX_INTERFACES[i].name,
+									   globals.SKYPIAX_INTERFACES[i].ib_failed_calls,
+									   globals.SKYPIAX_INTERFACES[i].ib_calls,
+									   globals.SKYPIAX_INTERFACES[i].ob_failed_calls,
+									   globals.SKYPIAX_INTERFACES[i].ob_calls,
+									   interface_status[globals.SKYPIAX_INTERFACES[i].interface_state],
+									   skype_callflow[globals.SKYPIAX_INTERFACES[i].skype_callflow], globals.SKYPIAX_INTERFACES[i].session_uuid_str);
+			} else if (argc > 1 && !strcasecmp(argv[1], "full")) {
+				stream->write_function(stream, "%c\t%d\n", next_flag_char, i);
+			}
+
+		}
+		stream->write_function(stream, "\nTotal: %d\n", globals.real_interfaces - 1);
+
+	} else if (!strcasecmp(argv[0], "console")) {
+		int i;
+		int found = 0;
+
+		if (argc == 2) {
+			for (i = 0; !found && i < SKYPIAX_MAX_INTERFACES; i++) {
+				/* we've been asked for a normal interface name, or we have not found idle interfaces to serve as the "ANY" interface */
+				if (strlen(globals.SKYPIAX_INTERFACES[i].name)
+					&& (strncmp(globals.SKYPIAX_INTERFACES[i].name, argv[1], strlen(argv[1])) == 0)) {
+					globals.sk_console = &globals.SKYPIAX_INTERFACES[i];
+					stream->write_function(stream,
+										   "sk console is now: globals.SKYPIAX_INTERFACES[%d].name=|||%s|||\n", i, globals.SKYPIAX_INTERFACES[i].name);
+					stream->write_function(stream, "sk console is: |||%s|||\n", globals.sk_console->name);
+					found = 1;
+					break;
+				}
+
+			}
+			if (!found)
+				stream->write_function(stream, "ERROR: A Skypiax interface with name='%s' was not found\n", argv[1]);
+		} else {
+
+			stream->write_function(stream, "-ERR Usage: sk console interface_name\n");
+			goto end;
+		}
+
+	} else if (!strcasecmp(argv[0], "ciapalino")) {
+
+/* BEGIN: Changes heres */
+	} else if (!strcasecmp(argv[0], "reload")) {
+		if (load_config(SOFT_RELOAD) != SWITCH_STATUS_SUCCESS) {
+			stream->write_function(stream, "sk reload failed\n");
+		} else {
+			stream->write_function(stream, "sk reload success\n");
+		}
+	} else if (!strcasecmp(argv[0], "remove")) {
+		if (argc == 2) {
+			if (remove_interface(argv[1]) == SWITCH_STATUS_SUCCESS) {
+				if (interface_exists(argv[1]) == SWITCH_STATUS_SUCCESS) {
+					stream->write_function(stream, "sk remove '%s' failed\n", argv[1]);
+				} else {
+					stream->write_function(stream, "sk remove '%s' success\n", argv[1]);
+				}
+			}
+		} else {
+			stream->write_function(stream, "-ERR Usage: sk remove interface_name\n");
+			goto end;
+		}
+/* END: Changes heres */
+
+	} else {
+		if (globals.sk_console)
+			skypiax_signaling_write(globals.sk_console, (char *) cmd);
+		else
+			stream->write_function(stream, "sk console is NOT yet assigned\n");
+	}
+  end:
+	switch_safe_free(mycmd);
+
+	return SWITCH_STATUS_SUCCESS;
+}
+
+SWITCH_STANDARD_API(skypiax_function)
+{
+	char *mycmd = NULL, *argv[10] = { 0 };
+	int argc = 0;
+	private_t *tech_pvt = NULL;
+
+	if (!switch_strlen_zero(cmd) && (mycmd = strdup(cmd))) {
+		argc = switch_separate_string(mycmd, ' ', argv, (sizeof(argv) / sizeof(argv[0])));
+	}
+
+	if (!argc) {
+		stream->write_function(stream, "ERROR, usage: %s", SKYPIAX_SYNTAX);
+		goto end;
+	}
+
+	if (argc < 2) {
+		stream->write_function(stream, "ERROR, usage: %s", SKYPIAX_SYNTAX);
+		goto end;
+	}
+
+	if (argv[0]) {
+		int i;
+		int found = 0;
+
+		for (i = 0; !found && i < SKYPIAX_MAX_INTERFACES; i++) {
+			/* we've been asked for a normal interface name, or we have not found idle interfaces to serve as the "ANY" interface */
+			if (strlen(globals.SKYPIAX_INTERFACES[i].name)
+				&& (strncmp(globals.SKYPIAX_INTERFACES[i].name, argv[0], strlen(argv[0])) == 0)) {
+				tech_pvt = &globals.SKYPIAX_INTERFACES[i];
+				stream->write_function(stream, "Using interface: globals.SKYPIAX_INTERFACES[%d].name=|||%s|||\n", i, globals.SKYPIAX_INTERFACES[i].name);
+				found = 1;
+				break;
+			}
+
+		}
+		if (!found) {
+			stream->write_function(stream, "ERROR: A Skypiax interface with name='%s' was not found\n", argv[0]);
+			switch_safe_free(mycmd);
+
+			return SWITCH_STATUS_SUCCESS;
+		} else {
+			skypiax_signaling_write(tech_pvt, (char *) &cmd[strlen(argv[0]) + 1]);
+		}
+	} else {
+		stream->write_function(stream, "ERROR, usage: %s", SKYPIAX_SYNTAX);
+	}
+  end:
+	switch_safe_free(mycmd);
+
+	return SWITCH_STATUS_SUCCESS;
+}
+
+int skypiax_answer(private_t * tech_pvt, char *id, char *value)
+{
+	char msg_to_skype[1024];
+	int i;
+	int found = 0;
+	private_t *giovatech;
+	struct timeval timenow;
+
+	switch_mutex_lock(globals.mutex);
+
+	gettimeofday(&timenow, NULL);
+	for (i = 0; !found && i < SKYPIAX_MAX_INTERFACES; i++) {
+		if (strlen(globals.SKYPIAX_INTERFACES[i].name)) {
+
+			giovatech = &globals.SKYPIAX_INTERFACES[i];
+			//NOTICA("skype interface: %d, name: %s, state: %d, value=%s, giovatech->callid_number=%s, giovatech->skype_user=%s\n", SKYPIAX_P_LOG, i, giovatech->name, giovatech->interface_state, value, giovatech->callid_number, giovatech->skype_user);
+			//FIXME check a timestamp here
+			if (strlen(giovatech->skype_call_id) && (giovatech->interface_state != SKYPIAX_STATE_DOWN) && (!strcmp(giovatech->skype_user, tech_pvt->skype_user)) && (!strcmp(giovatech->callid_number, value)) && ((((timenow.tv_sec - giovatech->answer_time.tv_sec) * 1000000) + (timenow.tv_usec - giovatech->answer_time.tv_usec)) < 500000)) {	//0.5sec
+				found = 1;
+				DEBUGA_SKYPE
+					("FOUND  (name=%s, giovatech->interface_state=%d != SKYPIAX_STATE_DOWN) && (giovatech->skype_user=%s == tech_pvt->skype_user=%s) && (giovatech->callid_number=%s == value=%s)\n",
+					 SKYPIAX_P_LOG, giovatech->name, giovatech->interface_state,
+					 giovatech->skype_user, tech_pvt->skype_user, giovatech->callid_number, value)
+					if (tech_pvt->interface_state == SKYPIAX_STATE_PRERING) {
+					tech_pvt->interface_state = SKYPIAX_STATE_DOWN;
+				} else if (tech_pvt->interface_state != 0 && tech_pvt->interface_state != SKYPIAX_STATE_DOWN) {
+					WARNINGA("Why an interface_state %d HERE?\n", SKYPIAX_P_LOG, tech_pvt->interface_state);
+					tech_pvt->interface_state = SKYPIAX_STATE_DOWN;
+				}
+
+				break;
+			}
+		}
+	}
+
+	if (found) {
+		//tech_pvt->callid_number[0]='\0';
+		//sprintf(msg_to_skype, "ALTER CALL %s END HANGUP", id);
+		//skypiax_signaling_write(tech_pvt, msg_to_skype);
+		switch_mutex_unlock(globals.mutex);
+		return 0;
+	}
+	DEBUGA_SKYPE("NOT FOUND\n", SKYPIAX_P_LOG);
+
+	if (tech_pvt && tech_pvt->skype_call_id && !strlen(tech_pvt->skype_call_id)) {
+		/* we are not inside an active call */
+
+		tech_pvt->ib_calls++;
+
+		sprintf(msg_to_skype, "GET CALL %s PARTNER_DISPNAME", id);
+		skypiax_signaling_write(tech_pvt, msg_to_skype);
+		switch_sleep(10000);
+		tech_pvt->interface_state = SKYPIAX_STATE_PREANSWER;
+		sprintf(msg_to_skype, "ALTER CALL %s ANSWER", id);
+		skypiax_signaling_write(tech_pvt, msg_to_skype);
+		DEBUGA_SKYPE("We answered a Skype RING on skype_call %s\n", SKYPIAX_P_LOG, id);
+		//FIXME write a timestamp here
+		gettimeofday(&tech_pvt->answer_time, NULL);
+		switch_copy_string(tech_pvt->skype_call_id, id, sizeof(tech_pvt->skype_call_id) - 1);
+
+		switch_copy_string(tech_pvt->callid_number, value, sizeof(tech_pvt->callid_number) - 1);
+
+		DEBUGA_SKYPE
+			("NEW!  name: %s, state: %d, value=%s, tech_pvt->callid_number=%s, tech_pvt->skype_user=%s\n",
+			 SKYPIAX_P_LOG, tech_pvt->name, tech_pvt->interface_state, value, tech_pvt->callid_number, tech_pvt->skype_user);
+	} else if (!tech_pvt || !tech_pvt->skype_call_id) {
+		ERRORA("No Call ID?\n", SKYPIAX_P_LOG);
+	} else {
+		DEBUGA_SKYPE("We're in a call now (%s), let's refuse this one (%s)\n", SKYPIAX_P_LOG, tech_pvt->skype_call_id, id);
+		sprintf(msg_to_skype, "ALTER CALL %s END HANGUP", id);
+		skypiax_signaling_write(tech_pvt, msg_to_skype);
+	}
+
+	switch_mutex_unlock(globals.mutex);
+	return 0;
+}
+int skypiax_transfer(private_t * tech_pvt, char *id, char *value)
+{
+	char msg_to_skype[1024];
+	int i;
+	int found = 0;
+	private_t *giovatech;
+	struct timeval timenow;
+
+	switch_mutex_lock(globals.mutex);
+
+	gettimeofday(&timenow, NULL);
+	for (i = 0; !found && i < SKYPIAX_MAX_INTERFACES; i++) {
+		if (strlen(globals.SKYPIAX_INTERFACES[i].name)) {
+
+			giovatech = &globals.SKYPIAX_INTERFACES[i];
+			//NOTICA("skype interface: %d, name: %s, state: %d, value=%s, giovatech->callid_number=%s, giovatech->skype_user=%s\n", SKYPIAX_P_LOG, i, giovatech->name, giovatech->interface_state, value, giovatech->callid_number, giovatech->skype_user);
+			//FIXME check a timestamp here
+			if (strlen(giovatech->skype_call_id) && (giovatech->interface_state != SKYPIAX_STATE_DOWN) && (!strcmp(giovatech->skype_user, tech_pvt->skype_user)) && (!strcmp(giovatech->callid_number, value)) && ((((timenow.tv_sec - giovatech->answer_time.tv_sec) * 1000000) + (timenow.tv_usec - giovatech->answer_time.tv_usec)) < 500000)) {	//0.5sec
+				found = 1;
+				DEBUGA_SKYPE
+					("FOUND  (name=%s, giovatech->interface_state=%d != SKYPIAX_STATE_DOWN) && (giovatech->skype_user=%s == tech_pvt->skype_user=%s) && (giovatech->callid_number=%s == value=%s)\n",
+					 SKYPIAX_P_LOG, giovatech->name, giovatech->interface_state,
+					 giovatech->skype_user, tech_pvt->skype_user, giovatech->callid_number, value)
+					break;
+			}
+		}
+	}
+
+	if (found) {
+		//tech_pvt->callid_number[0]='\0';
+		//sprintf(msg_to_skype, "ALTER CALL %s END HANGUP", id);
+		//skypiax_signaling_write(tech_pvt, msg_to_skype);
+		switch_mutex_unlock(globals.mutex);
+		return 0;
+	}
+	DEBUGA_SKYPE("NOT FOUND\n", SKYPIAX_P_LOG);
+
+	if (!tech_pvt || !tech_pvt->skype_call_id || !strlen(tech_pvt->skype_call_id)) {
+		/* we are not inside an active call */
+		DEBUGA_SKYPE("We're NO MORE in a call now %s\n", SKYPIAX_P_LOG, (tech_pvt && tech_pvt->skype_call_id) ? tech_pvt->skype_call_id : "");
+		switch_mutex_unlock(globals.mutex);
+
+	} else {
+
+		/* we're owned, we're in a call, let's try to transfer */
+		/************************** TODO
+		  Checking here if it is possible to transfer this call to Test2
+		  -> GET CALL 288 CAN_TRANSFER Test2
+		  <- CALL 288 CAN_TRANSFER test2 TRUE
+		 **********************************/
+
+		private_t *available_skypiax_interface = NULL;
+
+		gettimeofday(&timenow, NULL);
+		for (i = 0; !found && i < SKYPIAX_MAX_INTERFACES; i++) {
+			if (strlen(globals.SKYPIAX_INTERFACES[i].name)) {
+
+				giovatech = &globals.SKYPIAX_INTERFACES[i];
+				//NOTICA("skype interface: %d, name: %s, state: %d, value=%s, giovatech->callid_number=%s, giovatech->skype_user=%s\n", SKYPIAX_P_LOG, i, giovatech->name, giovatech->interface_state, value, giovatech->callid_number, giovatech->skype_user);
+				//FIXME check a timestamp here
+				if (strlen(giovatech->skype_transfer_call_id) && (giovatech->interface_state != SKYPIAX_STATE_DOWN) && (!strcmp(giovatech->skype_user, tech_pvt->skype_user)) && (!strcmp(giovatech->transfer_callid_number, value)) && ((((timenow.tv_sec - giovatech->transfer_time.tv_sec) * 1000000) + (timenow.tv_usec - giovatech->transfer_time.tv_usec)) < 1000000)) {	//1.0 sec
+					found = 1;
+					DEBUGA_SKYPE
+						("FOUND  (name=%s, giovatech->interface_state=%d != SKYPIAX_STATE_DOWN) && (giovatech->skype_user=%s == tech_pvt->skype_user=%s) && (giovatech->transfer_callid_number=%s == value=%s)\n",
+						 SKYPIAX_P_LOG, giovatech->name, giovatech->interface_state,
+						 giovatech->skype_user, tech_pvt->skype_user, giovatech->transfer_callid_number, value)
+						break;
+				}
+			}
+		}
+
+		if (found) {
+			//tech_pvt->callid_number[0]='\0';
+			//sprintf(msg_to_skype, "ALTER CALL %s END HANGUP", id);
+			//skypiax_signaling_write(tech_pvt, msg_to_skype);
+			switch_mutex_unlock(globals.mutex);
+			return 0;
+		}
+		DEBUGA_SKYPE("NOT FOUND\n", SKYPIAX_P_LOG);
+
+		available_skypiax_interface = find_available_skypiax_interface_rr(tech_pvt);
+		if (available_skypiax_interface) {
+			/* there is a skypiax interface idle, let's transfer the call to it */
+
+			//FIXME write a timestamp here
+			gettimeofday(&tech_pvt->transfer_time, NULL);
+			switch_copy_string(tech_pvt->skype_transfer_call_id, id, sizeof(tech_pvt->skype_transfer_call_id) - 1);
+
+			switch_copy_string(tech_pvt->transfer_callid_number, value, sizeof(tech_pvt->transfer_callid_number) - 1);
+
+			DEBUGA_SKYPE
+				("Let's transfer the skype_call %s to %s interface (with skype_user: %s), because we are already in a skypiax call(%s)\n",
+				 SKYPIAX_P_LOG, tech_pvt->skype_call_id, available_skypiax_interface->name, available_skypiax_interface->skype_user, id);
+
+			//FIXME why this? the inbound call will come, eventually, on that other interface
+			//available_skypiax_interface->ib_calls++;
+
+			sprintf(msg_to_skype, "ALTER CALL %s TRANSFER %s", id, available_skypiax_interface->skype_user);
+			skypiax_signaling_write(tech_pvt, msg_to_skype);
+			if (tech_pvt->interface_state == SKYPIAX_STATE_SELECTED) {
+				tech_pvt->interface_state = SKYPIAX_STATE_IDLE;	//we marked it SKYPIAX_STATE_SELECTED just in case it has to make an outbound call
+			}
+		} else {
+			/* no skypiax interfaces idle, do nothing */
+			DEBUGA_SKYPE
+				("Not answering the skype_call %s, because we are already in a skypiax call(%s) and not transferring, because no other skypiax interfaces are available\n",
+				 SKYPIAX_P_LOG, id, tech_pvt->skype_call_id);
+			sprintf(msg_to_skype, "ALTER CALL %s END HANGUP", id);
+			skypiax_signaling_write(tech_pvt, msg_to_skype);
+		}
+		switch_sleep(10000);
+		DEBUGA_SKYPE
+			("We have NOT answered a Skype RING from skype_call %s, because we are already in a skypiax call (%s)\n",
+			 SKYPIAX_P_LOG, id, tech_pvt->skype_call_id);
+
+		switch_mutex_unlock(globals.mutex);
+	}
+	return 0;
+}
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4 expandtab:
+ */

Added: freeswitch/branches/gmaruzz/mod_celliax/mod_skypiax.so (0 => 14544)


--- freeswitch/branches/gmaruzz/mod_celliax/mod_skypiax.so	                        (rev 0)
+++ freeswitch/branches/gmaruzz/mod_celliax/mod_skypiax.so	2009-08-17 09:17:09 UTC (rev 14544)
@@ -0,0 +1,129 @@
+#! /bin/sh
+
+# mod_skypiax.so - temporary wrapper script for .libs/mod_skypiax.so
+# Generated by ltmain.sh - GNU libtool 1.5.22 (1.1220.2.365 2005/12/18 22:14:06)
+#
+# The mod_skypiax.so program cannot be directly executed until all the libtool
+# libraries that it depends on are installed.
+#
+# This wrapper script should never be moved out of the build directory.
+# If it is, it will not operate correctly.
+
+# Sed substitution that helps us do robust quoting.  It backslashifies
+# metacharacters that are still active within double-quoted strings.
+Xsed='/bin/sed -e 1s/^X//'
+sed_quote_subst='s/\([\\`\\"$\\\\]\)/\\\1/g'
+
+# Be Bourne compatible (taken from Autoconf:_AS_BOURNE_COMPATIBLE).
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
+  emulate sh
+  NULLCMD=:
+  # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which
+  # is contrary to our usage.  Disable this feature.
+  alias -g '${1+"$@"}'='"$@"'
+  setopt NO_GLOB_SUBST
+else
+  case `(set -o) 2>/dev/null` in *posix*) set -o posix;; esac
+fi
+
+# The HP-UX ksh and POSIX shell print the target directory to stdout
+# if CDPATH is set.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+relink_command="(cd /usr/src/freeswitch/src/mod/endpoints/mod_skypiax; { test -z \"\${LIBRARY_PATH+set}\" || unset LIBRARY_PATH || { LIBRARY_PATH=; export LIBRARY_PATH; }; }; { test -z \"\${COMPILER_PATH+set}\" || unset COMPILER_PATH || { COMPILER_PATH=; export COMPILER_PATH; }; }; { test -z \"\${GCC_EXEC_PREFIX+set}\" || unset GCC_EXEC_PREFIX || { GCC_EXEC_PREFIX=; export GCC_EXEC_PREFIX; }; }; { test -z \"\${LD_RUN_PATH+set}\" || unset LD_RUN_PATH || { LD_RUN_PATH=; export LD_RUN_PATH; }; }; { test -z \"\${LD_LIBRARY_PATH+set}\" || unset LD_LIBRARY_PATH || { LD_LIBRARY_PATH=; export LD_LIBRARY_PATH; }; }; PATH=\"/usr/kerberos/sbin:/usr/kerberos/bin:/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin\"; export PATH; gcc -DSKYPIAX_SVN_VERSION=\\\"14534\\\" -I/usr/src/freeswitch/src/include -I/usr/src/freeswitch/libs/libteletone/src -fPIC -Werror -fvisibility=hidden -DSWITCH_API_VISIBILITY=1 -DHAVE_VISIBILITY=1 -g -ggdb -g -O2 -Wall -std=c99 -pedantic -D_GNU_SOURCE -shared -o \$progdir/\$file -shared -Wl,-x .libs/mod_skypiax.o skypiax_protocol.o  -lm /usr/src/freeswitch/.libs/libfreeswitch.so -L/usr/src/freeswitch/libs/apr-util/xml/expat/lib /usr/src/freeswitch/libs/apr-util/xml/expat/lib/.libs/libexpat.a /usr/src/freeswitch/libs/apr/.libs/libapr-1.a -lrt -lcrypt -lpthread -L/usr/src/freeswitch/libs/srtp -L/usr/kerberos/lib64 -lssl -lcrypto -ldl -lz -lncurses -lX11   -Wl,--rpath -Wl,/usr/src/freeswitch/.libs -Wl,--rpath -Wl,/usr/local/freeswitch/lib -Wl,--rpath -Wl,/usr/local/freeswitch/mod ) "
+
+# This environment variable determines our operation mode.
+if test "$libtool_install_magic" = "%%%MAGIC variable%%%"; then
+  # install mode needs the following variable:
+  notinst_deplibs=' /usr/src/freeswitch/libfreeswitch.la'
+else
+  # When we are sourced in execute mode, $file and $echo are already set.
+  if test "$libtool_execute_magic" != "%%%MAGIC variable%%%"; then
+    echo="echo"
+    file="$0"
+    # Make sure echo works.
+    if test "X$1" = X--no-reexec; then
+      # Discard the --no-reexec flag, and continue.
+      shift
+    elif test "X`($echo '\t') 2>/dev/null`" = 'X\t'; then
+      # Yippee, $echo works!
+      :
+    else
+      # Restart under the correct shell, and then maybe $echo will work.
+      exec /bin/sh "$0" --no-reexec ${1+"$@"}
+    fi
+  fi
+
+  # Find the directory that this script lives in.
+  thisdir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'`
+  test "x$thisdir" = "x$file" && thisdir=.
+
+  # Follow symbolic links until we get to the real thisdir.
+  file=`ls -ld "$file" | /bin/sed -n 's/.*-> //p'`
+  while test -n "$file"; do
+    destdir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'`
+
+    # If there was a directory component, then change thisdir.
+    if test "x$destdir" != "x$file"; then
+      case "$destdir" in
+      [\\/]* | [A-Za-z]:[\\/]*) thisdir="$destdir" ;;
+      *) thisdir="$thisdir/$destdir" ;;
+      esac
+    fi
+
+    file=`$echo "X$file" | $Xsed -e 's%^.*/%%'`
+    file=`ls -ld "$thisdir/$file" | /bin/sed -n 's/.*-> //p'`
+  done
+
+  # Try to get the absolute directory name.
+  absdir=`cd "$thisdir" && pwd`
+  test -n "$absdir" && thisdir="$absdir"
+
+  program=lt-'mod_skypiax.so'
+  progdir="$thisdir/.libs"
+
+  if test ! -f "$progdir/$program" || \
+     { file=`ls -1dt "$progdir/$program" "$progdir/../$program" 2>/dev/null | /bin/sed 1q`; \
+       test "X$file" != "X$progdir/$program"; }; then
+
+    file="$$-$program"
+
+    if test ! -d "$progdir"; then
+      mkdir "$progdir"
+    else
+      rm -f "$progdir/$file"
+    fi
+
+    # relink executable if necessary
+    if test -n "$relink_command"; then
+      if relink_command_output=`eval $relink_command 2>&1`; then :
+      else
+	echo "$relink_command_output" >&2
+	rm -f "$progdir/$file"
+	exit 1
+      fi
+    fi
+
+    mv -f "$progdir/$file" "$progdir/$program" 2>/dev/null ||
+    { rm -f "$progdir/$program";
+      mv -f "$progdir/$file" "$progdir/$program"; }
+    rm -f "$progdir/$file"
+  fi
+
+  if test -f "$progdir/$program"; then
+    if test "$libtool_execute_magic" != "%%%MAGIC variable%%%"; then
+      # Run the actual program with our arguments.
+
+      exec "$progdir/$program" ${1+"$@"}
+
+      $echo "$0: cannot exec $program $*"
+      exit 1
+    fi
+  else
+    # The program doesn't exist.
+    $echo "$0: error: \`$progdir/$program' does not exist" 1>&2
+    $echo "This script is just a wrapper for $program." 1>&2
+    echo "See the libtool documentation for more information." 1>&2
+    exit 1
+  fi
+fi
Property changes on: freeswitch/branches/gmaruzz/mod_celliax/mod_skypiax.so
___________________________________________________________________
Name: svn:executable
   + *

Added: freeswitch/branches/gmaruzz/mod_celliax/skypiax.h (0 => 14544)


--- freeswitch/branches/gmaruzz/mod_celliax/skypiax.h	                        (rev 0)
+++ freeswitch/branches/gmaruzz/mod_celliax/skypiax.h	2009-08-17 09:17:09 UTC (rev 14544)
@@ -0,0 +1,291 @@
+/*
+ * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ * Copyright (C) 2005/2006, Anthony Minessale II <anthmct@yahoo.com>
+ *
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ *
+ * The Initial Developer of the Original Code is
+ * Anthony Minessale II <anthmct@yahoo.com>
+ * Portions created by the Initial Developer are Copyright (C)
+ * the Initial Developer. All Rights Reserved.
+ *
+ * This module (mod_skypiax) has been contributed by:
+ *
+ * Giovanni Maruzzelli (gmaruzz@gmail.com)
+ *
+ *
+ * Further Contributors:
+ *
+ *
+ *
+ * mod_skypiax.c -- Skype compatible Endpoint Module
+ *
+ */
+
+#include <switch.h>
+#include <switch_version.h>
+
+#ifndef WIN32
+#include <sys/time.h>
+#include <X11/Xlib.h>
+#include <X11/Xlibint.h>
+#include <X11/Xatom.h>
+#endif //WIN32
+
+#ifdef _MSC_VER
+//Windows macro  for FD_SET includes a warning C4127: conditional expression is constant
+#pragma warning(push)
+#pragma warning(disable:4127)
+#endif
+
+#define SAMPLERATE_SKYPIAX 16000
+#define SAMPLES_PER_FRAME SAMPLERATE_SKYPIAX/50
+
+#ifndef SKYPIAX_SVN_VERSION
+#define SKYPIAX_SVN_VERSION SWITCH_VERSION_REVISION
+#endif /* SKYPIAX_SVN_VERSION */
+
+typedef enum {
+	TFLAG_IO = (1 << 0),
+	TFLAG_INBOUND = (1 << 1),
+	TFLAG_OUTBOUND = (1 << 2),
+	TFLAG_DTMF = (1 << 3),
+	TFLAG_VOICE = (1 << 4),
+	TFLAG_HANGUP = (1 << 5),
+	TFLAG_LINEAR = (1 << 6),
+	TFLAG_CODEC = (1 << 7),
+	TFLAG_BREAK = (1 << 8)
+} TFLAGS;
+
+typedef enum {
+	GFLAG_MY_CODEC_PREFS = (1 << 0)
+} GFLAGS;
+
+#define DEBUGA_SKYPE(...)  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, 		"rev "SKYPIAX_SVN_VERSION "[%p|%-7lx][DEBUG_SKYPE  %-5d][%-10s][%2d,%2d,%2d] " __VA_ARGS__ );
+#define DEBUGA_CALL(...)  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, 		"rev "SKYPIAX_SVN_VERSION "[%p|%-7lx][DEBUG_CALL  %-5d][%-10s][%2d,%2d,%2d] " __VA_ARGS__ );
+#define DEBUGA_PBX(...)  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, 		"rev "SKYPIAX_SVN_VERSION "[%p|%-7lx][DEBUG_PBX  %-5d][%-10s][%2d,%2d,%2d] " __VA_ARGS__ );
+#define ERRORA(...)  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, 		"rev "SKYPIAX_SVN_VERSION "[%p|%-7lx][ERRORA  %-5d][%-10s][%2d,%2d,%2d] " __VA_ARGS__ );
+#define WARNINGA(...)  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, 		"rev "SKYPIAX_SVN_VERSION "[%p|%-7lx][WARNINGA  %-5d][%-10s][%2d,%2d,%2d] " __VA_ARGS__ );
+#define NOTICA(...)  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, 		"rev "SKYPIAX_SVN_VERSION "[%p|%-7lx][NOTICA  %-5d][%-10s][%2d,%2d,%2d] " __VA_ARGS__ );
+
+#define SKYPIAX_P_LOG NULL, (unsigned long)55, __LINE__, tech_pvt ? tech_pvt->name ? tech_pvt->name : "none" : "none", -1, tech_pvt ? tech_pvt->interface_state : -1, tech_pvt ? tech_pvt->skype_callflow : -1
+
+/*********************************/
+#define SKYPIAX_CAUSE_NORMAL		1
+/*********************************/
+#define SKYPIAX_FRAME_DTMF			1
+/*********************************/
+#define SKYPIAX_CONTROL_RINGING		1
+#define SKYPIAX_CONTROL_ANSWER		2
+
+/*********************************/
+#define		SKYPIAX_STATE_IDLE					0
+#define		SKYPIAX_STATE_DOWN					1
+#define		SKYPIAX_STATE_RING					2
+#define		SKYPIAX_STATE_DIALING				3
+#define		SKYPIAX_STATE_BUSY					4
+#define		SKYPIAX_STATE_UP					5
+#define		SKYPIAX_STATE_RINGING				6
+#define		SKYPIAX_STATE_PRERING				7
+#define		SKYPIAX_STATE_ERROR_DOUBLE_CALL		8
+#define		SKYPIAX_STATE_SELECTED				9
+#define 	SKYPIAX_STATE_HANGUP_REQUESTED		10
+#define		SKYPIAX_STATE_PREANSWER				11
+/*********************************/
+/* call flow from the device */
+#define 	CALLFLOW_CALL_IDLE					0
+#define 	CALLFLOW_CALL_DOWN					1
+#define 	CALLFLOW_INCOMING_RING				2
+#define 	CALLFLOW_CALL_DIALING				3
+#define 	CALLFLOW_CALL_LINEBUSY				4
+#define 	CALLFLOW_CALL_ACTIVE				5
+#define 	CALLFLOW_INCOMING_HANGUP			6
+#define 	CALLFLOW_CALL_RELEASED				7
+#define 	CALLFLOW_CALL_NOCARRIER				8
+#define 	CALLFLOW_CALL_INFLUX				9
+#define 	CALLFLOW_CALL_INCOMING				10
+#define 	CALLFLOW_CALL_FAILED				11
+#define 	CALLFLOW_CALL_NOSERVICE				12
+#define 	CALLFLOW_CALL_OUTGOINGRESTRICTED	13
+#define 	CALLFLOW_CALL_SECURITYFAIL			14
+#define 	CALLFLOW_CALL_NOANSWER				15
+#define 	CALLFLOW_STATUS_FINISHED			16
+#define 	CALLFLOW_STATUS_CANCELLED			17
+#define 	CALLFLOW_STATUS_FAILED				18
+#define 	CALLFLOW_STATUS_REFUSED				19
+#define 	CALLFLOW_STATUS_RINGING				20
+#define 	CALLFLOW_STATUS_INPROGRESS			21
+#define 	CALLFLOW_STATUS_UNPLACED			22
+#define 	CALLFLOW_STATUS_ROUTING				23
+#define 	CALLFLOW_STATUS_EARLYMEDIA			24
+#define 	CALLFLOW_INCOMING_CALLID			25
+#define 	CALLFLOW_STATUS_REMOTEHOLD			26
+
+/*********************************/
+
+#define SKYPIAX_MAX_INTERFACES 64
+
+#ifndef WIN32
+struct SkypiaxHandles {
+	Window skype_win;
+	Display *disp;
+	Window win;
+	int currentuserhandle;
+	int api_connected;
+	int fdesc[2];
+};
+#else //WIN32
+
+struct SkypiaxHandles {
+	HWND win32_hInit_MainWindowHandle;
+	HWND win32_hGlobal_SkypeAPIWindowHandle;
+	HINSTANCE win32_hInit_ProcessHandle;
+	char win32_acInit_WindowClassName[128];
+	UINT win32_uiGlobal_MsgID_SkypeControlAPIAttach;
+	UINT win32_uiGlobal_MsgID_SkypeControlAPIDiscover;
+	int currentuserhandle;
+	int api_connected;
+	switch_file_t *fdesc[2];
+};
+
+#endif //WIN32
+
+struct private_object {
+	unsigned int flags;
+	switch_codec_t read_codec;
+	switch_codec_t write_codec;
+	switch_frame_t read_frame;
+	unsigned char databuf[SWITCH_RECOMMENDED_BUFFER_SIZE];
+	char session_uuid_str[SWITCH_UUID_FORMATTED_LENGTH + 1];
+	switch_caller_profile_t *caller_profile;
+	switch_mutex_t *mutex;
+	switch_mutex_t *flag_mutex;
+
+	char interface_id[80];
+	char name[80];
+	char dialplan[80];
+	char context[80];
+	char dial_regex[256];
+	char fail_dial_regex[256];
+	char hold_music[256];
+	char type[256];
+	char X11_display[256];
+#ifdef WIN32
+	unsigned short tcp_cli_port;
+	unsigned short tcp_srv_port;
+#else
+	int tcp_cli_port;
+	int tcp_srv_port;
+#endif
+	struct SkypiaxHandles SkypiaxHandles;
+
+	int interface_state;		/*!< \brief 'state' of the interface (channel) */
+	char language[80];			/*!< \brief default Asterisk dialplan language for this interface */
+	char exten[80];				/*!< \brief default Asterisk dialplan extension for this interface */
+	int skypiax_sound_rate;		/*!< \brief rate of the sound device, in Hz, eg: 8000 */
+	char callid_name[50];
+	char callid_number[50];
+	double playback_boost;
+	double capture_boost;
+	int stripmsd;
+	char skype_call_id[512];
+	int skype_call_ongoing;
+	char skype_friends[4096];
+	char skype_fullname[512];
+	char skype_displayname[512];
+	int skype_callflow;			/*!< \brief 'callflow' of the skype interface (as opposed to phone interface) */
+	int skype;					/*!< \brief config flag, bool, Skype support on this interface (0 if false, -1 if true) */
+	int control_to_send;
+#ifdef WIN32
+	switch_file_t *audiopipe[2];
+	switch_file_t *audioskypepipe[2];
+	switch_file_t *skypiax_sound_capt_fd;	/*!< \brief file descriptor for sound capture dev */
+#else							/* WIN32 */
+	int audiopipe[2];
+	int audioskypepipe[2];
+	int skypiax_sound_capt_fd;	/*!< \brief file descriptor for sound capture dev */
+#endif							/* WIN32 */
+	switch_thread_t *tcp_srv_thread;
+	switch_thread_t *tcp_cli_thread;
+	switch_thread_t *skypiax_signaling_thread;
+	switch_thread_t *skypiax_api_thread;
+	short audiobuf[SAMPLES_PER_FRAME];
+	int audiobuf_is_loaded;
+
+	//int phonebook_listing;
+	//int phonebook_querying;
+	//int phonebook_listing_received_calls;
+
+	//int phonebook_first_entry;
+	//int phonebook_last_entry;
+	//int phonebook_number_lenght;
+	//int phonebook_text_lenght;
+	FILE *phonebook_writing_fp;
+	int skypiax_dir_entry_extension_prefix;
+	char skype_user[256];
+	char skype_password[256];
+	char destination[256];
+	struct timeval answer_time;
+
+	struct timeval transfer_time;
+	char transfer_callid_number[50];
+	char skype_transfer_call_id[512];
+	int running;
+	unsigned long ib_calls;
+	unsigned long ob_calls;
+	unsigned long ib_failed_calls;
+	unsigned long ob_failed_calls;
+};
+
+typedef struct private_object private_t;
+
+void *SWITCH_THREAD_FUNC skypiax_api_thread_func(switch_thread_t * thread, void *obj);
+int skypiax_audio_read(private_t * tech_pvt);
+int skypiax_audio_init(private_t * tech_pvt);
+int skypiax_signaling_write(private_t * tech_pvt, char *msg_to_skype);
+int skypiax_signaling_read(private_t * tech_pvt);
+
+int skypiax_call(private_t * tech_pvt, char *idest, int timeout);
+int skypiax_senddigit(private_t * tech_pvt, char digit);
+
+void *skypiax_do_tcp_srv_thread_func(void *obj);
+void *SWITCH_THREAD_FUNC skypiax_do_tcp_srv_thread(switch_thread_t * thread, void *obj);
+
+void *skypiax_do_tcp_cli_thread_func(void *obj);
+void *SWITCH_THREAD_FUNC skypiax_do_tcp_cli_thread(switch_thread_t * thread, void *obj);
+
+void *skypiax_do_skypeapi_thread_func(void *obj);
+void *SWITCH_THREAD_FUNC skypiax_do_skypeapi_thread(switch_thread_t * thread, void *obj);
+int dtmf_received(private_t * tech_pvt, char *value);
+int start_audio_threads(private_t * tech_pvt);
+int new_inbound_channel(private_t * tech_pvt);
+int outbound_channel_answered(private_t * tech_pvt);
+int skypiax_signaling_write(private_t * tech_pvt, char *msg_to_skype);
+#if defined(WIN32) && !defined(__CYGWIN__)
+int skypiax_pipe_read(switch_file_t * pipe, short *buf, int howmany);
+int skypiax_pipe_write(switch_file_t * pipe, short *buf, int howmany);
+/* Visual C do not have strsep ? */
+char *strsep(char **stringp, const char *delim);
+#else
+int skypiax_pipe_read(int pipe, short *buf, int howmany);
+int skypiax_pipe_write(int pipe, short *buf, int howmany);
+#endif /* WIN32 */
+int skypiax_close_socket(unsigned int fd);
+private_t *find_available_skypiax_interface_rr(private_t * tech_pvt_calling);
+int remote_party_is_ringing(private_t * tech_pvt);
+int remote_party_is_early_media(private_t * tech_pvt);
+int skypiax_answer(private_t * tech_pvt, char *id, char *value);
+int skypiax_transfer(private_t * tech_pvt, char *id, char *value);
+int skypiax_socket_create_and_bind(private_t * tech_pvt, int *which_port);

Added: freeswitch/branches/gmaruzz/mod_celliax/skypiax_protocol.c (0 => 14544)


--- freeswitch/branches/gmaruzz/mod_celliax/skypiax_protocol.c	                        (rev 0)
+++ freeswitch/branches/gmaruzz/mod_celliax/skypiax_protocol.c	2009-08-17 09:17:09 UTC (rev 14544)
@@ -0,0 +1,1548 @@
+#include "skypiax.h"
+
+#ifdef ASTERISK
+#define skypiax_sleep usleep
+#define skypiax_strncpy strncpy
+#define tech_pvt p
+extern int skypiax_debug;
+extern char *skypiax_console_active;
+#else /* FREESWITCH */
+#define skypiax_sleep switch_sleep
+#define skypiax_strncpy switch_copy_string
+extern switch_memory_pool_t *skypiax_module_pool;
+extern switch_endpoint_interface_t *skypiax_endpoint_interface;
+#endif /* ASTERISK */
+int samplerate_skypiax = SAMPLERATE_SKYPIAX;
+
+extern int running;
+
+/*************************************/
+/* suspicious globals FIXME */
+#ifdef WIN32
+DWORD win32_dwThreadId;
+#else
+XErrorHandler old_handler = 0;
+int xerror = 0;
+#endif /* WIN32 */
+/*************************************/
+
+int skypiax_socket_create_and_bind(private_t * tech_pvt, int *which_port)
+{
+	int s = -1;
+	struct sockaddr_in my_addr;
+	int start_port = 6001;
+
+	memset(&my_addr, 0, sizeof(my_addr));
+	my_addr.sin_family = AF_INET;
+	my_addr.sin_addr.s_addr = htonl(0x7f000001);	/* use the localhost */
+
+	if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+		ERRORA("socket Error\n", SKYPIAX_P_LOG);
+		return -1;
+	}
+
+	if (*which_port != 0)
+		start_port = *which_port;
+
+	my_addr.sin_port = htons(start_port);
+	//tech_pvt->tcp_cli_port = start_port;
+	*which_port = start_port;
+	while (bind(s, (struct sockaddr *) &my_addr, sizeof(struct sockaddr)) < 0) {
+		DEBUGA_SKYPE("*which_port=%d, tech_pvt->tcp_cli_port=%d, tech_pvt->tcp_srv_port=%d\n", SKYPIAX_P_LOG, *which_port, tech_pvt->tcp_cli_port,
+					 tech_pvt->tcp_srv_port);
+		DEBUGA_SKYPE("bind errno=%d, error: %s\n", SKYPIAX_P_LOG, errno, strerror(errno));
+		start_port++;
+		my_addr.sin_port = htons(start_port);
+		*which_port = start_port;
+		DEBUGA_SKYPE("*which_port=%d, tech_pvt->tcp_cli_port=%d, tech_pvt->tcp_srv_port=%d\n", SKYPIAX_P_LOG, *which_port, tech_pvt->tcp_cli_port,
+					 tech_pvt->tcp_srv_port);
+
+		if (start_port > 65000) {
+			ERRORA("NO MORE PORTS! *which_port=%d, tech_pvt->tcp_cli_port=%d, tech_pvt->tcp_srv_port=%d\n", SKYPIAX_P_LOG, *which_port,
+				   tech_pvt->tcp_cli_port, tech_pvt->tcp_srv_port);
+			return -1;
+		}
+	}
+
+	DEBUGA_SKYPE("SUCCESS! *which_port=%d, tech_pvt->tcp_cli_port=%d, tech_pvt->tcp_srv_port=%d\n", SKYPIAX_P_LOG, *which_port, tech_pvt->tcp_cli_port,
+				 tech_pvt->tcp_srv_port);
+	return s;
+}
+
+int skypiax_signaling_read(private_t * tech_pvt)
+{
+	char read_from_pipe[4096];
+	char message[4096];
+	char message_2[4096];
+	char *buf, obj[512] = "", id[512] = "", prop[512] = "", value[512] = "", *where;
+	char **stringp = NULL;
+	int a;
+	unsigned int howmany;
+	unsigned int i;
+
+	memset(read_from_pipe, 0, 4096);
+	memset(message, 0, 4096);
+	memset(message_2, 0, 4096);
+
+	howmany = skypiax_pipe_read(tech_pvt->SkypiaxHandles.fdesc[0], (short *) read_from_pipe, sizeof(read_from_pipe));
+
+	a = 0;
+	for (i = 0; i < howmany; i++) {
+		message[a] = read_from_pipe[i];
+		a++;
+
+		if (read_from_pipe[i] == '\0') {
+
+			//if (!strstr(message, "DURATION")) {
+			DEBUGA_SKYPE("READING: |||%s||| \n", SKYPIAX_P_LOG, message);
+			//}
+
+			if (!strcasecmp(message, "ERROR 68")) {
+				DEBUGA_SKYPE
+					("If I don't connect immediately, please give the Skype client authorization to be connected by Skypiax (and to not ask you again)\n",
+					 SKYPIAX_P_LOG);
+				skypiax_sleep(1000000);
+				skypiax_signaling_write(tech_pvt, "PROTOCOL 7");
+				skypiax_sleep(10000);
+				return 0;
+			}
+			if (!strncasecmp(message, "ERROR 92 CALL", 12)) {
+				ERRORA("Skype got ERROR: |||%s|||, the (skypeout) number we called was not recognized as valid\n", SKYPIAX_P_LOG, message);
+				tech_pvt->skype_callflow = CALLFLOW_STATUS_FINISHED;
+				DEBUGA_SKYPE("skype_call now is DOWN\n", SKYPIAX_P_LOG);
+				tech_pvt->skype_call_id[0] = '\0';
+
+				if (tech_pvt->interface_state != SKYPIAX_STATE_HANGUP_REQUESTED) {
+					tech_pvt->interface_state = SKYPIAX_STATE_DOWN;
+					return CALLFLOW_INCOMING_HANGUP;
+				} else {
+					tech_pvt->interface_state = SKYPIAX_STATE_DOWN;
+				}
+			}
+
+			if (!strncasecmp(message, "ERROR", 4)) {
+				if (!strncasecmp(message, "ERROR 96 CALL", 12)) {
+					DEBUGA_SKYPE
+						("Skype got ERROR: |||%s|||, we are trying to use this interface to make or receive a call, but another call is half-active on this interface. Let's the previous one to continue.\n",
+						 SKYPIAX_P_LOG, message);
+				} else if (!strncasecmp(message, "ERROR 99 CALL", 12)) {
+					ERRORA("Skype got ERROR: |||%s|||, another call is active on this interface\n\n\n", SKYPIAX_P_LOG, message);
+					tech_pvt->interface_state = SKYPIAX_STATE_ERROR_DOUBLE_CALL;
+				} else if (!strncasecmp(message, "ERROR 592 ALTER CALL", 19)) {
+					ERRORA("Skype got ERROR about TRANSFERRING, no problem: |||%s|||\n", SKYPIAX_P_LOG, message);
+				} else if (!strncasecmp(message, "ERROR 559 CALL", 13)) {
+					DEBUGA_SKYPE("Skype got ERROR about a failed action (probably TRYING to HANGUP A CALL), no problem: |||%s|||\n", SKYPIAX_P_LOG,
+								 message);
+				} else {
+					ERRORA("Skype got ERROR: |||%s|||\n", SKYPIAX_P_LOG, message);
+					tech_pvt->skype_callflow = CALLFLOW_STATUS_FINISHED;
+					ERRORA("skype_call now is DOWN\n", SKYPIAX_P_LOG);
+					tech_pvt->skype_call_id[0] = '\0';
+
+					if (tech_pvt->interface_state != SKYPIAX_STATE_HANGUP_REQUESTED) {
+						tech_pvt->interface_state = SKYPIAX_STATE_DOWN;
+						return CALLFLOW_INCOMING_HANGUP;
+					} else {
+						tech_pvt->interface_state = SKYPIAX_STATE_DOWN;
+					}
+				}
+			}
+
+
+
+
+			skypiax_strncpy(message_2, message, sizeof(message) - 1);
+			buf = message;
+			stringp = &buf;
+			where = strsep(stringp, " ");
+			if (!where) {
+				WARNINGA("Skype MSG without spaces: %s\n", SKYPIAX_P_LOG, message);
+			}
+
+
+
+
+
+
+
+
+			if (!strcasecmp(message, "CURRENTUSERHANDLE")) {
+				skypiax_strncpy(obj, where, sizeof(obj) - 1);
+				where = strsep(stringp, " ");
+				skypiax_strncpy(id, where, sizeof(id) - 1);
+				if (!strcasecmp(id, tech_pvt->skype_user)) {
+					tech_pvt->SkypiaxHandles.currentuserhandle = 1;
+					DEBUGA_SKYPE
+						("Skype MSG: message: %s, currentuserhandle: %s, cuh: %s, skype_user: %s!\n",
+						 SKYPIAX_P_LOG, message, obj, id, tech_pvt->skype_user);
+				}
+			}
+			if (!strcasecmp(message, "USER")) {
+				skypiax_strncpy(obj, where, sizeof(obj) - 1);
+				where = strsep(stringp, " ");
+				skypiax_strncpy(id, where, sizeof(id) - 1);
+				where = strsep(stringp, " ");
+				skypiax_strncpy(prop, where, sizeof(prop) - 1);
+				if (!strcasecmp(prop, "RECEIVEDAUTHREQUEST")) {
+					char msg_to_skype[256];
+					DEBUGA_SKYPE("Skype MSG: message: %s, obj: %s, id: %s, prop: %s!\n", SKYPIAX_P_LOG, message, obj, id, prop);
+					//TODO: allow authorization based on config param
+					sprintf(msg_to_skype, "SET USER %s ISAUTHORIZED TRUE", id);
+					skypiax_signaling_write(tech_pvt, msg_to_skype);
+				}
+			}
+			if (!strcasecmp(message, "MESSAGE")) {
+				skypiax_strncpy(obj, where, sizeof(obj) - 1);
+				where = strsep(stringp, " ");
+				skypiax_strncpy(id, where, sizeof(id) - 1);
+				where = strsep(stringp, " ");
+				skypiax_strncpy(prop, where, sizeof(prop) - 1);
+				if (!strcasecmp(prop, "STATUS")) {
+					where = strsep(stringp, " ");
+					skypiax_strncpy(value, where, sizeof(value) - 1);
+					if (!strcasecmp(value, "RECEIVED")) {
+						char msg_to_skype[256];
+						DEBUGA_SKYPE("Skype MSG: message: %s, obj: %s, id: %s, prop: %s value: %s!\n", SKYPIAX_P_LOG, message, obj, id, prop, value);
+						//TODO: authomatically flag messages as read based on config param
+						sprintf(msg_to_skype, "SET MESSAGE %s SEEN", id);
+						skypiax_signaling_write(tech_pvt, msg_to_skype);
+					}
+				} else if (!strcasecmp(prop, "BODY")) {
+					char msg_to_skype[256];
+					DEBUGA_SKYPE("Skype MSG: message: %s, obj: %s, id: %s, prop: %s!\n", SKYPIAX_P_LOG, message, obj, id, prop);
+					//TODO: authomatically flag messages as read based on config param
+					sprintf(msg_to_skype, "SET MESSAGE %s SEEN", id);
+					skypiax_signaling_write(tech_pvt, msg_to_skype);
+				}
+			}
+			if (!strcasecmp(message, "CALL")) {
+				skypiax_strncpy(obj, where, sizeof(obj) - 1);
+				where = strsep(stringp, " ");
+				skypiax_strncpy(id, where, sizeof(id) - 1);
+				where = strsep(stringp, " ");
+				skypiax_strncpy(prop, where, sizeof(prop) - 1);
+				where = strsep(stringp, " ");
+				skypiax_strncpy(value, where, sizeof(value) - 1);
+				where = strsep(stringp, " ");
+
+				//DEBUGA_SKYPE
+				//("Skype MSG: message: %s, obj: %s, id: %s, prop: %s, value: %s,where: %s!\n",
+				//SKYPIAX_P_LOG, message, obj, id, prop, value, where ? where : "NULL");
+
+				if (!strcasecmp(prop, "PARTNER_HANDLE")) {
+					if (tech_pvt->interface_state != SKYPIAX_STATE_SELECTED && (!strlen(tech_pvt->skype_call_id) || !strlen(tech_pvt->session_uuid_str))) {
+						//if (!strlen(tech_pvt->skype_call_id)) {
+						/* we are NOT inside an active call */
+						DEBUGA_SKYPE("Call %s TRY ANSWER\n", SKYPIAX_P_LOG, id);
+						skypiax_answer(tech_pvt, id, value);
+					} else {
+						/* we are inside an active call */
+						if (!strcasecmp(tech_pvt->skype_call_id, id)) {
+							/* this is the call in which we are calling out */
+							DEBUGA_SKYPE("Call %s DO NOTHING\n", SKYPIAX_P_LOG, id);
+						} else {
+							skypiax_sleep(400000);	//0.4 seconds
+							DEBUGA_SKYPE("Call %s TRY TRANSFER\n", SKYPIAX_P_LOG, id);
+							skypiax_transfer(tech_pvt, id, value);
+						}
+					}
+				}
+				if (!strcasecmp(prop, "PARTNER_DISPNAME")) {
+					snprintf(tech_pvt->callid_name, sizeof(tech_pvt->callid_name) - 1, "%s%s%s", value, where ? " " : "", where ? where : "");
+					//DEBUGA_SKYPE
+					//("the skype_call %s caller PARTNER_DISPNAME (tech_pvt->callid_name) is: %s\n",
+					//SKYPIAX_P_LOG, id, tech_pvt->callid_name);
+				}
+				if (!strcasecmp(prop, "CONF_ID") && !strcasecmp(value, "0")) {
+					//DEBUGA_SKYPE("the skype_call %s is NOT a conference call\n", SKYPIAX_P_LOG, id);
+					//if (tech_pvt->interface_state == SKYPIAX_STATE_DOWN)
+					//tech_pvt->interface_state = SKYPIAX_STATE_PRERING;
+				}
+				if (!strcasecmp(prop, "CONF_ID") && strcasecmp(value, "0")) {
+					DEBUGA_SKYPE("the skype_call %s is a conference call\n", SKYPIAX_P_LOG, id);
+					//if (tech_pvt->interface_state == SKYPIAX_STATE_DOWN)
+					//tech_pvt->interface_state = SKYPIAX_STATE_PRERING;
+				}
+				if (!strcasecmp(prop, "DTMF")) {
+					DEBUGA_SKYPE("Call %s received a DTMF: %s\n", SKYPIAX_P_LOG, id, value);
+					dtmf_received(tech_pvt, value);
+				}
+				if (!strcasecmp(prop, "FAILUREREASON")) {
+					DEBUGA_SKYPE("Skype FAILED on skype_call %s. Let's wait for the FAILED message.\n", SKYPIAX_P_LOG, id);
+				}
+				if (!strcasecmp(prop, "DURATION") && (!strcasecmp(value, "1"))) {
+					if (strcasecmp(id, tech_pvt->skype_call_id)) {
+						skypiax_strncpy(tech_pvt->skype_call_id, id, sizeof(tech_pvt->skype_call_id) - 1);
+						DEBUGA_SKYPE("We called a Skype contact and he answered us on skype_call: %s.\n", SKYPIAX_P_LOG, id);
+					}
+				}
+
+				if (!strcasecmp(prop, "DURATION") && (tech_pvt->interface_state == SKYPIAX_STATE_ERROR_DOUBLE_CALL)) {
+					char msg_to_skype[1024];
+					skypiax_strncpy(tech_pvt->skype_call_id, id, sizeof(tech_pvt->skype_call_id) - 1);
+					ERRORA("We are in a double call situation, trying to get out hanging up call id: %s.\n", SKYPIAX_P_LOG, id);
+					sprintf(msg_to_skype, "ALTER CALL %s HANGUP", id);
+					skypiax_signaling_write(tech_pvt, msg_to_skype);
+					skypiax_sleep(10000);
+					//return CALLFLOW_INCOMING_HANGUP;
+				}
+
+				if (!strcasecmp(prop, "STATUS")) {
+
+					if (!strcasecmp(value, "RINGING")) {
+						char msg_to_skype[1024];
+						if ((tech_pvt->interface_state != SKYPIAX_STATE_SELECTED && tech_pvt->interface_state != SKYPIAX_STATE_DIALING)
+							&& (!strlen(tech_pvt->skype_call_id) || !strlen(tech_pvt->session_uuid_str))) {
+							/* we are NOT inside an active call */
+
+							DEBUGA_SKYPE("NO ACTIVE calls in this moment, skype_call %s is RINGING, to ask PARTNER_HANDLE\n", SKYPIAX_P_LOG, id);
+							sprintf(msg_to_skype, "GET CALL %s PARTNER_HANDLE", id);
+							skypiax_signaling_write(tech_pvt, msg_to_skype);
+							skypiax_sleep(10000);
+						} else {
+							/* we are inside an active call */
+							if (!strcasecmp(tech_pvt->skype_call_id, id)) {
+								/* this is the call in which we are calling out */
+								tech_pvt->skype_callflow = CALLFLOW_STATUS_RINGING;
+								tech_pvt->interface_state = SKYPIAX_STATE_RINGING;
+								skypiax_strncpy(tech_pvt->skype_call_id, id, sizeof(tech_pvt->skype_call_id) - 1);
+								DEBUGA_SKYPE("Our remote party in skype_call %s is RINGING\n", SKYPIAX_P_LOG, id);
+								remote_party_is_ringing(tech_pvt);
+							} else {
+								DEBUGA_SKYPE
+									("We are in another call, but skype_call %s is RINGING on us, let's ask PARTNER_HANDLE, so maybe we'll TRANSFER\n",
+									 SKYPIAX_P_LOG, id);
+								sprintf(msg_to_skype, "GET CALL %s PARTNER_HANDLE", id);
+								skypiax_signaling_write(tech_pvt, msg_to_skype);
+								skypiax_sleep(10000);
+							}
+						}
+					} else if (!strcasecmp(value, "EARLYMEDIA")) {
+						char msg_to_skype[1024];
+						tech_pvt->skype_callflow = CALLFLOW_STATUS_EARLYMEDIA;
+						tech_pvt->interface_state = SKYPIAX_STATE_DIALING;
+						DEBUGA_SKYPE("Our remote party in skype_call %s is EARLYMEDIA\n", SKYPIAX_P_LOG, id);
+						if (start_audio_threads(tech_pvt)) {
+							ERRORA("start_audio_threads FAILED\n", SKYPIAX_P_LOG);
+							return CALLFLOW_INCOMING_HANGUP;
+						}
+						skypiax_sleep(1000);
+						sprintf(msg_to_skype, "ALTER CALL %s SET_INPUT PORT=\"%d\"", id, tech_pvt->tcp_cli_port);
+						skypiax_signaling_write(tech_pvt, msg_to_skype);
+						sprintf(msg_to_skype, "#output ALTER CALL %s SET_OUTPUT PORT=\"%d\"", id, tech_pvt->tcp_srv_port);
+						skypiax_signaling_write(tech_pvt, msg_to_skype);
+
+						remote_party_is_early_media(tech_pvt);
+					} else if (!strcasecmp(value, "MISSED")) {
+						DEBUGA_SKYPE("We missed skype_call %s\n", SKYPIAX_P_LOG, id);
+					} else if (!strcasecmp(value, "FINISHED")) {
+						//DEBUGA_SKYPE("skype_call %s now is DOWN\n", SKYPIAX_P_LOG, id);
+						if (!strcasecmp(tech_pvt->skype_call_id, id)) {
+							//tech_pvt->skype_callflow = CALLFLOW_STATUS_FINISHED;
+							DEBUGA_SKYPE("skype_call %s is MY call, now I'm going DOWN\n", SKYPIAX_P_LOG, id);
+							//tech_pvt->skype_call_id[0] = '\0';
+							if (tech_pvt->interface_state != SKYPIAX_STATE_HANGUP_REQUESTED) {
+								//tech_pvt->interface_state = SKYPIAX_STATE_DOWN;
+								return CALLFLOW_INCOMING_HANGUP;
+							} else {
+								tech_pvt->interface_state = SKYPIAX_STATE_DOWN;
+							}
+						} else {
+							DEBUGA_SKYPE("skype_call %s is NOT MY call, ignoring\n", SKYPIAX_P_LOG, id);
+						}
+
+					} else if (!strcasecmp(value, "CANCELLED")) {
+						tech_pvt->skype_callflow = CALLFLOW_STATUS_CANCELLED;
+						DEBUGA_SKYPE("we tried to call Skype on skype_call %s and Skype has now CANCELLED\n", SKYPIAX_P_LOG, id);
+						tech_pvt->skype_call_id[0] = '\0';
+						if (tech_pvt->interface_state != SKYPIAX_STATE_HANGUP_REQUESTED) {
+							tech_pvt->interface_state = SKYPIAX_STATE_DOWN;
+							return CALLFLOW_INCOMING_HANGUP;
+						} else {
+							tech_pvt->interface_state = SKYPIAX_STATE_DOWN;
+						}
+					} else if (!strcasecmp(value, "FAILED")) {
+						tech_pvt->skype_callflow = CALLFLOW_STATUS_FAILED;
+						DEBUGA_SKYPE("we tried to call Skype on skype_call %s and Skype has now FAILED\n", SKYPIAX_P_LOG, id);
+						tech_pvt->skype_call_id[0] = '\0';
+						skypiax_strncpy(tech_pvt->skype_call_id, id, sizeof(tech_pvt->skype_call_id) - 1);
+						tech_pvt->interface_state = SKYPIAX_STATE_DOWN;
+						return CALLFLOW_INCOMING_HANGUP;
+					} else if (!strcasecmp(value, "REFUSED")) {
+						if (!strcasecmp(id, tech_pvt->skype_call_id)) {
+							/* this is the id of the call we are in, probably we generated it */
+							tech_pvt->skype_callflow = CALLFLOW_STATUS_REFUSED;
+							DEBUGA_SKYPE("we tried to call Skype on skype_call %s and Skype has now REFUSED\n", SKYPIAX_P_LOG, id);
+							skypiax_strncpy(tech_pvt->skype_call_id, id, sizeof(tech_pvt->skype_call_id) - 1);
+							tech_pvt->interface_state = SKYPIAX_STATE_DOWN;
+							tech_pvt->skype_call_id[0] = '\0';
+							return CALLFLOW_INCOMING_HANGUP;
+						} else {
+							/* we're here because were us that refused an incoming call */
+							DEBUGA_SKYPE("we REFUSED skype_call %s\n", SKYPIAX_P_LOG, id);
+						}
+					} else if (!strcasecmp(value, "TRANSFERRING")) {
+						DEBUGA_SKYPE("skype_call %s is transferring\n", SKYPIAX_P_LOG, id);
+					} else if (!strcasecmp(value, "TRANSFERRED")) {
+						DEBUGA_SKYPE("skype_call %s has been transferred\n", SKYPIAX_P_LOG, id);
+					} else if (!strcasecmp(value, "ROUTING")) {
+						tech_pvt->skype_callflow = CALLFLOW_STATUS_ROUTING;
+						tech_pvt->interface_state = SKYPIAX_STATE_DIALING;
+						skypiax_strncpy(tech_pvt->skype_call_id, id, sizeof(tech_pvt->skype_call_id) - 1);
+						DEBUGA_SKYPE("skype_call: %s is now ROUTING\n", SKYPIAX_P_LOG, id);
+					} else if (!strcasecmp(value, "UNPLACED")) {
+						tech_pvt->skype_callflow = CALLFLOW_STATUS_UNPLACED;
+						tech_pvt->interface_state = SKYPIAX_STATE_DIALING;
+						skypiax_strncpy(tech_pvt->skype_call_id, id, sizeof(tech_pvt->skype_call_id) - 1);
+						DEBUGA_SKYPE("skype_call: %s is now UNPLACED\n", SKYPIAX_P_LOG, id);
+					} else if (!strcasecmp(value, "INPROGRESS")) {
+						char msg_to_skype[1024];
+
+						if (!strlen(tech_pvt->session_uuid_str)) {
+							DEBUGA_SKYPE("no tech_pvt->session_uuid_str\n", SKYPIAX_P_LOG);
+						}
+						if (tech_pvt->skype_callflow != CALLFLOW_STATUS_REMOTEHOLD) {
+							if (!strlen(tech_pvt->session_uuid_str) || !strlen(tech_pvt->skype_call_id)
+								|| !strcasecmp(tech_pvt->skype_call_id, id)) {
+								skypiax_strncpy(tech_pvt->skype_call_id, id, sizeof(tech_pvt->skype_call_id) - 1);
+								DEBUGA_SKYPE("skype_call: %s is now active\n", SKYPIAX_P_LOG, id);
+
+								if (tech_pvt->skype_callflow != CALLFLOW_STATUS_EARLYMEDIA) {
+									tech_pvt->skype_callflow = CALLFLOW_STATUS_INPROGRESS;
+									tech_pvt->interface_state = SKYPIAX_STATE_UP;
+
+									if (start_audio_threads(tech_pvt)) {
+										ERRORA("start_audio_threads FAILED\n", SKYPIAX_P_LOG);
+										return CALLFLOW_INCOMING_HANGUP;
+									}
+									skypiax_sleep(1000);	//FIXME
+									sprintf(msg_to_skype, "ALTER CALL %s SET_INPUT PORT=\"%d\"", id, tech_pvt->tcp_cli_port);
+									skypiax_signaling_write(tech_pvt, msg_to_skype);
+									skypiax_sleep(1000);	//FIXME
+									sprintf(msg_to_skype, "#output ALTER CALL %s SET_OUTPUT PORT=\"%d\"", id, tech_pvt->tcp_srv_port);
+									skypiax_signaling_write(tech_pvt, msg_to_skype);
+								}
+								tech_pvt->skype_callflow = SKYPIAX_STATE_UP;
+								if (!strlen(tech_pvt->session_uuid_str)) {
+									DEBUGA_SKYPE("New Inbound Channel!\n\n\n\n", SKYPIAX_P_LOG);
+									new_inbound_channel(tech_pvt);
+								} else {
+									DEBUGA_SKYPE("Outbound Channel Answered! session_uuid_str=%s\n", SKYPIAX_P_LOG, tech_pvt->session_uuid_str);
+									outbound_channel_answered(tech_pvt);
+								}
+							} else {
+								DEBUGA_SKYPE("I'm on %s, skype_call %s is NOT MY call, ignoring\n", SKYPIAX_P_LOG, tech_pvt->skype_call_id, id);
+							}
+						} else {
+							tech_pvt->skype_callflow = CALLFLOW_STATUS_INPROGRESS;
+							DEBUGA_SKYPE("Back from REMOTEHOLD!\n", SKYPIAX_P_LOG);
+						}
+
+					} else if (!strcasecmp(value, "REMOTEHOLD")) {
+						tech_pvt->skype_callflow = CALLFLOW_STATUS_REMOTEHOLD;
+						DEBUGA_SKYPE("skype_call: %s is now REMOTEHOLD\n", SKYPIAX_P_LOG, id);
+
+					} else if (!strcasecmp(value, "BUSY")) {
+						tech_pvt->skype_callflow = CALLFLOW_STATUS_FAILED;
+						DEBUGA_SKYPE
+							("we tried to call Skype on skype_call %s and remote party (destination) was BUSY. Our outbound call has failed\n",
+							 SKYPIAX_P_LOG, id);
+						skypiax_strncpy(tech_pvt->skype_call_id, id, sizeof(tech_pvt->skype_call_id) - 1);
+						tech_pvt->interface_state = SKYPIAX_STATE_DOWN;
+						tech_pvt->skype_call_id[0] = '\0';
+						skypiax_sleep(1000);
+						return CALLFLOW_INCOMING_HANGUP;
+					} else if (!strcasecmp(value, "WAITING_REDIAL_COMMAND")) {
+						tech_pvt->skype_callflow = CALLFLOW_STATUS_FAILED;
+						DEBUGA_SKYPE
+							("we tried to call Skype on skype_call %s and remote party (destination) has rejected us (WAITING_REDIAL_COMMAND). Our outbound call has failed\n",
+							 SKYPIAX_P_LOG, id);
+						skypiax_strncpy(tech_pvt->skype_call_id, id, sizeof(tech_pvt->skype_call_id) - 1);
+						tech_pvt->interface_state = SKYPIAX_STATE_DOWN;
+						tech_pvt->skype_call_id[0] = '\0';
+						skypiax_sleep(1000);
+						return CALLFLOW_INCOMING_HANGUP;
+					} else {
+						WARNINGA("skype_call: %s, STATUS: %s is not recognized\n", SKYPIAX_P_LOG, id, value);
+					}
+				}				//STATUS
+			}					//CALL
+			/* the "numbered" messages that follows are used by the directory application, not yet ported */
+			if (!strcasecmp(message, "#333")) {
+				/* DEBUGA_SKYPE("Skype MSG: message_2: %s, message2[11]: %s\n", SKYPIAX_P_LOG,
+				 * message_2, &message_2[11]); */
+				memset(tech_pvt->skype_friends, 0, 4096);
+				skypiax_strncpy(tech_pvt->skype_friends, &message_2[11], 4095);
+			}
+			if (!strcasecmp(message, "#222")) {
+				/* DEBUGA_SKYPE("Skype MSG: message_2: %s, message2[10]: %s\n", SKYPIAX_P_LOG,
+				 * message_2, &message_2[10]); */
+				memset(tech_pvt->skype_fullname, 0, 512);
+				skypiax_strncpy(tech_pvt->skype_fullname, &message_2[10], 511);
+			}
+			if (!strcasecmp(message, "#765")) {
+				/* DEBUGA_SKYPE("Skype MSG: message_2: %s, message2[10]: %s\n", SKYPIAX_P_LOG,
+				 * message_2, &message_2[10]); */
+				memset(tech_pvt->skype_displayname, 0, 512);
+				skypiax_strncpy(tech_pvt->skype_displayname, &message_2[10], 511);
+			}
+			a = 0;
+		}						//message end
+	}							//read_from_pipe
+	return 0;
+}
+
+void *skypiax_do_tcp_srv_thread_func(void *obj)
+{
+	private_t *tech_pvt = obj;
+	int s;
+	unsigned int len;
+	unsigned int i;
+	unsigned int a;
+#if defined(WIN32) && !defined(__CYGWIN__)
+	int sin_size;
+#else /* WIN32 */
+	unsigned int sin_size;
+#endif /* WIN32 */
+	unsigned int fd;
+	short srv_in[SAMPLES_PER_FRAME];
+	short srv_out[SAMPLES_PER_FRAME / 2];
+	//struct sockaddr_in my_addr;
+	struct sockaddr_in remote_addr;
+	//int exit = 0;
+	unsigned int kill_cli_size;
+	short kill_cli_buff[SAMPLES_PER_FRAME];
+	short totalbuf[SAMPLES_PER_FRAME];
+
+	s = skypiax_socket_create_and_bind(tech_pvt, &tech_pvt->tcp_srv_port);
+	if (s < 0) {
+		ERRORA("skypiax_socket_create_and_bind error!\n", SKYPIAX_P_LOG);
+		return NULL;
+	}
+	DEBUGA_SKYPE("started tcp_srv_thread thread.\n", SKYPIAX_P_LOG);
+
+	listen(s, 6);
+
+	sin_size = sizeof(remote_addr);
+
+  /****************************/
+	while (tech_pvt->interface_state != SKYPIAX_STATE_DOWN
+		   && (tech_pvt->skype_callflow == CALLFLOW_STATUS_INPROGRESS
+			   || tech_pvt->skype_callflow == CALLFLOW_STATUS_EARLYMEDIA
+			   || tech_pvt->skype_callflow == CALLFLOW_STATUS_REMOTEHOLD || tech_pvt->skype_callflow == SKYPIAX_STATE_UP)) {
+
+		unsigned int fdselectgio;
+		int rtgio;
+		fd_set fsgio;
+		struct timeval togio;
+
+		if (!(running && tech_pvt->running))
+			break;
+		FD_ZERO(&fsgio);
+		togio.tv_usec = 20000;	//20msec
+		togio.tv_sec = 0;
+		fdselectgio = s;
+		FD_SET(fdselectgio, &fsgio);
+
+		rtgio = select(fdselectgio + 1, &fsgio, NULL, NULL, &togio);
+
+		if (rtgio) {
+
+  /****************************/
+
+			while ((fd = accept(s, (struct sockaddr *) &remote_addr, &sin_size)) > 0) {
+				DEBUGA_SKYPE("ACCEPTED here I send you %d\n", SKYPIAX_P_LOG, tech_pvt->tcp_srv_port);
+				if (!(running && tech_pvt->running))
+					break;
+				while (tech_pvt->interface_state != SKYPIAX_STATE_DOWN
+					   && (tech_pvt->skype_callflow == CALLFLOW_STATUS_INPROGRESS
+						   || tech_pvt->skype_callflow == CALLFLOW_STATUS_EARLYMEDIA
+						   || tech_pvt->skype_callflow == CALLFLOW_STATUS_REMOTEHOLD || tech_pvt->skype_callflow == SKYPIAX_STATE_UP)) {
+
+					unsigned int fdselect;
+					int rt;
+					fd_set fs;
+					struct timeval to;
+
+					if (!(running && tech_pvt->running))
+						break;
+					//exit = 1;
+
+					fdselect = fd;
+					FD_ZERO(&fs);
+					FD_SET(fdselect, &fs);
+					//to.tv_usec = 2000000;     //2000 msec
+					to.tv_usec = 60000;	//60 msec
+					to.tv_sec = 0;
+
+					rt = select(fdselect + 1, &fs, NULL, NULL, &to);
+					if (rt > 0) {
+
+						if (tech_pvt->skype_callflow != CALLFLOW_STATUS_REMOTEHOLD) {
+							len = recv(fd, (char *) srv_in, 320, 0);	//seems that Skype only sends 320 bytes at time
+						} else {
+							len = 0;
+						}
+
+						if (len == 320) {
+							unsigned int howmany;
+
+							if (samplerate_skypiax == 8000) {
+								/* we're downsampling from 16khz to 8khz, srv_out will contain each other sample from srv_in */
+								a = 0;
+								for (i = 0; i < len / sizeof(short); i++) {
+									srv_out[a] = srv_in[i];
+									i++;
+									a++;
+								}
+							} else if (samplerate_skypiax == 16000) {
+								/* we're NOT downsampling, srv_out will contain ALL samples from srv_in */
+								for (i = 0; i < len / sizeof(short); i++) {
+									srv_out[i] = srv_in[i];
+								}
+							} else {
+								ERRORA("SAMPLERATE_SKYPIAX can only be 8000 or 16000\n", SKYPIAX_P_LOG);
+							}
+							/* if not yet done, let's store the half incoming frame */
+							if (!tech_pvt->audiobuf_is_loaded) {
+								for (i = 0; i < SAMPLES_PER_FRAME / 2; i++) {
+									tech_pvt->audiobuf[i] = srv_out[i];
+								}
+								tech_pvt->audiobuf_is_loaded = 1;
+							} else {
+								/* we got a stored half frame, build a complete frame in totalbuf using the stored half frame and the current half frame */
+								for (i = 0; i < SAMPLES_PER_FRAME / 2; i++) {
+									totalbuf[i] = tech_pvt->audiobuf[i];
+								}
+								for (a = 0; a < SAMPLES_PER_FRAME / 2; a++) {
+									totalbuf[i] = srv_out[a];
+									i++;
+								}
+								/* send the complete frame through the pipe to our code waiting for incoming audio */
+								howmany = skypiax_pipe_write(tech_pvt->audiopipe[1], totalbuf, SAMPLES_PER_FRAME * sizeof(short));
+								if (howmany != SAMPLES_PER_FRAME * sizeof(short)) {
+									ERRORA("howmany is %d, but was expected to be %d\n", SKYPIAX_P_LOG,
+										   howmany, (int) (SAMPLES_PER_FRAME * sizeof(short)));
+								}
+								/* done with the stored half frame */
+								tech_pvt->audiobuf_is_loaded = 0;
+							}
+
+						} else if (len == 0) {
+							skypiax_sleep(1000);
+						} else {
+							DEBUGA_SKYPE("len=%d, expected 320\n", SKYPIAX_P_LOG, len);
+						}
+
+					} else {
+						if (rt)
+							ERRORA("SRV rt=%d\n", SKYPIAX_P_LOG, rt);
+						skypiax_sleep(10000);
+					}
+
+				}
+
+				/* let's send some frame in the pipes, so both tcp_cli and tcp_srv will have an occasion to die */
+				kill_cli_size = SAMPLES_PER_FRAME * sizeof(short);
+				len = skypiax_pipe_write(tech_pvt->audiopipe[1], kill_cli_buff, kill_cli_size);
+				kill_cli_size = SAMPLES_PER_FRAME * sizeof(short);
+				len = skypiax_pipe_write(tech_pvt->audioskypepipe[1], kill_cli_buff, kill_cli_size);
+				tech_pvt->interface_state = SKYPIAX_STATE_DOWN;
+				kill_cli_size = SAMPLES_PER_FRAME * sizeof(short);
+				len = skypiax_pipe_write(tech_pvt->audiopipe[1], kill_cli_buff, kill_cli_size);
+				kill_cli_size = SAMPLES_PER_FRAME * sizeof(short);
+				len = skypiax_pipe_write(tech_pvt->audioskypepipe[1], kill_cli_buff, kill_cli_size);
+
+				DEBUGA_SKYPE("Skype incoming audio GONE\n", SKYPIAX_P_LOG);
+				skypiax_close_socket(fd);
+				//if (exit)
+				break;
+			}
+		}
+	}
+
+	DEBUGA_SKYPE("incoming audio server (I am it) EXITING\n", SKYPIAX_P_LOG);
+	skypiax_close_socket(s);
+	tech_pvt->tcp_srv_thread = NULL;
+	return NULL;
+}
+
+void *skypiax_do_tcp_cli_thread_func(void *obj)
+{
+	private_t *tech_pvt = obj;
+	int s;
+	//struct sockaddr_in my_addr;
+	struct sockaddr_in remote_addr;
+	unsigned int got;
+	unsigned int len;
+	unsigned int i;
+	unsigned int a;
+	unsigned int fd;
+	short cli_out[SAMPLES_PER_FRAME * 2];
+	short cli_in[SAMPLES_PER_FRAME];
+#ifdef WIN32
+	int sin_size;
+#else
+	unsigned int sin_size;
+#endif /* WIN32 */
+
+	s = skypiax_socket_create_and_bind(tech_pvt, &tech_pvt->tcp_cli_port);
+	if (s < 0) {
+		ERRORA("skypiax_socket_create_and_bind error!\n", SKYPIAX_P_LOG);
+		return NULL;
+	}
+
+
+
+	DEBUGA_SKYPE("started tcp_cli_thread thread.\n", SKYPIAX_P_LOG);
+
+	listen(s, 6);
+
+	sin_size = sizeof(remote_addr);
+
+  /****************************/
+	while (tech_pvt->interface_state != SKYPIAX_STATE_DOWN
+		   && (tech_pvt->skype_callflow == CALLFLOW_STATUS_INPROGRESS
+			   || tech_pvt->skype_callflow == CALLFLOW_STATUS_EARLYMEDIA
+			   || tech_pvt->skype_callflow == CALLFLOW_STATUS_REMOTEHOLD || tech_pvt->skype_callflow == SKYPIAX_STATE_UP)) {
+
+		unsigned int fdselectgio;
+		int rtgio;
+		fd_set fsgio;
+		struct timeval togio;
+
+		if (!(running && tech_pvt->running))
+			break;
+		FD_ZERO(&fsgio);
+		togio.tv_usec = 20000;	//20msec
+		togio.tv_sec = 0;
+		fdselectgio = s;
+		FD_SET(fdselectgio, &fsgio);
+
+		rtgio = select(fdselectgio + 1, &fsgio, NULL, NULL, &togio);
+
+		if (rtgio) {
+
+  /****************************/
+
+			while ((fd = accept(s, (struct sockaddr *) &remote_addr, &sin_size)) > 0) {
+				DEBUGA_SKYPE("ACCEPTED here you send me %d\n", SKYPIAX_P_LOG, tech_pvt->tcp_cli_port);
+#ifndef WIN32
+				fcntl(tech_pvt->audioskypepipe[0], F_SETFL, O_NONBLOCK);
+				fcntl(tech_pvt->audioskypepipe[1], F_SETFL, O_NONBLOCK);
+#endif //WIN32
+
+				if (!(running && tech_pvt->running))
+					break;
+				while (tech_pvt->interface_state != SKYPIAX_STATE_DOWN
+					   && (tech_pvt->skype_callflow == CALLFLOW_STATUS_INPROGRESS
+						   || tech_pvt->skype_callflow == CALLFLOW_STATUS_EARLYMEDIA
+						   || tech_pvt->skype_callflow == CALLFLOW_STATUS_REMOTEHOLD || tech_pvt->skype_callflow == SKYPIAX_STATE_UP)) {
+					unsigned int fdselect;
+					int rt;
+					fd_set fs;
+					struct timeval to;
+
+					if (!(running && tech_pvt->running))
+						break;
+					FD_ZERO(&fs);
+					to.tv_usec = 120000;	//120msec
+					to.tv_sec = 0;
+#if defined(WIN32) && !defined(__CYGWIN__)
+/* on win32 we cannot select from the apr "pipe", so we select on socket writability */
+					fdselect = fd;
+					FD_SET(fdselect, &fs);
+
+					rt = select(fdselect + 1, NULL, &fs, NULL, &to);
+#else
+/* on *unix and cygwin we select from the real pipe */
+					fdselect = tech_pvt->audioskypepipe[0];
+					FD_SET(fdselect, &fs);
+
+					rt = select(fdselect + 1, &fs, NULL, NULL, &to);
+#endif
+
+					if (rt > 0) {
+						int counter;
+
+						/* until we drained the pipe to empty */
+						for (counter = 0; counter < 10; counter++) {
+							/* read from the pipe the audio frame we are supposed to send out */
+							got = skypiax_pipe_read(tech_pvt->audioskypepipe[0], cli_in, SAMPLES_PER_FRAME * sizeof(short));
+							if (got == -1)
+								break;
+
+							if (got != SAMPLES_PER_FRAME * sizeof(short)) {
+								WARNINGA("got is %d, but was expected to be %d\n", SKYPIAX_P_LOG, got, (int) (SAMPLES_PER_FRAME * sizeof(short)));
+							}
+
+							if (got == SAMPLES_PER_FRAME * sizeof(short)) {
+								if (samplerate_skypiax == 8000) {
+
+									/* we're upsampling from 8khz to 16khz, cli_out will contain two times each sample from cli_in */
+									a = 0;
+									for (i = 0; i < got / sizeof(short); i++) {
+										cli_out[a] = cli_in[i];
+										a++;
+										cli_out[a] = cli_in[i];
+										a++;
+									}
+									got = got * 2;
+								} else if (samplerate_skypiax == 16000) {
+									/* we're NOT upsampling, cli_out will contain just ALL samples from cli_in */
+									for (i = 0; i < got / sizeof(short); i++) {
+										cli_out[i] = cli_in[i];
+									}
+								} else {
+									ERRORA("SAMPLERATE_SKYPIAX can only be 8000 or 16000\n", SKYPIAX_P_LOG);
+								}
+
+								/* send the 16khz frame to the Skype client waiting for incoming audio to be sent to the remote party */
+								if (tech_pvt->skype_callflow != CALLFLOW_STATUS_REMOTEHOLD) {
+									len = send(fd, (char *) cli_out, got, 0);
+									skypiax_sleep(5000);	//5 msec
+
+									if (len == -1) {
+										break;
+									} else if (len != got) {
+										ERRORA("len=%d\n", SKYPIAX_P_LOG, len);
+										skypiax_sleep(1000);
+										break;
+									}
+								}
+
+							} else {
+
+								WARNINGA("got is %d, but was expected to be %d\n", SKYPIAX_P_LOG, got, (int) (SAMPLES_PER_FRAME * sizeof(short)));
+							}
+						}
+					} else {
+						if (rt)
+							ERRORA("CLI rt=%d\n", SKYPIAX_P_LOG, rt);
+						memset(cli_out, 0, sizeof(cli_out));
+						if (tech_pvt->skype_callflow != CALLFLOW_STATUS_REMOTEHOLD) {
+							len = send(fd, (char *) cli_out, sizeof(cli_out), 0);
+							len = send(fd, (char *) cli_out, sizeof(cli_out) / 2, 0);
+							//WARNINGA("sent %d of zeros to keep the Skype client socket busy\n", SKYPIAX_P_LOG, sizeof(cli_out) + sizeof(cli_out)/2);
+						} else {
+							/*
+							   XXX do nothing 
+							 */
+							//WARNINGA("we don't send it\n", SKYPIAX_P_LOG);
+						}
+						skypiax_sleep(1000);
+					}
+
+				}
+				DEBUGA_SKYPE("Skype outbound audio GONE\n", SKYPIAX_P_LOG);
+				skypiax_close_socket(fd);
+				break;
+			}
+		}
+	}
+
+	DEBUGA_SKYPE("outbound audio server (I am it) EXITING\n", SKYPIAX_P_LOG);
+	skypiax_close_socket(s);
+	tech_pvt->tcp_cli_thread = NULL;
+	return NULL;
+}
+
+int skypiax_audio_read(private_t * tech_pvt)
+{
+	unsigned int samples;
+
+	samples = skypiax_pipe_read(tech_pvt->audiopipe[0], tech_pvt->read_frame.data, SAMPLES_PER_FRAME * sizeof(short));
+
+	if (samples != SAMPLES_PER_FRAME * sizeof(short)) {
+		if (samples)
+			WARNINGA("read samples=%u expected=%u\n", SKYPIAX_P_LOG, samples, (int) (SAMPLES_PER_FRAME * sizeof(short)));
+		return 0;
+	} else {
+		/* A real frame */
+		tech_pvt->read_frame.datalen = samples;
+	}
+	return 1;
+}
+
+int skypiax_senddigit(private_t * tech_pvt, char digit)
+{
+	char msg_to_skype[1024];
+
+	DEBUGA_SKYPE("DIGIT received: %c\n", SKYPIAX_P_LOG, digit);
+	sprintf(msg_to_skype, "SET CALL %s DTMF %c", tech_pvt->skype_call_id, digit);
+	skypiax_signaling_write(tech_pvt, msg_to_skype);
+
+	return 0;
+}
+
+int skypiax_call(private_t * tech_pvt, char *rdest, int timeout)
+{
+	char msg_to_skype[1024];
+
+	//skypiax_sleep(5000);
+	DEBUGA_SKYPE("Calling Skype, rdest is: %s\n", SKYPIAX_P_LOG, rdest);
+	//skypiax_signaling_write(tech_pvt, "SET AGC OFF");
+	//skypiax_sleep(10000);
+	//skypiax_signaling_write(tech_pvt, "SET AEC OFF");
+	//skypiax_sleep(10000);
+
+	sprintf(msg_to_skype, "CALL %s", rdest);
+	if (skypiax_signaling_write(tech_pvt, msg_to_skype) < 0) {
+		ERRORA("failed to communicate with Skype client, now exit\n", SKYPIAX_P_LOG);
+		return -1;
+	}
+	return 0;
+}
+
+/***************************/
+/* PLATFORM SPECIFIC */
+/***************************/
+#if defined(WIN32) && !defined(__CYGWIN__)
+int skypiax_pipe_read(switch_file_t * pipe, short *buf, int howmany)
+{
+	switch_size_t quantity;
+
+	quantity = howmany;
+
+	switch_file_read(pipe, buf, &quantity);
+
+	howmany = quantity;
+
+	return howmany;
+}
+
+int skypiax_pipe_write(switch_file_t * pipe, short *buf, int howmany)
+{
+	switch_size_t quantity;
+
+	quantity = howmany;
+
+	switch_file_write(pipe, buf, &quantity);
+
+	howmany = quantity;
+
+	return howmany;
+}
+
+int skypiax_close_socket(unsigned int fd)
+{
+	int res;
+
+	res = closesocket(fd);
+
+	return res;
+}
+
+int skypiax_audio_init(private_t * tech_pvt)
+{
+	switch_status_t rv;
+	rv = switch_file_pipe_create(&tech_pvt->audiopipe[0], &tech_pvt->audiopipe[1], skypiax_module_pool);
+	rv = switch_file_pipe_create(&tech_pvt->audioskypepipe[0], &tech_pvt->audioskypepipe[1], skypiax_module_pool);
+	return 0;
+}
+#else /* WIN32 */
+int skypiax_pipe_read(int pipe, short *buf, int howmany)
+{
+	howmany = read(pipe, buf, howmany);
+	return howmany;
+}
+
+int skypiax_pipe_write(int pipe, short *buf, int howmany)
+{
+	howmany = write(pipe, buf, howmany);
+	return howmany;
+}
+
+int skypiax_close_socket(unsigned int fd)
+{
+	int res;
+
+	res = close(fd);
+
+	return res;
+}
+
+int skypiax_audio_init(private_t * tech_pvt)
+{
+	if (pipe(tech_pvt->audiopipe)) {
+		fcntl(tech_pvt->audiopipe[0], F_SETFL, O_NONBLOCK);
+		fcntl(tech_pvt->audiopipe[1], F_SETFL, O_NONBLOCK);
+	}
+	if (pipe(tech_pvt->audioskypepipe)) {
+		fcntl(tech_pvt->audioskypepipe[0], F_SETFL, O_NONBLOCK);
+		fcntl(tech_pvt->audioskypepipe[1], F_SETFL, O_NONBLOCK);
+	}
+
+/* this pipe is the audio fd for asterisk to poll on during a call. FS do not use it */
+	tech_pvt->skypiax_sound_capt_fd = tech_pvt->audiopipe[0];
+
+	return 0;
+}
+#endif /* WIN32 */
+
+#ifdef WIN32
+
+enum {
+	SKYPECONTROLAPI_ATTACH_SUCCESS = 0,	/*  Client is successfully 
+										   attached and API window handle can be found
+										   in wParam parameter */
+	SKYPECONTROLAPI_ATTACH_PENDING_AUTHORIZATION = 1,	/*  Skype has acknowledged
+														   connection request and is waiting
+														   for confirmation from the user. */
+	/*  The client is not yet attached 
+	 * and should wait for SKYPECONTROLAPI_ATTACH_SUCCESS message */
+	SKYPECONTROLAPI_ATTACH_REFUSED = 2,	/*  User has explicitly
+										   denied access to client */
+	SKYPECONTROLAPI_ATTACH_NOT_AVAILABLE = 3,	/*  API is not available
+												   at the moment.
+												   For example, this happens when no user
+												   is currently logged in. */
+	/*  Client should wait for 
+	 * SKYPECONTROLAPI_ATTACH_API_AVAILABLE 
+	 * broadcast before making any further */
+	/*  connection attempts. */
+	SKYPECONTROLAPI_ATTACH_API_AVAILABLE = 0x8001
+};
+
+/* Visual C do not have strsep? */
+char
+    *strsep(char **stringp, const char *delim)
+{
+	char *res;
+
+	if (!stringp || !*stringp || !**stringp)
+		return (char *) 0;
+
+	res = *stringp;
+	while (**stringp && !strchr(delim, **stringp))
+		++(*stringp);
+
+	if (**stringp) {
+		**stringp = '\0';
+		++(*stringp);
+	}
+
+	return res;
+}
+
+int skypiax_signaling_write(private_t * tech_pvt, char *msg_to_skype)
+{
+	static char acInputRow[1024];
+	COPYDATASTRUCT oCopyData;
+
+	DEBUGA_SKYPE("SENDING: |||%s||||\n", SKYPIAX_P_LOG, msg_to_skype);
+
+	sprintf(acInputRow, "%s", msg_to_skype);
+	DEBUGA_SKYPE("acInputRow: |||%s||||\n", SKYPIAX_P_LOG, acInputRow);
+	/*  send command to skype */
+	oCopyData.dwData = 0;
+	oCopyData.lpData = acInputRow;
+	oCopyData.cbData = strlen(acInputRow) + 1;
+	if (oCopyData.cbData != 1) {
+		if (SendMessage
+			(tech_pvt->SkypiaxHandles.win32_hGlobal_SkypeAPIWindowHandle, WM_COPYDATA,
+			 (WPARAM) tech_pvt->SkypiaxHandles.win32_hInit_MainWindowHandle, (LPARAM) & oCopyData) == FALSE) {
+			ERRORA("Sending message failed - probably Skype crashed.\n\nPlease shutdown Skypiax, then launch Skypiax and try again.\n", SKYPIAX_P_LOG);
+			return -1;
+		}
+	}
+
+	return 0;
+
+}
+
+LRESULT APIENTRY skypiax_present(HWND hWindow, UINT uiMessage, WPARAM uiParam, LPARAM ulParam)
+{
+	LRESULT lReturnCode;
+	int fIssueDefProc;
+	private_t *tech_pvt = NULL;
+
+	lReturnCode = 0;
+	fIssueDefProc = 0;
+	tech_pvt = (private_t *) GetWindowLong(hWindow, GWL_USERDATA);
+	if (!running)
+		return lReturnCode;
+	switch (uiMessage) {
+	case WM_CREATE:
+		tech_pvt = (private_t *) ((LPCREATESTRUCT) ulParam)->lpCreateParams;
+		SetWindowLong(hWindow, GWL_USERDATA, (LONG) tech_pvt);
+		DEBUGA_SKYPE("got CREATE\n", SKYPIAX_P_LOG);
+		break;
+	case WM_DESTROY:
+		DEBUGA_SKYPE("got DESTROY\n", SKYPIAX_P_LOG);
+		tech_pvt->SkypiaxHandles.win32_hInit_MainWindowHandle = NULL;
+		PostQuitMessage(0);
+		break;
+	case WM_COPYDATA:
+		if (tech_pvt->SkypiaxHandles.win32_hGlobal_SkypeAPIWindowHandle == (HWND) uiParam) {
+			unsigned int howmany;
+			char msg_from_skype[2048];
+
+			PCOPYDATASTRUCT poCopyData = (PCOPYDATASTRUCT) ulParam;
+
+			memset(msg_from_skype, '\0', sizeof(msg_from_skype));
+			skypiax_strncpy(msg_from_skype, (const char *) poCopyData->lpData, sizeof(msg_from_skype) - 2);
+
+			howmany = strlen(msg_from_skype) + 1;
+			howmany = skypiax_pipe_write(tech_pvt->SkypiaxHandles.fdesc[1], (short *) msg_from_skype, howmany);
+			//DEBUGA_SKYPE("From Skype API: %s\n", SKYPIAX_P_LOG, msg_from_skype);
+			lReturnCode = 1;
+		}
+		break;
+	default:
+		if (tech_pvt && tech_pvt->SkypiaxHandles.win32_uiGlobal_MsgID_SkypeControlAPIAttach) {
+			if (uiMessage == tech_pvt->SkypiaxHandles.win32_uiGlobal_MsgID_SkypeControlAPIAttach) {
+				switch (ulParam) {
+				case SKYPECONTROLAPI_ATTACH_SUCCESS:
+					if (!tech_pvt->SkypiaxHandles.currentuserhandle) {
+						//DEBUGA_SKYPE("\n\n\tConnected to Skype API!\n", SKYPIAX_P_LOG);
+						tech_pvt->SkypiaxHandles.api_connected = 1;
+						tech_pvt->SkypiaxHandles.win32_hGlobal_SkypeAPIWindowHandle = (HWND) uiParam;
+						tech_pvt->SkypiaxHandles.win32_hGlobal_SkypeAPIWindowHandle = tech_pvt->SkypiaxHandles.win32_hGlobal_SkypeAPIWindowHandle;
+					}
+					break;
+				case SKYPECONTROLAPI_ATTACH_PENDING_AUTHORIZATION:
+					//DEBUGA_SKYPE ("\n\n\tIf I do not (almost) immediately connect to Skype API,\n\tplease give the Skype client authorization to be connected \n\tby Asterisk and to not ask you again.\n\n", SKYPIAX_P_LOG);
+					skypiax_sleep(5000);
+#if 0
+					if (!tech_pvt->SkypiaxHandles.currentuserhandle) {
+						SendMessage(HWND_BROADCAST,
+									tech_pvt->SkypiaxHandles.
+									win32_uiGlobal_MsgID_SkypeControlAPIDiscover, (WPARAM) tech_pvt->SkypiaxHandles.win32_hInit_MainWindowHandle, 0);
+					}
+#endif
+					break;
+				case SKYPECONTROLAPI_ATTACH_REFUSED:
+					ERRORA("Skype client refused to be connected by Skypiax!\n", SKYPIAX_P_LOG);
+					break;
+				case SKYPECONTROLAPI_ATTACH_NOT_AVAILABLE:
+					ERRORA("Skype API not (yet?) available\n", SKYPIAX_P_LOG);
+					break;
+				case SKYPECONTROLAPI_ATTACH_API_AVAILABLE:
+					DEBUGA_SKYPE("Skype API available\n", SKYPIAX_P_LOG);
+					skypiax_sleep(5000);
+#if 0
+					if (!tech_pvt->SkypiaxHandles.currentuserhandle) {
+						SendMessage(HWND_BROADCAST,
+									tech_pvt->SkypiaxHandles.
+									win32_uiGlobal_MsgID_SkypeControlAPIDiscover, (WPARAM) tech_pvt->SkypiaxHandles.win32_hInit_MainWindowHandle, 0);
+					}
+#endif
+					break;
+				default:
+					WARNINGA("GOT AN UNKNOWN SKYPE WINDOWS MSG\n", SKYPIAX_P_LOG);
+				}
+				lReturnCode = 1;
+				break;
+			}
+		}
+		fIssueDefProc = 1;
+		break;
+	}
+	if (fIssueDefProc)
+		lReturnCode = DefWindowProc(hWindow, uiMessage, uiParam, ulParam);
+	return (lReturnCode);
+}
+
+int win32_Initialize_CreateWindowClass(private_t * tech_pvt)
+{
+	unsigned char *paucUUIDString;
+	RPC_STATUS lUUIDResult;
+	int fReturnStatus;
+	UUID oUUID;
+
+	fReturnStatus = 0;
+	lUUIDResult = UuidCreate(&oUUID);
+	tech_pvt->SkypiaxHandles.win32_hInit_ProcessHandle = (HINSTANCE) OpenProcess(PROCESS_DUP_HANDLE, FALSE, GetCurrentProcessId());
+	if (tech_pvt->SkypiaxHandles.win32_hInit_ProcessHandle != NULL && (lUUIDResult == RPC_S_OK || lUUIDResult == RPC_S_UUID_LOCAL_ONLY)) {
+		if (UuidToString(&oUUID, &paucUUIDString) == RPC_S_OK) {
+			WNDCLASS oWindowClass;
+
+			strcpy(tech_pvt->SkypiaxHandles.win32_acInit_WindowClassName, "Skype-API-Skypiax-");
+			strcat(tech_pvt->SkypiaxHandles.win32_acInit_WindowClassName, (char *) paucUUIDString);
+
+			oWindowClass.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
+			oWindowClass.lpfnWndProc = (WNDPROC) & skypiax_present;
+			oWindowClass.cbClsExtra = 0;
+			oWindowClass.cbWndExtra = 0;
+			oWindowClass.hInstance = tech_pvt->SkypiaxHandles.win32_hInit_ProcessHandle;
+			oWindowClass.hIcon = NULL;
+			oWindowClass.hCursor = NULL;
+			oWindowClass.hbrBackground = NULL;
+			oWindowClass.lpszMenuName = NULL;
+			oWindowClass.lpszClassName = tech_pvt->SkypiaxHandles.win32_acInit_WindowClassName;
+
+			if (RegisterClass(&oWindowClass) != 0)
+				fReturnStatus = 1;
+
+			RpcStringFree(&paucUUIDString);
+		}
+	}
+	if (fReturnStatus == 0)
+		CloseHandle(tech_pvt->SkypiaxHandles.win32_hInit_ProcessHandle);
+	tech_pvt->SkypiaxHandles.win32_hInit_ProcessHandle = NULL;
+	return (fReturnStatus);
+}
+
+void win32_DeInitialize_DestroyWindowClass(private_t * tech_pvt)
+{
+	UnregisterClass(tech_pvt->SkypiaxHandles.win32_acInit_WindowClassName, tech_pvt->SkypiaxHandles.win32_hInit_ProcessHandle);
+	CloseHandle(tech_pvt->SkypiaxHandles.win32_hInit_ProcessHandle);
+	tech_pvt->SkypiaxHandles.win32_hInit_ProcessHandle = NULL;
+}
+
+int win32_Initialize_CreateMainWindow(private_t * tech_pvt)
+{
+	tech_pvt->SkypiaxHandles.win32_hInit_MainWindowHandle =
+		CreateWindowEx(WS_EX_APPWINDOW | WS_EX_WINDOWEDGE,
+					   tech_pvt->SkypiaxHandles.win32_acInit_WindowClassName, "",
+					   WS_BORDER | WS_SYSMENU | WS_MINIMIZEBOX, CW_USEDEFAULT, CW_USEDEFAULT,
+					   128, 128, NULL, 0, tech_pvt->SkypiaxHandles.win32_hInit_ProcessHandle, tech_pvt);
+	return (tech_pvt->SkypiaxHandles.win32_hInit_MainWindowHandle != NULL ? 1 : 0);
+}
+
+void win32_DeInitialize_DestroyMainWindow(private_t * tech_pvt)
+{
+	if (tech_pvt->SkypiaxHandles.win32_hInit_MainWindowHandle != NULL)
+		DestroyWindow(tech_pvt->SkypiaxHandles.win32_hInit_MainWindowHandle), tech_pvt->SkypiaxHandles.win32_hInit_MainWindowHandle = NULL;
+}
+
+void *skypiax_do_skypeapi_thread_func(void *obj)
+{
+	private_t *tech_pvt = obj;
+#if defined(WIN32) && !defined(__CYGWIN__)
+	switch_status_t rv;
+
+	switch_file_pipe_create(&tech_pvt->SkypiaxHandles.fdesc[0], &tech_pvt->SkypiaxHandles.fdesc[1], skypiax_module_pool);
+	rv = switch_file_pipe_create(&tech_pvt->SkypiaxHandles.fdesc[0], &tech_pvt->SkypiaxHandles.fdesc[1], skypiax_module_pool);
+#else /* WIN32 */
+	if (pipe(tech_pvt->SkypiaxHandles.fdesc)) {
+		fcntl(tech_pvt->SkypiaxHandles.fdesc[0], F_SETFL, O_NONBLOCK);
+		fcntl(tech_pvt->SkypiaxHandles.fdesc[1], F_SETFL, O_NONBLOCK);
+	}
+#endif /* WIN32 */
+
+	tech_pvt->SkypiaxHandles.win32_uiGlobal_MsgID_SkypeControlAPIAttach = RegisterWindowMessage("SkypeControlAPIAttach");
+	tech_pvt->SkypiaxHandles.win32_uiGlobal_MsgID_SkypeControlAPIDiscover = RegisterWindowMessage("SkypeControlAPIDiscover");
+
+	skypiax_sleep(200000);		//0,2 sec
+
+	if (tech_pvt->SkypiaxHandles.win32_uiGlobal_MsgID_SkypeControlAPIAttach != 0
+		&& tech_pvt->SkypiaxHandles.win32_uiGlobal_MsgID_SkypeControlAPIDiscover != 0) {
+		if (win32_Initialize_CreateWindowClass(tech_pvt)) {
+			if (win32_Initialize_CreateMainWindow(tech_pvt)) {
+				if (SendMessage
+					(HWND_BROADCAST,
+					 tech_pvt->SkypiaxHandles.win32_uiGlobal_MsgID_SkypeControlAPIDiscover,
+					 (WPARAM) tech_pvt->SkypiaxHandles.win32_hInit_MainWindowHandle, 0) != 0) {
+					tech_pvt->SkypiaxHandles.win32_hInit_MainWindowHandle = tech_pvt->SkypiaxHandles.win32_hInit_MainWindowHandle;
+					while (running && tech_pvt->running) {
+						MSG oMessage;
+						if (!(running && tech_pvt->running))
+							break;
+						while (GetMessage(&oMessage, 0, 0, 0)) {
+							TranslateMessage(&oMessage);
+							DispatchMessage(&oMessage);
+						}
+					}
+				}
+				win32_DeInitialize_DestroyMainWindow(tech_pvt);
+			}
+			win32_DeInitialize_DestroyWindowClass(tech_pvt);
+		}
+	}
+
+	return NULL;
+}
+
+#else /* NOT WIN32 */
+int X11_errors_handler(Display * dpy, XErrorEvent * err)
+{
+	(void) dpy;
+	private_t *tech_pvt = NULL;
+
+	xerror = err->error_code;
+	ERRORA("Received error code %d from X Server\n\n", SKYPIAX_P_LOG, xerror);	///FIXME why crash the entire skypiax? just crash the interface, instead
+	running = 0;
+	return 0;					/*  ignore the error */
+}
+
+static void X11_errors_trap(void)
+{
+	xerror = 0;
+	old_handler = XSetErrorHandler(X11_errors_handler);
+}
+
+static int X11_errors_untrap(void)
+{
+	XSetErrorHandler(old_handler);
+	return (xerror != BadValue) && (xerror != BadWindow);
+}
+
+int skypiax_send_message(struct SkypiaxHandles *SkypiaxHandles, const char *message_P)
+{
+
+	Window w_P;
+	Display *disp;
+	Window handle_P;
+	int ok;
+	private_t *tech_pvt = NULL;
+
+	w_P = SkypiaxHandles->skype_win;
+	disp = SkypiaxHandles->disp;
+	handle_P = SkypiaxHandles->win;
+
+	Atom atom1 = XInternAtom(disp, "SKYPECONTROLAPI_MESSAGE_BEGIN", False);
+	Atom atom2 = XInternAtom(disp, "SKYPECONTROLAPI_MESSAGE", False);
+	unsigned int pos = 0;
+	unsigned int len = strlen(message_P);
+	XEvent e;
+
+	memset(&e, 0, sizeof(e));
+	e.xclient.type = ClientMessage;
+	e.xclient.message_type = atom1;	/*  leading message */
+	e.xclient.display = disp;
+	e.xclient.window = handle_P;
+	e.xclient.format = 8;
+
+	X11_errors_trap();
+	//XLockDisplay(disp);
+	do {
+		unsigned int i;
+		for (i = 0; i < 20 && i + pos <= len; ++i)
+			e.xclient.data.b[i] = message_P[i + pos];
+		XSendEvent(disp, w_P, False, 0, &e);
+
+		e.xclient.message_type = atom2;	/*  following messages */
+		pos += i;
+	} while (pos <= len);
+
+	XSync(disp, False);
+	ok = X11_errors_untrap();
+
+	if (!ok)
+		ERRORA("Sending message failed with status %d\n", SKYPIAX_P_LOG, xerror);
+	//XUnlockDisplay(disp);
+
+	return 1;
+}
+
+int skypiax_signaling_write(private_t * tech_pvt, char *msg_to_skype)
+{
+	struct SkypiaxHandles *SkypiaxHandles;
+
+	DEBUGA_SKYPE("SENDING: |||%s||||\n", SKYPIAX_P_LOG, msg_to_skype);
+
+	SkypiaxHandles = &tech_pvt->SkypiaxHandles;
+
+	if (!skypiax_send_message(SkypiaxHandles, msg_to_skype)) {
+		ERRORA
+			("Sending message failed - probably Skype crashed.\n\nPlease shutdown Skypiax, then restart Skype, then launch Skypiax and try again.\n",
+			 SKYPIAX_P_LOG);
+		return -1;
+	}
+
+	return 0;
+
+}
+
+int skypiax_present(struct SkypiaxHandles *SkypiaxHandles)
+{
+	Atom skype_inst = XInternAtom(SkypiaxHandles->disp, "_SKYPE_INSTANCE", True);
+
+	Atom type_ret;
+	int format_ret;
+	unsigned long nitems_ret;
+	unsigned long bytes_after_ret;
+	unsigned char *prop;
+	int status;
+	private_t *tech_pvt = NULL;
+
+	X11_errors_trap();
+	//XLockDisplay(disp);
+	status =
+		XGetWindowProperty(SkypiaxHandles->disp, DefaultRootWindow(SkypiaxHandles->disp),
+						   skype_inst, 0, 1, False, XA_WINDOW, &type_ret, &format_ret, &nitems_ret, &bytes_after_ret, &prop);
+	//XUnlockDisplay(disp);
+	X11_errors_untrap();
+
+	/*  sanity check */
+	if (status != Success || format_ret != 32 || nitems_ret != 1) {
+		SkypiaxHandles->skype_win = (Window) - 1;
+		DEBUGA_SKYPE("Skype instance not found\n", SKYPIAX_P_LOG);
+		running = 0;
+		SkypiaxHandles->api_connected = 0;
+		return 0;
+	}
+
+	SkypiaxHandles->skype_win = *(const unsigned long *) prop & 0xffffffff;
+	DEBUGA_SKYPE("Skype instance found with id #%d\n", SKYPIAX_P_LOG, (unsigned int) SkypiaxHandles->skype_win);
+	SkypiaxHandles->api_connected = 1;
+	return 1;
+}
+
+void skypiax_clean_disp(void *data)
+{
+
+	int *dispptr;
+	int disp;
+	private_t *tech_pvt = NULL;
+
+	dispptr = data;
+	disp = *dispptr;
+
+	if (disp) {
+		DEBUGA_SKYPE("to be destroyed disp %d\n", SKYPIAX_P_LOG, disp);
+		close(disp);
+		DEBUGA_SKYPE("destroyed disp\n", SKYPIAX_P_LOG);
+	} else {
+		DEBUGA_SKYPE("NOT destroyed disp\n", SKYPIAX_P_LOG);
+	}
+	DEBUGA_SKYPE("OUT destroyed disp\n", SKYPIAX_P_LOG);
+	skypiax_sleep(1000);
+}
+
+void *skypiax_do_skypeapi_thread_func(void *obj)
+{
+
+	private_t *tech_pvt = obj;
+	struct SkypiaxHandles *SkypiaxHandles;
+	char buf[512];
+	Display *disp = NULL;
+	Window root = -1;
+	Window win = -1;
+
+	if (!strlen(tech_pvt->X11_display))
+		strcpy(tech_pvt->X11_display, getenv("DISPLAY"));
+
+	if (!tech_pvt->tcp_srv_port)
+		tech_pvt->tcp_srv_port = 10160;
+
+	if (!tech_pvt->tcp_cli_port)
+		tech_pvt->tcp_cli_port = 10161;
+
+	if (pipe(tech_pvt->SkypiaxHandles.fdesc)) {
+		fcntl(tech_pvt->SkypiaxHandles.fdesc[0], F_SETFL, O_NONBLOCK);
+		fcntl(tech_pvt->SkypiaxHandles.fdesc[1], F_SETFL, O_NONBLOCK);
+	}
+	SkypiaxHandles = &tech_pvt->SkypiaxHandles;
+	disp = XOpenDisplay(tech_pvt->X11_display);
+	if (!disp) {
+		ERRORA("Cannot open X Display '%s', exiting skype thread\n", SKYPIAX_P_LOG, tech_pvt->X11_display);
+		running = 0;
+		return NULL;
+	} else {
+		DEBUGA_SKYPE("X Display '%s' opened\n", SKYPIAX_P_LOG, tech_pvt->X11_display);
+	}
+
+	int xfd;
+	xfd = XConnectionNumber(disp);
+	fcntl(xfd, F_SETFD, FD_CLOEXEC);
+
+	SkypiaxHandles->disp = disp;
+
+	if (skypiax_present(SkypiaxHandles)) {
+		root = DefaultRootWindow(disp);
+		win = XCreateSimpleWindow(disp, root, 0, 0, 1, 1, 0, BlackPixel(disp, DefaultScreen(disp)), BlackPixel(disp, DefaultScreen(disp)));
+
+		SkypiaxHandles->win = win;
+
+		snprintf(buf, 512, "NAME skypiax");
+
+		if (!skypiax_send_message(SkypiaxHandles, buf)) {
+			ERRORA("Sending message failed - probably Skype crashed. Please run/restart Skype manually and launch Skypiax again\n", SKYPIAX_P_LOG);
+			running = 0;
+			return NULL;
+		}
+
+		snprintf(buf, 512, "PROTOCOL 7");
+		if (!skypiax_send_message(SkypiaxHandles, buf)) {
+			ERRORA("Sending message failed - probably Skype crashed. Please run/restart Skype manually and launch Skypiax again\n", SKYPIAX_P_LOG);
+			running = 0;
+			return NULL;
+		}
+
+		/* perform an events loop */
+		XEvent an_event;
+		char buf[21];			/*  can't be longer */
+		char buffer[17000];
+		char *b;
+		int i;
+		int continue_is_broken = 0;
+		Atom atom_begin = XInternAtom(disp, "SKYPECONTROLAPI_MESSAGE_BEGIN", False);
+		Atom atom_continue = XInternAtom(disp, "SKYPECONTROLAPI_MESSAGE", False);
+
+		b = buffer;
+
+		while (1) {
+			XNextEvent(disp, &an_event);
+			if (!(running && tech_pvt->running))
+				break;
+			switch (an_event.type) {
+			case ClientMessage:
+
+				if (an_event.xclient.format != 8)
+					break;
+
+				for (i = 0; i < 20 && an_event.xclient.data.b[i] != '\0'; ++i)
+					buf[i] = an_event.xclient.data.b[i];
+
+				buf[i] = '\0';
+
+				//DEBUGA_SKYPE ("BUF=|||%s|||\n", SKYPIAX_P_LOG, buf);
+
+				if (an_event.xclient.message_type == atom_begin) {
+
+					if (strlen(buffer)) {
+						unsigned int howmany;
+						howmany = strlen(b) + 1;
+						howmany = write(SkypiaxHandles->fdesc[1], b, howmany);
+						DEBUGA_SKYPE("RECEIVED2=|||%s|||\n", SKYPIAX_P_LOG, buffer);
+						memset(buffer, '\0', 17000);
+					}
+				}
+				if (an_event.xclient.message_type == atom_continue) {
+
+					if (!strlen(buffer)) {
+						DEBUGA_SKYPE
+							("Got a 'continue' XAtom without a previous 'begin'. It's value (between vertical bars) is=|||%s|||\n", SKYPIAX_P_LOG, buf);
+						continue_is_broken = 1;
+						if (!strncmp(buf, "ognised identity", 15)) {
+							WARNINGA
+								("Got a 'continue' XAtom without a previous 'begin'. It's value (between vertical bars) is=|||%s|||. Let's introduce a 1 second delay.\n",
+								 SKYPIAX_P_LOG, buf);
+							skypiax_sleep(1000000);	//1 sec
+						}
+						break;
+					}
+				}
+
+				strcat(buffer, buf);
+
+				if (i < 20 || continue_is_broken) {	/* last fragment */
+					unsigned int howmany;
+
+					howmany = strlen(b) + 1;
+
+					howmany = write(SkypiaxHandles->fdesc[1], b, howmany);
+					//DEBUGA_SKYPE ("RECEIVED=|||%s|||\n", SKYPIAX_P_LOG, buffer);
+					memset(buffer, '\0', 17000);
+					XFlush(disp);
+					continue_is_broken = 0;
+				}
+
+				break;
+			default:
+				break;
+			}
+		}
+	} else {
+		ERRORA("Skype is not running, maybe crashed. Please run/restart Skype and relaunch Skypiax\n", SKYPIAX_P_LOG);
+		running = 0;
+		return NULL;
+	}
+	//running = 0;
+	return NULL;
+
+}
+#endif // WIN32