[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