[Freeswitch-svn] [commit] r11153 - in freeswitch/branches/ctrix/mod_airpe: . config

FreeSWITCH SVN ctrix at freeswitch.org
Mon Jan 12 15:24:44 PST 2009


Author: ctrix
Date: Mon Jan 12 17:24:44 2009
New Revision: 11153

Log:
Initial import of airpe...
Not yet fully working, don't expect too much.



Added:
   freeswitch/branches/ctrix/mod_airpe/airpe_api.c
   freeswitch/branches/ctrix/mod_airpe/airpe_apps.c
   freeswitch/branches/ctrix/mod_airpe/airpe_if_common.c
   freeswitch/branches/ctrix/mod_airpe/airpe_if_osx.c
   freeswitch/branches/ctrix/mod_airpe/airpe_if_win32.c
   freeswitch/branches/ctrix/mod_airpe/airpe_if_x11.c
   freeswitch/branches/ctrix/mod_airpe/config/
   freeswitch/branches/ctrix/mod_airpe/config/airpe.conf.xml
   freeswitch/branches/ctrix/mod_airpe/mod_airpe.c
   freeswitch/branches/ctrix/mod_airpe/mod_airpe.h

Added: freeswitch/branches/ctrix/mod_airpe/airpe_api.c
==============================================================================
--- (empty file)
+++ freeswitch/branches/ctrix/mod_airpe/airpe_api.c	Mon Jan 12 17:24:44 2009
@@ -0,0 +1,262 @@
+/* 
+ * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ * Copyright (C) 2005/2006, Anthony Minessale II <anthmct at 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 mod_airpe.
+ *
+ * The Initial Developer of the Original Code is
+ * Massimo Cetra <devel at navynet.it>
+ *
+ * Portions created by the Initial Developer are Copyright (C)
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Thanks to gmaruzz for his work on skypiax (both * and freeswitch).
+ * Some of his code inspired this module
+ *
+ */
+
+#include "mod_airpe.h"
+
+#define AIRPE_MOODTEXT_SYNTAX "airpe_moodtext <clientname> <text>"
+SWITCH_STANDARD_API(airpe_moodtext_command)
+{
+    int argc = 0;
+    char *argv[2] = { 0 };
+    char *mycmd  = NULL;
+    char *client = NULL;
+    airpe_interface_t *airpe = NULL;
+
+    if (!switch_strlen_zero(cmd) && (mycmd = strdup(cmd))) {
+	argc = switch_separate_string(mycmd, ' ', argv, (sizeof(argv) / sizeof(argv[0])));
+	switch_assert(argv[0]);
+    }
+
+    if ( argc < 1 ) {
+	stream->write_function(stream, "-USAGE: %s\n", AIRPE_MOODTEXT_SYNTAX);
+	goto done;
+    }
+
+    client = argv[0];
+    airpe = airpe_find_interface(client);
+
+    if ( !airpe ) {
+	stream->write_function(stream, "-ERR interface not found for client ");
+	stream->write_function(stream, client);
+	stream->write_function(stream, "\n");
+	goto done;
+    } 
+
+    if ( argc == 1 ) {
+        stream->write_function(stream, "+OK: ");
+	if ( airpe->mood_text )
+	    stream->write_function(stream, airpe->mood_text);
+	else
+	    stream->write_function(stream, "UNKNOWN");
+	stream->write_function(stream, "\n");
+    }
+    else {
+	if ( airpe_set_mood_text(airpe, argv[1]) != SWITCH_STATUS_SUCCESS ) {
+	    stream->write_function(stream, "-ERR cannot send message to the client\n");
+	    goto done;
+	}
+	else {
+	    char buf[SKYPE_MSG_LEN];
+	    snprintf(buf, SKYPE_MSG_LEN, "SET PROFILE MOOD_TEXT %s", airpe->mood_text );
+	    airpe_cmd_write(airpe, buf);
+	}
+	stream->write_function(stream, "+OK mood_text set.\n");
+    }
+
+ done:
+    return SWITCH_STATUS_SUCCESS;
+}
+
+#define AIRPE_INFO_SYNTAX "airpe_status <clientname>"
+SWITCH_STANDARD_API(airpe_info_command)
+{
+    int argc = 0;
+    char *argv[4] = { 0 };
+    char *mycmd  = NULL;
+    char *client = NULL;
+    char buf[512];
+    airpe_interface_t *airpe = NULL;
+
+    if (!switch_strlen_zero(cmd) && (mycmd = strdup(cmd))) {
+	argc = switch_separate_string(mycmd, ' ', argv, (sizeof(argv) / sizeof(argv[0])));
+	switch_assert(argv[0]);
+    }
+
+    if ( argc < 1 ) {
+	stream->write_function(stream, "-USAGE: %s\n", AIRPE_INFO_SYNTAX);
+	goto done;
+    }
+
+    client = argv[0];
+    airpe = airpe_find_interface(client);
+
+    if ( !airpe ) {
+	stream->write_function(stream, "-ERR interface not found for client ");
+	stream->write_function(stream, client);
+	stream->write_function(stream, "\n");
+	goto done;
+    } 
+
+    switch_snprintf(buf, sizeof(buf), "%-20s: %s\n", "Client name", airpe->name);
+    stream->write_function(stream, buf);
+    switch_snprintf(buf, sizeof(buf), "%-20s: %s\n", "Dialplan", airpe->dialplan);
+    stream->write_function(stream, buf);
+    switch_snprintf(buf, sizeof(buf), "%-20s: %s\n", "Context", airpe->context);
+    stream->write_function(stream, buf);
+    switch_snprintf(buf, sizeof(buf), "%-20s: %s\n", "Destination", airpe->destination);
+    stream->write_function(stream, buf);
+    switch_snprintf(buf, sizeof(buf), "%-20s: %s\n", "Skype username", airpe->skype_user);
+    stream->write_function(stream, buf);
+    if ( airpe->audio_in_port > 0 )
+	switch_snprintf(buf, sizeof(buf), "%-20s: %d\n", "Audio in port", airpe->audio_in_port);
+    else
+	switch_snprintf(buf, sizeof(buf), "%-20s: %s\n", "Audio in port", "NOT SET");
+    stream->write_function(stream, buf);
+    if ( airpe->audio_in_port > 0 )
+	switch_snprintf(buf, sizeof(buf), "%-20s: %d\n", "Audio out port", airpe->audio_out_port);
+    else
+	switch_snprintf(buf, sizeof(buf), "%-20s: %s\n", "Audio out port", "NOT SET");
+    stream->write_function(stream, buf);
+
+    switch_snprintf(buf, sizeof(buf), "%-20s: %s\n", "Connection status", skype_conn_status_string(airpe->conn_status) );
+    stream->write_function(stream, buf);
+    switch_snprintf(buf, sizeof(buf), "%-20s: %s\n", "Client status", skype_user_status_string(airpe->user_status) );
+    stream->write_function(stream, buf);
+
+    switch_snprintf(buf, sizeof(buf), "%-20s: %s\n", "Skype version", (airpe->skype_version) ? airpe->skype_version : "Unknown" );
+    stream->write_function(stream, buf);
+    switch_snprintf(buf, sizeof(buf), "%-20s: %s\n", "Mood text", (airpe->mood_text ) ? airpe->mood_text : "Unknown" );
+    stream->write_function(stream, buf);
+
+ done:
+    return SWITCH_STATUS_SUCCESS;
+}
+
+#define AIRPE_STATUS_SYNTAX "airpe_status <clientname> <status>"
+SWITCH_STANDARD_API(airpe_status_command)
+{
+    int argc = 0;
+    char *argv[4] = { 0 };
+    char *mycmd  = NULL;
+    char *client = NULL;
+    char *cstatus= NULL;
+    airpe_interface_t *airpe = NULL;
+
+    if (!switch_strlen_zero(cmd) && (mycmd = strdup(cmd))) {
+	argc = switch_separate_string(mycmd, ' ', argv, (sizeof(argv) / sizeof(argv[0])));
+	switch_assert(argv[0]);
+    }
+
+    if ( argc < 1 ) {
+	stream->write_function(stream, "-USAGE: %s\n", AIRPE_STATUS_SYNTAX);
+	goto done;
+    }    
+
+    client = argv[0];
+    if ( argc > 1 ) 
+	cstatus = argv[1];
+
+    airpe = airpe_find_interface(client);
+
+    if ( !airpe ) {
+	stream->write_function(stream, "-ERR interface not found: \n");
+	stream->write_function(stream, client);
+	stream->write_function(stream, "\n");
+	goto done;
+    } 
+
+    if ( !cstatus ) {
+	const char *str_status = NULL;
+	str_status = skype_user_status_string( airpe->user_status );
+	stream->write_function(stream, "+OK status is ");
+	if ( str_status )
+	    stream->write_function(stream, str_status);
+	else
+	    stream->write_function(stream, "... uhmmm, ehmm, DUNNO... ");
+	stream->write_function(stream, "\n");
+    }
+    else {
+	char buf[SKYPE_MSG_LEN];
+	const char *str_status = NULL;
+
+	if      ( !strncasecmp(cstatus, "unknown", sizeof("unknown") ) )
+	    str_status = skype_user_status_string(USER_STATUS_UNKNOWN);
+	else if ( !strncasecmp(cstatus, "online", sizeof("online") ) )
+	    str_status = skype_user_status_string(USER_STATUS_ONLINE);
+	else if ( !strncasecmp(cstatus, "offline", sizeof("offline") ) )
+	    str_status = skype_user_status_string(USER_STATUS_OFFLINE);
+	else if ( !strncasecmp(cstatus, "skypeme", sizeof("skypeme") ) )
+	    str_status = skype_user_status_string(USER_STATUS_SKYPEME);
+	else if ( !strncasecmp(cstatus, "away", sizeof("away") ) )
+	    str_status = skype_user_status_string(USER_STATUS_AWAY);
+	else if ( !strncasecmp(cstatus, "na", sizeof("na") ) )
+	    str_status = skype_user_status_string(USER_STATUS_NA);
+	else if ( !strncasecmp(cstatus, "dnd", sizeof("dnd") ) )
+	    str_status = skype_user_status_string(USER_STATUS_DND);
+	else if ( !strncasecmp(cstatus, "invisible", sizeof("invisible") ) )
+	    str_status = skype_user_status_string(USER_STATUS_INVISIBLE);
+	else if ( !strncasecmp(cstatus, "loggedout", sizeof("loggedout") ) )
+	    str_status = skype_user_status_string(USER_STATUS_LOGGEDOUT);
+
+	if ( str_status ) {
+	    snprintf(buf, SKYPE_MSG_LEN, "SET USERSTATUS %s", cstatus );
+	    if ( airpe_cmd_write(airpe, buf) != SWITCH_STATUS_SUCCESS ) {
+		stream->write_function(stream, "-ERR cannot send message to the client\n");
+		goto done;
+	    }
+	    stream->write_function(stream, "+OK status set.\n");
+	}
+	else {
+	    stream->write_function(stream, "-ERR invalid status string\n");
+	}
+    }
+
+ done:
+    return SWITCH_STATUS_SUCCESS;
+}
+
+
+
+switch_status_t airpe_register_api( switch_loadable_module_interface_t **module_interface ) {
+
+    switch_api_interface_t *api;
+
+    switch_console_set_complete("add airpe_moodtext ");
+    SWITCH_ADD_API(api, "airpe_moodtext", "sets the mood text of an airpe client", airpe_moodtext_command, AIRPE_MOODTEXT_SYNTAX);
+
+    switch_console_set_complete("add airpe_info ");
+    SWITCH_ADD_API(api, "airpe_info", "shows the status of an airpe client", airpe_info_command, AIRPE_INFO_SYNTAX);
+
+    switch_console_set_complete("add airpe_status ");
+    SWITCH_ADD_API(api, "airpe_status", "sets the status of an airpe client", airpe_status_command, AIRPE_STATUS_SYNTAX);
+
+    return SWITCH_STATUS_SUCCESS;
+}
+
+/* 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/ctrix/mod_airpe/airpe_apps.c
==============================================================================
--- (empty file)
+++ freeswitch/branches/ctrix/mod_airpe/airpe_apps.c	Mon Jan 12 17:24:44 2009
@@ -0,0 +1,56 @@
+/* 
+ * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ * Copyright (C) 2005/2006, Anthony Minessale II <anthmct at 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 mod_airpe.
+ *
+ * The Initial Developer of the Original Code is
+ * Massimo Cetra <devel at navynet.it>
+ *
+ * Portions created by the Initial Developer are Copyright (C)
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Thanks to gmaruzz for his work on skypiax (both * and freeswitch).
+ * Some of his code inspired this module
+ *
+ */
+
+#include "mod_airpe.h"
+
+SWITCH_STANDARD_APP(airpe_app_test) 
+{
+}
+
+
+switch_status_t airpe_register_apps( switch_loadable_module_interface_t **module_interface ) {
+    switch_application_interface_t *app_interface;
+
+    SWITCH_ADD_APP(app_interface, "airpe_test", "test text", "test text", airpe_app_test, "", SAF_SUPPORT_NOMEDIA);
+
+    return SWITCH_STATUS_SUCCESS;
+}
+
+/* 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/ctrix/mod_airpe/airpe_if_common.c
==============================================================================
--- (empty file)
+++ freeswitch/branches/ctrix/mod_airpe/airpe_if_common.c	Mon Jan 12 17:24:44 2009
@@ -0,0 +1,770 @@
+/* 
+ * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ * Copyright (C) 2005/2006, Anthony Minessale II <anthmct at 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 mod_airpe.
+ *
+ * The Initial Developer of the Original Code is
+ * Massimo Cetra <devel at navynet.it>
+ *
+ * Portions created by the Initial Developer are Copyright (C)
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Thanks to gmaruzz for his work on skypiax (both * and freeswitch).
+ * Some of his code inspired this module
+ *
+ */
+
+#include "mod_airpe.h"
+
+static struct {
+    USER_STATUS 	status;
+    const char		*name;
+} user_status_names[] = {
+    { USER_STATUS_UNKNOWN,	"UNKNOWN" },
+    { USER_STATUS_ONLINE,	"ONLINE" },
+    { USER_STATUS_OFFLINE,	"OFFLINE" },
+    { USER_STATUS_SKYPEME,	"SKYPEME" },
+    { USER_STATUS_AWAY,		"AWAY" },
+    { USER_STATUS_NA,		"NA" },
+    { USER_STATUS_DND,		"DND" },
+    { USER_STATUS_INVISIBLE,	"INVISIBLE" },
+    { USER_STATUS_LOGGEDOUT,	"LOGGEDOUT" },
+};
+
+static struct {
+    CONN_STATUS 	status;
+    const char		*name;
+} connection_status_names[] = {
+    { CONN_STATUS_UNKNOWN,	"UNKNOWN" },
+    { CONN_STATUS_OFFLINE,	"OFFLINE" },
+    { CONN_STATUS_CONNECTING,	"CONNECTING" },
+    { CONN_STATUS_PAUSING,	"PAUSING" },
+    { CONN_STATUS_ONLINE,	"ONLINE" },
+};
+
+/* ************************************************************************* */
+
+const char *skype_user_status_string(USER_STATUS st) {
+    int t;
+    const char *ret = NULL;
+
+    for ( t = 0; t < sizeof(user_status_names) / sizeof(user_status_names[0]); t++ ) {
+	if ( user_status_names[t].status == st ) {
+	    ret = user_status_names[t].name;
+	    break;
+	}
+    }
+    return ret;
+}
+
+USER_STATUS skype_user_status(const char *str) {
+    int t;
+    USER_STATUS ret = USER_STATUS_UNKNOWN;
+
+    for ( t = 0; t < sizeof(user_status_names) / sizeof(user_status_names[0]); t++ ) {
+	if ( !strncasecmp(user_status_names[t].name, str, strlen(user_status_names[t].name) ) ) {
+	    ret = user_status_names[t].status;
+	    break;
+	}
+    }
+    return ret;
+}
+
+/* ************************************************************************* */
+
+const char *skype_conn_status_string(CONN_STATUS st) {
+    int t;
+    const char *ret = NULL;
+
+    for ( t = 0; t < sizeof(connection_status_names) / sizeof(connection_status_names[0]); t++ ) {
+	if ( connection_status_names[t].status == st ) {
+	    ret = connection_status_names[t].name;
+	    break;
+	}
+    }
+    return ret;
+}
+
+CONN_STATUS skype_conn_status(const char *str) {
+    int t;
+    CONN_STATUS ret = CONN_STATUS_UNKNOWN;
+
+    for ( t = 0; t < sizeof(connection_status_names) / sizeof(connection_status_names[0]); t++ ) {
+	if ( !strncasecmp(connection_status_names[t].name, str, strlen(connection_status_names[t].name) ) ) {
+	    ret = connection_status_names[t].status;
+	    break;
+	}
+    }
+    return ret;
+}
+
+/* ************************************************************************* */
+
+switch_status_t	airpe_set_version(airpe_interface_t *airpe, char *string) {
+    assert(airpe);
+    switch_safe_free(airpe->skype_version);
+    if ( string )
+	airpe->skype_version = strdup(string);
+    return SWITCH_STATUS_SUCCESS;
+}
+
+switch_status_t	airpe_set_mood_text(airpe_interface_t *airpe, char *string) {
+    assert(airpe);
+    switch_safe_free(airpe->mood_text);
+    if ( string )
+        airpe->mood_text = strdup(string);
+    return SWITCH_STATUS_SUCCESS;
+}
+
+switch_status_t	airpe_set_partner_displayname(airpe_interface_t *airpe, char *string) {
+    assert(airpe);
+    switch_safe_free(airpe->partner_displayname);
+    if ( string )
+	airpe->partner_displayname = strdup(string);
+    return SWITCH_STATUS_SUCCESS;
+}
+
+switch_status_t	airpe_set_partner_handle(airpe_interface_t *airpe, char *string) {
+    assert(airpe);
+    switch_safe_free(airpe->partner_handle);
+    if ( string )
+	airpe->partner_handle = strdup(string);
+    return SWITCH_STATUS_SUCCESS;
+}
+
+switch_status_t airpe_cmd_write(airpe_interface_t *airpe, char *msg) {
+    if ( airpe->debug )
+	switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "msg to airpe client %s: %s\n", airpe->name, msg);
+    return airpe_skype_send_message(airpe->skype_window, msg);
+}
+
+switch_status_t airpe_originate(airpe_interface_t *airpe, char *dest) {
+    char msg[SKYPE_MSG_LEN];
+
+    /*
+    Those commands are outdated and shouldn't be used
+    Documented so that no one adds them.
+    airpe_cmd_write(p, "SET AGC OFF");
+    airpe_cmd_write(p, "SET AEC OFF");
+    */
+    switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "airpe client %s: Originating to %s\n", airpe->name, dest);
+
+    snprintf(msg, sizeof(msg), "CALL %s", dest);
+
+    if ( (airpe_cmd_write(airpe, msg) != SWITCH_STATUS_SUCCESS) ) {
+	return SWITCH_STATUS_FALSE;
+    }
+
+    return SWITCH_STATUS_SUCCESS;
+}
+
+switch_status_t airpe_explicit_hangup(airpe_interface_t *airpe) {
+    char buf[SKYPE_MSG_LEN];
+
+    if ( airpe->active_call_id > 0 ) {
+	snprintf(buf, sizeof(buf), "SET CALL %d STATUS FINISHED", airpe->active_call_id);
+	return airpe_cmd_write(airpe, buf);
+    }
+    return SWITCH_STATUS_FALSE;
+}
+
+
+
+/*****************************************************************************
+    SKYPE AUDIO
+ *****************************************************************************/
+
+switch_status_t airpe_hangup( private_object_t *pvt ) {
+    airpe_interface_t *airpe;
+
+    assert(pvt);
+    assert(pvt->session);
+    assert(pvt->airpe);
+    
+    airpe = pvt->airpe;
+
+    if ( airpe->audio_in_active_socket ) {
+	switch_socket_shutdown(airpe->audio_in_active_socket, SWITCH_SHUTDOWN_READWRITE);
+	switch_socket_close(airpe->audio_in_active_socket);
+	airpe->audio_in_active_socket = 0;
+    }
+
+    if ( airpe->audio_out_active_socket ) {
+	switch_socket_shutdown(airpe->audio_out_active_socket, SWITCH_SHUTDOWN_READWRITE);
+	switch_socket_close(airpe->audio_out_active_socket);
+	airpe->audio_out_active_socket = 0;
+    }
+
+    airpe->tech_pvt = NULL;
+
+    return SWITCH_STATUS_SUCCESS;
+}
+
+switch_status_t airpe_audio_write( private_object_t *pvt, switch_frame_t *frame ) {
+    switch_socket_t *inbound_socket = NULL;
+    switch_memory_pool_t *pool;
+    airpe_interface_t *airpe;
+    switch_status_t rv;
+    switch_size_t mlen;
+    char *mbuf;
+
+    assert(pvt);
+    assert(pvt->session);
+    assert(pvt->airpe);
+    
+    airpe = pvt->airpe;
+    pool = switch_core_session_get_pool(pvt->session);
+
+    if ( !airpe->audio_in_active_socket ) {
+	rv = switch_socket_accept(&inbound_socket, airpe->audio_in_socket, pool);
+        if ( rv == SWITCH_STATUS_SUCCESS ) {
+	    airpe->audio_in_active_socket = inbound_socket;
+	    switch_sleep(100000);
+	}
+	else {
+	    return SWITCH_STATUS_FALSE;
+	}
+    }
+
+    mbuf = frame->data;
+    mlen = frame->datalen;
+    rv = switch_socket_send(airpe->audio_in_active_socket, mbuf, &mlen);
+
+    return rv;
+}
+
+switch_status_t airpe_audio_read( private_object_t *pvt ) {
+    switch_socket_t *inbound_socket = NULL;
+    switch_memory_pool_t *pool;
+    airpe_interface_t *airpe;
+    switch_status_t rv;
+    switch_size_t mlen;
+    char *ptr;
+
+    assert(pvt);
+    assert(pvt->session);
+    assert(pvt->airpe);
+    
+    airpe = pvt->airpe;
+    pool = switch_core_session_get_pool(pvt->session);
+
+    if ( !airpe->audio_out_active_socket ) {
+	rv = switch_socket_accept(&inbound_socket, airpe->audio_out_socket, pool);
+        if ( rv == SWITCH_STATUS_SUCCESS ) {
+	    airpe->audio_out_active_socket = inbound_socket;
+	    switch_sleep(100000);
+	}
+	else {
+	    return SWITCH_STATUS_FALSE;
+	}
+    }
+
+    pvt->read_frame.datalen = 0;
+    ptr = pvt->read_frame.data;
+    mlen = sizeof(pvt->databuf);
+    rv = switch_socket_recv(airpe->audio_out_active_socket, ptr, &mlen);
+
+    if ( (rv==SWITCH_STATUS_SUCCESS) ) {
+	    pvt->read_frame.datalen = mlen;
+    }
+//    if ( mlen == 0 )
+//	return SWITCH_STATUS_SUCCESS;
+
+    return rv;
+}
+
+/*****************************************************************************
+    SKYPE CONTROL MESSAGES
+ *****************************************************************************/
+
+static switch_status_t airpe_manage_incoming_call( airpe_interface_t *airpe, int callid ) {
+    char chan_name[256];
+    switch_channel_t *channel = NULL;
+    switch_core_session_t *new_session = NULL;
+    private_object_t *tech_pvt = NULL;
+
+    new_session = airpe_request_session(NULL);
+    if ( !new_session ) {
+	return SWITCH_STATUS_FALSE;
+    }
+
+    switch_core_session_add_stream(new_session, NULL);
+
+    tech_pvt = (private_object_t *) switch_core_session_alloc(new_session, sizeof(private_object_t));
+    if ( !tech_pvt ) {
+	switch_core_session_destroy(&new_session);
+	return SWITCH_STATUS_FALSE;
+    }
+    memset(tech_pvt, 0, sizeof(private_object_t));
+
+    channel = switch_core_session_get_channel(new_session);
+    assert(channel);
+
+    if ( airpe_tech_init(tech_pvt, new_session) != SWITCH_STATUS_SUCCESS ) {
+	switch_core_session_destroy(&new_session);
+	return SWITCH_STATUS_FALSE;
+    }
+    tech_pvt->airpe = airpe;
+
+    switch_snprintf(chan_name, sizeof(chan_name), MODNAME"/%s", airpe->name);
+    switch_channel_set_name(channel, chan_name);
+
+    tech_pvt->caller_profile = switch_caller_profile_new( switch_core_session_get_pool(new_session),
+                                    	    airpe->name, 	/* Username */
+					    airpe->dialplan,	/* Diaplan */
+					    airpe->partner_displayname,	/* cid_name */
+                                    	    airpe->partner_handle, 	/* cid_number */
+					    NULL, 		/* network_addr */
+					    NULL,		/* ani */
+                                            NULL, 		/* aniii */
+					    NULL, 		/* rdnis */
+					    MODNAME, 		/* source */
+					    airpe->context,	/* context */
+                                    	    airpe->destination	/* destination_number */
+					);
+
+    if ( !tech_pvt->caller_profile ) {
+	switch_core_session_destroy(&new_session);
+	return SWITCH_STATUS_FALSE;
+    }
+    else
+	switch_channel_set_caller_profile(channel, tech_pvt->caller_profile);
+
+
+    switch_set_flag(tech_pvt, TFLAG_INBOUND);
+    airpe->active_call_id = callid;
+    switch_channel_set_state(channel, CS_INIT);
+
+    if ( switch_core_session_thread_launch(new_session) != SWITCH_STATUS_SUCCESS ) {
+	airpe->active_call_id = 0;
+    	switch_core_session_destroy(&new_session);
+	return SWITCH_STATUS_FALSE;
+    }
+
+    return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status_t airpe_manage_call_status( airpe_interface_t *airpe, int callid, const char *status ) {
+    char buf[SKYPE_MSG_LEN];
+    switch_core_session_t *session = NULL;
+    switch_channel_t *channel = NULL;
+
+    if ( airpe->active_call_id && airpe->active_call_id != callid ) {
+ADEBUG("CASE 1 - different call\n");
+	if      ( !strncmp(status, "UNPLACED", strlen("UNPLACED")) ) {	    
+	    snprintf(buf, sizeof(buf), "SET CALL %d STATUS FINISHED", callid);
+	    airpe_cmd_write(airpe, buf);
+	}
+	else {
+	    ADEBUG("*** (%d/%d) Unmanaged status %s\n", airpe->active_call_id, callid, status);
+	}
+
+    }
+    else if ( airpe->active_call_id && airpe->active_call_id == callid ) {
+ADEBUG("CASE 2 - my call\n");
+	if ( airpe->tech_pvt ) {
+	    assert(airpe->tech_pvt);
+	    session = airpe->tech_pvt->session;
+	    assert(session);
+
+	    channel = switch_core_session_get_channel(session);
+    	    assert(channel);
+	}
+
+	if ( !strncmp(status, "ROUTING", strlen("ROUTING")) ) {
+	}
+	else if ( !strncmp(status, "RINGING", strlen("RINGING")) ) {
+	    //if ( switch_test_flag(tech_pvt, TFLAG_OUTBOUND) ) {
+		//switch_channel_set_state(channel, CS_RINGING);
+	    switch_core_session_queue_indication(session, SWITCH_MESSAGE_INDICATE_RINGING);
+	    switch_channel_mark_ring_ready(channel);
+	    //}
+
+	    snprintf(buf, sizeof(buf), "ALTER CALL %d SET_INPUT PORT=\"%d\"", callid, airpe->audio_in_port);
+	    airpe_cmd_write(airpe, buf);
+	    snprintf(buf, sizeof(buf), "ALTER CALL %d SET_OUTPUT PORT=\"%d\"", callid, airpe->audio_out_port);
+	    airpe_cmd_write(airpe, buf);
+
+
+
+	    switch_channel_set_state(channel, CS_ROUTING);
+
+	}
+	else if ( !strncmp(status, "INPROGRESS", strlen("INPROGRESS")) ) {
+	    snprintf(buf, sizeof(buf), "ALTER CALL %d STOP_VIDEO_SEND", callid );
+	    airpe_cmd_write(airpe, buf);
+	    snprintf(buf, sizeof(buf), "ALTER CALL %d STOP_VIDEO_RECEIVE", callid );
+	    airpe_cmd_write(airpe, buf);
+
+	    if ( channel ) {
+	        switch_channel_mark_answered(channel);
+	    }
+	    else {
+		if ( airpe_manage_incoming_call(airpe, callid) != SWITCH_STATUS_SUCCESS ) {
+		    snprintf(buf, sizeof(buf), "ALTER CALL %d END HANGUP", callid );
+		    airpe_cmd_write(airpe, buf);
+		    airpe->active_call_id = 0;
+		}
+	    }
+	}
+	else if ( !strncmp(status, "FINISHED", strlen("FINISHED")) ) {
+	    if ( channel )
+	        switch_channel_hangup(channel, SWITCH_CAUSE_NORMAL_CLEARING);
+	    airpe->active_call_id = 0;
+	}
+	else if ( !strncmp(status, "FAILED", strlen("FAILED")) ) {
+	    if ( channel )
+	        switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
+	    airpe->active_call_id = 0;
+	}
+	else if ( !strncmp(status, "CANCELLED", strlen("CANCELLED")) ) {
+	    if ( channel )
+	        switch_channel_hangup(channel, SWITCH_CAUSE_ORIGINATOR_CANCEL);
+	    airpe->active_call_id = 0;
+	}
+	else if ( !strncmp(status, "REFUSED", strlen("REFUSED")) ) {
+	    if ( channel )
+	        switch_channel_hangup(channel, SWITCH_CAUSE_CALL_REJECTED);
+	    airpe->active_call_id = 0;
+	}
+	else if ( !strncmp(status, "MISSED", strlen("MISSED")) ) {
+	    if ( channel )
+	        switch_channel_hangup(channel, SWITCH_CAUSE_NO_ANSWER);
+	    airpe->active_call_id = 0;
+	}
+	else if ( !strncmp(status, "UNPLACED", strlen("UNPLACED")) ) {
+	}
+	else {
+ADEBUG("Unmanaged status \n");
+	}
+    }
+    else {
+ADEBUG("CASE 3 - no calls online\n");
+	if      ( !strncmp(status, "UNPLACED", strlen("UNPLACED")) ) {	    
+	    airpe->active_call_id = callid;
+	}
+	else if ( !strncmp(status, "RINGING", strlen("RINGING")) ) {
+	    airpe->active_call_id = callid;
+	    snprintf(buf, sizeof(buf), "ALTER CALL %d ANSWER", callid );
+	    airpe_cmd_write(airpe, buf);
+	}
+	else {
+	    ADEBUG("--- (%d/%d) Unmanaged status %s\n", airpe->active_call_id, callid, status);
+	}
+    }
+
+    return SWITCH_STATUS_SUCCESS;
+}
+
+switch_status_t airpe_manage_skype_msg( airpe_interface_t *airpe, const char *msg ) {
+    char *buf = NULL;
+    int argc = 0;
+    char *argv[9] = { 0 };
+
+    assert(airpe);
+    assert(msg);
+
+    if ( airpe->debug )
+	switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "airpe client %s: %s\n", airpe->name, msg);
+
+    buf = strdup(msg);
+    argc = switch_separate_string(buf, ' ', argv, (sizeof(argv) / sizeof(argv[0])));
+
+    if ( argc == 0 ) {
+	switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "airpe client %s: %s - Message without arguments? uh?\n", airpe->name, msg);
+	free(buf);
+	return  SWITCH_STATUS_FALSE;
+    }
+
+
+
+    if      ( !strncmp( buf, "CURRENTUSERHANDLE", strlen("CURRENTUSERHANDLE")) ) {
+	/* The username that the client is using. */
+	// TODO ... if the user handle mismatches, disconnect the channel or simply disable
+	// all operations
+    }
+    else if ( !strncmp( buf, "USERSTATUS", strlen("USERSTATUS")) && argc > 1 ) {
+	/* The status of the user of the client (ex: NA, ONLINE) */
+	airpe->user_status = skype_user_status(argv[1]);
+    }
+    else if ( !strncmp( buf, "PROTOCOL", strlen("PROTOCOL")) && argc > 1 ) {
+	/* The protocol of the client */
+	airpe->protocol = atoi(argv[1]);
+    }
+    else if ( !strncmp( buf, "CLEAR", strlen("CLEAR")) ) {
+	/* something has been cleared in the UI - Ignored */
+    }
+    else if ( !strncmp( buf, "PONG", strlen("PONG")) ) {
+	/* keepalive */
+	airpe_skype_watchdog_reset(airpe->skype_window);
+    }
+    else if ( !strncmp( buf, "CONNSTATUS", strlen("CONNSTATUS")) && argc >= 2 ) {
+	/* The connection status of the client (ex: ONLINE) */
+	airpe->conn_status = skype_conn_status( argv[1] );
+    }
+    else if ( !strncmp( buf, "USER", strlen("USER")) ) {
+	/* Updates about the users of our list - ignored */
+    }
+    else if ( !strncmp( buf, "GROUP", strlen("GROUP")) ) {
+	/* Updates about the groups of our list - ignored */
+    }
+    else if ( !strncmp( buf, "CONTACTS", strlen("CONTACTS")) ) {
+	/* Other messages referring to the contact list - ignored */
+    }
+    else if ( !strncmp( buf, "OK", strlen("OK")) ) {
+	/* Acknowledge - ignored */
+    }
+    else if ( !strncmp( buf, "AUTOAWAY", strlen("AUTOAWAY")) ) {
+	/* Autoaway - ignored */
+    }
+//TODO: RECEIVEDAUTHREQUEST - Add a config option to authorize or forget about it.
+    else if ( !strncmp( buf, "MUTE", strlen("MUTE")) && argc >= 2 ) {
+	if ( !strncmp(argv[1], "ON", 2) ) { 
+	    switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "airpe client %s: I don't like to be muted...\n", airpe->name);
+	    airpe_cmd_write(airpe, "MUTE OFF");
+	}
+    }
+    else if ( !strncmp( buf, "CHATMESSAGE", strlen("CHATMESSAGE")) ) {
+	/* a message has been received (unknown content) - ignored */
+    }
+    else if ( !strncmp( buf, "CHAT", strlen("CHAT")) && argc >=2 ) {
+	/* Chat status - ignored. */
+	if ( airpe->protocol > 6 ) {
+	    //TODO : ALTER CHAT <chat_id> DISBAND - Doesn't seems to work on linux
+	    char buf[SKYPE_MSG_LEN] = "";
+	    snprintf(buf, sizeof(buf), "ALTER CHAT %s DISBAND", argv[1]);
+	    airpe_cmd_write(airpe, buf);
+	}
+    }
+    else if ( !strncmp( buf, "CHATMEMBER", strlen("CHATMEMBER")) ) {
+	/* Informations about the chat members - ignored */
+    }
+    else if ( !strncmp( buf, "PROFILE", strlen("PROFILE")) && argc >= 2 ) {
+	if ( !strncmp(argv[1], "MOOD_TEXT", strlen("MOOD_TEXT")) ) {
+	    char *tmp = NULL;
+	    char *mood;
+	    tmp = strdup(msg);
+	    if ( tmp  ) {
+		mood = strstr(tmp, "PROFILE MOOD_TEXT ");
+		if ( mood ) {
+		    mood += strlen("PROFILE MOOD_TEXT ");
+		    airpe_set_mood_text(airpe, mood);
+		}
+		switch_safe_free(tmp);
+	    }
+	}
+    }
+    else if ( !strncmp( buf, "SKYPEVERSION", strlen("SKYPEVERSION")) ) {
+	airpe_set_version(airpe, argv[1]);
+    }
+    else if ( !strncmp( buf, "CALL", strlen("CALL")) && argc >= 3 ) {
+	char *cmd = argv[2];
+	int callid = atoi(argv[1]);
+
+	if ( !strncmp(cmd, "DURATION", strlen("DURATION")) ) {
+	    /* Ignore the duration that is updated every second */
+	    if ( callid != airpe->active_call_id ) {
+		char buf[SKYPE_MSG_LEN] = "";
+		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "airpe client %s: hanging up unknown call id %d\n", airpe->name, callid);
+		snprintf(buf, sizeof(buf), "SET CALL %d STATUS FINISHED", callid);
+		airpe_cmd_write(airpe, buf);
+	    }
+	    //TODO: maybe we could consider this message as a keepalive signal
+	}
+	else if ( !strncmp(cmd, "STATUS", strlen("STATUS")) && argc >=4 ) {
+	    char *callstatus = argv[3];
+	    airpe_manage_call_status( airpe, callid, callstatus );
+	}
+	else if ( !strncmp(cmd, "CONF_ID", strlen("CONF_ID")) ) {
+	    char buf[SKYPE_MSG_LEN];
+
+	    if ( !airpe->active_call_id ) {
+		airpe_set_partner_displayname(airpe, NULL);
+		airpe_set_partner_handle(airpe, NULL);
+
+		snprintf(buf, sizeof(buf), "GET CALL %d PARTNER_DISPNAME", callid);
+		airpe_cmd_write(airpe, buf);
+
+		snprintf(buf, sizeof(buf), "GET CALL %d PARTNER_HANDLE", callid);
+		airpe_cmd_write(airpe, buf);
+
+		airpe_cmd_write(airpe, "PING");
+	    }
+	    else {
+		snprintf(buf, sizeof(buf), "ALTER CALL %d END HANGUP", callid );
+		airpe_cmd_write(airpe, buf);
+	    }
+	}
+	else if ( !strncmp(cmd, "VAA_INPUT_STATUS", strlen("VAA_INPUT_STATUS")) ) {
+	    /* Let's ignore */
+	}
+	else if ( !strncmp(cmd, "DTMF", strlen("DTMF")) ) {
+	    /* This is an incoming DTMF */
+	    switch_core_session_t *session;
+	    switch_channel_t *channel;
+	    switch_dtmf_t dtmf = { 0, switch_core_default_dtmf_duration(0) };
+	    const char *signal_ptr;
+	    int tmp;
+
+	    assert(airpe->tech_pvt);
+    	    session = airpe->tech_pvt->session;
+	    assert(session);
+	    channel = switch_core_session_get_channel(session);
+	    assert(channel);
+
+	    signal_ptr = argv[3];
+
+	    if (*signal_ptr && (*signal_ptr == '*' || *signal_ptr == '#' || *signal_ptr == 'A' || *signal_ptr == 'B' || *signal_ptr == 'C' || *signal_ptr == 'D')) {
+		dtmf.digit = *signal_ptr;
+	    } else {
+		tmp = atoi(signal_ptr);
+		dtmf.digit = switch_rfc2833_to_char(tmp);
+	    }
+
+	    switch_mutex_lock(airpe->tech_pvt->flag_mutex);
+	    switch_channel_queue_dtmf(channel, &dtmf);
+	    switch_mutex_unlock(airpe->tech_pvt->flag_mutex);
+	}
+	else if ( !strncmp(cmd, "FAILUREREASON", strlen("FAILUREREASON")) && argc >=2 ) {
+	    airpe->last_fail_reason = atoi(argv[1]);
+	    airpe_cmd_write(airpe, "CLEAR CALLHISTORY ALL");
+	}
+	else if ( !strncmp(cmd, "SEEN", strlen("SEEN")) && argc >=4 ) {
+	    /*
+	    char buf[SKYPE_MSG_LEN] = "";
+	    char *seenstatus = argv[3];
+	    if ( !strncmp(seenstatus, "FALSE", strlen("FALSE")) ) {
+		snprintf(buf, sizeof(buf), "SET CALL %d SEEN", callid);
+	        airpe_cmd_write(airpe, buf);
+	    }
+	    */
+	    airpe_cmd_write(airpe, "CLEAR CALLHISTORY ALL");
+	}
+	else if ( !strncmp(cmd, "PARTNER_DISPNAME", strlen("PARTNER_DISPNAME")) && argc >=2 ) {
+	    char *data, *tmp = NULL;
+	    tmp = strdup(msg);
+	    if ( tmp && (callid == airpe->active_call_id) ) {
+		data = strstr(tmp, "PARTNER_DISPNAME ");
+		if ( data ) {
+		    data += strlen("PARTNER_DISPNAME ");
+		    airpe_set_partner_displayname(airpe, data);
+		}
+	    }
+	    switch_safe_free(tmp);
+	}
+	else if ( !strncmp(cmd, "PARTNER_HANDLE", strlen("PARTNER_HANDLE")) && argc >=2 ) {
+	    char *data, *tmp = NULL;
+	    tmp = strdup(msg);
+	    if ( tmp && (callid == airpe->active_call_id) ) {
+		data = strstr(tmp, "PARTNER_HANDLE ");
+		if ( data ) {
+		    data += strlen("PARTNER_HANDLE ");
+		    airpe_set_partner_handle(airpe, data);
+		}
+		switch_safe_free(tmp);
+	    }
+	}
+	else {
+	    switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "CALL ID %d\n", callid);
+	}
+    }
+    else if ( !strncmp( buf, "DTMF", strlen("DTMF")) && argc>3 ) {
+	/* We are alerted that a DTMF we was sent to the other party - Ignored */
+    }
+    else if ( !strncmp( msg, "ERROR 68", strlen("ERROR 68")) ) {
+	/* The client needs authorization. Probably we reconnected to a new skype window. */
+	switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Airpe client %s needs authorization.\n", airpe->name);
+	switch_sleep(1000000);
+	airpe_on_connect_messages(airpe, airpe->protocol);
+    }
+    else if ( !strncmp( msg, "ALTER CALL", strlen("ALTER CALL")) ) {
+	/* The response to our hangup - Ignored */
+    }
+    else if ( !strncmp( msg, "SET CALL", strlen("SET CALL")) ) {
+	/* Ignoring by now */
+    }
+    else if ( !strncmp( buf, "ERROR", strlen("ERROR")) ) {
+	//TODO If we are in the middle of a call, hangup
+    }
+    else {
+	switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Unmanaged message\n");
+    }
+
+    switch_safe_free(buf);
+
+    return SWITCH_STATUS_SUCCESS;
+}
+
+switch_status_t airpe_on_connect_messages( airpe_interface_t *airpe, int protocol ) {
+	char buf[SKYPE_MSG_LEN] = "";
+
+	snprintf(buf, sizeof(buf), "NAME airpe");
+	if ( airpe_cmd_write(airpe, buf) != SWITCH_STATUS_SUCCESS )
+    	    return SWITCH_STATUS_FALSE;
+	snprintf(buf, sizeof(buf), "PROTOCOL %d", protocol);
+	if ( airpe_cmd_write(airpe, buf) != SWITCH_STATUS_SUCCESS )
+    	    return SWITCH_STATUS_FALSE;
+	snprintf(buf, sizeof(buf), "CLEAR CALLHISTORY ALL");
+	if ( airpe_cmd_write(airpe, buf) != SWITCH_STATUS_SUCCESS )
+    	    return SWITCH_STATUS_FALSE;
+	snprintf(buf, sizeof(buf), "CLEAR CHATHISTORY");
+	if ( airpe_cmd_write(airpe, buf) != SWITCH_STATUS_SUCCESS )
+    	    return SWITCH_STATUS_FALSE;
+	snprintf(buf, sizeof(buf), "GET SKYPEVERSION");
+	if ( airpe_cmd_write(airpe, buf) != SWITCH_STATUS_SUCCESS )
+    	    return SWITCH_STATUS_FALSE;
+	snprintf(buf, sizeof(buf), "GET PROFILE MOOD_TEXT");
+	if ( airpe_cmd_write(airpe, buf) != SWITCH_STATUS_SUCCESS )
+    	    return SWITCH_STATUS_FALSE;
+	snprintf(buf, sizeof(buf), "GET PROFILE FULLNAME");
+	if ( airpe_cmd_write(airpe, buf) != SWITCH_STATUS_SUCCESS )
+    	    return SWITCH_STATUS_FALSE;
+	snprintf(buf, sizeof(buf), "GET CONNSTATUS");
+	if ( airpe_cmd_write(airpe, buf) != SWITCH_STATUS_SUCCESS )
+    	    return SWITCH_STATUS_FALSE;
+	snprintf(buf, sizeof(buf), "SET AUTOAWAY OFF");
+	if ( airpe_cmd_write(airpe, buf) != SWITCH_STATUS_SUCCESS )
+    	    return SWITCH_STATUS_FALSE;
+	snprintf(buf, sizeof(buf), "SET MUTE OFF");
+	if ( airpe_cmd_write(airpe, buf) != SWITCH_STATUS_SUCCESS )
+    	    return SWITCH_STATUS_FALSE;
+
+	/* 
+	    The following two raise an error on linux, even if are supported from protocol 6 upwards.
+	    That's not a big problem so we'll send them.
+	 */
+
+	snprintf(buf, sizeof(buf), "SET PCSPEAKER OFF");
+	if ( airpe_cmd_write(airpe, buf) != SWITCH_STATUS_SUCCESS )
+    	    return SWITCH_STATUS_FALSE;
+	snprintf(buf, sizeof(buf), "SET SILENT_MODE ON");
+	if ( airpe_cmd_write(airpe, buf) != SWITCH_STATUS_SUCCESS )
+    	    return SWITCH_STATUS_FALSE;
+
+	return SWITCH_STATUS_SUCCESS;
+}
+
+/* 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/ctrix/mod_airpe/airpe_if_osx.c
==============================================================================
--- (empty file)
+++ freeswitch/branches/ctrix/mod_airpe/airpe_if_osx.c	Mon Jan 12 17:24:44 2009
@@ -0,0 +1,19 @@
+
+#include "mod_airpe.h"
+
+#if defined (MACOSX) || defined(DARWIN)
+
+#error OSX Not yet supported
+
+#endif
+
+/* 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/ctrix/mod_airpe/airpe_if_win32.c
==============================================================================
--- (empty file)
+++ freeswitch/branches/ctrix/mod_airpe/airpe_if_win32.c	Mon Jan 12 17:24:44 2009
@@ -0,0 +1,19 @@
+
+#include "mod_airpe.h"
+
+#ifdef WIN32
+
+#error WIN32 Not yet supported
+
+#endif
+
+/* 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/ctrix/mod_airpe/airpe_if_x11.c
==============================================================================
--- (empty file)
+++ freeswitch/branches/ctrix/mod_airpe/airpe_if_x11.c	Mon Jan 12 17:24:44 2009
@@ -0,0 +1,355 @@
+/* 
+ * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ * Copyright (C) 2005/2006, Anthony Minessale II <anthmct at 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 mod_airpe.
+ *
+ * The Initial Developer of the Original Code is
+ * Massimo Cetra <devel at navynet.it>
+ *
+ * Portions created by the Initial Developer are Copyright (C)
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Thanks to gmaruzz for his work on skypiax (both * and freeswitch).
+ * Some of his code inspired this module
+ *
+ */
+
+#if defined (__GNUC__) && !(defined (MACOSX) || defined(DARWIN) ) 
+    
+#include "mod_airpe.h"
+
+#include <X11/Xlib.h>
+#include <X11/Xlibint.h>
+#include <X11/Xatom.h>
+
+#define X11_MSG_LEN	20
+
+struct skype_window_handler_s {
+    Display 	*disp;
+    Window 	win;
+    uint8_t	api_connected;
+    int 	fdesc[2];
+    Window 	skype_win;
+    int		watchdog;
+};
+
+
+
+
+static XErrorHandler old_handler = 0;
+static int xerror = 0;
+
+static int xerrhandler(Display *dpy, XErrorEvent *err)
+{
+    xerror = err->error_code;
+    /* Return 0 so that the error is ignored */
+    return 0; 
+}
+
+static void trap_errors()
+{
+    xerror = 0;
+    old_handler = XSetErrorHandler(xerrhandler);
+}
+
+static int untrap_errors()
+{
+    XSetErrorHandler(old_handler);
+    return (xerror != BadValue) && (xerror != BadWindow);
+}
+
+switch_status_t airpe_skype_watchdog_reset(skype_window_handler_t *window) {
+    window->watchdog = 0;
+    return SWITCH_STATUS_SUCCESS;
+}
+
+switch_status_t airpe_skype_watchdog_increment(skype_window_handler_t *window) {
+    window->watchdog++;
+
+    if ( window->watchdog >= 5 ) {
+    }
+
+    return SWITCH_STATUS_SUCCESS;
+}
+
+skype_window_handler_t *skype_window_alloc( switch_memory_pool_t *pool) {
+    return switch_core_alloc( pool, sizeof(skype_window_handler_t));
+}
+
+switch_status_t skype_restart( skype_window_handler_t *window, const char *params ) {
+
+    switch_log_printf(	SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, 
+			"HEY! where is my skype window gone ? Restarting skype for client...\n");
+/*
+
+    TODO AND TO USE
+
+    int fid;
+    const char *args[] = { "skype", "--actiondispatch", params, 0 };
+
+    if((fid = fork()) == 0) {
+	if(execvp("skype", (char *const*)args) == -1) {
+	    switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "airpe client: cannot launch Skype, error %d: %s.\n", errno, strerror(errno) );
+	    return SWITCH_STATUS_FALSE;
+	}
+    }
+    else if(fid == -1) {
+	switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "airpe client: cannot launch Skype.\n");
+	return SWITCH_STATUS_FALSE;
+    }
+*/
+    return SWITCH_STATUS_SUCCESS;
+}
+
+switch_status_t airpe_skype_send_message(skype_window_handler_t *window, const char *message_P) {
+    Window w_P;
+    Display *disp;
+    Window handle_P;
+    Atom atom1;
+    Atom atom2;
+    unsigned int pos;
+    unsigned int len;
+    XEvent xev;
+    int ok;
+
+    w_P 	= window->skype_win;
+    disp 	= window->disp;
+    handle_P 	= window->win;
+
+    atom1 = XInternAtom(disp, "SKYPECONTROLAPI_MESSAGE_BEGIN", False);
+    atom2 = XInternAtom(disp, "SKYPECONTROLAPI_MESSAGE", False);
+    pos = 0;
+    len = strlen(message_P);
+
+    memset(&xev, 0, sizeof(XEvent));
+    xev.xclient.type 		= ClientMessage;
+    xev.xclient.message_type 	= atom1;
+    xev.xclient.display 	= disp;
+    xev.xclient.window 		= handle_P;
+    xev.xclient.format 		= 8;
+
+    trap_errors();
+    do {
+	unsigned int i;
+	for (i = 0; i < 20 && i + pos <= len; ++i)
+    	    xev.xclient.data.b[i] = message_P[i + pos];
+	XSendEvent(disp, w_P, False, 0, &xev);
+
+	xev.xclient.message_type = atom2;
+	pos += i;
+    } while (pos <= len);
+
+    XSync(disp, False);
+    ok = untrap_errors();
+    if (!ok) { 
+	switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "airpe client X11 error.\n");
+	airpe_skype_avalaible(window);
+    }
+    return SWITCH_STATUS_SUCCESS;
+}
+
+switch_status_t airpe_skype_avalaible(skype_window_handler_t *window)
+{
+
+    Atom skype_inst;
+    Atom type_ret;
+    int format_ret;
+    unsigned long nitems_ret;
+    unsigned long bytes_after_ret;
+    unsigned char *prop;
+    int status, ok;
+
+    skype_inst = XInternAtom(window->disp, "_SKYPE_INSTANCE", True);
+
+    trap_errors();
+    status = XGetWindowProperty(
+			window->disp,
+        		DefaultRootWindow(window->disp), 
+			skype_inst, 
+			0, 
+			1,
+        		False, 
+			XA_WINDOW, 
+			&type_ret, 
+			&format_ret, 
+			&nitems_ret,
+        		&bytes_after_ret, &prop);
+
+    ok = untrap_errors();
+    if (!ok) { 
+	switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "airpe client X11 error.\n");
+	airpe_skype_avalaible(window);
+    }
+
+    /*  sanity check */
+    if (status != Success || format_ret != 32 || nitems_ret != 1) {
+	window->skype_win = (Window) - 1;
+	return SWITCH_STATUS_FALSE;
+    }
+
+    window->skype_win = *(const unsigned long *) prop & 0xffffffff;
+
+    return SWITCH_STATUS_SUCCESS;
+}
+
+
+
+/*****************************************************************************
+    THREADS
+ *****************************************************************************/
+
+void *SWITCH_THREAD_FUNC airpe_skype_thread(switch_thread_t * thread, void *obj) {
+
+    skype_window_handler_t *skype_window = NULL;
+    airpe_interface_t *airpe = NULL;
+    Display *disp = NULL;
+    Window root = -1;
+    Window win = -1;
+    int xfd;
+
+    assert(obj);
+
+    airpe = obj;
+
+    skype_window = airpe->skype_window;
+    assert(skype_window);
+
+    disp = XOpenDisplay(airpe->X11_display);
+    if (!disp) {
+	switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "airpe client %s: cannot open display %s\n", airpe->name, airpe->X11_display);
+	return NULL;
+    }
+
+    xfd = XConnectionNumber(disp);
+    fcntl(xfd, F_SETFD, FD_CLOEXEC);
+
+    skype_window->disp = disp;
+
+    if ( airpe_skype_avalaible(skype_window) == SWITCH_STATUS_SUCCESS ) {
+	root = DefaultRootWindow(disp);
+	win  = XCreateSimpleWindow(
+				disp, 
+				root, 
+				0, 0, 1, 1, 0,
+                        	BlackPixel(disp, DefaultScreen(disp)), 
+				BlackPixel(disp, DefaultScreen(disp))
+				);
+
+	skype_window->win = win;
+
+	if ( airpe_on_connect_messages( airpe, 6 ) != SWITCH_STATUS_SUCCESS ) {
+	    switch_log_printf(	SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, 
+				"airpe client %s. Failed to send handshake messages\n", 
+				airpe->name);
+    	    return NULL;
+	}
+
+	// perform an events loop
+	XEvent an_event;
+	char buf[X11_MSG_LEN + 2] = ""; 
+	char buffer[SKYPE_MSG_LEN] = "";
+	int i;
+	fd_set rset;
+	int x11_fd;
+	int empty_loops = 0;
+
+	airpe->running = 1;
+	XFlush(disp);
+        x11_fd = ConnectionNumber(disp);
+
+	while ( airpe->running ) {
+	    FD_ZERO(&rset);
+	    FD_SET( x11_fd, &rset);
+
+	    struct timeval timeout;
+	    int ret;
+
+	    timeout.tv_usec = 10 * 1000;
+	    ret = select(x11_fd+1, &rset, 0, 0, &timeout);
+
+	    if ( !airpe->running ) /* Quick way to skip the loop when we are signaled to exit. */
+		break;
+
+	    if ( ret <=0 ) {
+		empty_loops ++;
+		if ( empty_loops >= 250 ) {
+	            airpe_cmd_write(airpe, "PING");
+		    airpe_skype_watchdog_increment(skype_window);
+		    empty_loops = 0;
+		}
+		continue;
+	    }
+
+	    airpe_skype_watchdog_reset(skype_window);
+
+	    /* Process all the pending messages queued (not only one) */
+	    while ( XPending(disp) ) 
+	    {
+		XNextEvent(disp, &an_event);
+
+		switch (an_event.type) 
+	        {
+    		    case ClientMessage:
+			if (an_event.xclient.format != 8)
+        		    break;
+
+			for (i = 0; i < X11_MSG_LEN && an_event.xclient.data.b[i] != '\0'; ++i) {
+        		    buf[i] = an_event.xclient.data.b[i];
+			}
+    			buf[i] = '\0';
+
+			strcat(buffer, buf);
+
+			if (i < X11_MSG_LEN) { 
+			    unsigned int howmany;
+			    howmany = strlen(buffer) + 1;
+			    airpe_manage_skype_msg( airpe, buffer);
+			    memset(&buffer, 0, sizeof(buffer));
+			}
+    			break;
+		    default:
+			if ( airpe->debug )
+			    switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "airpe client %s: unknown event\n", airpe->name);
+			break;
+		}
+	    }
+	}
+
+	switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "airpe client %s: exiting thread\n", airpe->name);
+
+	/* Hangup our call, if we have one */
+	airpe_explicit_hangup(airpe);
+
+    } else {
+	switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "airpe client %s: skype not running on display %s\n", airpe->name, airpe->X11_display);
+    }
+
+  return NULL;
+}
+
+#endif
+
+/* 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/ctrix/mod_airpe/config/airpe.conf.xml
==============================================================================
--- (empty file)
+++ freeswitch/branches/ctrix/mod_airpe/config/airpe.conf.xml	Mon Jan 12 17:24:44 2009
@@ -0,0 +1,36 @@
+<configuration name="airpe.conf" description="Airpe Configuration">
+  <globals>
+    <param name="audio-tcp-port_start" value="21000"/>
+
+    <!-- Those params are used for all clients if not explicitly set for each one -->
+    <param name="context" value="public"/>
+    <param name="dialplan" value="XML"/>
+    <param name="destination" value="5000"/>
+  </globals>
+
+  <!-- one entry here per airpe client -->
+  <clients>
+    <client name="airpe1">
+	<!-- Print out as notices the client messages -->
+	<param name="debug" value="1"/>
+
+	<!-- Where our calls will land -->
+	<param name="dialplan" value="XML"/>
+	<param name="context" value="default"/>
+	<param name="destination" value="4321"/>
+
+	<!-- Linux only -->
+	<param name="X11-display" value=":101"/>
+
+	<!-- Not used yet -->
+	<param name="cid-name" value="Skype 1"/>
+	<param name="cid-num" value="0000001"/>
+
+	<!-- Not used... maybe should be removed. 
+	    The purpose is restarting the client with those credentials -->
+	<param name="skype-user" value="username"/>
+	<param name="skype-password" value="password"/>
+    </client>
+  </clients>
+
+</configuration>

Added: freeswitch/branches/ctrix/mod_airpe/mod_airpe.c
==============================================================================
--- (empty file)
+++ freeswitch/branches/ctrix/mod_airpe/mod_airpe.c	Mon Jan 12 17:24:44 2009
@@ -0,0 +1,868 @@
+/* 
+ * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ * Copyright (C) 2005/2006, Anthony Minessale II <anthmct at 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 mod_airpe.
+ *
+ * The Initial Developer of the Original Code is
+ * Massimo Cetra <devel at navynet.it>
+ *
+ * Portions created by the Initial Developer are Copyright (C)
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Thanks to gmaruzz for his work on skypiax (both * and freeswitch).
+ * Some of his code inspired this module
+ *
+ */
+
+#include "mod_airpe.h"
+
+/*****************************************************************************
+    MODULE PRIVATE STRUCTS && FUNCTIONS
+ *****************************************************************************/
+
+static switch_endpoint_interface_t *airpe_endpoint_interface;
+
+static struct {
+    char *dialplan;
+    char *context;
+    char *destination;
+    int  audio_tcp_port_start;
+
+    switch_mutex_t *mutex;
+    switch_hash_t  *interfaces_hash;
+    int  last_port_used;
+} globals;
+
+static switch_memory_pool_t *airpe_module_pool = NULL;
+
+
+airpe_interface_t *airpe_find_interface( const char *name) {
+    return switch_core_hash_find(globals.interfaces_hash, name);
+}
+
+
+/*****************************************************************************
+    TECH STUFF
+ *****************************************************************************/
+
+static switch_status_t airpe_codec_init(private_object_t * tech_pvt, int sample_rate, int codec_ms) {
+    airpe_interface_t *airpe = 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) {
+	switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "airpe client: %s - Cannot init read codec.\n", airpe->name);
+	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 ) {
+	switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "airpe client: %s - Cannot init write codec.\n", airpe->name);
+	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;
+
+    switch_core_session_set_read_codec(tech_pvt->session, &tech_pvt->read_codec);
+    switch_core_session_set_write_codec(tech_pvt->session, &tech_pvt->write_codec);
+
+    return SWITCH_STATUS_SUCCESS;
+}
+
+switch_status_t airpe_tech_init( private_object_t * tech_pvt, switch_core_session_t * session ) {
+
+    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);
+    tech_pvt->session = session;
+    return airpe_codec_init(tech_pvt, CODEC_SAMPLE_RATE, CODEC_INTERVAL_MS);
+}
+
+static switch_socket_t *airpe_socket_create( const char *host, int port ) {
+    switch_status_t rv;
+    switch_socket_t *new_sock = NULL;
+    switch_sockaddr_t *sa;
+
+    rv = switch_sockaddr_info_get(&sa, host, AF_INET, port, 0, airpe_module_pool);
+    if ( rv != SWITCH_STATUS_SUCCESS ) {
+	switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Socket Creation Error! (1)\n");
+	return NULL;
+    }
+
+    rv = switch_socket_create(&new_sock, AF_INET, SOCK_STREAM, SWITCH_PROTO_TCP, airpe_module_pool);
+    if ( rv != SWITCH_STATUS_SUCCESS ) {
+	switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Socket Creation Error! (2)\n");
+	return NULL;
+    }
+
+    rv = switch_socket_opt_set(new_sock, SWITCH_SO_REUSEADDR, 1);
+    if ( rv != SWITCH_STATUS_SUCCESS ) {
+	switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Socket Creation Error! (3)\n");
+	return NULL;
+    }
+
+    rv = switch_socket_opt_set(new_sock, SWITCH_SO_NONBLOCK, 1);
+    if ( rv != SWITCH_STATUS_SUCCESS ) {
+	switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Socket Creation Error! (3)\n");
+	return NULL;
+    }
+
+    rv = switch_socket_bind(new_sock, sa);
+    if ( rv != SWITCH_STATUS_SUCCESS ) {
+	switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Socket Creation Error! (4)\n");
+	return NULL;
+    }
+
+    rv = switch_socket_listen(new_sock, 5);
+    if ( rv != SWITCH_STATUS_SUCCESS ) {
+	switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Socket Creation Error! (5)\n");
+	return NULL;
+    }
+
+    return new_sock;
+}
+
+static int fetch_next_port(void) {
+    int port = 0;
+
+    if ( !globals.last_port_used )
+	globals.last_port_used = globals.audio_tcp_port_start;
+
+    switch_mutex_lock(globals.mutex);
+    port = globals.last_port_used;
+    globals.last_port_used++;
+    switch_mutex_unlock(globals.mutex);
+
+    return port;
+}
+
+static switch_status_t airpe_audio_sockets_create( airpe_interface_t *airpe ) {
+    switch_socket_t *new_sock;
+    int port;
+
+    new_sock = NULL;
+    while ( !new_sock ) {
+	port = fetch_next_port();
+	if ( airpe->debug )
+	    switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Assigning in port %d for client %s\n", port, airpe->name);
+	new_sock = airpe_socket_create("127.0.0.1", port);    
+	if ( new_sock ) {
+	    airpe->audio_in_socket = new_sock;
+	    airpe->audio_in_port   = port;
+	}
+    }
+
+    new_sock = NULL;
+    while ( !new_sock ) {
+	port = fetch_next_port();
+	if ( airpe->debug )
+	    switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Assigning out port %d for client %s\n", port, airpe->name);
+	new_sock = airpe_socket_create("127.0.0.1", port);    
+	if ( new_sock ) {
+	    airpe->audio_out_socket = new_sock;
+	    airpe->audio_out_port   = port;
+	}
+    }
+
+    return SWITCH_STATUS_SUCCESS;
+}
+
+
+static switch_status_t airpe_start_client(airpe_interface_t *airpe) {
+
+    switch_threadattr_t *attr_skype = NULL;
+
+    airpe->user_status = USER_STATUS_UNKNOWN;
+    airpe->conn_status = CONN_STATUS_UNKNOWN;
+    airpe->call_status = CALL_STATUS_UNKNOWN;
+
+    airpe_audio_sockets_create(airpe);
+
+    switch_threadattr_create(&attr_skype, airpe_module_pool);
+    //switch_threadattr_detach_set(attr_skype, 1);
+    switch_threadattr_stacksize_set(attr_skype, SWITCH_THREAD_STACKSIZE);
+
+    switch_thread_create(&airpe->airpe_thread_skype, 
+			attr_skype,
+                        airpe_skype_thread, 
+			airpe,
+                        airpe_module_pool);
+
+    return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status_t airpe_stop_client(airpe_interface_t *airpe) {
+
+    if ( airpe->audio_in_socket ) {
+	if ( airpe->debug )
+	    switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Shutting down socket on port %d for client %s\n", airpe->audio_in_port, airpe->name);
+	airpe->audio_in_port = 0;
+	switch_socket_shutdown(airpe->audio_in_socket, SWITCH_SHUTDOWN_READWRITE);
+	switch_socket_close(airpe->audio_in_socket);
+    }
+
+    if ( airpe->audio_out_socket ) {
+	if ( airpe->debug )
+	    switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Shutting down socket on port %d for client %s\n", airpe->audio_out_port, airpe->name);
+	airpe->audio_out_port = 0;
+	switch_socket_shutdown(airpe->audio_out_socket, SWITCH_SHUTDOWN_READWRITE);
+	switch_socket_close(airpe->audio_out_socket);
+    }
+
+    airpe_set_version(airpe, NULL);
+    airpe_set_mood_text(airpe, NULL);
+    airpe_set_partner_displayname(airpe, NULL);
+    airpe_set_partner_handle(airpe, NULL);
+
+    return SWITCH_STATUS_SUCCESS;
+}
+
+switch_core_session_t *airpe_request_session( switch_memory_pool_t **pool ) {
+    /* I prefer not to expose airpe_endpoint_interface out of this file. */
+    return switch_core_session_request(airpe_endpoint_interface, pool);
+}
+
+
+/*****************************************************************************
+    CHANNEL STATE HANDLERS
+ *****************************************************************************/
+
+static switch_status_t channel_on_init(switch_core_session_t * session)
+{
+    switch_channel_t *channel;
+    private_object_t *tech_pvt = NULL;
+
+    channel = switch_core_session_get_channel(session);
+    assert(channel);
+
+    tech_pvt = switch_core_session_get_private(session);
+    assert(tech_pvt);
+    assert(tech_pvt->airpe);
+
+    tech_pvt->airpe->tech_pvt = tech_pvt;
+
+    if ( switch_test_flag(tech_pvt, TFLAG_OUTBOUND) ) {
+	airpe_originate(tech_pvt->airpe, tech_pvt->destination );
+	// TODO if fail switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
+    }
+
+    if ( switch_test_flag(tech_pvt, TFLAG_INBOUND) ) {
+	char buf[SKYPE_MSG_LEN];
+	snprintf(buf, sizeof(buf), "ALTER CALL %d SET_INPUT PORT=\"%d\"", tech_pvt->airpe->active_call_id, tech_pvt->airpe->audio_in_port);
+	airpe_cmd_write(tech_pvt->airpe, buf);
+	snprintf(buf, sizeof(buf), "ALTER CALL %d SET_OUTPUT PORT=\"%d\"", tech_pvt->airpe->active_call_id, tech_pvt->airpe->audio_out_port);
+	airpe_cmd_write(tech_pvt->airpe, buf);
+
+        switch_channel_set_state(channel, CS_ROUTING);
+    }
+
+    return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status_t channel_on_routing(switch_core_session_t * session) {
+    char buf[SKYPE_MSG_LEN];
+    switch_channel_t *channel = NULL;
+    private_object_t *tech_pvt = NULL;
+
+    channel = switch_core_session_get_channel(session);
+    assert(channel);
+
+    tech_pvt = switch_core_session_get_private(session);
+    assert(tech_pvt);
+
+    if ( switch_test_flag(tech_pvt, TFLAG_INBOUND) ) {
+        snprintf(buf, sizeof(buf), "ALTER CALL %d ANSWER", tech_pvt->airpe->active_call_id);
+        airpe_cmd_write(tech_pvt->airpe, buf);
+    }
+
+    return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status_t channel_on_execute(switch_core_session_t * session) {
+    switch_channel_t *channel = NULL;
+    private_object_t *tech_pvt = NULL;
+
+    channel = switch_core_session_get_channel(session);
+    assert(channel);
+
+    tech_pvt = switch_core_session_get_private(session);
+    assert(tech_pvt);
+
+    return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status_t channel_on_hangup(switch_core_session_t * session)
+{
+    switch_channel_t *channel = NULL;
+    private_object_t *tech_pvt = NULL;
+    airpe_interface_t *airpe = NULL;
+    char msg[SKYPE_MSG_LEN];
+
+    channel = switch_core_session_get_channel(session);
+    assert(channel);
+
+    tech_pvt = switch_core_session_get_private(session);
+    assert(tech_pvt);
+
+    airpe = tech_pvt->airpe;
+    assert(airpe);
+
+    if ( airpe->active_call_id ) {
+	snprintf(msg, sizeof(msg), "ALTER CALL %d HANGUP", airpe->active_call_id);
+	airpe_cmd_write(airpe, msg);
+//	airpe->active_call_id = 0;
+//	airpe->tech_pvt = NULL;
+    }
+
+    airpe_hangup( tech_pvt );
+
+    if (tech_pvt->read_codec.implementation) {
+	switch_core_codec_destroy(&tech_pvt->read_codec);
+    }
+
+    if (tech_pvt->write_codec.implementation) {
+	switch_core_codec_destroy(&tech_pvt->write_codec);
+    }
+
+    return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status_t channel_on_exchange_media(switch_core_session_t * session) {
+    return SWITCH_STATUS_SUCCESS;
+}
+
+/*****************************************************************************
+    CHANNEL IO INTERFACE / ROUTINES
+ *****************************************************************************/
+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) 
+{
+    switch_caller_profile_t *caller_profile = NULL;
+    private_object_t *tech_pvt = NULL;
+    switch_channel_t *channel = NULL;
+
+    assert(outbound_profile);
+
+    /* New session creation */
+    *new_session = airpe_request_session(pool);
+    if ( *new_session ) 
+    {
+	char *chan_interface = NULL;
+	char *chan_destination = NULL;
+
+	switch_core_session_add_stream(*new_session, NULL);
+
+	tech_pvt = (private_object_t *) switch_core_session_alloc(*new_session, sizeof(private_object_t));
+
+	if ( tech_pvt ) {
+	    channel = switch_core_session_get_channel(*new_session);
+	    if ( airpe_tech_init( tech_pvt, *new_session ) != SWITCH_STATUS_SUCCESS ) {
+	        switch_core_session_destroy(new_session);
+		return SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER;
+	    }
+	} else {
+	    switch_core_session_destroy(new_session);
+	    return SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER;
+	}
+
+
+	chan_interface = switch_core_session_strdup( *new_session, outbound_profile->destination_number);
+	if (( chan_destination = strchr(chan_interface, '/'))) {
+		*chan_destination++ = '\0';
+	}	
+	if ( !chan_interface || !chan_destination ) {
+	    switch_core_session_destroy(new_session);
+	    return SWITCH_CAUSE_INVALID_NUMBER_FORMAT;
+	}
+
+	if ( (tech_pvt->airpe = airpe_find_interface(chan_interface))==NULL ) {
+	    switch_core_session_destroy(new_session);
+	    return SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER;
+	}
+	tech_pvt->destination = chan_destination;
+
+	if ( tech_pvt->airpe->active_call_id != 0 ) {
+	    /* We're busy, man! */
+	    switch_core_session_destroy(new_session);
+	    return SWITCH_CAUSE_REQUESTED_CHAN_UNAVAIL;
+	}
+
+	if (outbound_profile) {
+	    char name[128];
+	    snprintf(name, sizeof(name), "airpe/%s", outbound_profile->destination_number);
+	    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 
+	{
+	    switch_core_session_destroy(new_session);
+    	    return SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER;
+	}
+
+	switch_channel_set_flag(channel, CF_OUTBOUND);	
+	switch_set_flag_locked(tech_pvt, TFLAG_OUTBOUND);
+	switch_channel_set_state(channel, CS_INIT);
+	return SWITCH_CAUSE_SUCCESS;
+    }
+    else 
+    {
+	return SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER;
+    }
+}
+
+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_object_t *tech_pvt = NULL;
+    switch_byte_t *data;
+
+    channel = switch_core_session_get_channel(session);
+    assert(channel);
+
+    tech_pvt = switch_core_session_get_private(session);
+    assert(tech_pvt);
+
+    tech_pvt->read_frame.flags = SFF_NONE;
+    *frame = NULL;
+
+    if ( airpe_audio_read(tech_pvt) != SWITCH_STATUS_SUCCESS) {
+	ADEBUG("airpe_audio_read ERROR\n");
+	return SWITCH_STATUS_FALSE;
+    }
+
+    if (!tech_pvt->read_frame.datalen) {
+	goto cng;
+    }
+
+    *frame = &tech_pvt->read_frame;
+
+    return SWITCH_STATUS_SUCCESS;
+
+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_object_t *tech_pvt = NULL;
+    airpe_interface_t *airpe = NULL;
+    switch_status_t rv;
+
+    channel = switch_core_session_get_channel(session);
+    assert(channel);
+
+    tech_pvt = switch_core_session_get_private(session);
+    assert(tech_pvt);
+
+    if ( !tech_pvt->airpe ) {
+	return SWITCH_STATUS_FALSE;
+    }
+
+    airpe = tech_pvt->airpe;
+
+    rv = airpe_audio_write(tech_pvt, frame);
+    return rv;
+}
+
+static switch_status_t channel_kill_channel(switch_core_session_t * session, int sig)
+{
+    switch_channel_t *channel = NULL;
+    private_object_t *tech_pvt = NULL;
+
+    channel = switch_core_session_get_channel(session);
+    assert(channel);
+
+    tech_pvt = switch_core_session_get_private(session);
+    assert(tech_pvt);
+
+    switch (sig) {
+	case SWITCH_SIG_KILL:
+	    break;
+    case SWITCH_SIG_BREAK:
+	    break;
+    default:
+	//TODO Log unhandled signal
+	break;
+  }
+
+  return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status_t channel_send_dtmf(switch_core_session_t * session, const switch_dtmf_t * dtmf) {
+    private_object_t *tech_pvt = switch_core_session_get_private(session);
+    airpe_interface_t *airpe;
+    char buf[SKYPE_MSG_LEN];
+
+    switch_assert(tech_pvt);
+
+    airpe = tech_pvt->airpe;
+
+    if ( airpe->active_call_id ) {
+	snprintf(buf, sizeof(buf), "SET CALL %d DTMF %c", airpe->active_call_id, dtmf->digit);
+	airpe_cmd_write(airpe, buf);
+    }
+
+    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_object_t *tech_pvt;
+
+    channel = switch_core_session_get_channel(session);
+    assert(channel);
+
+    tech_pvt = (private_object_t *) switch_core_session_get_private(session);
+    assert(tech_pvt);
+
+    switch (msg->message_id) {
+	case SWITCH_MESSAGE_INDICATE_ANSWER:
+	    ADEBUG("received message indicate answer...\n");
+/*
+    	    //switch_answer_channel(session);
+	    char buf[SKYPE_MSG_LEN];
+	    snprintf(buf, sizeof(buf), "ALTER CALL %d ANSWER", tech_pvt->airpe->active_call_id );
+	    airpe_cmd_write(tech_pvt->airpe, buf);
+*/
+	    break;
+	case SWITCH_MESSAGE_INDICATE_UNBRIDGE:
+	    ADEBUG("received message indicate unbridge...\n");
+	    break;
+	case SWITCH_MESSAGE_INDICATE_TRANSCODING_NECESSARY:
+	    ADEBUG("received message indicate transcode necessary...\n");
+	    break;
+	case SWITCH_MESSAGE_INDICATE_AUDIO_SYNC:
+	    ADEBUG("received message indicate audio sync...\n");
+	    break;
+	case SWITCH_MESSAGE_INDICATE_TRANSFER:
+	    ADEBUG("received message indicate transfer...\n");
+	    break;
+	default:
+	    ADEBUG("Unmanaged received message... %d\n", msg->message_id);
+	    break;
+    }
+
+    return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status_t channel_receive_event(switch_core_session_t * session, switch_event_t * event)
+{
+    char *body = NULL;
+    switch_channel_t *channel;
+    private_object_t *tech_pvt;
+
+    channel = switch_core_session_get_channel(session);
+    assert(channel);
+
+    tech_pvt = (private_object_t *) switch_core_session_get_private(session);
+    assert(tech_pvt);
+
+    body = switch_event_get_body(event);
+
+    if (!body) {
+	body = "";
+    }
+
+    return SWITCH_STATUS_SUCCESS;
+}
+
+
+/*****************************************************************************
+    CONFIGURATION
+ *****************************************************************************/
+
+static switch_status_t load_config(void) {
+    switch_xml_t    	cfg, 
+			xml, 
+			global_settings, 
+			param, 
+			clients, 
+			client;
+    switch_memory_pool_t *pool;
+
+    pool = airpe_module_pool;
+    
+    if (!(xml = switch_xml_open_cfg("airpe.conf", &cfg, NULL))) {
+	return SWITCH_STATUS_TERM;
+    }
+
+    if ( (global_settings = switch_xml_child(cfg, "globals") ) ) {
+	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 (!strcmp(var, "dialplan")) {
+		globals.dialplan = switch_core_strdup(pool, val);
+	    } else if (!strcmp(var, "context")) {
+		globals.context = switch_core_strdup(pool, val);
+	    } else if (!strcmp(var, "destination")) {
+		globals.destination = switch_core_strdup(pool, val);
+	    } else if (!strcmp(var, "audio-tcp-port_start")) {
+		globals.audio_tcp_port_start = atoi(val);
+	    }
+	}
+    }
+
+    if ( globals.audio_tcp_port_start <= 0 ) {
+	globals.audio_tcp_port_start = 21000;
+    }
+
+    if ( !globals.dialplan )
+	globals.dialplan = switch_core_strdup(pool, "XML");
+    if ( !globals.context )
+	globals.context = switch_core_strdup(pool, "default");
+    if ( !globals.destination )
+	globals.destination = switch_core_strdup(pool, "4321");
+
+    if ((clients = switch_xml_child(cfg, "clients"))) {
+
+	for (client = switch_xml_child(clients, "client"); client; client = client->next) 
+	{
+    	    char *name 		= (char *) switch_xml_attr(client, "name");
+    	    char *context 	= NULL;
+    	    char *dialplan 	= NULL;
+    	    char *destination 	= NULL;
+    	    char *X11_display 	= NULL;
+    	    char *skype_user 	= NULL;
+    	    char *skype_password= NULL;
+	    char *cid_name	= NULL;
+	    char *cid_num	= NULL;
+	    int	 debug		= 0;
+
+    	    airpe_interface_t 	*newconf = NULL;
+
+	    if (!name) {
+		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "No name attribute. Skipping unnamed client.\n");
+		continue;
+    	    }
+
+	    if ( (newconf = switch_core_hash_find(globals.interfaces_hash, name)) ) {
+		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Duplicated client %s. Skipping\n", name);
+		continue;
+	    }
+
+	    for (param = switch_xml_child(client, "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")) {
+		    debug = switch_true(val) ? 1 : 0;
+    		} 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, "skype-user")) {
+        	    skype_user = val;
+    		} else if (!strcasecmp(var, "skype-password")) {
+        	    skype_password = val;
+    		} else if (!strcasecmp(var, "X11-display")) {
+        	    X11_display = val;
+    		} else if (!strcasecmp(var, "cid-name")) {
+        	    cid_name = val;
+    		} else if (!strcasecmp(var, "cid-num")) {
+        	    cid_num = val;
+    		}
+		else
+		    switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Unknown config param %s\n", var);
+	    }
+	    if (!skype_user) {
+		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "No skype-user param for client %s. Skipping\n", name);
+    		continue;
+	    }
+	    if (!skype_password) {
+		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "No skype-password param for client %s. Skipping\n", name);
+    		continue;
+    	    }
+    	    if (!X11_display) {
+		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "No X11-display param for client %s. Skipping\n", name);
+    		continue;
+    	    }
+
+	    if ( !dialplan )
+		dialplan = globals.dialplan;
+	    if ( !context )
+		context = globals.context;
+	    if ( !destination )
+		destination = globals.destination;
+
+	    newconf = (airpe_interface_t *) switch_core_alloc( pool, sizeof(airpe_interface_t) );
+
+	    if ( newconf ) {
+		switch_status_t status;
+
+		memset(newconf, 0, sizeof(airpe_interface_t));
+
+		newconf->name     	= switch_core_strdup(pool, name);
+		newconf->dialplan 	= switch_core_strdup(pool, dialplan);
+		newconf->context  	= switch_core_strdup(pool, context);
+		newconf->destination  	= switch_core_strdup(pool, destination);
+		newconf->skype_user  	= switch_core_strdup(pool, skype_user);
+		newconf->skype_password = switch_core_strdup(pool, skype_password);
+		newconf->X11_display  	= switch_core_strdup(pool, X11_display);
+		newconf->audio_in_port  = 0;
+		newconf->audio_in_port  = 0;
+		newconf->debug  	= debug;
+
+		newconf->skype_window = skype_window_alloc(pool);
+
+		if ( newconf->skype_window ) {
+		    status = airpe_start_client(newconf);
+
+		    if ( status == SWITCH_STATUS_SUCCESS ) {
+			switch_core_hash_insert(globals.interfaces_hash, name, newconf);
+		    }
+		    else {
+			// LOG OUR ERROR
+		    }
+		}
+		else {
+		    // LOG OUR ERROR
+		}
+
+	    }
+	    else {
+		//TODO LOG ERROR ABOUT CREATING INTERFACE
+	    }
+	}
+
+    }
+
+    switch_xml_free(xml);
+    return SWITCH_STATUS_SUCCESS;
+}
+
+
+/*****************************************************************************
+    MODULE INITIALIZATION FUNCTIONS
+ *****************************************************************************/
+
+static switch_state_handler_table_t airpe_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 */ 	NULL
+};
+
+static switch_io_routines_t airpe_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
+};
+
+SWITCH_MODULE_LOAD_FUNCTION(mod_airpe_load);
+SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_airpe_shutdown);
+SWITCH_MODULE_DEFINITION(mod_airpe, mod_airpe_load, mod_airpe_shutdown, NULL);
+
+SWITCH_MODULE_LOAD_FUNCTION(mod_airpe_load)
+{
+    airpe_module_pool = pool;
+
+    memset(&globals, 0, sizeof(globals));
+
+    switch_core_hash_init(&globals.interfaces_hash, pool);
+    switch_mutex_init(&globals.mutex, SWITCH_MUTEX_NESTED, pool);
+
+    load_config();
+
+    *module_interface = switch_loadable_module_create_module_interface(pool, modname);
+
+    airpe_endpoint_interface = switch_loadable_module_create_interface(*module_interface, SWITCH_ENDPOINT_INTERFACE);
+
+    airpe_endpoint_interface->interface_name = "airpe";
+    airpe_endpoint_interface->io_routines    = &airpe_io_routines;
+    airpe_endpoint_interface->state_handler  = &airpe_state_handlers;
+
+    airpe_register_api( &*module_interface );
+    airpe_register_apps( &*module_interface );
+
+
+    return SWITCH_STATUS_SUCCESS;
+}
+
+SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_airpe_shutdown)
+{
+    switch_memory_pool_t *pool;
+    airpe_interface_t *airpe;
+    switch_hash_index_t *hi;
+    void *val;
+
+    pool = airpe_module_pool;
+
+    for (hi = switch_hash_first(NULL, globals.interfaces_hash); hi; hi = switch_hash_next(hi)) {
+	switch_hash_this(hi, NULL, NULL, &val);
+	airpe = ( airpe_interface_t *) val;
+	switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Shutting down airpe client: %s\n", airpe->name);
+	airpe->running = 0;
+	/* Wake up the socket */
+	airpe_cmd_write(airpe, "PING");
+	airpe_stop_client(airpe);
+	/*
+	we won't delete the hash element. we're going to destroy the whole pool 
+	switch_core_hash_delete(globals.interfaces_hash, airpe->name); 
+	*/
+    }
+    switch_yield(500000);
+
+    /* TODO... should we check that all interfaces has been switched off ? */
+
+    switch_core_hash_destroy(&globals.interfaces_hash);
+    switch_core_destroy_memory_pool(&pool);
+    return SWITCH_STATUS_UNLOAD;
+}
+
+/* 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/ctrix/mod_airpe/mod_airpe.h
==============================================================================
--- (empty file)
+++ freeswitch/branches/ctrix/mod_airpe/mod_airpe.h	Mon Jan 12 17:24:44 2009
@@ -0,0 +1,235 @@
+/* 
+ * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ * Copyright (C) 2005/2006, Anthony Minessale II <anthmct at 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 mod_airpe.
+ *
+ * The Initial Developer of the Original Code is
+ * Massimo Cetra <devel at navynet.it>
+ *
+ * Portions created by the Initial Developer are Copyright (C)
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Thanks to gmaruzz for his work on skypiax (both * and freeswitch).
+ * Some of his code inspired this module
+ *
+ */
+
+#include <switch.h>
+#include <switch_version.h>
+
+#define MODNAME "airpe"
+
+#define SKYPE_MSG_LEN	1024
+
+#define CODEC_SAMPLE_RATE	16000
+#define CODEC_INTERVAL_MS	20
+#define FRAMES_PER_SECOND	1000 / CODEC_INTERVAL_MS
+#define	SAMPLES_PER_FRAME	CODEC_SAMPLE_RATE / FRAMES_PER_SECOND
+
+#define ADEBUG(...)  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, __VA_ARGS__ );
+
+typedef enum {
+    CONN_STATUS_UNKNOWN,
+    CONN_STATUS_OFFLINE,
+    CONN_STATUS_CONNECTING,
+    CONN_STATUS_PAUSING,
+    CONN_STATUS_ONLINE,
+} CONN_STATUS;
+
+typedef enum {
+    USER_STATUS_UNKNOWN,
+    USER_STATUS_ONLINE,
+    USER_STATUS_OFFLINE,
+    USER_STATUS_SKYPEME,
+    USER_STATUS_AWAY,
+    USER_STATUS_NA,
+    USER_STATUS_DND,
+    USER_STATUS_INVISIBLE,
+    USER_STATUS_LOGGEDOUT
+} USER_STATUS;
+
+typedef enum {
+    CALL_STATUS_UNKNOWN,
+    CALL_STATUS_UNPLACED,
+    CALL_STATUS_ROUTING,
+    CALL_STATUS_EARLYMEDIA,
+    CALL_STATUS_FAILED,
+    CALL_STATUS_RINGING,
+    CALL_STATUS_INPROGRESS,
+    CALL_STATUS_ONHOLD,
+    CALL_STATUS_LOCALHOLD,
+    CALL_STATUS_REMOTEHOLD,
+    CALL_STATUS_FINISHED,
+    CALL_STATUS_MISSED,
+    CALL_STATUS_REFUSED,
+    CALL_STATUS_BUSY,
+    CALL_STATUS_CANCELLED,
+    CALL_STATUS_TRANSFERRING,			/* Protocol 7 */
+    CALL_STATUS_TRANSFERRED,			/* Protocol 7 */
+
+    CALL_STATUS_VM_BUFFERING_GREETING,
+    CALL_STATUS_VM_PLAYING_GREETING,
+    CALL_STATUS_VM_RECORDING,
+    CALL_STATUS_VM_UPLOADING,
+    CALL_STATUS_VM_SENT,
+    CALL_STATUS_VM_CANCELLED ,
+    CALL_STATUS_VM_FAILED,
+    CALL_STATUS_WAITING_REDIAL_COMMAND,		
+    CALL_STATUS_REDIAL_PENDING,			/* Protocol 8 */
+
+} CALL_STATUS;
+
+typedef enum {
+    FAILURE_CODE_MISC			= 1,
+    FAILURE_CODE_BAD_DESTINATION_NUM	= 2,
+    FAILURE_CODE_USER_OFFLINE		= 3,
+    FAILURE_CODE_NO_PROXY_FOUND		= 4,
+    FAILURE_CODE_SESSION_TERMINATED	= 5,
+    FAILURE_CODE_NO_CODEC_FOUND		= 6,
+    FAILURE_CODE_LOCAL_SOUND_ERR	= 7,
+    FAILURE_CODE_REMOTE_SOUND_ERR	= 8,
+    FAILURE_CODE_CALL_BLOCKED		= 9,
+    FAILURE_CODE_RECIPIENT_NOT_FRIEND	= 10,
+    FAILURE_CODE_CALL_UNAUTHORIZED	= 11,
+    FAILURE_CODE_SOUND_REC_ERR		= 12,    
+} FAILURE_CODES;
+
+
+typedef enum {
+  TFLAG_INBOUND 	= (1 << 1),
+  TFLAG_OUTBOUND	= (1 << 2),
+/*
+  TFLAG_IO 		= (1 << 0),
+  TFLAG_DTMF 		= (1 << 3),
+  TFLAG_VOICE 		= (1 << 4),
+  TFLAG_HANGUP 		= (1 << 5),
+  TFLAG_LINEAR 		= (1 << 6),
+  TFLAG_CODEC 		= (1 << 7),
+  TFLAG_BREAK 		= (1 << 8),
+  TFLAG_ANSWER 		= (1 << 9)
+*/
+} TFLAGS;
+
+typedef struct skype_window_handler_s skype_window_handler_t;
+
+typedef struct airpe_interface_s airpe_interface_t;
+typedef struct private_object_s private_object_t;
+
+struct airpe_interface_s {
+    char 			*name;
+    int  			debug;
+    char 			*dialplan;
+    char 			*context;
+    char 			*destination;
+    char 			*X11_display;
+    char 			*skype_user;
+    char 			*skype_password;
+
+    int 			audio_in_port;
+    int 			audio_out_port;
+    switch_socket_t		*audio_in_socket;
+    switch_socket_t		*audio_out_socket;
+    switch_socket_t		*audio_in_active_socket;
+    switch_socket_t		*audio_out_active_socket;
+
+    switch_thread_t 		*airpe_thread_skype;
+    skype_window_handler_t 	*skype_window;
+
+    int				protocol;
+    USER_STATUS			user_status;
+    CALL_STATUS			call_status;
+    CONN_STATUS			conn_status;
+
+    char			*skype_version;
+    char			*mood_text;
+    int 			active_call_id;
+    int				last_fail_reason;
+    int				running;
+    private_object_t		*tech_pvt;
+    char			*partner_displayname;
+    char			*partner_handle;
+};
+
+struct private_object_s {
+    unsigned int 		flags;
+    switch_mutex_t 		*flag_mutex;
+    switch_mutex_t 		*mutex;
+
+    airpe_interface_t 		*airpe;
+    switch_core_session_t	*session;
+    switch_caller_profile_t 	*caller_profile;
+    char			*destination;
+
+    switch_codec_t 		read_codec;
+    switch_codec_t 		write_codec;
+    switch_frame_t 		read_frame;
+    uint8_t 			databuf[SWITCH_RECOMMENDED_BUFFER_SIZE];
+};
+
+
+/* CORE */
+airpe_interface_t *airpe_find_interface( const char *name);
+switch_core_session_t *airpe_request_session( switch_memory_pool_t **pool );
+switch_status_t airpe_tech_init( private_object_t * tech_pvt, switch_core_session_t * session );
+
+/* API */
+switch_status_t airpe_register_api( switch_loadable_module_interface_t **module_interface );
+
+/* APPS */
+switch_status_t airpe_register_apps( switch_loadable_module_interface_t **module_interface );
+
+/* INTERFACE - COMMON FUNCTIONS */
+const char *skype_user_status_string(USER_STATUS st);
+USER_STATUS skype_user_status(const char *str);
+const char *skype_conn_status_string(CONN_STATUS st);
+CONN_STATUS skype_conn_status(const char *str);
+
+switch_status_t	airpe_set_version(airpe_interface_t *airpe, char *string);
+switch_status_t	airpe_set_mood_text(airpe_interface_t *airpe, char *string);
+switch_status_t	airpe_set_partner_displayname(airpe_interface_t *airpe, char *string);
+switch_status_t	airpe_set_partner_handle(airpe_interface_t *airpe, char *string);
+
+switch_status_t airpe_hangup( private_object_t *pvt );
+switch_status_t airpe_audio_read( private_object_t *pvt );
+switch_status_t airpe_audio_write( private_object_t *pvt, switch_frame_t *frame );
+
+switch_status_t airpe_cmd_write(airpe_interface_t *p, char *msg);
+switch_status_t airpe_originate(airpe_interface_t *p, char *dest);
+switch_status_t airpe_explicit_hangup(airpe_interface_t *airpe);
+switch_status_t airpe_manage_skype_msg( airpe_interface_t *airpe, const char *msg );
+
+switch_status_t airpe_on_connect_messages( airpe_interface_t *airpe, int protocol );
+
+/* INTERFACE - PLATFORM DEPENDANT FUNCTIONS */
+switch_status_t airpe_skype_watchdog_reset(skype_window_handler_t *window);
+switch_status_t airpe_skype_watchdog_increment(skype_window_handler_t *window);
+skype_window_handler_t *skype_window_alloc( switch_memory_pool_t *pool);
+switch_status_t airpe_skype_avalaible(skype_window_handler_t *window);
+switch_status_t skype_restart( skype_window_handler_t *airpe, const char *params );
+switch_status_t airpe_skype_send_message(skype_window_handler_t *window, const char *message_P);
+void *SWITCH_THREAD_FUNC airpe_skype_thread(switch_thread_t * thread, void *obj);
+
+/* 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:
+ */



More information about the Freeswitch-svn mailing list