smsc_cimd.c
资源名称:gateway-1.2.1 [点击查看]
上传用户:gzpyjq
上传日期:2013-01-31
资源大小:1852k
文件大小:39k
源码类别:
手机WAP编程
开发平台:
WINDOWS
- /*****************************************************************************
- * smsc_cimd.c - Nokia SMS Center (CIMD 1.3).
- * Mikael Gueck for WapIT Ltd.
- */
- #include <errno.h>
- #include <string.h>
- #include <stdio.h>
- #include <unistd.h>
- #include <stdlib.h>
- #include <time.h>
- #include <sys/time.h>
- #include <sys/types.h>
- #include <sys/socket.h>
- #include "smsc.h"
- #include "smsc_p.h"
- #include "gwlib/gwlib.h"
- #include "alt_charsets.h"
- /******************************************************************************
- * Static functions
- */
- /* do the handshake baby */
- static int cimd_open_connection(SMSCenter *smsc);
- /* waits for an ACK message, returns the ACK command number or -1 for error */
- static int expect_acknowledge(SMSCenter *smsc, int *cmd, int *err);
- /* sends a general ACK */
- static int send_acknowledge(SMSCenter *smsc);
- /* Reconnect to a CIMD server, use an existing structure */
- static int connect_tcpip(SMSCenter *smsc);
- static int parse_cimd_to_iso88591(char *from, char *to, int length);
- static int parse_iso88591_to_cimd(
- char *from, char *to, int length, int alt_charset);
- /******************************************************************************
- * Open the connection and log in
- *
- * return 0 if ok, -1 on failure
- */
- static int cimd_open_connection(SMSCenter *smsc)
- {
- char *tmpbuff = NULL;
- int ret = 0;
- int cmd = 0, err = 0;
- /* allocate some spare space */
- tmpbuff = gw_malloc(10 * 1024);
- memset(tmpbuff, 0, 10*1024);
- /* connect */
- smsc->socket = tcpip_connect_to_server(smsc->cimd_hostname, smsc->cimd_port,
- NULL);
- /* XXX add interface_name if required */
- if (smsc->socket == -1)
- goto error;
- /* receive protocol string "CIMD rel 1.37n" */
- for (;;) {
- ret = smscenter_read_into_buffer(smsc);
- if (strstr(smsc->buffer, "CIMD rel 1.37n") != NULL)
- break;
- if (ret < 0) goto logout;
- }
- debug("bb.sms.cimd", 0, "got the server identification tag");
- smscenter_remove_from_buffer(smsc, smsc->buflen);
- /* send login string */
- sprintf(tmpbuff, "%c%s%c%s%c%s%c%s%c%c",
- 0x02,
- "01", 0x09,
- smsc->cimd_username, 0x09,
- smsc->cimd_password, 0x09,
- "11",
- 0x03, 0x0A);
- ret = write_to_socket(smsc->socket, tmpbuff);
- if (ret < 0) goto logout;
- /* get an acknowledge message */
- smsc->cimd_last_spoke = 0;
- if (expect_acknowledge(smsc, &cmd, &err) < 1)
- goto logout;
- debug("bb.sms.cimd", 0, "logged in");
- gw_free(tmpbuff);
- return 0;
- logout:
- cimd_close(smsc);
- error:
- error(0, "cimd_open: could not open/handshake");
- gw_free(tmpbuff);
- return -1;
- }
- /******************************************************************************
- * Open the smscenter
- */
- SMSCenter *cimd_open(char *hostname, int port, char *username, char *password)
- {
- SMSCenter *smsc = NULL;
- int ret = 0;
- /* create a SMSCenter structure */
- smsc = smscenter_construct();
- if (smsc == NULL) goto error;
- smsc->type = SMSC_TYPE_CIMD;
- smsc->cimd_hostname = gw_strdup(hostname);
- smsc->hostname = gw_strdup(hostname); /* Needed by read_into_buffer() */
- smsc->cimd_port = port;
- smsc->cimd_username = gw_strdup(username);
- smsc->cimd_password = gw_strdup(password);
- ret = cimd_open_connection(smsc);
- if (ret < 0)
- goto error;
- sprintf(smsc->name, "CIMD:%s:%d:%s", smsc->cimd_hostname,
- smsc->cimd_port, smsc->cimd_username);
- return smsc;
- error:
- error(0, "cimd_open: could not open!");
- smscenter_destruct(smsc);
- return NULL;
- }
- /******************************************************************************
- * Re-open the connection and log in
- *
- * return -1 if failed
- */
- int cimd_reopen(SMSCenter *smsc)
- {
- cimd_close(smsc);
- if (cimd_open_connection(smsc) < 0) {
- error(0, "Failed to re-open the connection!");
- return -1;
- }
- return 0;
- }
- /******************************************************************************
- * Log out and close the socket
- *
- */
- int cimd_close(SMSCenter *smsc)
- {
- char *cbuff = NULL;
- int sum;
- int ret;
- if (smsc->socket == -1) {
- debug("bb.sms.cimd", 0, "Trying to close cimd while already closed!");
- return 0;
- }
- cbuff = gw_malloc(2 * 1024);
- sprintf(cbuff, "%c%s%c%s%c%c", 0x02, "02", 0x09, "11", 0x03, 0x0A);
- sum = write_to_socket(smsc->socket, cbuff);
- if (sum < 0) goto error;
- /* this time we don't block waiting for acknowledge */
- recv(smsc->socket, cbuff, 2*1024, 0);
- gw_free(cbuff);
- ret = close(smsc->socket);
- smsc->socket = -1;
- return ret;
- error:
- gw_free(cbuff);
- return -1;
- }
- /******************************************************************************
- * Check for MO messages, returns as in smsc_submit_smsmessage in smsc.h
- */
- int cimd_pending_smsmessage(SMSCenter *smsc)
- {
- char *tmpbuff = NULL, *newline = NULL;
- int ret = 0;
- time_t thetime = 0;
- /* check for input sanity */
- if (smsc == NULL)
- goto error;
- /* we can only query every 5 seconds */
- thetime = time(NULL);
- if ((smsc->cimd_last_spoke + 5) > thetime) goto no_messages;
- smsc->cimd_last_spoke = thetime;
- /* allocate some spare space */
- tmpbuff = gw_malloc(10 * 1024);
- memset(tmpbuff, 0, 10*1024);
- sprintf(tmpbuff, "%c%s%c%s%c%c",
- 0x02, /* stx */
- "05", 0x09, /* request for message, tab */
- "11", /* dummy chksum */
- 0x03, 0x0A); /* etx, lf */
- /* send the poll message to determine if we have messages in queue */
- ret = write_to_socket(smsc->socket, tmpbuff);
- if (ret < 0) {
- debug("bb.sms.cimd", 0, "sending poll message failed");
- goto error;
- }
- /* block while waiting for answer that dataset ends to a 0x0A */
- for (;;) {
- newline = memchr(smsc->buffer, 0x0A, smsc->buflen);
- if (newline != NULL) break;
- newline = memchr(smsc->buffer, 0x03, smsc->buflen);
- if (newline != NULL) break;
- ret = smscenter_read_into_buffer(smsc);
- if (ret <= 0) {
- debug("bb.sms.cimd", 0, "read_into_buffer failed!, ret=%d", ret);
- goto error;
- }
- usleep(500);
- /* Reconnect if no results in 30 seconds */
- if (time(NULL) > (thetime + 30)) {
- error(0, "timeout occurred, maybe the connection was broken?");
- /* Reconnect if neccessary, this catches most of them */
- /* XXX this is an ugly kludge, but then again,
- CIMD 1.3 is an ugly kludge. */
- connect_tcpip(smsc);
- goto no_messages;
- }
- }
- /* if we got an nck, cut the message out and return 0 */
- newline = memchr(smsc->buffer, 0x15, smsc->buflen);
- if (newline != NULL) {
- newline = memchr(smsc->buffer, 0x0A, smsc->buflen);
- if (newline == NULL)
- newline = memchr(smsc->buffer, 0x03, smsc->buflen);
- smscenter_remove_from_buffer(smsc, newline - smsc->buffer + 1);
- goto no_messages;
- }
- /* miracle of miracles, we got a message */
- gw_free(tmpbuff);
- return 1;
- no_messages:
- gw_free(tmpbuff);
- return 0;
- error:
- debug("bb.sms.cimd", 0, "smscenter_pending_smsmessage: returning error");
- gw_free(tmpbuff);
- return -1;
- }
- /******************************************************************************
- * Send a MT message, returns as in smsc_submit_smsmessage in smsc.h
- */
- int cimd_submit_msg(SMSCenter *smsc, Msg *msg)
- {
- char *tmpbuff = NULL, *tmptext = NULL;
- char msgtext[1024];
- int ret;
- int cmd = 0, err = 0;
- /* Fix these by implementing a could-not-send-because-
- protocol-does-not-allow in smsc.c or smsgateway.c */
- if (octstr_len(msg->sms.msgdata) + octstr_len(msg->sms.udhdata) < 1) {
- if (msg->sms.msgdata == NULL)
- msg->sms.msgdata = octstr_create("");
- octstr_append_from_hex(msg->sms.msgdata, "20");
- }
- if (octstr_len(msg->sms.sender) < 1) {
- warning(0, "cimd_submit_smsmessage: ignoring message with 0-length field");
- goto okay; /* THIS IS NOT OKAY!!!! XXX */
- }
- if (octstr_len(msg->sms.receiver) < 1) {
- warning(0, "cimd_submit_smsmessage: ignoring message with 0-length field");
- goto okay; /* THIS IS NOT OKAY!!!! XXX */
- }
- tmpbuff = gw_malloc(10 * 1024);
- tmptext = gw_malloc(10 * 1024);
- memset(tmpbuff, 0, 10*1024);
- memset(tmptext, 0, 10*1024);
- memset(msgtext, 0, sizeof(msgtext));
- if (octstr_len(msg->sms.udhdata)) {
- octstr_get_many_chars(msgtext, msg->sms.udhdata, 0, octstr_len(msg->sms.udhdata));
- octstr_get_many_chars(msgtext + octstr_len(msg->sms.udhdata),
- msg->sms.msgdata, 0,
- 140 - octstr_len(msg->sms.udhdata));
- } else {
- octstr_get_many_chars(msgtext, msg->sms.msgdata, 0,
- octstr_len(msg->sms.msgdata));
- }
- /* XXX parse_iso88591_to_cimd should use Octstr
- * directly, or get a char* and a length, instead of using NUL
- * terminated strings.
- */
- parse_iso88591_to_cimd(msgtext, tmptext, 10*1024, smsc->alt_charset);
- /* If messages has UDHs, add the magic number 31 to the right spot */
- sprintf(tmpbuff, "%c%s%c%s%c%s%c%s%c%s%c%s%c%s%c%c",
- 0x02,
- "03", 0x09,
- octstr_get_cstr(msg->sms.receiver), 0x09,
- tmptext, 0x09,
- "", 0x09,
- "", 0x09,
- (octstr_len(msg->sms.udhdata)) ? "31" : "", 0x09,
- "11", 0x03, 0x0A);
- ret = write_to_socket(smsc->socket, tmpbuff);
- if (ret < 0) {
- debug("bb.sms.cimd", 0, "cimd_submit_smsmessage: socket write error");
- goto error;
- }
- /* The Nokia SMSC MAY be configured to send delivery
- information, which we then will HAVE to acknowledge.
- Naturally the CIMD 1.3 protocol does not include any
- kind of negotiation mechanism. */
- ret = expect_acknowledge(smsc, &cmd, &err);
- if (ret >= 1) {
- if (cmd == 4) {
- send_acknowledge(smsc);
- goto okay;
- } else if (cmd == 3) {
- goto okay;
- }
- } else if (ret == 0) {
- if (cmd == 4) {
- send_acknowledge(smsc);
- goto okay; /* FIXME XXX THIS IS BOGUS, FIX SMSGATEWAY.C */
- goto error;
- } else if (cmd == 3) {
- goto okay; /* FIXME XXX THIS IS BOGUS, FIX SMSGATEWAY.C */
- goto error;
- } else {
- error(0, "Unexpected behaviour from the CIMD server");
- debug("bb.sms.cimd", 0, "cimd_submit_smsmessage: acknowledge was <%i>", ret);
- debug("bb.sms.cimd", 0, "cimd_submit_smsmessage: buffer==<%s>", smsc->buffer);
- goto error;
- }
- }
- okay:
- gw_free(tmpbuff);
- gw_free(tmptext);
- return 0;
- error:
- debug("bb.sms.cimd", 0, "cimd_submit_smsmessage: returning error");
- gw_free(tmpbuff);
- gw_free(tmptext);
- return -1;
- }
- int cimd_receive_msg(SMSCenter *smsc, Msg **msg)
- {
- char *tmpbuff = NULL, *sender = NULL;
- char *receiver = NULL, *text = NULL, *scts = NULL;
- char *tmpchar = NULL;
- debug("bb.sms.cimd", 0, "cimd_receive_smsmessage: starting");
- /* the PENDING function has previously requested for
- the message and checked that it safely found its
- way into the memory buffer (smsc->buffer) */
- /* we want to temporarily store some data */
- tmpbuff = gw_malloc(10 * 1024);
- sender = gw_malloc(10 * 1024);
- receiver = gw_malloc(10 * 1024);
- text = gw_malloc(10 * 1024);
- scts = gw_malloc(10 * 1024);
- memset(tmpbuff, 0, 10 * 1024);
- memset(sender, 0, 10 * 1024);
- memset(receiver, 0, 10 * 1024);
- memset(text, 0, 10 * 1024);
- memset(scts, 0, 10 * 1024);
- /* cut the raw message out from the message buffer */
- tmpchar = memchr(smsc->buffer, 0x0A, smsc->buflen);
- if (tmpchar == NULL) {
- tmpchar = memchr(smsc->buffer, 0x03, smsc->buflen);
- if (tmpchar == NULL) goto error;
- }
- strncpy(tmpbuff, smsc->buffer, tmpchar - smsc->buffer);
- smscenter_remove_from_buffer(smsc, tmpchar - smsc->buffer + 1);
- /* Parse the raw message */
- sscanf(tmpbuff,
- "x02x06tC:05t%[^t]t%[^t]t%[^t]t%[^t]t11x03x0A",
- receiver, sender, text, scts);
- sscanf(tmpbuff,
- "x02x06tC:05t%[^t]t%[^t]t%[^t]t%[^t]t11x03",
- receiver, sender, text, scts);
- /* Translate from the CIMD character set to iso8859-1 */
- parse_cimd_to_iso88591(text, tmpbuff, 10*1024);
- strncpy(text, tmpbuff, 480);
- /* create a smsmessage structure out of the components */
- *msg = msg_create(sms);
- if (*msg == NULL) return -1;
- (*msg)->sms.sender = octstr_create(sender);
- (*msg)->sms.receiver = octstr_create(receiver);
- (*msg)->sms.msgdata = octstr_create(text);
- /* Send acknowledge */
- send_acknowledge(smsc);
- /* We got a message so we can instantly check for a new one. */
- smsc->cimd_last_spoke -= 5;
- /* Free and Finish */
- gw_free(tmpbuff);
- gw_free(sender);
- gw_free(receiver);
- gw_free(text);
- gw_free(scts);
- debug("bb.sms.cimd", 0, "cimd_receive_smsmessage: return ok");
- return 1;
- error:
- debug("bb.sms.cimd", 0, "cimd_receive_smsmessage: failed");
- gw_free(tmpbuff);
- gw_free(sender);
- gw_free(receiver);
- gw_free(text);
- gw_free(scts);
- debug("bb.sms.cimd", 0, "cimd_receive_smsmessage: return failed");
- return -1;
- }
- /******************************************************************************
- * In(f)ternal Functions
- */
- static int connect_tcpip(SMSCenter *smsc)
- {
- char *tmpbuff = NULL;
- int ret = 0;
- int cmd = 0, err = 0;
- debug("bb.sms.cimd", 0, "reconnecting to <%s>", smsc->name);
- /* allocate some spare space */
- tmpbuff = gw_malloc(10 * 1024);
- memset(tmpbuff, 0, 10*1024);
- /* Close connection */
- close(smsc->socket);
- smsc->socket = -1;
- /* Be sure to open a socket. */
- for (;;) {
- smsc->socket = tcpip_connect_to_server(
- smsc->cimd_hostname, smsc->cimd_port,
- NULL);
- /* XXX add interface_name if required */
- if (smsc->socket != -1) break;
- usleep(1000);
- }
- /* Empty the buffer, there might be an evil ghost inside... */
- memset(smsc->buffer, 0, smsc->bufsize);
- smsc->buflen = 0;
- /* Expect the protocol string "CIMD rel 1.37n" */
- for (;;) {
- ret = smscenter_read_into_buffer(smsc);
- if (ret < 0) goto logout;
- if (strstr(smsc->buffer, "CIMD rel 1.37n") != NULL)
- break;
- usleep(1000);
- }
- smscenter_remove_from_buffer(smsc, smsc->buflen);
- /* send login string */
- sprintf(tmpbuff, "%c%s%c%s%c%s%c%s%c%c",
- 0x02,
- "01", 0x09,
- smsc->cimd_username, 0x09,
- smsc->cimd_password, 0x09,
- "11",
- 0x03, 0x0A);
- ret = write_to_socket(smsc->socket, tmpbuff);
- if (ret < 0) goto logout;
- /* get an acknowledge message */
- smsc->cimd_last_spoke = 0;
- if (expect_acknowledge(smsc, &cmd, &err) < 1)
- goto logout;
- debug("bb.sms.cimd", 0, "cimd_connect_tcpip: logged in");
- gw_free(tmpbuff);
- return 1;
- logout:
- close(smsc->socket);
- gw_free(tmpbuff);
- return 0;
- }
- /******************************************************************************
- * Yeah, we got the message!
- */
- static int send_acknowledge(SMSCenter *smsc)
- {
- char tmpbuff[100];
- int tmpint;
- if (tmpbuff == NULL) {
- error(0, "cimd_send_acknowledge: memory allocation failure");
- goto error;
- }
- memset(tmpbuff, 0, sizeof(tmpbuff));
- sprintf(tmpbuff, "26t113n");
- tmpint = write_to_socket(smsc->socket, tmpbuff);
- if (tmpint == -1) {
- error(0, "cimd_send_acknowledge: connection failure");
- goto error;
- }
- return 0;
- error:
- debug("bb.sms.cimd", 0, "cimd_send_acknowledge: failed");
- return -1;
- }
- /******************************************************************************
- * Wait for the Nokia piece of *!%&%*^H^H^H^H^H^H^H^H^H^H^H^H^H^H^H^H SMSC
- * to catch up with our swift operation, block until... (~1sec?)
- */
- static int expect_acknowledge(SMSCenter *smsc, int *cmd, int *err)
- {
- char *end_of_dataset = NULL;
- char *ack = NULL, *nck = NULL;
- char *cmdspecifier = NULL, *errorspecifier = NULL;
- int ret = 0;
- #if 0
- time_t thetime;
- time(&thetime);
- #endif
- if (smsc == NULL) goto error;
- /* Loop until we get an acknowledgement message. */
- for (;;) {
- /* If the server is configured in to end a dataset with a n */
- end_of_dataset = memchr(smsc->buffer, 'n', smsc->buflen);
- if (end_of_dataset != NULL) break;
- /* If the server is configured in to end a dataset with a 3 */
- end_of_dataset = memchr(smsc->buffer, 0x03, smsc->buflen);
- if (end_of_dataset != NULL) break;
- ret = smscenter_read_into_buffer(smsc);
- if (ret <= 0) {
- if (errno == EAGAIN) continue;
- if (errno == EINTR) continue;
- return -1;
- }
- usleep(500);
- #if 0
- /* Abort if no results in 30 seconds */
- if (time(NULL) > (thetime + 30)) {
- error(0, "timeout occurred, maybe the connection was broken?");
- if (errno == EPIPE) {
- error(0, "broken pipe");
- } /* if errno */
- goto error;
- } /* if time */
- #endif
- }
- /* Check if our request was answered or denied */
- ack = memchr(smsc->buffer, 0x06, end_of_dataset - smsc->buffer);
- nck = memchr(smsc->buffer, 0x15, end_of_dataset - smsc->buffer);
- /* Get the command code from the acknowledge message */
- cmdspecifier = strstr(smsc->buffer, "tC:");
- if (cmdspecifier != NULL)
- *cmd = strtol(cmdspecifier + 3, NULL, 10);
- else
- *cmd = 0;
- errorspecifier = strstr(smsc->buffer, "tE:");
- if (errorspecifier != NULL)
- *err = strtol(errorspecifier + 3, NULL, 10);
- else
- *err = 0;
- debug("bb.sms.cimd", 0, "cimd_pending_smsmessage: smsc->buffer == <%s>", smsc->buffer);
- /* Remove the acknowledge message from the incoming buffer. */
- smscenter_remove_from_buffer(smsc, end_of_dataset - smsc->buffer + 1);
- /* if we got an acknowledge */
- if (ack != NULL) {
- info(0, "cimd_pending_smsmessage: got ACK");
- return 1;
- }
- /* if we got an NOT acknowledge */
- if (nck != NULL) {
- info(0, "cimd_pending_smsmessage: got NCK");
- return 0;
- }
- /* if we got an ERROR */
- error:
- error(0, "cimd_expect_acknowledge failed");
- return -1;
- }
- /******************************************************************************
- * Convert a string from ISO-8859-1 to the CIMD character set
- */
- static int parse_iso88591_to_cimd(char* from, char* to,
- int length, int alt_charset)
- {
- char *temp = to;
- if (from == NULL || to == NULL || length == 0)
- return -1;
- *to = ' ';
- while ((*from != ' ') && ((int) strlen(temp) < (length - 2))) {
- switch (*from) {
- case '@': strcat(to, "_Oa"); to += 3; break;
- case '