smsc_emi.c
资源名称:gateway-1.2.1 [点击查看]
上传用户:gzpyjq
上传日期:2013-01-31
资源大小:1852k
文件大小:45k
源码类别:
手机WAP编程
开发平台:
WINDOWS
- /*****************************************************************************
- * smsc_emi.c - implement interface to the CMG SMS Center (UCP/EMI).
- * Mikael Gueck for WapIT Ltd.
- */
- /* This file implements two smsc interfaces: EMI and EMI_IP */
- #include <errno.h>
- #include <string.h>
- #include <stdio.h>
- #include <unistd.h>
- #include <fcntl.h>
- #include <termios.h>
- #include <stdarg.h>
- #include <stdlib.h>
- #include <string.h>
- #include <strings.h>
- #include <sys/time.h>
- #include <sys/types.h>
- #include <sys/socket.h>
- #include <sys/param.h>
- #include <sys/ioctl.h>
- #include "config.h"
- #include "smsc.h"
- #include "smsc_p.h"
- #include "gwlib/gwlib.h"
- #include "alt_charsets.h"
- #include "sms.h"
- #ifndef CRTSCTS
- #define CRTSCTS 0
- #endif
- /******************************************************************************
- * Static functions
- */
- static int get_data(SMSCenter *smsc, char *buff, int length);
- static int put_data(SMSCenter *smsc, char *buff, int length, int is_backup);
- static int memorybuffer_append_data(SMSCenter *smsc, char *buff, int length);
- static int memorybuffer_insert_data(SMSCenter *smsc, char *buff, int length);
- static int memorybuffer_has_rawmessage(SMSCenter *smsc, int type, char auth);
- static int memorybuffer_cut_rawmessage(SMSCenter *smsc, char *buff, int length);
- static int parse_rawmessage_to_msg(SMSCenter *smsc, Msg **msg,
- char *rawmessage, int length);
- static int parse_msg_to_rawmessage(SMSCenter *smsc, Msg *msg,
- char *rawmessage, int length);
- static int acknowledge_from_rawmessage(SMSCenter *smsc,
- char *rawmessage, int length);
- static int parse_emi_to_iso88591(char *from, char *to,
- int length, int alt_charset);
- static int parse_iso88591_to_emi(char *from, char *to,
- int length, int alt_charset);
- static int parse_binary_to_emi(char *from, char *to, int length);
- static int at_dial(char *device, char *phonenum,
- char *at_prefix, time_t how_long);
- static int guarantee_link(SMSCenter *smsc);
- static void generate_checksum(const unsigned char *buffer,
- unsigned char *checksum_out);
- static int wait_for_ack(SMSCenter *smsc, int op_type);
- static char char_iso_to_sms(unsigned char from, int alt_charset);
- static char char_sms_to_iso(unsigned char from, int alt_charset);
- /******************************************************************************
- * Open the connection and log in - handshake baby
- */
- static int emi_open_connection(SMSCenter *smsc)
- {
- char tmpbuff[1024];
- sprintf(tmpbuff, "/dev/%s", smsc->emi_serialdevice);
- smsc->emi_fd = at_dial(tmpbuff, smsc->emi_phonenum, "ATD", 30);
- if (smsc->emi_fd <= 0)
- return -1;
- return 0;
- }
- /* open EMI smscenter */
- SMSCenter *emi_open(char *phonenum, char *serialdevice, char *username, char *password)
- {
- SMSCenter *smsc;
- smsc = smscenter_construct();
- if (smsc == NULL)
- goto error;
- smsc->type = SMSC_TYPE_EMI;
- smsc->emi_phonenum = gw_strdup(phonenum);
- smsc->emi_serialdevice = gw_strdup(serialdevice);
- smsc->emi_username = gw_strdup(username);
- smsc->emi_password = gw_strdup(password);
- smsc->emi_current_msg_number = 0;
- if (emi_open_connection(smsc) < 0)
- goto error;
- sprintf(smsc->name, "EMI:%s:%s", smsc->emi_phonenum,
- smsc->emi_username);
- return smsc;
- error:
- error(0, "emi_open failed");
- smscenter_destruct(smsc);
- return NULL;
- }
- int emi_reopen(SMSCenter *smsc)
- {
- emi_close(smsc);
- if (emi_open_connection(smsc) < 0) {
- error(0, "emi_reopen failed");
- return -1;
- }
- return 0;
- }
- int emi_close(SMSCenter *smsc)
- {
- return emi_close_ip(smsc);
- }
- static int emi_fill_ucp60_login(char *buf, char *OAdC, char *passwd) {
- int max_ia5passwd_len;
- char *ia5passwd;
- max_ia5passwd_len = strlen(passwd) * 2 + 1;
- ia5passwd = gw_malloc(max_ia5passwd_len);
- if (parse_binary_to_emi(passwd, ia5passwd, strlen(passwd)) < 0) {
- error(0, "parse_binary_to_emi failed");
- gw_free(ia5passwd);
- return -1;
- }
- sprintf(buf, "%s/%c/%c/%c/%s//%s/////",
- OAdC, /* OAdC: Address code originator */
- '6', /* OTON: 6 = Abbreviated number (short number alias) */
- '5', /* ONPI: 5 = Private (TCP/IP address/abbreviated number address) */
- '1', /* STYP: 1 = open session */
- ia5passwd, /* PWD: Current password encoded into IA5 characters */
- "0100" /* VERS: Version number 0100 */
- );
- gw_free(ia5passwd);
- return 0;
- }
- static int emi_open_session(SMSCenter *smsc)
- {
- char message_whole [1024];
- char message_body [1024];
- char message_header [50];
- char message_footer [10];
- char my_buffer [1024];
- int length;
- memset(message_whole, 0, sizeof(message_whole));
- memset(message_body, 0, sizeof(message_body));
- memset(message_header, 0, sizeof(message_header));
- memset(message_footer, 0, sizeof(message_footer));
- if (emi_fill_ucp60_login(message_body, smsc->emi_username, smsc->emi_password) < 0) {
- error(0, "emi_fill_ucp60_login failed");
- return -1;
- }
- length = strlen(message_body);
- length += 13; /* header (fixed) */
- length += 2; /* footer (fixed) */
- length += 2; /* slashes between header, body, footer */
- sprintf(message_header, "%02i/%05i/O/60",
- (smsc->emi_current_msg_number++ % 100), length);
- /* FOOTER */
- sprintf(my_buffer, "%s/%s/", message_header, message_body);
- generate_checksum(my_buffer, message_footer);
- sprintf(message_whole, "x02%s/%s/%sx03", message_header,
- message_body, message_footer);
- debug("bb.sms.emi", 0, "final UCP60 msg: <%s>", message_whole);
- put_data(smsc, message_whole, strlen(message_whole), 0);
- if (!wait_for_ack(smsc, 60)) {
- info(0, "emi_open_session: wait for ack failed!");
- return -1;
- }
- return 0;
- }
- /*******************************************************
- * the actual protocol open... quite simple here */
- static int emi_open_connection_ip(SMSCenter *smsc)
- {
- smsc->emi_fd =
- tcpip_connect_to_server_with_port(smsc->emi_hostname,
- smsc->emi_port, smsc->emi_our_port,
- NULL);
- /* XXX add interface_name if required */
- if (smsc->emi_fd < 0)
- return -1;
- if (smsc->emi_username && smsc->emi_password) {
- return emi_open_session(smsc);
- }
- return 0;
- }
- /******************************************************************************
- * Open the connection and log in
- */
- SMSCenter *emi_open_ip(char *hostname, int port, char *username,
- char *password, int receive_port, char *allow_ip,
- int our_port)
- {
- SMSCenter *smsc;
- smsc = smscenter_construct();
- if (smsc == NULL)
- goto error;
- smsc->type = SMSC_TYPE_EMI_IP;
- smsc->emi_hostname = gw_strdup(hostname);
- smsc->emi_port = port;
- smsc->emi_username = username ? gw_strdup(username) : NULL;
- smsc->emi_password = password ? gw_strdup(password) : NULL;
- smsc->emi_backup_port = receive_port;
- smsc->emi_backup_allow_ip = allow_ip ? gw_strdup(allow_ip) : NULL;
- smsc->emi_our_port = our_port;
- if (receive_port > 0 && allow_ip == NULL)
- warning(0, "EMI IP: receive-port set but no IPs allowed to connect!");
- smsc->emi_current_msg_number = 0;
- if (emi_open_connection_ip(smsc) < 0)
- goto error;
- sprintf(smsc->name, "EMIIP:%s:%s", smsc->emi_hostname,
- username ? smsc->emi_username : "n/a");
- /* if receive-port is defined, set it ready */
- if (receive_port > 0) {
- if ((smsc->emi_backup_fd = make_server_socket(receive_port, NULL)) <= 0)
- /* XXX add interface_name if required */
- goto error;
- debug("bb.sms.emi", 0, "EMI IP backup port at %d opened", receive_port);
- }
- return smsc;
- error:
- error(0, "emi_open_ip failed");
- smscenter_destruct(smsc);
- return NULL;
- }
- int emi_reopen_ip(SMSCenter *smsc)
- {
- emi_close_ip(smsc);
- return emi_open_connection_ip(smsc);
- }
- int emi_close_ip(SMSCenter *smsc)
- {
- if (smsc->emi_fd == -1) {
- info(0, "Trying to close already closed EMI, ignoring");
- return 0;
- }
- close(smsc->emi_fd);
- smsc->emi_fd = -1;
- return 0;
- }
- /******************************************************************************
- * Check if the buffers contain any messages
- */
- int emi_pending_smsmessage(SMSCenter *smsc)
- {
- char *tmpbuff;
- int n = 0;
- /* time_t timenow; */
- /* Block until we have a connection */
- guarantee_link(smsc);
- /* If we have MO-message, then act (return 1) */
- if (memorybuffer_has_rawmessage(smsc, 52, 'O') > 0 ||
- memorybuffer_has_rawmessage(smsc, 1, 'O') > 0 )
- return 1;
- tmpbuff = gw_malloc(10 * 1024);
- memset(tmpbuff, 0, 10*1024);
- /* check for data */
- n = get_data(smsc, tmpbuff, 10 * 1024);
- if (n > 0)
- memorybuffer_insert_data(smsc, tmpbuff, n);
- /* delete all ACKs/NACKs/whatever */
- while (memorybuffer_has_rawmessage(smsc, 51, 'R') > 0 ||
- memorybuffer_has_rawmessage(smsc, 1, 'R') > 0)
- memorybuffer_cut_rawmessage(smsc, tmpbuff, 10*1024);
- gw_free(tmpbuff);
- /* If we have MO-message, then act (return 1) */
- if (memorybuffer_has_rawmessage(smsc, 52, 'O') > 0 ||
- memorybuffer_has_rawmessage(smsc, 1, 'O') > 0)
- return 1;
- /*
- time(&timenow);
- if( (smsc->emi_last_spoke + 60*20) < timenow) {
- time(&smsc->emi_last_spoke);
- }
- */
- return 0;
- }
- /******************************************************************************
- * Submit (send) a Mobile Terminated message to the EMI server
- */
- int emi_submit_msg(SMSCenter *smsc, Msg *omsg)
- {
- char *tmpbuff = NULL;
- if (smsc == NULL) goto error;
- if (omsg == NULL) goto error;
- tmpbuff = gw_malloc(10 * 1024);
- memset(tmpbuff, 0, 10*1024);
- if (parse_msg_to_rawmessage(smsc, omsg, tmpbuff, 10*1024) < 1)
- goto error;
- if (put_data(smsc, tmpbuff, strlen(tmpbuff), 0) < 0) {
- info(0, "put_data failed!");
- goto error;
- }
- if (smsc->type == SMSC_TYPE_EMI_IP) {
- if (!wait_for_ack(smsc, 51)) {
- info(0, "emi_submit_smsmessage: wait for ack failed!");
- goto error;
- }
- }
- if (smsc->type == SMSC_TYPE_EMI)
- wait_for_ack(smsc, 51);
- /* smsc->emi_current_msg_number += 1; */
- debug("bb.sms.emi", 0, "Submit Ok...");
- gw_free(tmpbuff);
- return 0;
- error:
- debug("bb.sms.emi", 0, "Submit Error...");
- gw_free(tmpbuff);
- return -1;
- }
- /******************************************************************************
- * Receive a Mobile Terminated message to the EMI server
- */
- int emi_receive_msg(SMSCenter *smsc, Msg **tmsg)
- {
- char *tmpbuff;
- Msg *msg = NULL;
- *tmsg = NULL;
- tmpbuff = gw_malloc(10 * 1024);
- memset(tmpbuff, 0, 10*1024);
- /* get and delete message from buffer */
- memorybuffer_cut_rawmessage(smsc, tmpbuff, 10*1024);
- parse_rawmessage_to_msg(smsc, &msg, tmpbuff, strlen(tmpbuff));
- /* yeah yeah, I got the message... */
- acknowledge_from_rawmessage(smsc, tmpbuff, strlen(tmpbuff));
- /* return with the joyful news */
- gw_free(tmpbuff);
- if (msg == NULL) goto error;
- *tmsg = msg;
- return 1;
- error:
- gw_free(tmpbuff);
- msg_destroy(msg);
- return -1;
- }
- /******************************************************************************
- * Internal functions
- */
- /******************************************************************************
- * Guarantee that we have a link
- */
- static int guarantee_link(SMSCenter *smsc)
- {
- int need_to_connect = 0;
- if (smsc->type == SMSC_TYPE_EMI_IP) {
- /* We don't currently guarantee TCP connections. */
- return 0;
- }
- /* If something is obviously wrong. */
- if (strstr(smsc->buffer, "OK")) need_to_connect = 1;
- if (strstr(smsc->buffer, "NO CARRIER")) need_to_connect = 1;
- if (strstr(smsc->buffer, "NO DIALTONE")) need_to_connect = 1;
- /* Clear the buffer */
- while (need_to_connect) {
- /* Connect */
- need_to_connect = emi_open_connection(smsc) < 0;
- /* Clear the buffer so that the next call to guarantee
- doesn't find the "NO CARRIER" string again. */
- smsc->buflen = 0;
- memset(smsc->buffer, 0, smsc->bufsize);
- }
- return 0;
- }
- static int at_dial(char *device, char *phonenum, char *at_prefix, time_t how_long)
- {
- char tmpbuff[1024];
- int howmanyread = 0;
- int thistime = 0;
- int redial;
- int fd = -1;
- int ret;
- time_t timestart;
- struct termios tios;
- /* The time at the start of the function is used when
- determining whether we have used up our allotted
- dial time and have to abort. */
- time(×tart);
- /* Open the device properly. Remember to set the
- access codes correctly. */
- fd = open(device, O_RDWR | O_NONBLOCK | O_NOCTTY);
- if (fd == -1) {
- error(errno, "at_dial: error opening character device <%s>", device);
- goto error;
- }
- tcflush(fd, TCIOFLUSH);
- /* The speed initialisation is pretty important. */
- tcgetattr(fd, &tios);
- cfsetospeed(&tios, B115200);
- cfsetispeed(&tios, B115200);
- kannel_cfmakeraw(&tios);
- tios.c_cflag |= (HUPCL | CREAD | CRTSCTS);
- tcsetattr(fd, TCSANOW, &tios);
- /* Dial using an AT command string. */
- for (redial = 1; redial; ) {
- info(0, "at_dial: dialing <%s> on <%s> for <%i> seconds",
- phonenum, device,
- (int)(how_long - (time(NULL) - timestart)));
- /* Send AT dial request. */
- howmanyread = 0;
- sprintf(tmpbuff, "%s%srn", at_prefix, phonenum);
- ret = write(fd, tmpbuff, strlen(tmpbuff)); /* errors... -mg */
- memset(&tmpbuff, 0, sizeof(tmpbuff));
- /* Read the answer to the AT command and react accordingly. */
- for (; ; ) {
- /* We don't want to dial forever */
- if (how_long != 0 && time(NULL) > timestart + how_long)
- goto timeout;
- /* We don't need more space for dialout */
- if (howmanyread >= (int) sizeof(tmpbuff))
- goto error;
- /* We read 1 char a time so that we don't
- accidentally read past the modem chat and
- into the SMSC datastream -mg */
- thistime = read(fd, &tmpbuff[howmanyread], 1);
- if (thistime == -1) {
- if (errno == EAGAIN) continue;
- if (errno == EINTR) continue;
- goto error;
- } else {
- howmanyread += thistime;
- }
- /* Search for the newline on the AT status line. */
- if (tmpbuff[howmanyread - 1] == 'r'
- || tmpbuff[howmanyread - 1] == 'n') {
- /* XXX ADD ALL POSSIBLE CHAT STRINGS XXX */
- if (strstr(tmpbuff, "CONNECT") != NULL) {
- debug("bb.sms.emi", 0, "at_dial: CONNECT");
- redial = 0;
- break;
- } else if (strstr(tmpbuff, "NO CARRIER") != NULL) {
- debug("bb.sms.emi", 0, "at_dial: NO CARRIER");
- redial = 1;
- break;
- } else if (strstr(tmpbuff, "BUSY") != NULL) {
- debug("bb.sms.emi", 0, "at_dial: BUSY");
- redial = 1;
- break;
- } else if (strstr(tmpbuff, "NO DIALTONE") != NULL) {
- debug("bb.sms.emi", 0, "at_dial: NO DIALTONE");
- redial = 1;
- break;
- }
- } /* End of if lastchr=='r'||'n'. */
- /* Thou shall not consume all system resources
- by repeatedly looping a strstr search when
- the string update latency is very high as it
- is in serial communication. -mg */
- usleep(1000);
- } /* End of read loop. */
- /* Thou shall not flood the modem with dial requests. -mg */
- sleep(1);
- } /* End of dial loop. */
- debug("bb.sms.emi", 0, "at_dial: done with dialing");
- return fd;
- timeout:
- error(0, "at_dial timed out");
- close(fd);
- return -1;
- error:
- error(0, "at_dial failed");
- close(fd);
- return -1;
- }
- /******************************************************************************
- * Wait for an ACK or NACK from the remote
- *
- * REQUIRED by the protocol that it must be waited...
- */
- static int wait_for_ack(SMSCenter *smsc, int op_type)
- {
- char *tmpbuff;
- int found = 0;
- int n;
- time_t start;
- tmpbuff = gw_malloc(10 * 1024);
- memset(tmpbuff, 0, 10*1024);
- start = time(NULL);
- do {
- /* check for data */
- n = get_data(smsc, tmpbuff, 1024 * 10);
- if (smsc->type == SMSC_TYPE_EMI) {
- /* At least the X.31 interface wants to append the data.
- Kalle, what about the TCP/IP interface? Am I correct
- that you are assuming that the message arrives in a
- single read(2)? -mg */
- if (n > 0)
- memorybuffer_append_data(smsc, tmpbuff, n);
- } else if (smsc->type == SMSC_TYPE_EMI_IP) {
- if (n > 0)
- memorybuffer_insert_data(smsc, tmpbuff, n);
- }
- /* act on data */
- if (memorybuffer_has_rawmessage(smsc, op_type, 'R') > 0) {
- memorybuffer_cut_rawmessage(smsc, tmpbuff, 10*1024);
- debug("bb.sms.emi", 0, "Found ACK/NACK: <%s>", tmpbuff);
- found = 1;
- }
- } while (!found && ((time(NULL) - start) < 5));
- gw_free(tmpbuff);
- return found;
- }
- /******************************************************************************
- * Get the modem buffer data to buff, return the amount read
- *
- * Reads from main fd, but also from backup-fd - does accept if needed
- */
- static int get_data(SMSCenter *smsc, char *buff, int length)
- {
- int n = 0;
- struct sockaddr_in client_addr;
- socklen_t client_addr_len;
- fd_set rf;
- struct timeval to;
- int ret;
- memset(buff, 0, length);
- if (smsc->type == SMSC_TYPE_EMI) {
- tcdrain(smsc->emi_fd);
- n = read(smsc->emi_fd, buff, length);
- return n;
- }
- FD_ZERO(&rf);
- if (smsc->emi_fd >= 0) FD_SET(smsc->emi_fd, &rf);
- if (smsc->emi_secondary_fd >= 0) FD_SET(smsc->emi_secondary_fd, &rf);
- if (smsc->emi_backup_fd > 0) FD_SET(smsc->emi_backup_fd, &rf);
- FD_SET(0, &rf);
- to.tv_sec = 0;
- to.tv_usec = 100;
- ret = select(FD_SETSIZE, &rf, NULL, NULL, &to);
- if (ret > 0) {
- if (smsc->emi_secondary_fd >= 0 && FD_ISSET(smsc->emi_secondary_fd, &rf)) {
- n = read(smsc->emi_secondary_fd, buff, length - 1);
- if (n == -1) {
- error(errno, "Error - Secondary socket closed");
- close(smsc->emi_secondary_fd);
- smsc->emi_secondary_fd = -1;
- } else if (n == 0) {
- info(0, "Secondary socket closed by SMSC");
- close(smsc->emi_secondary_fd);
- smsc->emi_secondary_fd = -1;
- } else { /* UGLY! We put 'X' after message */
- buff[n] = 'X'; /* if it is from secondary fd!!! */
- n++;
- }
- } else if (smsc->emi_fd >= 0 && FD_ISSET(smsc->emi_fd, &rf)) {
- n = read(smsc->emi_fd, buff, length);
- if (n == 0) {
- close(smsc->emi_fd);
- info(0, "Main EMI socket closed by SMSC");
- smsc->emi_fd = -1; /* ready to be re-opened */
- }
- }
- if ((smsc->emi_backup_fd > 0) && FD_ISSET(smsc->emi_backup_fd, &rf)) {
- if (smsc->emi_secondary_fd == -1) {
- Octstr *ip, *allow;
- smsc->emi_secondary_fd = accept(smsc->emi_backup_fd,
- (struct sockaddr *)&client_addr, &client_addr_len);
- ip = host_ip(client_addr);
- if (smsc->emi_backup_allow_ip == NULL)
- allow = NULL;
- else
- allow = octstr_create(smsc->emi_backup_allow_ip);
- if (is_allowed_ip(allow, octstr_imm("*.*.*.*"), ip) == 0) {
- info(0, "SMSC secondary connection tried from <%s>, "
- "disconnected",
- octstr_get_cstr(ip));
- octstr_destroy(ip);
- octstr_destroy(allow);
- close(smsc->emi_secondary_fd);
- smsc->emi_secondary_fd = -1;
- return 0;
- }
- info(0, "Secondary socket opened by SMSC from <%s>",
- octstr_get_cstr(ip));
- octstr_destroy(ip);
- octstr_destroy(allow);
- } else
- info(0, "New connection request while old secondary is open!");
- }
- }
- if (n > 0) {
- debug("bb.sms.emi", 0, "get_data:Read %d bytes: <%.*s>", n, n, buff);
- debug("bb.sms.emi", 0, "get_data:smsc->buffer == <%s>", smsc->buffer);
- }
- return n;
- }
- /******************************************************************************
- * Put the buff data to the modem buffer, return the amount of data put
- */
- static int put_data(SMSCenter *smsc, char *buff, int length, int is_backup)
- {
- size_t len = length;
- int ret;
- int fd = -1;
- if (smsc->type == SMSC_TYPE_EMI_IP) {
- if (is_backup) {
- fd = smsc->emi_secondary_fd;
- info(0, "Writing into secondary (backup) fd!");
- } else {
- if (smsc->emi_fd == -1) {
- info(0, "Reopening connection to SMSC");
- if (emi_open_connection_ip(smsc) < 0) {
- error(0, "put_data: Reopening failed!");
- return -1;
- }
- }
- fd = smsc->emi_fd;
- }
- }
- if (smsc->type == SMSC_TYPE_EMI) {
- fd = smsc->emi_fd;
- tcdrain(smsc->emi_fd);
- }
- /* Write until all data has been successfully written to the fd. */
- while (len > 0) {
- ret = write(fd, buff, len);
- if (ret == -1) {
- if (errno == EINTR) continue;
- if (errno == EAGAIN) continue;
- error(errno, "Writing to fd failed");
- if (fd == smsc->emi_fd && smsc->type == SMSC_TYPE_EMI_IP) {
- close(fd);
- smsc->emi_fd = -1;
- info(0, "Closed main EMI socket.");
- }
- return -1;
- }
- /* ret may be less than len, if the writing
- was interrupted by a signal. */
- len -= ret;
- buff += ret;
- }
- if (smsc->type == SMSC_TYPE_EMI) {
- /* Make sure the data gets written immediately.
- Wait a while just to add some latency so
- that the modem (or the UART) doesn't choke
- on the data. */
- tcdrain(smsc->emi_fd);
- usleep(1000);
- }
- return 0;
- }
- /******************************************************************************
- * Append the buff data to smsc->buffer
- */
- static int memorybuffer_append_data(SMSCenter *smsc, char *buff, int length)
- {
- while (smsc->bufsize < (smsc->buflen + length)) { /* buffer too small */
- char *p = gw_realloc(smsc->buffer, smsc->bufsize * 2);
- smsc->buffer = p;
- smsc->bufsize *= 2;
- }
- memcpy(smsc->buffer + smsc->buflen, buff, length);
- smsc->buflen += length;
- return 0;
- }
- /******************************************************************************
- * Insert (put to head) the buff data to smsc->buffer
- */
- static int memorybuffer_insert_data(SMSCenter *smsc, char *buff, int length)
- {
- while (smsc->bufsize < (smsc->buflen + length)) { /* buffer too small */
- char *p = gw_realloc(smsc->buffer, smsc->bufsize * 2);
- smsc->buffer = p;
- smsc->bufsize *= 2;
- }
- memmove(smsc->buffer + length, smsc->buffer, smsc->buflen);
- memcpy(smsc->buffer, buff, length);
- smsc->buflen += length;
- return 0;
- }
- /******************************************************************************
- * Check the smsc->buffer for a raw STX...ETX message
- */
- static int memorybuffer_has_rawmessage(SMSCenter *smsc, int type, char auth)
- {
- char tmpbuff[1024], tmpbuff2[1024];
- char *stx, *etx;
- stx = memchr(smsc->buffer, '2', smsc->buflen);
- etx = memchr(smsc->buffer, '3', smsc->buflen);
- if (stx && etx && stx < etx) {
- strncpy(tmpbuff, stx, etx - stx + 1);
- tmpbuff[etx - stx + 1] = ' ';
- if (auth)
- sprintf(tmpbuff2, "/%c/%02i/", auth, type);
- else
- sprintf(tmpbuff2, "/%02i/", type);
- if (strstr(tmpbuff, tmpbuff2) != NULL) {
- debug("bb.sms.emi", 0, "found message <%c/%02i>...msg <%s>", auth, type, tmpbuff);
- return 1;
- }
- }
- return 0;
- }
- /******************************************************************************
- * Cut the first raw message from the smsc->buffer
- * and put it in buff, return success 0, failure -1
- */
- static int memorybuffer_cut_rawmessage(SMSCenter *smsc, char *buff, int length)
- {
- char *stx, *etx;
- int size_of_cut_piece;
- int size_of_the_rest;
- /* We don't check for NULLs since we're sure that nobody has fooled
- around with smsc->buffer since has_rawmessage was last called... */
- stx = memchr(smsc->buffer, '2', smsc->buflen);
- etx = memchr(smsc->buffer, '3', smsc->buflen);
- if (*(etx + 1) == 'X') /* secondary! UGLY KLUDGE */
- etx++;
- size_of_cut_piece = (etx - stx) + 1;
- size_of_the_rest = (smsc->buflen - size_of_cut_piece);
- if (length < size_of_cut_piece) {
- error(0, "the buffer you provided for cutting was too small");
- return -1;
- }
- /* move the part before our magic rawmessage to the safe house */
- memcpy(buff, stx, size_of_cut_piece);
- buff[size_of_cut_piece] = ' '; /* NULL-terminate */
- /* move the stuff in membuffer one step down */
- memmove(stx, etx + 1, (smsc->buffer + smsc->bufsize) - stx );
- smsc->buflen -= size_of_cut_piece;
- return 0;
- }
- /******************************************************************************
- * Parse the raw message to the Msg structure
- */
- static int parse_rawmessage_to_msg(SMSCenter *smsc, Msg **msg,
- char *rawmessage, int length)
- {
- char emivars[128][1024];
- char *leftslash, *rightslash;
- char isotext[2048];
- int msgnbr;
- int tmpint;
- msgnbr = -1;
- memset(isotext, 0, sizeof(isotext));
- strncpy(isotext, rawmessage, length);
- leftslash = isotext;
- for (tmpint = 0; leftslash != NULL; tmpint++) {
- rightslash = strchr(leftslash + 1, '/');
- if (rightslash == NULL)
- rightslash = strchr(leftslash + 1, '3');
- if (rightslash == NULL)
- break;
- *rightslash = ' ';
- strcpy(emivars[tmpint], leftslash + 1);
- leftslash = rightslash;
- }
- if (strcmp(emivars[3], "01") == 0) {
- if (strcmp(emivars[7], "2") == 0) {
- strcpy(isotext, emivars[8]);
- } else if (strcmp(emivars[7], "3") == 0) {
- parse_emi_to_iso88591(emivars[8], isotext, sizeof(isotext),
- smsc->alt_charset);
- } else {
- error(0, "Unknown 01-type EMI SMS (%s)", emivars[7]);
- strcpy(isotext, "");
- }
- } else if (strcmp(emivars[3], "51") == 0) {
- parse_emi_to_iso88591(emivars[24], isotext, sizeof(isotext),
- smsc->alt_charset);
- } else if (strcmp(emivars[3], "52") == 0) {
- parse_emi_to_iso88591(emivars[24], isotext, sizeof(isotext),
- smsc->alt_charset);
- } else {
- error(0, "HEY WE SHOULD NOT BE HERE!! Type = %s", emivars[3]);
- strcpy(isotext, "");
- }
- *msg = msg_create(sms);
- if (*msg == NULL) goto error;
- (*msg)->sms.sender = octstr_create(emivars[5]);
- (*msg)->sms.receiver = octstr_create(emivars[4]);
- (*msg)->sms.msgdata = octstr_create(isotext);
- (*msg)->sms.udhdata = NULL;
- return msgnbr;
- error:
- return -1;
- }
- /*
- * notify the SMSC that we got the message
- */
- static int acknowledge_from_rawmessage(SMSCenter *smsc,
- char *rawmessage, int length)
- {
- char emivars[128][1024];
- char timestamp[2048], sender[2048], receiver[2048];
- char emitext[2048], isotext[2048];
- char *leftslash, *rightslash;
- int msgnbr;
- int tmpint;
- int is_backup = 0;
- msgnbr = -1;
- memset(&sender, 0, sizeof(sender));
- memset(&receiver, 0, sizeof(receiver));
- memset(&emitext, 0, sizeof(emitext));
- memset(&isotext, 0, sizeof(isotext));
- memset(×tamp, 0, sizeof(timestamp));
- strncpy(isotext, rawmessage, length);
- leftslash = isotext;
- if (isotext[length - 1] == 'X')
- is_backup = 1;
- for (tmpint = 0; leftslash != NULL; tmpint++) {
- rightslash = strchr(leftslash + 1, '/');
- if (rightslash == NULL)
- rightslash = strchr(leftslash + 1, '3');
- if (rightslash == NULL)
- break;
- *rightslash = ' ';
- strcpy(emivars[tmpint], leftslash + 1);
- leftslash = rightslash;
- }
- /* BODY */
- if (smsc->type == SMSC_TYPE_EMI) {
- sprintf(isotext, "A//%s:%s", emivars[4], emivars[18]);
- sprintf(isotext, "A//%s:", emivars[5]);
- is_backup = 0;
- }
- if (smsc->type == SMSC_TYPE_EMI_IP) {
- if (strcmp(emivars[3], "01") == 0)
- sprintf(isotext, "A/%s:", emivars[4]);
- else
- sprintf(isotext, "A//%s:%s", emivars[4], emivars[18]);
- }
- /* HEADER */
- debug("bb.sms.emi", 0, "acknowledge: type = '%s'", emivars[3]);
- sprintf(emitext, "%s/%05i/%s/%s", emivars[0], (int) strlen(isotext) + 17,
- "R", emivars[3]);
- smsc->emi_current_msg_number = atoi(emivars[0]) + 1;
- /* FOOTER */
- sprintf(timestamp, "%s/%s/", emitext, isotext);
- generate_checksum(timestamp, receiver);
- sprintf(sender, "%c%s/%s/%s%c", 0x02, emitext, isotext, receiver, 0x03);
- put_data(smsc, sender, strlen(sender), is_backup);
- return msgnbr;
- }
- /******************************************************************************
- * Parse the Msg structure to the raw message format
- */
- static int parse_msg_to_rawmessage(SMSCenter *smsc, Msg *msg, char *rawmessage, int rawmessage_length)
- {
- char message_whole[10*1024];
- char message_body[10*1024];
- char message_header[1024];
- char message_footer[1024];
- char my_buffer[10*1024];
- char my_buffer2[10*1024];
- char msgtext[1024];
- int length;
- char mt;
- char mcl[20];
- char snumbits[20];
- char xser[1024];
- int udh_len;
- memset(&message_whole, 0, sizeof(message_whole));
- memset(&message_body, 0, sizeof(message_body));
- memset(&message_header, 0, sizeof(message_header));
- memset(&message_footer, 0, sizeof(message_footer));
- memset(&my_buffer, 0, sizeof(my_buffer));
- memset(&my_buffer2, 0, sizeof(my_buffer2));
- mt = '3';
- memset(&snumbits, 0, sizeof(snumbits));
- memset(&xser, 0, sizeof(xser));
- /* XXX parse_iso88591_to_emi shouldn't use NUL terminated
- * strings, but Octstr directly, or a char* and a length.
- */
- if (octstr_len(msg->sms.udhdata)) {
- char xserbuf[258];
- /* we need a properly formated UDH here, there first byte contains his length
- * this will be formatted in the xser field of the EMI Protocol
- */
- udh_len = octstr_get_char(msg->sms.udhdata, 0) + 1;
- xserbuf[0] = 1;
- xserbuf[1] = udh_len;
- octstr_get_many_chars(&xserbuf[2], msg->sms.udhdata, 0, udh_len);
- parse_binary_to_emi(xserbuf, xser, udh_len + 2);
- } else {
- udh_len = 0;
- }
- if (msg->sms.coding == DC_7BIT ) {
- octstr_get_many_chars(msgtext, msg->sms.msgdata, 0, octstr_len(msg->sms.msgdata));
- msgtext[octstr_len(msg->sms.msgdata)] = ' ';
- parse_iso88591_to_emi(msgtext, my_buffer2,
- octstr_len(msg->sms.msgdata),
- smsc->alt_charset);
- strcpy(snumbits, "");
- mt = '3';
- strcpy(mcl, "");
- } else {
- octstr_get_many_chars(msgtext, msg->sms.msgdata, 0, octstr_len(msg->sms.msgdata));
- parse_binary_to_emi(msgtext, my_buffer2, octstr_len(msg->sms.msgdata));
- sprintf(snumbits, "%04ld", octstr_len(msg->sms.msgdata)*8);
- mt = '4';
- strcpy(mcl, "1");
- }
- /* XXX Where is DCS ? Is it in XSER like in emi2 ?
- * Please someone encode it with fields_to_dcs
- */
- sprintf(message_body,
- "%s/%s/%s/%s/%s//%s////////////%c/%s/%s////%s//////%s//",
- octstr_get_cstr(msg->sms.receiver),
- msg->sms.sender ? octstr_get_cstr(msg->sms.sender) : "",
- "",
- "",
- "",
- "0100",
- mt,
- snumbits,
- my_buffer2,
- mcl,
- xser);
- /* HEADER */
- length = strlen(message_body);
- length += 13; /* header (fixed) */
- length += 2; /* footer (fixed) */
- length += 2; /* slashes between header, body, footer */
- sprintf(message_header, "%02i/%05i/%s/%s", (smsc->emi_current_msg_number++ % 100), length, "O", "51");
- /* FOOTER */
- sprintf(my_buffer, "%s/%s/", message_header, message_body);
- generate_checksum(my_buffer, message_footer);
- sprintf(message_whole, "%c%s/%s/%s%c", 0x02, message_header, message_body, message_footer, 0x03);
- strncpy(rawmessage, message_whole, rawmessage_length);
- if (smsc->type == SMSC_TYPE_EMI) {
- /* IC3S braindead EMI stack chokes on this... must fix it at the next time... */
- strcat(rawmessage, "r");
- }
- debug("bb.sms.emi", 0, "emi %d message %s",
- smsc->emi_current_msg_number, rawmessage);
- return strlen(rawmessage);
- }
- /******************************************************************************
- * Parse the data from the two byte EMI code to normal ISO-8869-1
- */
- static int parse_emi_to_iso88591(char *from, char *to, int length,
- int alt_charset)
- {
- int hmtg = 0;
- unsigned int mychar;
- char tmpbuff[128];
- for (hmtg = 0; hmtg <= (int)strlen(from); hmtg += 2) {
- strncpy(tmpbuff, from + hmtg, 2);
- sscanf(tmpbuff, "%x", &mychar);
- to[hmtg / 2] = char_sms_to_iso(mychar, alt_charset);
- }
- to[(hmtg / 2)-1] = ' ';
- return 0;
- }
- /******************************************************************************
- * Parse the data from normal ISO-8869-1 to the two byte EMI code
- */
- static int parse_iso88591_to_emi(char *from, char *to,
- int length, int alt_charset)
- {
- char buf[10];
- unsigned char tmpchar;
- char *ptr;
- if (!from || !to || length <= 0)
- return -1;
- *to = ' ';
- debug("bb.sms.emi", 0, "emi parsing <%s> to emi, length %d", from, length);
- for (ptr = from; length > 0; ptr++, length--) {
- tmpchar = char_iso_to_sms(*ptr, alt_charset);
- sprintf(buf, "%02X", tmpchar);
- strncat(to, buf, 2);
- }
- return 0;
- }
- /******************************************************************************
- * Parse the data from binary to the two byte EMI code
- */
- static int parse_binary_to_emi(char *from, char *to, int length)
- {
- char buf[10];
- char *ptr;
- if (!from || !to || length <= 0)
- return -1;
- *to = ' ';
- for (ptr = from; length > 0; ptr++, length--) {
- sprintf(buf, "%02X", (unsigned char)*ptr);
- strncat(to, buf, 2);
- }
- return 0;
- }
- /******************************************************************************
- * Generate the EMI message checksum
- */
- static void generate_checksum(const unsigned char *buf, unsigned char *out)
- {
- const unsigned char *p;
- int j;
- j = 0;
- for (p = buf; *p != ' '; p++) {
- j += *p;
- if (j >= 256)
- j -= 256;
- }
- sprintf(out, "%02X", j);
- }
- /******************************************************************************
- * Translate character from iso to emi_mt
- * PGr鰊holm
- */
- static char char_iso_to_sms(unsigned char from, int alt_charset)
- {
- switch ((char)from) {
- case 'A':
- return 0x41;
- case 'B':
- return 0x42;
- case 'C':
- return 0x43;
- case 'D':
- return 0x44;
- case 'E':
- return 0x45;
- case 'F':
- return 0x46;
- case 'G':
- return 0x47;
- case 'H':
- return 0x48;
- case 'I':
- return 0x49;
- case 'J':
- return 0x4A;
- case 'K':
- return 0x4B;
- case 'L':
- return 0x4C;
- case 'M':
- return 0x4D;
- case 'N':
- return 0x4E;
- case 'O':
- return 0x4F;
- case 'P':
- return 0x50;
- case 'Q':
- return 0x51;
- case 'R':
- return 0x52;
- case 'S':
- return 0x53;
- case 'T':
- return 0x54;
- case 'U':
- return 0x55;
- case 'V':
- return 0x56;
- case 'W':
- return 0x57;
- case 'X':
- return 0x58;
- case 'Y':
- return 0x59;
- case 'Z':
- return 0x5A;
- case 'a':
- return 0x61;
- case 'b':
- return 0x62;
- case 'c':
- return 0x63;
- case 'd':
- return 0x64;
- case 'e':
- return 0x65;
- case 'f':
- return 0x66;
- case 'g':
- return 0x67;
- case 'h':
- return 0x68;
- case 'i':
- return 0x69;
- case 'j':
- return 0x6A;
- case 'k':
- return 0x6B;
- case 'l':
- return 0x6C;
- case 'm':
- return 0x6D;
- case 'n':
- return 0x6E;
- case 'o':
- return 0x6F;
- case 'p':
- return 0x70;
- case 'q':
- return 0x71;
- case 'r':
- return 0x72;
- case 's':
- return 0x73;
- case 't':
- return 0x74;
- case 'u':
- return 0x75;
- case 'v':
- return 0x76;
- case 'w':
- return 0x77;
- case 'x':
- return 0x78;
- case 'y':
- return 0x79;
- case 'z':
- return 0x7A;
- case '0':
- return 0x30;
- case '1':
- return 0x31;
- case '2':
- return 0x32;
- case '3':
- return 0x33;
- case '4':
- return 0x34;
- case '5':
- return 0x35;
- case '6':
- return 0x36;
- case '7':
- return 0x37;
- case '8':
- return 0x38;
- case '9':
- return 0x39;
- case ':':
- return 0x3A;
- case ';':
- return 0x3B;
- case '<':
- return 0x3C;
- case '=':
- return 0x3D;
- case '>':
- return 0x3E;
- case '?':
- return 0x3F;
- case '