From 6568cd6aa85b788b428953e21579d09fb242c0c6 Mon Sep 17 00:00:00 2001 From: Matthew Nicholson <mnicholson@digium.com> Date: Wed, 29 Jul 2009 21:46:17 +0000 Subject: [PATCH] This patch adds the ability to send a CUSD command to a bluetooth device. (closes issue #15278) Reported by: Artem Patches: cusd5.patch uploaded by Artem (license 800) Tested by: mnicholson, Artem Review: https://reviewboard.asterisk.org/r/274/ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@209484 65c4cc65-6c06-0410-ace0-fbb531ad65f3 --- addons/chan_mobile.c | 163 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 163 insertions(+) diff --git a/addons/chan_mobile.c b/addons/chan_mobile.c index 2e3ccdf3dc..9b7ccd3418 100644 --- a/addons/chan_mobile.c +++ b/addons/chan_mobile.c @@ -161,17 +161,20 @@ static int handle_response_clip(struct mbl_pvt *pvt, char *buf); static int handle_response_ring(struct mbl_pvt *pvt, char *buf); static int handle_response_cmti(struct mbl_pvt *pvt, char *buf); static int handle_response_cmgr(struct mbl_pvt *pvt, char *buf); +static int handle_response_cusd(struct mbl_pvt *pvt, char *buf); static int handle_sms_prompt(struct mbl_pvt *pvt, char *buf); /* CLI stuff */ static char *handle_cli_mobile_show_devices(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a); static char *handle_cli_mobile_search(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a); static char *handle_cli_mobile_rfcomm(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a); +static char *handle_cli_mobile_cusd(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a); static struct ast_cli_entry mbl_cli[] = { AST_CLI_DEFINE(handle_cli_mobile_show_devices, "Show Bluetooth Cell / Mobile devices"), AST_CLI_DEFINE(handle_cli_mobile_search, "Search for Bluetooth Cell / Mobile devices"), AST_CLI_DEFINE(handle_cli_mobile_rfcomm, "Send commands to the rfcomm port for debugging"), + AST_CLI_DEFINE(handle_cli_mobile_cusd, "Send CUSD commands to the mobile"), }; /* App stuff */ @@ -347,6 +350,7 @@ static int hfp_parse_cmgr(struct hfp_pvt *hfp, char *buf, char **from_number, ch static int hfp_parse_brsf(struct hfp_pvt *hfp, const char *buf); static int hfp_parse_cind(struct hfp_pvt *hfp, char *buf); static int hfp_parse_cind_test(struct hfp_pvt *hfp, char *buf); +static char *hfp_parse_cusd(struct hfp_pvt *hfp, char *buf); static int hfp_brsf2int(struct hfp_hf *hf); static struct hfp_ag *hfp_int2brsf(int brsf, struct hfp_ag *ag); @@ -370,6 +374,7 @@ static int hfp_send_sms_text(struct hfp_pvt *hfp, const char *message); static int hfp_send_chup(struct hfp_pvt *hfp); static int hfp_send_atd(struct hfp_pvt *hfp, const char *number); static int hfp_send_ata(struct hfp_pvt *hfp); +static int hfp_send_cusd(struct hfp_pvt *hfp, const char *code); /* * bluetooth headset profile helpers @@ -414,6 +419,7 @@ typedef enum { AT_CNMI, AT_CMER, AT_CIND_TEST, + AT_CUSD, } at_message_t; static int at_match_prefix(char *buf, char *prefix); @@ -620,6 +626,56 @@ e_return: return CLI_SUCCESS; } +static char *handle_cli_mobile_cusd(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) +{ + char buf[128]; + struct mbl_pvt *pvt = NULL; + + switch (cmd) { + case CLI_INIT: + e->command = "mobile cusd"; + e->usage = + "Usage: mobile cusd <device ID> <command>\n" + " Send cusd <command> to the rfcomm port on the device\n" + " with the specified <device ID>.\n"; + return NULL; + case CLI_GENERATE: + return NULL; + } + + if (a->argc != 4) + return CLI_SHOWUSAGE; + + AST_RWLIST_RDLOCK(&devices); + AST_RWLIST_TRAVERSE(&devices, pvt, entry) { + if (!strcmp(pvt->id, a->argv[2])) + break; + } + AST_RWLIST_UNLOCK(&devices); + + if (!pvt) { + ast_cli(a->fd, "Device %s not found.\n", a->argv[2]); + goto e_return; + } + + ast_mutex_lock(&pvt->lock); + if (!pvt->connected) { + ast_cli(a->fd, "Device %s not connected.\n", a->argv[2]); + goto e_unlock_pvt; + } + + snprintf(buf, sizeof(buf), "%s", a->argv[3]); + if (hfp_send_cusd(pvt->hfp, buf) || msg_queue_push(pvt, AT_OK, AT_CUSD)) { + ast_cli(a->fd, "[%s] error sending CUSD\n", pvt->id); + goto e_unlock_pvt; + } + +e_unlock_pvt: + ast_mutex_unlock(&pvt->lock); +e_return: + return CLI_SUCCESS; +} + /* Dialplan applications implementation @@ -1827,6 +1883,8 @@ static at_message_t at_read_full(int rsock, char *buf, size_t count) return AT_VGM; } else if (at_match_prefix(buf, "AT+VGS=")) { return AT_VGS; + } else if (at_match_prefix(buf, "+CUSD:")) { + return AT_CUSD; } else { return AT_UNKNOWN; } @@ -1896,6 +1954,8 @@ static inline const char *at_msg2str(at_message_t msg) return "AT+CMER"; case AT_CIND_TEST: return "AT+CIND=?"; + case AT_CUSD: + return "AT+CUSD"; } } @@ -2066,6 +2126,62 @@ static int hfp_parse_cmgr(struct hfp_pvt *hfp, char *buf, char **from_number, ch return 0; } +/*! + * \brief Parse a CUSD answer. + * \param hfp an hfp_pvt struct + * \param buf the buffer to parse (null terminated) + * @note buf will be modified when the CUSD string is parsed + * \return NULL on error (parse error) or a pointer to the cusd message + * information in buf + */ +static char *hfp_parse_cusd(struct hfp_pvt *hfp, char *buf) +{ + int i, state, message_start, message_end; + char *cusd; + size_t s; + + /* parse cusd message in the following format: + * +CUSD: 0,"100,00 EURO, valid till 01.01.2010, you are using tariff "Mega Tariff". More informations *111#." + */ + state = 0; + message_start = 0; + message_end = 0; + s = strlen(buf); + + /* Find the start of the message (") */ + for (i = 0; i < s; i++) { + if (buf[i] == '"') { + message_start = i + 1; + break; + } + } + + if (message_start == 0 || message_start >= s) { + return NULL; + } + + /* Find the end of the message (") */ + for (i = s; i > 0; i--) { + if (buf[i] == '"') { + message_end = i; + break; + } + } + + if (message_end == 0) { + return NULL; + } + + if (message_start >= message_end) { + return NULL; + } + + cusd = &buf[message_start]; + buf[message_end] = '\0'; + + return cusd; +} + /*! * \brief Convert a hfp_hf struct to a BRSF int. * \param hf an hfp_hf brsf object @@ -2310,6 +2426,18 @@ static int hfp_send_ata(struct hfp_pvt *hfp) return rfcomm_write(hfp->rsock, "ATA\r"); } +/*! + * \brief Send CUSD. + * \param hfp an hfp_pvt struct + * \param code the CUSD code to send + */ +static int hfp_send_cusd(struct hfp_pvt *hfp, const char *code) +{ + char cmd[128]; + snprintf(cmd, sizeof(cmd), "AT+CUSD=1,\"%s\",15\r", code); + return rfcomm_write(hfp->rsock, cmd); +} + /*! * \brief Parse BRSF data. * \param hfp an hfp_pvt struct @@ -2997,6 +3125,9 @@ static int handle_response_ok(struct mbl_pvt *pvt, char *buf) case AT_VTS: ast_debug(1, "[%s] digit sent successfully\n", pvt->id); break; + case AT_CUSD: + ast_debug(1, "[%s] CUSD code sent successfully\n", pvt->id); + break; case AT_UNKNOWN: default: ast_debug(1, "[%s] received OK for unhandled request: %s\n", pvt->id, at_msg2str(entry->response_to)); @@ -3093,6 +3224,9 @@ static int handle_response_error(struct mbl_pvt *pvt, char *buf) case AT_VTS: ast_debug(1, "[%s] error sending digit\n", pvt->id); break; + case AT_CUSD: + ast_verb(0, "[%s] error sending CUSD command\n", pvt->id); + break; case AT_UNKNOWN: default: ast_debug(1, "[%s] received ERROR for unhandled request: %s\n", pvt->id, at_msg2str(entry->response_to)); @@ -3360,6 +3494,27 @@ static int handle_sms_prompt(struct mbl_pvt *pvt, char *buf) return 0; } +/*! + * \brief Handle CUSD messages. + * \param pvt a mbl_pvt structure + * \param buf a null terminated buffer containing an AT message + * \retval 0 success + * \retval -1 error + */ +static int handle_response_cusd(struct mbl_pvt *pvt, char *buf) +{ + char *cusd; + + if (!(cusd = hfp_parse_cusd(pvt->hfp, buf))) { + ast_verb(0, "[%s] error parsing CUSD: %s\n", pvt->id, buf); + return 0; + } + + ast_verb(0, "[%s] CUSD response: %s\n", pvt->id, cusd); + + return 0; +} + static void *do_monitor_phone(void *data) { @@ -3510,6 +3665,14 @@ static void *do_monitor_phone(void *data) } ast_mutex_unlock(&pvt->lock); break; + case AT_CUSD: + ast_mutex_lock(&pvt->lock); + if (handle_response_cusd(pvt, buf)) { + ast_mutex_unlock(&pvt->lock); + goto e_cleanup; + } + ast_mutex_unlock(&pvt->lock); + break; case AT_UNKNOWN: ast_debug(1, "[%s] ignoring unknown message: %s\n", pvt->id, buf); break; -- GitLab