[asterisk-commits] nadi: branch group/asterisk-1.4-gsm r60067 - in /team/group/asterisk-1.4-gsm:...

asterisk-commits at lists.digium.com asterisk-commits at lists.digium.com
Wed Apr 4 05:31:48 MST 2007


Author: nadi
Date: Wed Apr  4 07:31:47 2007
New Revision: 60067

URL: http://svn.digium.com/view/asterisk?view=rev&rev=60067
Log:
adding chan_gsm

Added:
    team/group/asterisk-1.4-gsm/channels/chan_gsm.c   (with props)
    team/group/asterisk-1.4-gsm/channels/gsmctl.c   (with props)
    team/group/asterisk-1.4-gsm/channels/gsmctl.h   (with props)
    team/group/asterisk-1.4-gsm/configs/gsm.conf.sample   (with props)
Modified:
    team/group/asterisk-1.4-gsm/channels/Makefile

Modified: team/group/asterisk-1.4-gsm/channels/Makefile
URL: http://svn.digium.com/view/asterisk/team/group/asterisk-1.4-gsm/channels/Makefile?view=diff&rev=60067&r1=60066&r2=60067
==============================================================================
--- team/group/asterisk-1.4-gsm/channels/Makefile (original)
+++ team/group/asterisk-1.4-gsm/channels/Makefile Wed Apr  4 07:31:47 2007
@@ -114,3 +114,5 @@
 misdn/isdn_lib.o: ASTCFLAGS+=-Wno-strict-aliasing
 
 $(if $(filter chan_misdn,$(EMBEDDED_MODS)),modules.link,chan_misdn.so): chan_misdn.o misdn_config.o misdn/isdn_lib.o misdn/isdn_msg_parser.o
+
+$(if $(filter chan_gsm,$(EMBEDDED_MODS)),modules.link,chan_gsm.so): chan_gsm.o gsmctl.o

Added: team/group/asterisk-1.4-gsm/channels/chan_gsm.c
URL: http://svn.digium.com/view/asterisk/team/group/asterisk-1.4-gsm/channels/chan_gsm.c?view=auto&rev=60067
==============================================================================
--- team/group/asterisk-1.4-gsm/channels/chan_gsm.c (added)
+++ team/group/asterisk-1.4-gsm/channels/chan_gsm.c Wed Apr  4 07:31:47 2007
@@ -1,0 +1,1353 @@
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <pthread.h>
+#include <semaphore.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <time.h>
+#include <errno.h>
+#include <unistd.h>
+#include <arpa/inet.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <sys/file.h>
+
+#include <asterisk/module.h>
+#include <asterisk/channel.h>
+#include <asterisk/config.h>
+#include <asterisk/logger.h>
+#include <asterisk/pbx.h>
+#include <asterisk/options.h>
+#include <asterisk/io.h>
+#include <asterisk/frame.h>
+#include <asterisk/translate.h>
+#include <asterisk/cli.h>
+#include <asterisk/musiconhold.h>
+#include <asterisk/dsp.h>
+#include <asterisk/translate.h>
+#include <asterisk/file.h>
+#include <asterisk/callerid.h>
+#include <asterisk/indications.h>
+#include <asterisk/app.h>
+#include <asterisk/features.h>
+#include <asterisk/manager.h>
+
+#include <asterisk/configman.h>
+
+#include "gsmctl.h"
+
+static int gsm_debug = 0 ;
+
+const char tdesc[]="GSM driver";
+
+static int gsm_digit_begin(struct ast_channel *c, char digit);
+static int gsm_digit_end(struct ast_channel *c, char digit, unsigned int duration);
+static int gsm_text(struct ast_channel *c, const char *text);
+static int gsm_call(struct ast_channel *c, char *dest, int timeout);
+static int gsm_answer(struct ast_channel *c);
+static int gsm_hangup(struct ast_channel *c);
+static int gsm_write(struct ast_channel *c, struct ast_frame *f);
+static struct ast_frame *gsm_read(struct ast_channel *c);
+static int gsm_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
+static int gsm_indicate(struct ast_channel *c, int cond, const void *data, size_t datalen);
+static struct ast_channel *gsm_request(const char *type, int format, void *data, int *cause);
+
+static const struct ast_channel_tech gsm_tech = {
+	.type = "GSM",
+	.description = tdesc,
+	.capabilities = AST_FORMAT_SLINEAR,
+	.requester = gsm_request,
+	.send_digit_begin = gsm_digit_begin,
+	.send_digit_end = gsm_digit_end,
+	.send_text = gsm_text,
+	.hangup = gsm_hangup,
+	.answer = gsm_answer,
+	.read = gsm_read,
+	.call = gsm_call,
+	.write = gsm_write,
+	.indicate = gsm_indicate,
+	.fixup = gsm_fixup,
+};
+
+enum gsm_state {
+	GSM_STATE_ATD_OUT,
+	GSM_STATE_PROCEEDING,
+	GSM_STATE_ALERTING,
+	GSM_STATE_ANSWERED,
+	GSM_STATE_HANGUPED,
+	GSM_STATE_NONE
+};
+
+static char default_context[]="default";
+static char default_exten[]="s";
+
+
+static struct gsm_config gsm_cfg[MAX_GSM_PORTS]; 
+
+
+struct gsm_pvt {
+	enum gsm_state state;
+	int port;
+	int portfd;
+	char context[256];
+	char exten[256];
+        struct ast_channel *ast_chan;
+	struct ast_frame read_f;
+	char readbuf[160];
+	int hidecallerid;
+};
+
+/** Config Stuff **/
+
+/*
+ * Global Variables
+ */
+#define CONFIG_FILE     "gsm.conf"
+#define GROUPNAME_MAX   128
+
+static cm_t *config = NULL;
+
+/*
+ * Configuration
+ */
+static const cm_dir_t gen_dirs[] = {
+	{},
+	{ "debug", "0", "debug level" },
+//	{ "tracefile", "", "trace AT commands to file" },
+	{ "smsdir", "/var/spool/asterisk/smsin", "The directory where inbound sms are stored" }
+};
+
+enum {
+	CFG_GEN_NAME = 0,
+	CFG_GEN_DEBUG,
+//	CFG_GEN_ATTRACE,
+	CFG_GEN_SMS_DIR,
+};
+
+static const cm_dir_t port_dirs[] = {
+	{ "name", 0, "name of the group" },
+	{ "ports", 0, "comma separated list of port numbers" },
+	{ "pin", "", "PIN for all ports in this group" },
+	{ "context", "default", "context to use for incoming calls" },
+	{ "exten", "s", "extension to use for incoming calls" },
+	{ "initfile", "", "filename containing an alternative module init sequence" },
+	{ "hidecallerid", "no", "if set to yes hide the callerid" },
+	{ "smsc", "+491760000443", "The number of your SMS Service Provider" },
+	{ "provider", "", "Name of your GSM Provider (Number Format, try \"gsm show ops\" to get a list of all possible values" },
+};
+
+enum {
+	CFG_PORT_NAME = 0,
+	CFG_PORT_PORTS,
+	CFG_PORT_PIN,
+	CFG_PORT_CONTEXT,
+	CFG_PORT_EXTEN,
+	CFG_PORT_INITFILE,
+	CFG_PORT_HIDECALLERID,
+	CFG_PORT_SMSC,
+	CFG_PORT_PROVIDER,
+	CFG_PORT_STRATEGY,
+	CFG_PORT_STRATEGY_PARMS,
+};
+
+static const cm_section_t config_sections[] = {
+	{ "general", NULL, NULL, KTYPE_NONE, sizeof(gen_dirs) / sizeof(cm_dir_t), gen_dirs},
+	{ "port", "default", "ports", KTYPE_INTEGER, sizeof(port_dirs) / sizeof(cm_dir_t), port_dirs},
+};
+
+enum {
+	SECT_GENERAL = 0,
+	SECT_PORT
+};
+
+static int gsm_config_init (void)
+{
+	if (!(config = cm_create("gsm", config_sections, sizeof(config_sections) / sizeof(cm_section_t)))) {
+		ast_log(LOG_ERROR, "failed to initialize config manager!\n");   
+		goto err1;
+	}
+
+	if (cm_load(config, CONFIG_FILE)) {
+		ast_log(LOG_ERROR, "failed to load config file: %s\n", CONFIG_FILE);
+		goto err2;
+	}
+
+	return 0;
+
+err2:
+	cm_destroy(config);
+	config = NULL;
+err1:
+	return -1;
+}
+
+static void gsm_config_exit (void)
+{
+	if (config) {
+		cm_destroy(config);
+		config = NULL;
+	}
+}
+
+/** CLI STUFF **/
+static int gsm_send_at(int fd, int argc, char *argv[])
+{
+	char *portstr, *cmd, *p;
+	int port;
+
+        if (argc != 5)
+                return RESULT_SHOWUSAGE;
+
+        portstr = argv[3];
+        cmd= strdup(argv[4]);
+
+	port=atoi(portstr);
+
+	while( (p=strchr(cmd,'/')) )
+		*p='?';
+
+	gsm_send(port, cmd, 100);
+
+	free (cmd);
+
+	return 0;
+}
+
+enum gsm_sms_work {
+	GSM_SMS_WORK_SHOW=0,
+	GSM_SMS_WORK_FETCH,
+	GSM_SMS_WORK_FLUSH,
+};
+
+enum gsm_sms_state {
+	GSM_SMS_STATE_NONE=0,
+	GSM_SMS_STATE_EXPECTING_PROMPT,
+	GSM_SMS_STATE_EXPECTING_SMSLIST,
+	GSM_SMS_STATE_SMS_SENT,
+	GSM_SMS_STATE_SMS_OK,
+	GSM_SMS_STATE_LIST,
+	GSM_SMS_STATE_GET_TEXT,
+	GSM_SMS_STATE_FLUSHING,
+};
+
+struct gsm_sms_message {
+	int idx;
+	char number[32];
+	char date[32];
+	char text[4096];
+};
+
+struct gsm_sms {
+	enum gsm_sms_state state;
+	char sms[4096];
+	char number[32];
+	
+	enum gsm_sms_work work;
+	//FIXME:
+	/*we should lock the sms sending procedure till we get either OK or 
+	 * ERROR ..*/
+	sem_t smslock;
+
+	/*manager stuff*/
+	struct mansession *s;
+	struct message *m;
+
+	struct gsm_sms_message inbound_msg; /*temporary message, where we work on*/
+} gsm_sms[MAX_GSM_PORTS];
+
+static int _gsm_send_sms(int port, const char *number, const char *sms)
+{
+	strcpy(gsm_sms[port].number, number);
+	strcpy(gsm_sms[port].sms, sms);
+	
+	if (gsm_sms[port].state != GSM_SMS_STATE_NONE) {
+		ast_log(LOG_WARNING, "SMS Statemachine busy, try later\n");
+		return -1;
+	}
+	
+	char buf[1024];
+	sprintf(buf,"AT+CMGS=%s", number);
+
+	gsm_sms[port].state=GSM_SMS_STATE_EXPECTING_PROMPT;
+
+	gsm_send(port, buf, 100);
+
+	return 0;
+}
+
+static int gsm_send_sms(int fd, int argc, char *argv[])
+{
+        if (argc != 6)
+                return RESULT_SHOWUSAGE;
+
+	_gsm_send_sms(atoi(argv[3]), argv[4], argv[5]);
+	return 0;
+}
+
+static int _gsm_list_sms(int port)
+{
+	gsm_sms[port].state=GSM_SMS_STATE_EXPECTING_SMSLIST;
+	gsm_send(port, "AT+CMGL=ALL",100);
+	return 0;	
+}
+
+static int gsm_fetch_sms(int fd, int argc, char *argv[])
+{
+        if (argc != 4)
+                return RESULT_SHOWUSAGE;
+
+	gsm_sms[atoi(argv[3])].work=GSM_SMS_WORK_FETCH;
+	_gsm_list_sms(atoi(argv[3]));
+	return 0;
+}
+
+static int gsm_show_sms(int fd, int argc, char *argv[])
+{
+        if (argc != 4)
+                return RESULT_SHOWUSAGE;
+
+	gsm_sms[atoi(argv[3])].work=GSM_SMS_WORK_SHOW;
+	_gsm_list_sms(atoi(argv[3]));
+	return 0;
+}
+
+static int gsm_set_debug(int fd, int argc, char *argv[])
+{
+        if (argc != 4)
+                return RESULT_SHOWUSAGE;
+
+	gsm_debug=atoi(argv[3]);
+	return 0;
+}
+
+
+static int gsm_debug_info(int fd, int argc, char *argv[])
+{
+	ast_verbose("Sms_State (%d) sms_work (%d)\n",gsm_sms[1].state, gsm_sms[1].work);
+	return 0;
+}
+
+
+static int cli_gsm_shutdown_port(int fd, int argc, char *argv[])
+{
+        if (argc != 4)
+                return RESULT_SHOWUSAGE;
+
+	gsm_shutdown_port(atoi(argv[3]));
+	return 0;
+}
+
+
+static int _gsm_init_port(int port)
+{
+	struct gsm_config cfg;
+	
+	ast_verbose("Initializing port %d\n",port);
+	memset(&cfg,0,sizeof(cfg));
+
+	/*initialize the gsm_config*/
+	char buf[256];
+
+	cfg.port=1;
+	cm_get(config, cfg.pin, sizeof(cfg.pin), SECT_PORT, CFG_PORT_PIN, port);
+	if (cm_get(config, buf, sizeof(buf), SECT_PORT, CFG_PORT_INITFILE, port)) {
+		cfg.initfile=strdup(buf);
+	}
+
+	cm_get(config, cfg.smsc, sizeof(cfg.smsc), SECT_PORT, CFG_PORT_SMSC, port);
+
+	gsm_init_port(port, cfg);
+	gsm_wait_ready(port);
+	ast_verbose("started gsm port %d\n",port);
+
+	return 0;
+}
+
+static int cli_gsm_init_port(int fd, int argc, char *argv[])
+{
+        if (argc != 4)
+                return RESULT_SHOWUSAGE;
+
+	_gsm_init_port(atoi(argv[3]));
+		
+	return 0;
+}
+
+
+static int cli_gsm_set_next_simslot(int fd, int argc, char *argv[])
+{
+        if (argc != 6)
+                return RESULT_SHOWUSAGE;
+
+	int i=gsm_set_next_simslot(atoi(argv[4]),atoi(argv[5]));
+
+	if (i<0) 
+		ast_verbose("Setting simslot failed (%s)\n", strerror(errno));
+	
+	return 0;
+}
+
+static void _gsm_restart_port(int port)
+{
+	unsigned long then = time(NULL);
+
+	gsm_shutdown_port(port);
+	sleep(3);
+	_gsm_init_port(port);
+
+	unsigned long now = time(NULL);
+	ast_verbose("It took us %ld seconds\n", now-then);
+}
+
+static int cli_gsm_restart_port(int fd, int argc, char *argv[])
+{
+        if (argc != 4)
+                return RESULT_SHOWUSAGE;
+
+	_gsm_restart_port(atoi(argv[3]));
+	
+	return 0;
+}
+
+
+struct gsm_op {
+	char name[128];
+	char origname[128];
+	char number[32];
+} ;
+
+static int cli_gsm_show_ops(int fd, int argc, char *argv[])
+{
+        if (argc != 4)
+                return RESULT_SHOWUSAGE;
+
+	gsm_send(atoi(argv[3]), "AT^SOPS=?", 100);
+	ast_verbose("Getting Operator List, please stand by\n");
+
+	return 0;
+}
+
+static int cli_gsm_set_op(int fd, int argc, char *argv[])
+{
+        if (argc != 5)
+                return RESULT_SHOWUSAGE;
+	
+	char buf[64];
+
+	sprintf(buf,"AT+COPS=1,2,%s",argv[4]);
+	gsm_send(atoi(argv[3]), buf, 100);
+
+	ast_verbose("Setting Operator, please stand by\n");
+	return 0;
+}
+
+
+static int cli_gsm_show_registrations(int fd, int argc, char *argv[])
+{
+	int i;
+	for(i=0; i<MAX_GSM_PORTS; i++) {
+		if (gsm_cfg[i].port)
+			gsm_send(i, "AT+COPS?", 100);
+	}
+	return 0;
+}
+
+
+
+static struct ast_cli_entry chan_gsm_clis[] = {         
+	{ {"gsm", "send", "at", NULL}, gsm_send_at, "sends at command to port <port>", "Usage: gsm send at <port> \"<command>\" \n", NULL},
+	{ {"gsm", "send", "sms", NULL}, gsm_send_sms, "sends a sms to port <port> with number <number>", "Usage: gsm send sms <port> <number> \"<smstext>\" \n", NULL},
+	{ {"gsm", "fetch", "sms", NULL}, gsm_fetch_sms, "fetches all the stored sms from port <port> and stores them in smsdir (gsm.conf)", "Usage: gsm fetch sms <port>\n", NULL},
+	{ {"gsm", "show", "sms", NULL}, gsm_show_sms, "shows all the stored sms from port <port>", "Usage: gsm show sms <port>\n", NULL},
+	{ {"gsm", "set", "debug", NULL}, gsm_set_debug, "sets the debuglevel to <level>", "Usage: gsm set debug <level>\n", NULL},
+	{ {"gsm", "debug","info", NULL}, gsm_debug_info,"print some debug info", "Usage: gsm debug\n", NULL},
+	{ {"gsm", "shutdown","port", NULL}, cli_gsm_shutdown_port,"shuts down port", "Usage: gsm shutdown port <port>\n", NULL},
+	{ {"gsm", "init","port", NULL}, cli_gsm_init_port,"inits port", "Usage: gsm init port <port>\n", NULL},
+	{ {"gsm", "set","next","simslot", NULL}, cli_gsm_set_next_simslot,"sets next simslog", "Usage: gsm set next simslot <port> <0|1>\n", NULL},
+	{ {"gsm", "restart","port", NULL}, cli_gsm_restart_port,"restarts the gsm port", "Usage: gsm restart port <port>\n", NULL},
+	{ {"gsm", "show","ops", NULL}, cli_gsm_show_ops,"shows a list of operators", "Usage: gsm show ops <port>\n", NULL},
+	{ {"gsm", "show","registrations", NULL}, cli_gsm_show_registrations,"shows at which ops we're registered", "Usage: gsm show registrations\n", NULL},
+	{ {"gsm", "set","op", NULL}, cli_gsm_set_op,"sets an operator", 
+	  "Usage: gsm set op <port> <operator>\n\n<operator> must be given in numeric format\n", NULL},
+};
+
+/*manager commands*/
+static int action_send_sms(struct mansession *s, const struct message *m)
+{
+        const char *port= astman_get_header(m, "Port");
+        const char *number= astman_get_header(m, "Number");
+        const char *text= astman_get_header(m, "Text");
+
+        if (ast_strlen_zero(port)) {
+                astman_send_error(s, m, "No port specified");
+                return 0;
+        }
+        if (ast_strlen_zero(number)) {
+                astman_send_error(s, m, "No number specified");
+                return 0;
+        }
+        if (ast_strlen_zero(text)) {
+                astman_send_error(s, m, "No text specified");
+                return 0;
+        }
+
+	gsm_sms[atoi(port)].s=s;
+	gsm_sms[atoi(port)].m=(struct message*)m;
+
+	_gsm_send_sms(atoi(port), number, text);
+
+
+	astman_send_ack(s, m, "GsmSendSms: Success");
+        return 0;
+}
+
+
+
+/*
+ *  * some of the standard methods supported by channels.
+ *   */
+static int gsm_digit_begin(struct ast_channel *c, char digit)
+{
+        return 0;
+}
+
+static int gsm_digit_end(struct ast_channel *c, char digit, unsigned int duration)
+{
+       /* no better use for received digits than print them */
+        ast_verbose(" << GSM Received digit %c of duration %u ms >> \n",
+	                digit, duration);
+		        return 0;
+}
+
+
+
+static int gsm_text(struct ast_channel *c, const char *text)
+{
+        /* print received messages */
+        ast_verbose(" << GSM Received text %s >> \n", text);
+        return 0;
+}
+
+static int gsm_call(struct ast_channel *c, char *dest, int timeout)
+{
+	struct gsm_pvt *gsm=c->tech_pvt;
+	int hidecallerid=0;
+	
+	if (!gsm) return -1;
+
+	char buf[128];
+	char *port_str, *dad, *p;
+
+	ast_copy_string(buf, dest, sizeof(buf)-1);
+	p=buf;
+	port_str=strsep(&p, "/");
+	dad=strsep(&p, "/");
+
+	ast_verbose("Call: ext:%s port:%d dest:(%s) -> dad(%s) \n", c->exten, gsm->port, dest, dad);
+
+	char dialstring[128];
+
+	if (gsm->hidecallerid) {
+		hidecallerid=1;
+	}
+
+	if (hidecallerid)
+		sprintf(dialstring,"ATD#31#%s;",dad);
+	else
+		sprintf(dialstring,"ATD%s;",dad);
+
+	gsm_send(gsm->port,dialstring,100);
+	gsm->state=GSM_STATE_ATD_OUT;
+	
+	return 0;
+}
+
+static int gsm_answer(struct ast_channel *c)
+{
+	struct gsm_pvt *gsm=c->tech_pvt;
+
+	gsm_send(gsm->port,"ATA",100);
+	return 0;
+}
+
+static int gsm_hangup(struct ast_channel *c)
+{
+	struct gsm_pvt *gsm=c->tech_pvt;
+	
+	gsm_send(gsm->port,"ATH",100);
+	gsm_put_priv(gsm->port,NULL);
+	gsm_audio_stop(gsm->port);
+	gsm_audio_close(gsm->port, gsm->portfd);
+	free(gsm);
+	c->tech_pvt=NULL;
+
+	return 0;
+}
+
+static int gsm_write(struct ast_channel *c, struct ast_frame *f)
+{
+        struct gsm_pvt*gsm= c->tech_pvt;
+        int count = 0,
+                again = 1,
+                len;
+
+        switch (f->frametype) {
+        case AST_FRAME_VOICE:
+                do {
+                        len = write(gsm->portfd, (char*)f->data, f->datalen);
+			//printf("written %d\n", len);
+			
+                        if (len < 0) {
+				
+				if (errno == EAGAIN) {
+                                	ast_log(LOG_WARNING, "droping frame, EAGAIN\n");
+					return 0;
+				}
+
+                                ast_log(LOG_WARNING, "%d: error writing to port fd(%d) error(%d,%s)\n", gsm->port, gsm->portfd, errno, strerror(errno));
+                                ast_queue_hangup(c);
+                                return 0;
+                        }
+                        count += len;
+                } while (again-- && count < f->datalen);
+                if (count < f->datalen)
+                        ast_log(LOG_WARNING, "%d: port congestion, dropping %d of %d frames\n", gsm->port, f->datalen - count, f->datalen);
+                break;
+        default:
+                ast_log(LOG_WARNING, "%d unhandled frame type: %d\n",gsm->port, f->frametype);
+                return -1;
+        }
+
+
+	return 0;
+}
+
+static struct ast_frame *gsm_read(struct ast_channel *c)
+{
+	struct gsm_pvt *gsm = c->tech_pvt;
+        int count;
+
+
+        count = read(gsm->portfd, gsm->readbuf, sizeof(gsm->readbuf));
+        gsm->read_f.samples = count;
+        gsm->read_f.datalen = count;
+        gettimeofday(&gsm->read_f.delivery, NULL);
+	gsm->read_f.data = gsm->readbuf;
+	gsm->read_f.mallocd = 0;
+	gsm->read_f.frametype= AST_FRAME_VOICE;
+	gsm->read_f.subclass= AST_FORMAT_ALAW;
+	
+        return &gsm->read_f;
+
+}
+
+static int gsm_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
+{
+        return 0;
+}
+
+static int gsm_indicate(struct ast_channel *c, int cond, const void *data, size_t datalen)
+{
+        int res = -1;
+
+        switch (cond) {
+                case AST_CONTROL_BUSY:
+                case AST_CONTROL_CONGESTION:
+                case AST_CONTROL_RINGING:
+			return -1;
+                case -1:
+                        return 0;
+
+                case AST_CONTROL_VIDUPDATE:
+                        res = -1;
+                        break;
+                case AST_CONTROL_HOLD:
+                        ast_verbose(" << Console Has Been Placed on Hold >> \n");
+                        //ast_moh_start(c, data, g->mohinterpret);
+                        break;
+                case AST_CONTROL_UNHOLD:
+                        ast_verbose(" << Console Has Been Retrieved from Hold >> \n");
+                        //ast_moh_stop(c);
+                        break;
+
+                default:
+                        ast_log(LOG_WARNING, "Don't know how to display condition %d on %s\n", cond, c->name);
+                        return -1;
+        }
+
+        return 0;
+}
+
+static struct ast_channel * gsm_new (struct gsm_pvt *gsm, const char *exten, const char *cidnum, char *cidname, const int state)
+{
+        struct ast_channel *tmp;
+	char gsmname[128];
+	sprintf(gsmname,"GSM/%d", gsm->port);
+	
+        tmp = ast_channel_alloc(1, state, cidnum , cidname, gsmname);
+
+        if (tmp) {
+                ast_string_field_build(tmp, name, "%s", gsmname);
+                tmp->tech = &gsm_tech;
+                tmp->tech_pvt = gsm;
+
+		gsm->portfd=gsm_audio_open(gsm->port);
+
+		if (gsm->portfd>=0) {
+             		tmp->fds[0] = gsm->portfd;
+		} else {
+			ast_log(LOG_WARNING,"Could not open audio fd (%s)\n", strerror(errno));
+		}
+
+                tmp->nativeformats = AST_FORMAT_ALAW;
+                tmp->readformat = AST_FORMAT_ALAW;
+                tmp->writeformat = AST_FORMAT_ALAW;
+                if (exten)
+                        ast_copy_string(tmp->exten, exten, AST_MAX_EXTENSION);
+
+                ast_copy_string(tmp->context, gsm->context, AST_MAX_CONTEXT);
+
+		if (cidnum) {
+                        tmp->cid.cid_num = ast_strdup(cidnum);
+                        tmp->cid.cid_ani = ast_strdup(cidnum);
+		}
+		
+		if (cidname) 
+                        tmp->cid.cid_name = ast_strdup(cidname);
+
+#if 0
+		ast_mutex_lock(&bnxgsm_usecnt_lock);
+                ++bnxgsm_usecnt;
+                ast_mutex_unlock(&bnxgsm_usecnt_lock);
+#endif
+                ast_update_use_count();
+        }
+
+        gsm->ast_chan = tmp;
+
+	gsm_put_priv(gsm->port, tmp);
+	gsm->state=GSM_STATE_NONE;
+
+        return tmp;
+}
+
+static void configure_gsm(struct gsm_pvt *gsm)
+{
+	if (cm_get(config, gsm->context, sizeof(gsm->context), SECT_PORT, CFG_PORT_CONTEXT, gsm->port)) {
+		strcpy(gsm->context,default_context);
+        }
+
+	if (cm_get(config, gsm->exten, sizeof(gsm->exten), SECT_PORT, CFG_PORT_EXTEN, gsm->port)) {
+		strcpy(gsm->exten,default_exten);
+        }
+
+	cm_get_bool(config, gsm->hidecallerid, SECT_PORT, CFG_PORT_HIDECALLERID, gsm->port);
+
+}
+
+static struct ast_channel *gsm_request(const char *type, int format, void *data, int *cause)
+{	
+
+	char buf[128];
+	char *port_str, *ext, *p;
+
+	ast_copy_string(buf, data, sizeof(buf)-1);
+	p=buf;
+	port_str=strsep(&p, "/");
+	ext=strsep(&p, "/");
+
+	ast_verbose("portstr:%s ext:%s\n",port_str, ext);
+
+	struct gsm_pvt *gsm=malloc(sizeof(struct gsm_pvt));
+
+	memset(gsm,0,sizeof(struct gsm_pvt));
+
+	gsm->port=atoi(port_str);
+
+	configure_gsm(gsm);	
+
+	return gsm_new(gsm, ext, NULL, NULL, AST_STATE_RINGING);
+}
+
+
+/*sms functions*/
+static void output_sms(int port, struct gsm_sms_message *msg)
+{
+	ast_verbose("P(%d) SMS RECEIVED: Idx(%d) Number(%s) Date(%s) Text(%s)\n", port,
+			msg->idx,
+			msg->number,
+			msg->date,
+			msg->text
+			);	
+}
+
+static void save_sms(int port, struct gsm_sms_message *msg)
+{
+	char filename[128];
+	cm_get(config, filename, sizeof(filename)-32, SECT_GENERAL, CFG_GEN_SMS_DIR );
+
+	if (!strlen(filename)) {
+		ast_log(LOG_WARNING,"cannot save sms, no directory specified (see gsm.conf)\n");
+		return;
+	}
+
+	struct timeval tv;
+	gettimeofday(&tv,NULL);
+
+	char name[32];
+	sprintf(name,"/%d-%d.sms",(int)tv.tv_sec, (int)tv.tv_usec);
+	strcat(filename, name);
+
+	//ast_verbose("Saving SMS in %s\n",filename);
+
+	FILE *f=fopen(filename, "w+");
+	
+	if (!f) {
+		ast_log(LOG_WARNING,"cannot save sms at (%s) error (%s)\n",filename, strerror(errno));
+		return;
+	}
+
+	fprintf(f,"callerid=%s\n",msg->number);
+	fprintf(f,"date=%s\n",msg->date);
+	fprintf(f,"text=%s\n",msg->text);
+
+	fclose(f);
+}
+
+static int sms_idx[256];
+
+
+static void sms_idx_add(int idx)
+{
+	int i;
+	for (i=0; i<256; i++) {
+		if (!sms_idx[i]) {
+			sms_idx[i]=idx;
+			ast_verbose("adding i%d idx %d\n", i,idx);
+			break;
+		}
+	}
+}
+
+static int sms_idx_get_next(void)
+{
+	int i;
+	for (i=0; i<256; i++) {
+		if (sms_idx[i]) {
+			int idx=sms_idx[i];
+			sms_idx[i]=0;
+			ast_verbose("returnind i%d idx %d\n", i,idx);
+			return idx; 
+		}
+	}
+	return 0;
+}
+
+enum gsm_events {
+	GSM_EVENT_NONE=0,
+	GSM_EVENT_RING,
+	GSM_EVENT_BUSY,
+	GSM_EVENT_NO_CARRIER,
+	GSM_EVENT_OK,
+	GSM_EVENT_CIEV_CALL_1,
+	GSM_EVENT_CIEV_CALL_0,
+	GSM_EVENT_CIEV_SOUNDER_1,
+	GSM_EVENT_CIEV_SOUNDER_0,
+	GSM_EVENT_CIEV_MESSAGE_1,
+	GSM_EVENT_SLCC,
+	GSM_EVENT_ENTER_SMS,
+	GSM_EVENT_SMS_ECHO,
+	GSM_EVENT_SMS_CMGL_ECHO,
+	GSM_EVENT_SMS_TRANSMITTED,
+	GSM_EVENT_SMS_NEW_MESSAGE,
+	GSM_EVENT_ERROR,
+	GSM_EVENT_GSMERROR,
+	GSM_EVENT_SOPS,
+	GSM_EVENT_COPS,
+};
+
+static enum gsm_events parse_events (char *event) {
+	if (strstr(event, "RING")) {
+		return GSM_EVENT_RING;
+	} else if (strstr(event, "BUSY")) {
+		return GSM_EVENT_BUSY;
+	} else if (strstr(event, "OK")) {
+		return GSM_EVENT_OK;
+	} else if (strstr(event, "NO CARRIER")) {
+		return GSM_EVENT_NO_CARRIER;
+	} else if (strstr(event, "+CIEV: call,1")) {
+		return GSM_EVENT_CIEV_CALL_1;
+	} else if (strstr(event, "+CIEV: call,0")) {
+		return GSM_EVENT_CIEV_CALL_0;
+	} else if (strstr(event, "+CIEV: sounder,1")) {
+		return GSM_EVENT_CIEV_SOUNDER_1;
+	} else if (strstr(event, "+CIEV: sounder,0")) {
+		return GSM_EVENT_CIEV_SOUNDER_0;
+	} else if (strstr(event, "+CIEV: message,1")) {
+		return GSM_EVENT_CIEV_MESSAGE_1;
+	} else if (strstr(event, "^SLCC:")) {
+		return GSM_EVENT_SLCC;
+	} else if (strstr(event, "> ")) {
+		return GSM_EVENT_ENTER_SMS;
+	} else if (strstr(event, "AT+CMGS")) {
+		return GSM_EVENT_SMS_ECHO;
+	} else if (strstr(event, "+CMGS: ")) {
+		return GSM_EVENT_SMS_TRANSMITTED;
+	} else if (strstr(event, "AT+CMGL=ALL")) {
+		return GSM_EVENT_SMS_CMGL_ECHO;
+	} else if (strstr(event, "+CMGL: ")) {
+		return GSM_EVENT_SMS_NEW_MESSAGE;
+	} else if (strstr(event, "ERROR")) {
+		return GSM_EVENT_ERROR;
+	} else if (strstr(event, "GSMERR:")) {
+		return GSM_EVENT_GSMERROR;
+	} else if (strstr(event, "^SOPS:")) {
+		return GSM_EVENT_SOPS;
+	} else if (strstr(event, "+COPS:")) {
+		return GSM_EVENT_COPS;
+	} else {
+		return GSM_EVENT_NONE;
+	}
+}
+
+/*see doc p.151*/
+struct gsm_slcc {
+	int idx,dir,stat,mode,mpty,tca;
+	char callerid[64];
+	int type;
+} gsm_slcc[MAX_GSM_PORTS];
+
+static void cb_events(int port, char *event)
+{
+	struct ast_channel *ast=gsm_get_priv(port);
+	struct gsm_pvt *gsm=NULL;
+	enum gsm_events ev=parse_events(event);
+	
+	if (ast)
+		gsm=ast->tech_pvt;
+
+	if (!strlen(event)) return ; /*skip empty lines*/
+
+	if (gsm_debug) {
+		if (ev != GSM_EVENT_NONE) 
+			ast_verbose("P(%d)> ev (%d) state (%d) event (%s) smsstate (%d)\n", port, ev, gsm?gsm->state:-1, event, gsm_sms[port].state);
+		else
+			ast_verbose("P(%d)> unkown event state (%d) event (%s) smsstate (%d)\n",port, gsm?gsm->state:-1, event, gsm_sms[port].state);
+	}
+
+	/*note that the OK event might be handled under different switches*/
+	/*sms handling*/
+	//ast_verbose("SMS_STATE: ev(%d)  sms_state(%d)\n", gsm_sms[port].state);
+	if (gsm_sms[port].state != GSM_SMS_STATE_NONE) {
+		struct gsm_sms_message *msg=&gsm_sms[port].inbound_msg;
+		char buf[1048];
+		//ast_verbose("SMS_STATE != NONE\n");
+
+		switch (ev) {
+			/*RECEIVING SMS*/	
+			case GSM_EVENT_SMS_CMGL_ECHO:
+				/*enter list mode*/
+				gsm_sms[port].state=GSM_SMS_STATE_LIST;
+				//ast_verbose("CMGL_ECHO -> STATE_LIST\n");
+			break;
+			case GSM_EVENT_SMS_NEW_MESSAGE:
+			/*new sms*/
+			/*are we the first new message ?*/
+			//ast_verbose("NEW_MESSAGE->GET_TEXT\n");
+			if (gsm_sms[port].state==GSM_SMS_STATE_GET_TEXT) {
+				if(gsm_sms[port].work==GSM_SMS_WORK_SHOW)
+					output_sms(port, &gsm_sms[port].inbound_msg);
+				if(gsm_sms[port].work==GSM_SMS_WORK_FETCH) {
+					save_sms(port, &gsm_sms[port].inbound_msg);
+					sms_idx_add(gsm_sms[port].inbound_msg.idx);
+				}
+			}
+
+			{ /*parse the sms header*/
+				char *p=event, *r;
+				r=strsep(&p,":"); if (!r) break; /*CMGL*/
+				r=strsep(&p,","); if (!r) break; /*idx*/
+				msg->idx=atoi(r);
+				r=strsep(&p,","); if (!r) break;/*REC READ*/
+				r=strsep(&p,"\""); if (!r) break;/*skip*/
+				r=strsep(&p,"\""); if (!r) break;/*Number*/
+				strcpy(msg->number,r);
+				r=strsep(&p,"\""); if (!r) break;/*skip*/
+				r=strsep(&p,"\""); if (!r) break;/*date*/
+				strcpy(msg->date,r);
+				gsm_sms[port].state=GSM_SMS_STATE_GET_TEXT;
+				msg->text[0]=0;
+			}
+			break;
+			case GSM_EVENT_NONE:
+			if (gsm_sms[port].state==GSM_SMS_STATE_GET_TEXT) {
+				/*its the Text*/
+				strcat(msg->text, event);
+			}
+			break;
+			case GSM_EVENT_OK:
+			ast_verbose("EVENT_OK\n");
+			if (gsm_sms[port].state==GSM_SMS_STATE_GET_TEXT) {
+				if(gsm_sms[port].work==GSM_SMS_WORK_SHOW)
+					output_sms(port, &gsm_sms[port].inbound_msg);
+				if(gsm_sms[port].work==GSM_SMS_WORK_FETCH) {
+					save_sms(port, &gsm_sms[port].inbound_msg);
+					sms_idx_add(gsm_sms[port].inbound_msg.idx);
+				}
+				
+				/*finish sms list mode*/
+				int idx = sms_idx_get_next();
+				if (idx) {
+					char buf[32];
+					sprintf(buf, "AT+CMGD=%d",idx);
+					gsm_sms[port].state=GSM_SMS_STATE_FLUSHING;
+					gsm_send(port,buf,100);
+					ast_verbose("sms del %d\n",idx);
+					break;
+				}
+			}
+
+			if (gsm_sms[port].state==GSM_SMS_STATE_FLUSHING) {
+				/*FIXME*/
+				int idx = sms_idx_get_next();
+				if (idx) {
+					char buf[32];
+					sprintf(buf, "AT+CMGD=%d",idx);
+					gsm_sms[port].state=GSM_SMS_STATE_FLUSHING;
+					gsm_send(port,buf,100);
+					ast_verbose("sms del %d\n",idx);
+					break;
+				} 
+			}
+
+			gsm_sms[port].state=GSM_SMS_STATE_NONE;
+			gsm_sms[port].work=GSM_SMS_WORK_SHOW;
+			break;
+			/*TRANSMITTING SMS*/
+			case GSM_EVENT_SMS_TRANSMITTED:
+			/*if (gsm_sms[port].s && gsm_sms[port].m) 
+				astman_send_ack(gsm_sms[port].s, gsm_sms[port].m, 
+						"GsmSendSms: Success");
+			*/
+			gsm_sms[port].s=NULL;
+			gsm_sms[port].m=NULL;
+			gsm_sms[port].state=GSM_SMS_STATE_NONE;
+			break;
+			case GSM_EVENT_SMS_ECHO:
+				ast_verbose("Enter SMS Mode\n");
+				gsm_sms_enter(port);
+			break;
+			case GSM_EVENT_ENTER_SMS:
+				gsm_sms[port].state=GSM_SMS_STATE_SMS_SENT;
+				ast_verbose("Sending sms (%s)\n",gsm_sms[port].sms);
+				sprintf(buf,"%s\x1A",gsm_sms[port].sms);
+				gsm_send_raw(port, buf, 100);
+			break;
+			/*ERRORS*/
+			case GSM_EVENT_ERROR:
+				ast_verbose("GSM EVENT ERROR\n");
+				if (gsm_sms[port].state == GSM_SMS_STATE_SMS_SENT) {
+					/*
+					if (gsm_sms[port].s && gsm_sms[port].m) 
+						astman_send_ack(gsm_sms[port].s, gsm_sms[port].m, 
+							"GsmSendSms: Error");
+					*/
+					gsm_sms[port].state=GSM_SMS_STATE_NONE;
+					ast_verbose("SMS send error\n");
+				} else if (gsm_sms[port].state == GSM_SMS_STATE_LIST) {
+					ast_verbose("SMS List not yet available, try later\n");
+					gsm_sms[port].state=GSM_SMS_STATE_NONE;
+				}
+			break;
+			default:
+			break;
+		}
+	}
+
+	/*pre call handling*/
+	if (!gsm) {
+		switch(ev) {
+			case GSM_EVENT_COPS:
+				if (!strcasecmp(event, "+COPS: 1")) {
+					ast_verbose("P(%d)> ! Module not registered @ Provider\n", port);
+				} else {
+					char *p=event, *prov;
+					strsep(&p,",");
+					strsep(&p,",");
+					prov=strsep(&p,",");
+					ast_verbose("P(%d)> Module registered @ Provider (%s)\n", port, prov);
+				}
+			break;
+			case GSM_EVENT_SOPS:
+				{
+					char *p=event;
+					while(p) {
+						char *opstr;
+						opstr=strsep(&p,"()");
+						if (strlen(opstr)>7) { 
+							struct gsm_op op;
+							/*skip the first 2 args*/
+							strsep(&opstr,","); strsep(&opstr,",");
+							strcpy(op.name,strsep(&opstr,","));
+							strcpy(op.origname,strsep(&opstr,","));
+							strcpy(op.number,strsep(&opstr,","));
+							ast_verbose("Op. Name (%s) Orig. Op. Name (%s) Op.Number(%s)\n",
+									op.name, op.origname, op.number);
+
+						}
+					}
+
+				}
+				break;
+			case GSM_EVENT_CIEV_MESSAGE_1:
+				gsm_sms[port].work=GSM_SMS_WORK_FETCH;
+				_gsm_list_sms(port);
+			break;
+			case GSM_EVENT_SLCC:
+			if (strlen(event)>7) {
+				sscanf(event,"^SLCC: %d,%d,%d,%d,%d,%d,\"%[+0-9]\",%d",
+					&gsm_slcc[port].idx,
+					&gsm_slcc[port].dir,
+					&gsm_slcc[port].stat,
+					&gsm_slcc[port].mode,
+					&gsm_slcc[port].mpty,
+					&gsm_slcc[port].tca,
+					gsm_slcc[port].callerid,
+					&gsm_slcc[port].type);
+
+				ast_verbose("mode: %s cid: %s\n", 
+					gsm_slcc[port].type==145?"INT":"OTHER", 
+					gsm_slcc[port].callerid);
+					
+			}
+			break;
+			case GSM_EVENT_RING:
+				gsm=malloc(sizeof(struct gsm_pvt));
+
+				memset(gsm,0,sizeof(struct gsm_pvt));
+
+				gsm->port=port;
+		
+				configure_gsm(gsm);	
+				ast_verbose(" --> exten:%s callerid:%s\n",gsm->exten,
+					gsm_slcc[port].callerid);
+
+				char *cid=gsm_slcc[port].callerid;
+				if (gsm_slcc[port].type==145) {
+					cid++; /*skip the '+'*/
+				}
+
+				struct ast_channel *chan=gsm_new(gsm, gsm->exten, cid, NULL, AST_STATE_RINGING);
+	
+				ast_pbx_start(chan);
+			break;
+			case GSM_EVENT_ERROR:
+				ast_verbose("GSM EVENT ERROR\n");
+			break;
+			default: 
+			break;
+		}
+	}
+
+	if (!gsm) return;
+
+	/*during call handling*/
+	switch (ev) {
+	case GSM_EVENT_RING:
+		ast_verbose(" -> RING\n");
+		break;
+	case GSM_EVENT_CIEV_CALL_0:
+	case GSM_EVENT_NO_CARRIER:
+	case GSM_EVENT_BUSY:
+		ast_verbose(" -> BUSY/NO CARRIER/CALL_0\n");
+		if (ast && gsm->state != GSM_STATE_HANGUPED) {
+			gsm->state=GSM_STATE_HANGUPED;
+			ast_queue_hangup(ast);
+		}
+		break;
+	case GSM_EVENT_OK:
+		ast_verbose(" -> OK\n");
+		if (gsm->state != GSM_STATE_ATD_OUT) break;
+	break;
+	case GSM_EVENT_CIEV_CALL_1:
+		ast_verbose(" -> ANSWER\n");
+		ast_queue_control(ast, AST_CONTROL_ANSWER);
+		int res=gsm_audio_start(gsm->port);
+		if (res<0) {
+			ast_log(LOG_WARNING, " couldn't start audio error (%d,%s)\n", errno, strerror(errno));
+		}
+		gsm->state = GSM_STATE_ANSWERED;
+
+		break;
+	case GSM_EVENT_CIEV_SOUNDER_1:
+		if (gsm->state == GSM_STATE_ATD_OUT) {
+			ast_verbose(" -> PROCEEDING\n");
+			ast_queue_control(ast, AST_CONTROL_PROCEEDING);
+			gsm->state = GSM_STATE_PROCEEDING;
+		}
+		break;
+	case GSM_EVENT_CIEV_SOUNDER_0:
+		if (gsm->state == GSM_STATE_PROCEEDING) {
+			ast_verbose(" -> ALERTING\n");
+			ast_queue_control(ast, AST_CONTROL_RINGING);
+			gsm->state = GSM_STATE_ALERTING;
+		}
+		break;
+/*	case GSM_EVENT_OK:
+		ast_verbose(" -> OK\n");
+		break;*/
+	case GSM_EVENT_NONE:
+		ast_verbose(" -> NONE\n");
+		break;
+	case GSM_EVENT_ERROR:
+		ast_verbose("GSM EVENT ERROR\n");
+		break;
+	case GSM_EVENT_GSMERROR:
+		ast_verbose("shutting down port, due to GSMERROR (lib)\n");
+		gsm_shutdown_port(port);
+		break;
+	default:
+		break;
+	}
+}
+
+
+static int gsm_set_simslot_exec(struct ast_channel *chan, void *data)
+{
+	AST_DECLARE_APP_ARGS(args,
+		AST_APP_ARG(port);
+		AST_APP_ARG(slot);
+	);
+
+ 	if (ast_strlen_zero(data)) {
+		ast_log(LOG_WARNING, "This application requires arguments.\n");
+		return -1;
+	}
+
+	/* Extract username (agt), password and name from agent (args). */
+	AST_STANDARD_APP_ARGS(args, data);
+
+	if (args.argc != 2) {
+		ast_log(LOG_WARNING, "Wrong argument count\n");
+		return 0;
+	}
+	
+	int i=gsm_set_next_simslot(atoi(args.port),atoi(args.slot));
+	if (i<0) {
+		ast_verbose("Setting simslot failed (%s)\n", strerror(errno));
+		return -1;
+	}
+	
+	if (i)	_gsm_restart_port(atoi(args.port)) ;
+	else ast_verbose("not setting Simslot, we have it already\n");
+
+	return 0;
+}
+
+static int load_module(void)
+{
+	int i = 0;
+
+	memset(gsm_slcc, 0, sizeof(gsm_slcc));
+
+	gsm_config_init();
+
+	char filename[128];
+	cm_get(config, filename, sizeof(filename)-32, SECT_GENERAL, CFG_GEN_SMS_DIR );
+
+	if (mkdir(filename,0777)<0 && errno != EEXIST)
+	{
+		ast_log(LOG_WARNING, "Couldn't create sms save dir (%s) error(%s)\n",filename, strerror(errno));
+	}
+	
+	char debug[16];
+	cm_get(config, debug, sizeof(debug), SECT_GENERAL, CFG_GEN_DEBUG);
+	gsm_debug=strtol(debug,NULL,0);
+
+	memset(gsm_cfg,0,sizeof(gsm_cfg));
+
+	/*initialize the gsm_config*/
+	int  next;
+	int *prev = NULL;
+	for (; cm_get_next_id(config, SECT_PORT, prev, &next); prev = &next) {
+		char buf[256];
+
+		if (next > MAX_GSM_PORTS) {
+			ast_log(LOG_WARNING, "ignoring port %d: invalid port id\n", next);
+			continue;
+		}
+
+		gsm_cfg[next].port=1;
+		cm_get(config, gsm_cfg[next].pin, sizeof(gsm_cfg[next].pin), SECT_PORT, CFG_PORT_PIN, next);
+		if (cm_get(config, buf, sizeof(buf), SECT_PORT, CFG_PORT_INITFILE, next)) {
+			gsm_cfg[i].initfile=strdup(buf);
+		}
+		
+		cm_get(config, gsm_cfg[next].smsc, sizeof(gsm_cfg[next].smsc), SECT_PORT, CFG_PORT_SMSC, next);
+	}
+
+
+	for (i=0; i<256; i++)
+		sms_idx[i]=0;
+	
+#if 1
+	if (gsm_init( cb_events , gsm_cfg) <0) {
+                ast_log(LOG_ERROR, "Unable to initialize GSM\n");
+                return AST_MODULE_LOAD_DECLINE;
+	}
+#endif
+
+        if (ast_channel_register(&gsm_tech)) {
+                ast_log(LOG_ERROR, "Unable to register channel type 'GSM'\n");
+                return AST_MODULE_LOAD_FAILURE;
+        }
+
+	ast_cli_register_multiple(chan_gsm_clis, sizeof(chan_gsm_clis) / sizeof(struct ast_cli_entry));
+
+	ast_manager_register( "GsmSendSms", 0, action_send_sms, "Send SMS on GSM" );
+
+	ast_register_application("gsm_set_simslot", gsm_set_simslot_exec, "gsm_set_simslot",
+				 "gsm_set_simslot(<port>,<0|1>)n"
+				 "changes the to be used simslot for port <port> to either\n"
+				 "0 or 1 (0 is the external accessible)\n"
+		);
+
+
+        return AST_MODULE_LOAD_SUCCESS;
+}
+
+
+
+static int unload_module(void)
+{
+	ast_cli_unregister_multiple(chan_gsm_clis, sizeof(chan_gsm_clis) / sizeof(struct ast_cli_entry));
+
+	ast_manager_unregister( "GsmSendSms" );
+	ast_unregister_application("gsm_set_simslot");
+
+ 	ast_channel_unregister(&gsm_tech);
+
+	gsm_config_exit();
+	gsm_shutdown();
+
+	return 0;
+}
+
+static int reload_module(void)
+{
+	gsm_config_exit();
+	gsm_config_init ();
+	return 0;
+}
+
+#define AST_MODULE "chan_gsm"
+AST_MODULE_INFO(ASTERISK_GPL_KEY,
+                                AST_MODFLAG_DEFAULT,
+                                "Channel driver for gsm cards",
+                                .load = load_module,
+                                .unload = unload_module,
+                                .reload = reload_module,
+                           );
+

Propchange: team/group/asterisk-1.4-gsm/channels/chan_gsm.c
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: team/group/asterisk-1.4-gsm/channels/chan_gsm.c
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Propchange: team/group/asterisk-1.4-gsm/channels/chan_gsm.c
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: team/group/asterisk-1.4-gsm/channels/gsmctl.c
URL: http://svn.digium.com/view/asterisk/team/group/asterisk-1.4-gsm/channels/gsmctl.c?view=auto&rev=60067
==============================================================================
--- team/group/asterisk-1.4-gsm/channels/gsmctl.c (added)
+++ team/group/asterisk-1.4-gsm/channels/gsmctl.c Wed Apr  4 07:31:47 2007
@@ -1,0 +1,545 @@
+#include <stdio.h>
+#include <string.h>
+#include <sys/select.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <semaphore.h>
+#include <pthread.h>
+#include <sys/ioctl.h>
+#include <signal.h>
+
+#include "gsmctl.h"
+#define GSM_LINE_LENGTH 4096
+
+#define DEFAULT_WAIT4MOD 10
+
+
+static int debug = 0;
+FILE *debugfp = NULL;
+
+
+enum ctlport_state {
+	CTLPORT_STATE_NONE=0,
+	CTLPORT_STATE_SMS,
+	CTLPORT_STATE_KILLME,
+	CTLPORT_STATE_KILLED,
+}; 
+
+struct ctlport {
+	FILE *fpw,*fpr;
+	pthread_t t;
+	int fd;
+	char *initfile;
+	int port;
+	struct gsm_config *cfg;
+	enum ctlport_state state;
+	void *priv;
+};
+
+sem_t ready[MAX_GSM_PORTS];
+
+struct ctlport ctlport[MAX_GSM_PORTS];
+
+
+void (*cbEvents)(int port, char *event);
+
+void gsm_close_port(int port);
+
+static struct ctlport *getctlport(int port)
+{
+	int i;
+	for (i=1; i<MAX_GSM_PORTS; i++) {
+		if (ctlport[i].port == port) return &ctlport[i];
+	}
+	return NULL;
+}
+
+int gsm_sms_enter(int port)
+{
+	struct ctlport *ctl=getctlport(port);
+
+	ctl->state=CTLPORT_STATE_SMS;
+	return 0;
+}
+
+
+int gsm_set_next_simslot(int port, int slot)
+{
+	struct ctlport *ctl=getctlport(port);
+
+	if (!ctl->fpr) return -1;
+	int fd=fileno(ctl->fpr);
+
+	if (debug) fprintf(debugfp, "Setting next sim slot port (%d) slot (%d)\n", port, slot);
+
+      	return ioctl( fd, GSM_SETNEXTSIMSLOT, slot?1:0);
+}
+
+int gsm_audio_start(int port)
+{
+	struct ctlport *ctl=getctlport(port);

[... 582 lines stripped ...]


More information about the asterisk-commits mailing list