FS-5078 gsmopen: adding ussd capabilities, thanks Boris
This commit is contained in:
parent
efef505e26
commit
40c56c621a
|
@ -197,6 +197,12 @@ typedef enum {
|
|||
|
||||
#define GSMOPEN_MAX_INTERFACES 64
|
||||
|
||||
#define USSD_ENCODING_AUTO 0
|
||||
#define USSD_ENCODING_PLAIN 1
|
||||
#define USSD_ENCODING_HEX_7BIT 2
|
||||
#define USSD_ENCODING_HEX_8BIT 3
|
||||
#define USSD_ENCODING_UCS2 4
|
||||
|
||||
#ifndef WIN32
|
||||
struct GSMopenHandles {
|
||||
int currentuserhandle;
|
||||
|
@ -405,6 +411,14 @@ struct private_object {
|
|||
int sms_cnmi_not_supported;
|
||||
int sms_pdu_not_supported;
|
||||
|
||||
int ussd_request_encoding;
|
||||
int ussd_response_encoding;
|
||||
int ussd_request_hex;
|
||||
int ussd_received;
|
||||
int ussd_status;
|
||||
char ussd_message[1024];
|
||||
char ussd_dcs[256];
|
||||
|
||||
struct timeval call_incoming_time;
|
||||
switch_mutex_t *controldev_lock;
|
||||
|
||||
|
@ -561,3 +575,5 @@ int serial_audio_shutdown(private_t *tech_pvt);
|
|||
#ifndef WIN32
|
||||
void find_ttyusb_devices(private_t *tech_pvt, const char *dirname);
|
||||
#endif// WIN32
|
||||
int gsmopen_ussd(private_t *tech_pvt, char *ussd, int waittime);
|
||||
int ussd_incoming(private_t *tech_pvt);
|
||||
|
|
|
@ -1392,6 +1392,69 @@ int gsmopen_serial_read_AT(private_t *tech_pvt, int look_for_ack, int timeout_us
|
|||
}
|
||||
|
||||
}
|
||||
if ((strncmp(tech_pvt->line_array.result[i], "+CUSD:", 6) == 0)) {
|
||||
if (option_debug > 1)
|
||||
DEBUGA_GSMOPEN("|%s| USSD received\n", GSMOPEN_P_LOG, tech_pvt->line_array.result[i]);
|
||||
int res = 0, status = 0;
|
||||
unsigned int dcs = 0;
|
||||
char ussd_msg[1024];
|
||||
memset(tech_pvt->ussd_message, '\0', sizeof(tech_pvt->ussd_message));
|
||||
memset(tech_pvt->ussd_dcs, '\0', sizeof(tech_pvt->ussd_dcs));
|
||||
res = sscanf(&tech_pvt->line_array.result[i][6], "%d,\"%1023[0-9A-F]\",%d", &status, ussd_msg, &dcs);
|
||||
if (res == 1) {
|
||||
NOTICA("received +CUSD with status %d\n", GSMOPEN_P_LOG, status);
|
||||
tech_pvt->ussd_received = 1;
|
||||
tech_pvt->ussd_status = status;
|
||||
} else if (res == 3) {
|
||||
tech_pvt->ussd_received = 1;
|
||||
tech_pvt->ussd_status = status;
|
||||
|
||||
//identifying dcs alphabet according to GSM 03.38 Cell Broadcast Data Coding Scheme
|
||||
//CBDataCodingScheme should be used here, but it appears to be buggy (ucs2 messages are not recognized)
|
||||
int alphabet = DCS_RESERVED_ALPHABET;
|
||||
if (dcs == 0x11) {
|
||||
alphabet = DCS_SIXTEEN_BIT_ALPHABET;
|
||||
} else if ((dcs & 0xF0) <= 0x30){
|
||||
alphabet = DCS_DEFAULT_ALPHABET;
|
||||
} else if ((dcs & 0xC0) == 0x40 || (dcs & 0xF0) == 0x90) {
|
||||
alphabet = dcs & (3 << 2);
|
||||
};
|
||||
|
||||
if ( (tech_pvt->ussd_response_encoding == USSD_ENCODING_AUTO && alphabet == DCS_DEFAULT_ALPHABET)
|
||||
|| tech_pvt->ussd_response_encoding == USSD_ENCODING_HEX_7BIT ) {
|
||||
SMSDecoder d(ussd_msg);
|
||||
d.markSeptet();
|
||||
string ussd_dec = gsmToLatin1(d.getString(strlen(ussd_msg) / 2 * 8 / 7));
|
||||
iso_8859_1_to_utf8(tech_pvt, (char *) ussd_dec.c_str(), tech_pvt->ussd_message, sizeof(tech_pvt->ussd_message));
|
||||
strcpy(tech_pvt->ussd_dcs, "default alphabet");
|
||||
} else if ( (tech_pvt->ussd_response_encoding == USSD_ENCODING_AUTO && alphabet == DCS_SIXTEEN_BIT_ALPHABET)
|
||||
|| tech_pvt->ussd_response_encoding == USSD_ENCODING_UCS2 ) {
|
||||
ucs2_to_utf8(tech_pvt, ussd_msg, tech_pvt->ussd_message, sizeof(tech_pvt->ussd_message));
|
||||
strcpy(tech_pvt->ussd_dcs, "16-bit alphabet");
|
||||
} else if ( (tech_pvt->ussd_response_encoding == USSD_ENCODING_AUTO && alphabet == DCS_EIGHT_BIT_ALPHABET)
|
||||
|| tech_pvt->ussd_response_encoding == USSD_ENCODING_HEX_8BIT ) {
|
||||
char ussd_dec[1024];
|
||||
memset(ussd_dec, '\0', sizeof(ussd_dec));
|
||||
hexToBuf(ussd_msg, (unsigned char*)ussd_dec);
|
||||
iso_8859_1_to_utf8(tech_pvt, (char *) ussd_dec, tech_pvt->ussd_message, sizeof(tech_pvt->ussd_message));
|
||||
strcpy(tech_pvt->ussd_dcs, "8-bit alphabet");
|
||||
} else if ( tech_pvt->ussd_response_encoding == USSD_ENCODING_PLAIN ) {
|
||||
string ussd_dec = gsmToLatin1(ussd_msg);
|
||||
iso_8859_1_to_utf8(tech_pvt, (char *) ussd_dec.c_str(), tech_pvt->ussd_message, sizeof(tech_pvt->ussd_message));
|
||||
strcpy(tech_pvt->ussd_dcs, "default alphabet");
|
||||
} else {
|
||||
ERRORA("USSD data coding scheme not supported=%d\n", GSMOPEN_P_LOG, dcs);
|
||||
}
|
||||
|
||||
NOTICA("USSD received: status=%d, message='%s', dcs='%d'\n",
|
||||
GSMOPEN_P_LOG, tech_pvt->ussd_status, tech_pvt->ussd_message, dcs);
|
||||
|
||||
ussd_incoming(tech_pvt);
|
||||
} else {
|
||||
ERRORA ("res=%d, +CUSD command has wrong format: %s\n",
|
||||
GSMOPEN_P_LOG, res, tech_pvt->line_array.result[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if ((strncmp(tech_pvt->line_array.result[i], "*ECAV", 5) == 0) || (strncmp(tech_pvt->line_array.result[i], "*ECAM", 5) == 0)) { /* sony-ericsson call processing unsolicited messages */
|
||||
int res, ccid, ccstatus, calltype, processid, exitcause, number, type;
|
||||
|
@ -2858,6 +2921,57 @@ int gsmopen_sendsms(private_t *tech_pvt, char *dest, char *text)
|
|||
return RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
int gsmopen_ussd(private_t *tech_pvt, char *ussd, int waittime)
|
||||
{
|
||||
int res = 0;
|
||||
DEBUGA_GSMOPEN("gsmopen_ussd: %s\n", GSMOPEN_P_LOG, ussd);
|
||||
if (tech_pvt->controldevprotocol == PROTOCOL_AT) {
|
||||
char at_command[1024];
|
||||
|
||||
string ussd_enc = latin1ToGsm(ussd);
|
||||
SMSEncoder e;
|
||||
e.markSeptet();
|
||||
e.setString(ussd_enc);
|
||||
string ussd_hex = e.getHexString();
|
||||
|
||||
memset(at_command, '\0', sizeof(at_command));
|
||||
tech_pvt->ussd_received = 0;
|
||||
if (tech_pvt->ussd_request_encoding == USSD_ENCODING_PLAIN
|
||||
||tech_pvt->ussd_request_encoding == USSD_ENCODING_AUTO) {
|
||||
snprintf(at_command, sizeof(at_command), "AT+CUSD=1,\"%s\",15", ussd_enc.c_str());
|
||||
res = gsmopen_serial_write_AT_ack(tech_pvt, at_command);
|
||||
if (res && tech_pvt->ussd_request_encoding == USSD_ENCODING_AUTO) {
|
||||
DEBUGA_GSMOPEN("Plain request failed, trying HEX7 encoding...\n", GSMOPEN_P_LOG);
|
||||
snprintf(at_command, sizeof(at_command), "AT+CUSD=1,\"%s\",15", ussd_hex.c_str());
|
||||
res = gsmopen_serial_write_AT_ack(tech_pvt, at_command);
|
||||
if (res == 0) {
|
||||
DEBUGA_GSMOPEN("HEX 7-bit request encoding will be used from now on\n", GSMOPEN_P_LOG);
|
||||
tech_pvt->ussd_request_encoding = USSD_ENCODING_HEX_7BIT;
|
||||
}
|
||||
}
|
||||
} else if (tech_pvt->ussd_request_encoding == USSD_ENCODING_HEX_7BIT) {
|
||||
snprintf(at_command, sizeof(at_command), "AT+CUSD=1,\"%s\",15", ussd_hex.c_str());
|
||||
res = gsmopen_serial_write_AT_ack(tech_pvt, at_command);
|
||||
} else if (tech_pvt->ussd_request_encoding == USSD_ENCODING_HEX_8BIT) {
|
||||
string ussd_h8 = bufToHex((const unsigned char*)ussd_enc.c_str(), ussd_enc.length());
|
||||
snprintf(at_command, sizeof(at_command), "AT+CUSD=1,\"%s\",15", ussd_h8.c_str());
|
||||
res = gsmopen_serial_write_AT_ack(tech_pvt, at_command);
|
||||
} else if (tech_pvt->ussd_request_encoding == USSD_ENCODING_UCS2) {
|
||||
char ussd_ucs2[1000];
|
||||
memset(ussd_ucs2, '\0', sizeof(ussd_ucs2));
|
||||
utf8_to_ucs2(tech_pvt, ussd, strlen(ussd), ussd_ucs2, sizeof(ussd_ucs2));
|
||||
snprintf(at_command, sizeof(at_command), "AT+CUSD=1,\"%s\",15", ussd_ucs2);
|
||||
res = gsmopen_serial_write_AT_ack(tech_pvt, at_command);
|
||||
}
|
||||
if (res) {
|
||||
return res;
|
||||
}
|
||||
if (waittime > 0)
|
||||
res = gsmopen_serial_read_AT(tech_pvt, 1, 0, waittime, "+CUSD", 1);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/************************************************/
|
||||
|
||||
/* LUIGI RIZZO's magic */
|
||||
|
|
|
@ -49,6 +49,8 @@ SWITCH_STANDARD_API(sendsms_function);
|
|||
#define SENDSMS_SYNTAX "gsmopen_sendsms interface_name destination_number SMS_text"
|
||||
SWITCH_STANDARD_API(gsmopen_dump_function);
|
||||
#define GSMOPEN_DUMP_SYNTAX "gsmopen_dump <interface_name|list>"
|
||||
SWITCH_STANDARD_API(gsmopen_ussd_function);
|
||||
#define USSD_SYNTAX "gsmopen_ussd <interface_name> <ussd_code> [nowait]"
|
||||
#define FULL_RELOAD 0
|
||||
#define SOFT_RELOAD 1
|
||||
|
||||
|
@ -1231,6 +1233,8 @@ static switch_status_t load_config(int reload_type)
|
|||
const char *portaudiopindex = "1";
|
||||
const char *speexecho = "1";
|
||||
const char *speexpreprocess = "1";
|
||||
const char *ussd_request_encoding = "auto";
|
||||
const char *ussd_response_encoding = "auto";
|
||||
|
||||
uint32_t interface_id = 0;
|
||||
int controldevice_speed = 115200; //FIXME TODO
|
||||
|
@ -1403,6 +1407,10 @@ static switch_status_t load_config(int reload_type)
|
|||
imei = val;
|
||||
} else if (!strcasecmp(var, "gsmopen_serial_sync_period")) {
|
||||
gsmopen_serial_sync_period = val;
|
||||
} else if (!strcasecmp(var, "ussd_request_encoding")) {
|
||||
ussd_request_encoding = val;
|
||||
} else if (!strcasecmp(var, "ussd_response_encoding")) {
|
||||
ussd_response_encoding = val;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1554,6 +1562,18 @@ static switch_status_t load_config(int reload_type)
|
|||
globals.GSMOPEN_INTERFACES[interface_id].no_sound = atoi(no_sound);
|
||||
globals.GSMOPEN_INTERFACES[interface_id].gsmopen_serial_sync_period = atoi(gsmopen_serial_sync_period);
|
||||
|
||||
globals.GSMOPEN_INTERFACES[interface_id].ussd_request_encoding =
|
||||
strcasecmp(ussd_request_encoding, "plain") == 0 ? USSD_ENCODING_PLAIN :
|
||||
strcasecmp(ussd_request_encoding, "hex7") == 0 ? USSD_ENCODING_HEX_7BIT :
|
||||
strcasecmp(ussd_request_encoding, "hex8") == 0 ? USSD_ENCODING_HEX_8BIT :
|
||||
strcasecmp(ussd_request_encoding, "ucs2") == 0 ? USSD_ENCODING_UCS2 : USSD_ENCODING_AUTO;
|
||||
|
||||
globals.GSMOPEN_INTERFACES[interface_id].ussd_response_encoding =
|
||||
strcasecmp(ussd_response_encoding, "plain") == 0 ? USSD_ENCODING_PLAIN :
|
||||
strcasecmp(ussd_response_encoding, "hex7") == 0 ? USSD_ENCODING_HEX_7BIT :
|
||||
strcasecmp(ussd_response_encoding, "hex8") == 0 ? USSD_ENCODING_HEX_8BIT :
|
||||
strcasecmp(ussd_response_encoding, "ucs2") == 0 ? USSD_ENCODING_UCS2 : USSD_ENCODING_AUTO;
|
||||
|
||||
globals.GSMOPEN_INTERFACES[interface_id].controldevice_speed = controldevice_speed; //FIXME
|
||||
globals.GSMOPEN_INTERFACES[interface_id].controldevprotocol = controldevprotocol; //FIXME
|
||||
globals.GSMOPEN_INTERFACES[interface_id].running = running; //FIXME
|
||||
|
@ -1781,7 +1801,12 @@ static switch_status_t chat_send(switch_event_t *message_event)
|
|||
from ? from : "NULL");
|
||||
goto end;
|
||||
} else {
|
||||
gsmopen_sendsms(tech_pvt, (char *) to, (char *) body);
|
||||
if (strcasecmp(to, "ussd") == 0) {
|
||||
gsmopen_ussd(tech_pvt, (char *) body, 0);
|
||||
} else {
|
||||
gsmopen_sendsms(tech_pvt, (char *) to, (char *) body);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
end:
|
||||
|
@ -1853,6 +1878,8 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_gsmopen_load)
|
|||
SWITCH_ADD_API(commands_api_interface, "gsmopen_dump", "gsmopen_dump interface", gsmopen_dump_function, GSMOPEN_DUMP_SYNTAX);
|
||||
SWITCH_ADD_API(commands_api_interface, "gsmopen_sendsms", "gsmopen_sendsms interface destination_number SMS_text", sendsms_function,
|
||||
SENDSMS_SYNTAX);
|
||||
SWITCH_ADD_API(commands_api_interface, "gsmopen_ussd", "gsmopen_ussd interface ussd_code wait_seconds", gsmopen_ussd_function,
|
||||
SENDSMS_SYNTAX);
|
||||
SWITCH_ADD_CHAT(chat_interface, GSMOPEN_CHAT_PROTO, chat_send);
|
||||
|
||||
/* indicate that the module should continue to be loaded */
|
||||
|
@ -2660,6 +2687,79 @@ SWITCH_STANDARD_API(sendsms_function)
|
|||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
SWITCH_STANDARD_API(gsmopen_ussd_function)
|
||||
{
|
||||
char *mycmd = NULL, *argv[3] = { 0 };
|
||||
int argc = 0;
|
||||
int waittime = 20;
|
||||
private_t *tech_pvt = NULL;
|
||||
|
||||
if (!zstr(cmd) && (mycmd = strdup(cmd))) {
|
||||
argc = switch_separate_string(mycmd, ' ', argv, (sizeof(argv) / sizeof(argv[0])));
|
||||
}
|
||||
|
||||
if (!argc) {
|
||||
stream->write_function(stream, "ERROR, usage: %s", USSD_SYNTAX);
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (argc < 2) {
|
||||
stream->write_function(stream, "ERROR, usage: %s", USSD_SYNTAX);
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (argc >= 3 && strcasecmp(argv[2], "nowait")==0) {
|
||||
waittime = 0;
|
||||
}
|
||||
|
||||
if (argv[0]) {
|
||||
int i;
|
||||
int found = 0;
|
||||
|
||||
for (i = 0; !found && i < GSMOPEN_MAX_INTERFACES; i++) {
|
||||
/* we've been asked for a normal interface name, or we have not found idle interfaces to serve as the "ANY" interface */
|
||||
if (strlen(globals.GSMOPEN_INTERFACES[i].name)
|
||||
&& (strncmp(globals.GSMOPEN_INTERFACES[i].name, argv[0], strlen(argv[0])) == 0)) {
|
||||
tech_pvt = &globals.GSMOPEN_INTERFACES[i];
|
||||
NOTICA("Trying to send USSD request: interface=%s, ussd=%s\n", GSMOPEN_P_LOG, argv[0], argv[1]);
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
if (!found) {
|
||||
stream->write_function(stream, "ERROR: A GSMopen interface with name='%s' was not found\n", argv[0]);
|
||||
switch_safe_free(mycmd);
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
} else {
|
||||
int err = gsmopen_ussd(tech_pvt, (char *) argv[1], waittime);
|
||||
if (err == AT_ERROR) {
|
||||
stream->write_function(stream, "ERROR: command failed\n");
|
||||
} else if (!waittime) {
|
||||
stream->write_function(stream, "USSD request has been sent\n");
|
||||
} else if (err) {
|
||||
stream->write_function(stream, "ERROR: USSD request timeout (%d)\n", err);
|
||||
} else if (!tech_pvt->ussd_received) {
|
||||
stream->write_function(stream, "ERROR: no response received\n");
|
||||
} else {
|
||||
stream->write_function(stream, "Status: %d%s\n", tech_pvt->ussd_status,
|
||||
tech_pvt->ussd_status == 0 ? " - completed" :
|
||||
tech_pvt->ussd_status == 1 ? " - action required" :
|
||||
tech_pvt->ussd_status == 2 ? " - error" : "");
|
||||
if (strlen(tech_pvt->ussd_message) != 0)
|
||||
stream->write_function(stream, "Text: %s\n", tech_pvt->ussd_message);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
stream->write_function(stream, "ERROR, usage: %s", USSD_SYNTAX);
|
||||
}
|
||||
end:
|
||||
switch_safe_free(mycmd);
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
int dump_event_full(private_t *tech_pvt, int is_alarm, int alarm_code, const char *alarm_message)
|
||||
{
|
||||
switch_event_t *event;
|
||||
|
@ -2807,7 +2907,44 @@ int sms_incoming(private_t *tech_pvt)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int ussd_incoming(private_t *tech_pvt)
|
||||
{
|
||||
switch_event_t *event;
|
||||
switch_core_session_t *session = NULL;
|
||||
int event_sent_to_esl = 0;
|
||||
|
||||
DEBUGA_GSMOPEN("received USSD on interface %s: TEXT=%s|\n", GSMOPEN_P_LOG, tech_pvt->name, tech_pvt->ussd_message);
|
||||
|
||||
/* mod_sms begin */
|
||||
if (switch_event_create(&event, SWITCH_EVENT_MESSAGE) == SWITCH_STATUS_SUCCESS) {
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "proto", GSMOPEN_CHAT_PROTO);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "login", tech_pvt->name);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "from", "ussd");
|
||||
//switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "date", tech_pvt->sms_date);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "datacodingscheme", tech_pvt->ussd_dcs);
|
||||
//switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "servicecentreaddress", tech_pvt->sms_servicecentreaddress);
|
||||
//switch_event_add_header(event, SWITCH_STACK_BOTTOM, "messagetype", "%d", tech_pvt->sms_messagetype);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "subject", "USSD MESSAGE");
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "to", tech_pvt->name);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "hint", tech_pvt->name);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "to_proto", GSMOPEN_CHAT_PROTO);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "from_user", "ussd");
|
||||
//switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "from_host", "from_host");
|
||||
//switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "from_full", "from_full");
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "to_user", tech_pvt->name);
|
||||
//switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "to_host", "to_host");
|
||||
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "ussd_status", "%d", tech_pvt->ussd_status);
|
||||
switch_event_add_body(event, "%s\n", tech_pvt->ussd_message);
|
||||
//switch_core_chat_send("GLOBAL", event); /* mod_sms */
|
||||
switch_core_chat_send("GLOBAL", event); /* mod_sms */
|
||||
} else {
|
||||
|
||||
ERRORA("cannot create event on interface %s. WHY?????\n", GSMOPEN_P_LOG, tech_pvt->name);
|
||||
}
|
||||
/* mod_sms end */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifndef WIN32
|
||||
#define PATH_MAX_GIOVA PATH_MAX
|
||||
|
|
Loading…
Reference in New Issue