smsc_ois.c
上传用户:gzpyjq
上传日期:2013-01-31
资源大小:1852k
文件大小:42k
源码类别:

手机WAP编程

开发平台:

WINDOWS

  1. /*****************************************************************************
  2.  * smsc_ois.c - Sema Group SMS2000 (G6.0) Center (OIS 5.0).
  3.  * Jouko Koski (EDS) for WapIT Ltd.
  4.  *
  5.  * The SMS2000 has a general X.25 access gateway for accessing the SMSC,
  6.  * as described in the Open Interface Specification 5.0 document.
  7.  * A protocol translator - like the Cisco 2501 router - hides all the
  8.  * X.25 trickery from us. We just connect to a preconfigured router
  9.  * address/port, and the translator forwards the connection to the SMS2000.
  10.  * Correspondingly, if the SMSC has something to say, it looks like
  11.  * the router were contacting our port. The router should be configured so,
  12.  * that it has a pre-defined address and tcp port in X.25 automode establishing
  13.  * a X.25 link and a similar configuration in X.25 side connecting to a pre-
  14.  * defined address and port, it shall not encapsulate everything in Telnet
  15.  * (set the stream mode), and it should suppress banner messages like "Trying
  16.  * 9876...Open" (set the quiet mode).
  17.  *
  18.  * Whenever possible, I've tried to steal ideas and code from other smsc_*
  19.  * files, particularly from Hao Shi's (EDS) original implementation for a
  20.  * serial-line-connected PAD. However, the code is highly evolutionary,
  21.  * because during the implementation new technical details kept popping
  22.  * up all the time (initially, PAD commands were supposed to be used,
  23.  * but the router was configured to "automode", so they weren't necessary;
  24.  * instead the router gave banner messages and wanted some telnet negotiations;
  25.  * the router insisted echoing everything and delayed <nul>s after <cr>s;
  26.  * telnet transmit-binary mode solved that; then the stream mode (no telnet
  27.  * encapsulation) was discovered; suddenly the banners were turned off also;
  28.  * but still the smsc didn't deliver mo messages, because it wanted to
  29.  * connect instead of using our existing connection; then we began to use
  30.  * short connection sessions for transmitting instead of a single ever-
  31.  * lasting connection, and also started to specifically listen for smsc
  32.  * initiated connections, which yielded two separate input buffers; then
  33.  * suddenly the banners were there again, so some intelligence had to be
  34.  * added to adapt their (non-)existence; then revealed the spec version 4.5
  35.  * had been obsolete all the time and we got 5.0; the router apparently
  36.  * caused some extra packets on the x.25 side and everybody was blaming the
  37.  * application; then the connection maintenance and buffering was again
  38.  * revisited to achieve better performance and reliability... Really an
  39.  * interesting story but think if it were about you instead of me :-)
  40.  *
  41.  * Really funny thing is that according to the spec the SMS2000 does have
  42.  * a direct TCP/IP access interface. However, here we have the general X.25
  43.  * access interface, since we started with the old spec and probably the
  44.  * simpler TCP/IP access is not available in our particular customer's
  45.  * installation, not at least when this was written. In the direct access
  46.  * only single ever-lasting connection is necessary, and the messages are
  47.  * the same but their format is different. Encoding tricks are the same.
  48.  * So, if you are implementing that access mode some day, there are probably
  49.  * differences between this access mode and yours on so many levels, that
  50.  * simple if () selections won't work; write your own code from (nearly)
  51.  * scratch and take appropriate encoding conversion functions here. Or do
  52.  * just whatever you want, what should I care :-).
  53.  */
  54. #include <unistd.h>
  55. #include <ctype.h>
  56. #include <errno.h>
  57. #include <string.h>
  58. #include <sys/time.h>
  59. #include <sys/types.h>
  60. #include <sys/timeb.h>
  61. #include <sys/socket.h>
  62. #include <netinet/in.h>
  63. #include <arpa/inet.h>
  64. #include "smsc.h"
  65. #include "smsc_p.h"
  66. #include "gwlib/gwlib.h"
  67. #include "sms.h"
  68. /* XXX Delete me and replace dcs with dcs_to_fields */
  69. enum dcs_body_type {
  70.     DCS_GSM_TEXT = 0,
  71.     DCS_OCTET_DATA = 4    /* flag_8bit */
  72. };
  73. /* 'private:' */
  74. int ois_debug_level = 0; /* some extra verbosity in debug logging */
  75. /* 0=just normal debugging, 1=input/output messages, 2=function entries, */
  76. /* 3=message assembly/disassembly, 4=disconnection tracing, */
  77. /* 5=message conversions, and 8=message polling (=too much) */
  78. #define SAY(d,s) { if (d<=ois_debug_level) debug("bb.sms.ois",0,s); }
  79. #define SAY2(d,s,t) { if (d<=ois_debug_level) debug("bb.sms.ois",0,s,t); }
  80. #define SAY3(d,s,t,u) { if (d<=ois_debug_level) debug("bb.sms.ois",0,s,t,u); }
  81. #define IOTRACE(x,s,l) SAY3(1,"%s [%s]",x,ois_debug_str(s,l))
  82. #define BUFLEN (511) /* sure enough for ois messages */
  83. #define OIS_OPEN_WAITTIME (15) /* seconds, waiting for banners */
  84. #define OIS_MESSAGE_WAITTIME (30) /* seconds, until closing idle connection */
  85. #define OIS_WAITTIME (999999) /* microseconds, waiting for banners at a time */
  86. #define OIS_NOWAIT (0) /* microseconds, not waiting */
  87. #define MAXCOUNTER (10000) /* ois message id */
  88. #define EOL ('r') /* ois definition for the eol */
  89. typedef struct ois_listentry {
  90.     struct ois_listentry *next;
  91.     Msg *msg;
  92. } ois_listentry;
  93. #define OIS_FLAG_DEBUG (0x000f)
  94. #define OIS_FLAG_ERROR (0x0100)
  95. #define OIS_FLAG_NOBANNER (0x0200)
  96. #define OIS_FLAG_MULTIPLE_CALL (0x0400)
  97. #define OIS_FLAG_CLOSED (0x0800)
  98. static int ois_counter = 0; /* [0..MAXCOUNTER), ois "unique" message id */
  99. static int ois_open_listener(SMSCenter *smsc);
  100. static int ois_open_sender(SMSCenter *smsc);
  101. static int ois_open_receiver(SMSCenter *smsc);
  102. static void ois_disconnect_all(SMSCenter *smsc);
  103. static void ois_disconnect(SMSCenter *smsc);
  104. static int ois_read_into_buffer(SMSCenter *smsc, long wait_usec);
  105. static int ois_check_input(SMSCenter *smsc, long wait_usec);
  106. static int ois_check_incoming(SMSCenter *smsc, long wait_usec);
  107. static void ois_append_to_list(ois_listentry **head, Msg *msg);
  108. static int ois_int_to_i4(char *raw, int nbr);
  109. static int ois_increment_counter(void);
  110. static int ois_submit_sm_invoke(SMSCenter *smsc, const Msg *msg);
  111. static int ois_encode_submit_sm_invoke(char *str, const Msg *msg);
  112. static int ois_append_msisdn(char *raw, const Msg *msg);
  113. static int ois_append_sme_reference_number(char *raw);
  114. static int ois_append_priority(char *raw);
  115. static int ois_append_originating_address(char *raw);
  116. static int ois_append_validity_period(char *raw);
  117. static int ois_append_data_coding_scheme(char *raw, const Msg *msg);
  118. static int ois_append_status_report_request(char *raw);
  119. static int ois_append_protocol_id(char *raw);
  120. static int ois_append_submission_options(char *raw, const Msg *msg);
  121. static int ois_append_sm_text(char *raw, const Msg *msg);
  122. static int ois_submit_sm_result(SMSCenter *smsc, const char *buffer);
  123. static int ois_decode_submit_sm_result(int *code, const char *str);
  124. static int ois_deliver_sm_invoke(SMSCenter *smsc, const char *buffer);
  125. static int ois_decode_deliver_sm_invoke(Msg *msg, const char *str);
  126. static int ois_check_deliver_sm_invoke(const char *str);
  127. static int ois_adjust_destination_address(Msg *msg, const char *raw);
  128. static int ois_ignore_smsc_reference_number(const char *raw);
  129. static int ois_adjust_originating_address(Msg *msg, const char *raw);
  130. static int ois_adjust_data_coding_scheme(Msg *msg, const char *raw);
  131. static int ois_ignore_protocol_id(const char *raw);
  132. static int ois_adjust_additional_information(Msg *msg, const char *raw);
  133. static int ois_adjust_sm_text(Msg *msg, const char *raw);
  134. static int ois_ignore_time(const char *raw);
  135. static int ois_deliver_sm_result(SMSCenter *smsc, int result, const char *str);
  136. static int ois_encode_deliver_sm_result(char *str, int result);
  137. static int ois_expand_gsm7(char *raw8, const char *raw7, int len);
  138. static int ois_expand_gsm7_to_bits(char *bits, const char *raw7, int len);
  139. static char ois_expand_gsm7_from_bits(const char *bits, int pos);
  140. static int ois_convert_to_ia5(char *str, const char *raw, int len);
  141. static int ois_convert_from_ia5(char *raw, const char *str);
  142. static int ois_convert_to_iso88591(char *raw, int len);
  143. static int ois_extract_msg_from_buffer(char *str, SMSCenter *smsc);
  144. static int ois_extract_line_from_buffer(char *str, SMSCenter *smsc);
  145. static void ois_swap_buffering(SMSCenter *smsc);
  146. static const char *ois_debug_str(const char *raw, int len);
  147. /* 'public:' */
  148. /*
  149.  * Establish a connection to the SMSC.
  150.  */
  151. SMSCenter *ois_open(int receiveport, const char *hostname, int port, int debug_level)
  152. {
  153.     SMSCenter *smsc;
  154.     int ret;
  155.     ois_debug_level = debug_level & OIS_FLAG_DEBUG;
  156.     SAY(2, "ois_open");
  157.     /* create a SMSCenter structure */
  158.     smsc = smscenter_construct();
  159.     if (smsc == NULL) {
  160. goto error;
  161.     }
  162.     smsc->type = SMSC_TYPE_OIS;
  163.     smsc->receive_port = receiveport;
  164.     smsc->hostname = gw_strdup(hostname);
  165.     smsc->port = port;
  166.     smsc->ois_flags = ois_debug_level;
  167.     ret = ois_open_listener(smsc);
  168.     if (ret < 0) {
  169. goto error;
  170.     }
  171.     sprintf(smsc->name, "OIS:TCP/X.25-Translator:localhost:%d:TCP:%.512s:%d",
  172.     smsc->receive_port, smsc->hostname, smsc->port);
  173.     return smsc;
  174.  error:
  175.     error(0, "ois_open: could not open");
  176.     smscenter_destruct(smsc);
  177.     return NULL;
  178. }
  179. /*
  180.  * Terminate the SMSC connection.
  181.  */
  182. int ois_close(SMSCenter *smsc)
  183. {
  184.     ois_debug_level = smsc->ois_flags & OIS_FLAG_DEBUG;
  185.     SAY(2, "ois_close");
  186.     if (smsc->type != SMSC_TYPE_OIS) {
  187. warning(0, "ois_close: closing a not-ois connection...");
  188.     }
  189.     ois_swap_buffering(smsc);
  190.     smscenter_remove_from_buffer(smsc, smsc->buflen);
  191.     ois_swap_buffering(smsc);
  192.     smscenter_remove_from_buffer(smsc, smsc->buflen);
  193.     SAY(4, "ois_close: ois_disconnect_all");
  194.     ois_disconnect_all(smsc);
  195.     return 0;
  196. }
  197. /*
  198.  * Re-establish a SMSC connection.
  199.  */
  200. int ois_reopen(SMSCenter *smsc)
  201. {
  202.     int ret;
  203.     ois_debug_level = smsc->ois_flags & OIS_FLAG_DEBUG;
  204.     SAY(2, "ois_reopen");
  205.     ois_close(smsc);
  206.     if (smsc->type == SMSC_TYPE_OIS) {
  207. ret = ois_open_listener(smsc);
  208. if (ret < 0) {
  209.     goto error;
  210. }
  211.     } else {
  212. error(0, "ois_reopen: wrong smsc type");
  213. goto error;
  214.     }
  215.     return 0;
  216.  error:
  217.     error(0, "ois_reopen: could not open");
  218.     return -1;
  219. }
  220. /*
  221.  * Check for MO messages.
  222.  * Put all incoming MO messages into an internal queue.
  223.  */
  224. int ois_pending_smsmessage(SMSCenter *smsc)
  225. {
  226.     int ret;
  227.     ois_debug_level = smsc->ois_flags & OIS_FLAG_DEBUG;
  228.     SAY(8, "ois_pending_smsmessage");
  229.     ret = ois_check_incoming(smsc, OIS_NOWAIT);
  230.     if (ret == 0 && smsc->socket != -1) {
  231. ret = ois_check_input(smsc, OIS_NOWAIT);
  232.     }
  233.     if (ret == 0 && smsc->ois_socket != -1) {
  234. ois_swap_buffering(smsc);
  235. ret = ois_check_input(smsc, OIS_NOWAIT);
  236. ois_swap_buffering(smsc);
  237. if (smsc->ois_socket == -1 && smsc->ois_ack_debt != 0) {
  238.     warning(0, "ois_pending_smsmessage: missing %d ack(s)...",
  239.     smsc->ois_ack_debt);
  240. }
  241.     }
  242.     return ret;
  243. }
  244. /*
  245.  * Send a MT message.
  246.  */
  247. int ois_submit_msg(SMSCenter *smsc, const Msg *msg)
  248. {
  249.     int ret;
  250.     ois_debug_level = smsc->ois_flags & OIS_FLAG_DEBUG;
  251.     SAY(2, "ois_submit_msg");
  252.     ois_swap_buffering(smsc);
  253.     if (msg_type((Msg *)msg) != sms) {
  254. error(0, "ois_submit_msg: can not handle message types other than smart_msg");
  255. goto error;
  256.     }
  257.     if (smsc->socket == -1) {
  258. ret = ois_open_sender(smsc);
  259. if (ret < 0) {
  260.     goto error;
  261. }
  262.     }
  263.     ret = ois_submit_sm_invoke(smsc, msg);
  264.     if (ret < 0) {
  265. goto error_close;
  266.     }
  267.     ++smsc->ois_ack_debt;
  268.     time(&smsc->ois_alive);
  269.     ret = 0;
  270.     goto out;
  271.  error_close:
  272.     if (smsc->ois_ack_debt != 0) {
  273. warning(0, "ois_submit_msg: missing %d ack(s)...",
  274. smsc->ois_ack_debt);
  275.     }
  276.     SAY(4, "ois_submit_msg: ois_disconnect in error_close");
  277.     ois_disconnect(smsc);
  278.  error:
  279.     SAY(2, "ois_submit_msg error");
  280.     ret = -1;
  281.  out:
  282.     ois_swap_buffering(smsc);
  283.     return ret;
  284. }
  285. /*
  286.  * Receive a MO message (from the internal queue).
  287.  */
  288. int ois_receive_msg(SMSCenter *smsc, Msg **msg)
  289. {
  290.     ois_listentry *item;
  291.     ois_debug_level = smsc->ois_flags & OIS_FLAG_DEBUG;
  292.     SAY(2, "ois_receive_msg");
  293.     item = smsc->ois_received_mo;
  294.     if (item == NULL) { /* no mo messages */
  295. if ((smsc->ois_flags & OIS_FLAG_ERROR) == 0) {
  296.     return 0;   /* should actually not happen */
  297. } else {
  298.     return -1;  /* error pending, reopen? */
  299. }
  300.     } else {            /* we have a message waiting */
  301. smsc->ois_received_mo = item->next;
  302. *msg = item->msg;
  303. gw_free(item);
  304. return 1;       /* got the message */
  305.     }
  306. }
  307. /*
  308.  * Destruct the internal queue.
  309.  */
  310. void ois_delete_queue(SMSCenter *smsc)
  311. {
  312.     Msg *msg;
  313.     ois_debug_level = smsc->ois_flags & OIS_FLAG_DEBUG;
  314.     SAY(2, "ois_delete_queue");
  315.     while (ois_receive_msg(smsc, &msg) > 0) {
  316. gw_free(msg);
  317.     }
  318.     return;
  319. }
  320. /*
  321.  * Implementation of 'private:'
  322.  */
  323. static int ois_open_listener(SMSCenter *smsc)
  324. {
  325.     SAY(2, "ois_open_listener");
  326.     smsc->ois_listening_socket = make_server_socket(smsc->receive_port, 
  327.     NULL);
  328. /* XXX add interface_name if required */
  329.     if (smsc->ois_listening_socket < 0) {
  330. goto error;
  331.     }
  332.     if (socket_set_blocking(smsc->ois_listening_socket, 0) < 0) {
  333. ois_close(smsc);
  334. goto error;
  335.     }
  336.     smsc->ois_flags &= ~OIS_FLAG_ERROR;
  337.     smsc->ois_flags &= ~OIS_FLAG_NOBANNER;
  338.     smsc->ois_alive2 = time(&smsc->ois_alive);
  339.     SAY2(2, "ois_open_listener fd=%d", smsc->ois_listening_socket);
  340.     return 0;
  341.  error:
  342.     error(0, "ois_open_listener: failed to open listening socket");
  343.     return -1;
  344. }
  345. static int ois_open_sender(SMSCenter *smsc)
  346. {
  347.     int ret;
  348.     char buffer[BUFLEN+1];
  349.     time_t now;
  350.     time_t beginning;
  351.     
  352.     SAY(2, "ois_open_sender");
  353.     debug("bb.sms.ois", 0, "connecting to host %s port %d",
  354.   smsc->hostname, smsc->port);
  355.     time(&beginning);
  356.     smsc->socket = tcpip_connect_to_server(smsc->hostname, smsc->port,
  357.     NULL);
  358. /* XXX add interface_name if required */
  359.     if (smsc->socket < 0) {
  360. return -1;
  361.     } else {
  362. smsc->buflen = 0;
  363. time(&smsc->ois_alive);
  364. smsc->ois_ack_debt = 0;
  365.     }
  366.     SAY2(2, "ois_open_sender fd=%d", smsc->socket);
  367.     if (smsc->ois_flags & OIS_FLAG_NOBANNER) {
  368. return 0;
  369.     }
  370.     buffer[0] = '';
  371.     for (time(&now); (now - beginning) < OIS_OPEN_WAITTIME; time(&now)) {
  372. ret = ois_read_into_buffer(smsc, OIS_WAITTIME);
  373. if (ret < 0) {
  374.     goto error;
  375. }
  376. if (smsc->buflen == 0) {
  377.     /* assume that the router is in the quiet mode */
  378.     /* there will be no banners */
  379.     smsc->ois_flags |= OIS_FLAG_NOBANNER;
  380.     debug("bb.sms.ois", 0, "assuming that %s:%d is in the quiet mode",
  381.   smsc->hostname, smsc->port);
  382.     return 0;
  383. }
  384. ret = ois_extract_line_from_buffer(buffer, smsc);
  385. if (ret > 0) {
  386.     if (strncmp(buffer, "Trying", 6) == 0 &&
  387. strstr(buffer, "...Openrn") != NULL) {
  388. time(&smsc->ois_alive);
  389. return 0;
  390.     } else {
  391. break;
  392.     }
  393. }
  394.     }
  395.  error:
  396.     SAY(4, "ois_open_sender: ois_disconnect in error");
  397.     ois_disconnect(smsc);
  398.     error(0, "ois_open_sender: failed to connect [%s%s]",
  399.   buffer, ois_debug_str(smsc->buffer, smsc->buflen));
  400.     return -1;
  401. }
  402. static int ois_open_receiver(SMSCenter *smsc)
  403. {
  404.     struct sockaddr_in addr;
  405.     int addrlen;
  406.     Octstr *os;
  407.     SAY(2, "ois_open_receiver");
  408.     /* the listening socket should be non-blocking... */
  409.     addrlen = sizeof(addr);
  410.     smsc->socket = accept(smsc->ois_listening_socket,
  411.   (struct sockaddr *)&addr, &addrlen);
  412.     if (smsc->socket == -1) {
  413. if (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK)
  414.     /* || errno == ECONNABORTED || errno == EPROTO) -Kalle 6.7 */
  415. {
  416.     return 0;
  417. } else {
  418.     error(errno, "ois_open_receiver: accept failed");
  419.     smsc->ois_flags |= OIS_FLAG_ERROR;
  420.     return -1;
  421. }
  422.     }
  423.     SAY2(2, "ois_open_receiver fd=%d", smsc->socket);
  424.     os = gw_netaddr_to_octstr(AF_INET, &addr.sin_addr);
  425.     debug("bb.sms.ois", 0, "connection from host %s port %hu",
  426.   octstr_get_cstr(os), ntohs(addr.sin_port));
  427.     octstr_destroy(os);
  428.     time(&smsc->ois_alive);
  429.     return 0;
  430. }
  431. static void ois_disconnect_all(SMSCenter *smsc)
  432. {
  433.     SAY2(2, "ois_disconnect_all fd=%d", smsc->ois_listening_socket);
  434.     ois_swap_buffering(smsc);
  435.     SAY(4, "ois_disconnect_all: ois_disconnect");
  436.     ois_disconnect(smsc); /* smsc->socket */
  437.     ois_swap_buffering(smsc);
  438.     SAY(4, "ois_disconnect_all: ois_disconnect");
  439.     ois_disconnect(smsc); /* smsc->socket */
  440.     if (smsc->ois_listening_socket != -1) {
  441. if (close(smsc->ois_listening_socket) == -1) {
  442.     warning(errno, "ois_disconnect_all: close failed...");
  443. }
  444. smsc->ois_listening_socket = -1;
  445.     }
  446.     return;
  447. }
  448. static void ois_disconnect(SMSCenter *smsc)
  449. {
  450.     SAY2(2, "ois_disconnect fd=%d", smsc->socket);
  451.     if (smsc->socket != -1) {
  452. if (close(smsc->socket) == -1) {
  453.     warning(errno, "ois_disconnect: close failed...");
  454. }
  455. smsc->socket = -1;
  456.     }
  457.     return;
  458. }
  459. static int ois_read_into_buffer(SMSCenter *smsc, long wait_usec)
  460. {
  461.     int ret;
  462.     SAY(8, "ois_read_into_buffer");
  463.     if (smsc->socket == -1) {
  464. if ((smsc->ois_flags & OIS_FLAG_CLOSED) == 0) {
  465.     debug("bb.sms.ois", 0, "attempting to read from a closed socket");
  466.     smsc->ois_flags |= OIS_FLAG_CLOSED;
  467. }
  468. return 0;
  469.     } else {
  470. smsc->ois_flags &= ~OIS_FLAG_CLOSED;
  471.     }
  472.     ret = read_available(smsc->socket, wait_usec);
  473.     if (ret > 0) {
  474. time(&smsc->ois_alive);
  475. ret = smscenter_read_into_buffer(smsc);
  476. if (ret > 0 || (ret == 0 && smsc->buflen > 0)) {
  477.     SAY(2, "ois_read_into_buffer got something");
  478. } else if (ret == 0) {
  479.     if (smsc->buflen > 0) {
  480. SAY(2, "ois_read_into_buffer has something");
  481. ret = 1;
  482.     }
  483.     SAY(4, "ois_read_into_buffer: ois_disconnect");
  484.     ois_disconnect(smsc);
  485. }
  486.     }
  487.     return ret;
  488. }
  489. static int ois_check_input(SMSCenter *smsc, long wait_usec)
  490. {
  491.     char buffer[BUFLEN+1];
  492.     time_t now;
  493.     int ret;
  494.     SAY(8, "ois_check_input");
  495.     ret = ois_read_into_buffer(smsc, wait_usec);
  496.     if (ret < 0) {
  497. goto error;
  498.     }
  499.     ret = ois_extract_msg_from_buffer(buffer, smsc);
  500.     if (ret > 0) {
  501. IOTRACE("received", buffer, ret);
  502. switch (buffer[0]) {
  503. case 's':
  504.     ret = ois_submit_sm_result(smsc, buffer);
  505.     if (ret > 0) {
  506. warning(0, "ois_check_input: submit sm result signals (%d)...", ret);
  507.     } else if (ret < 0) {
  508. error(0, "ois_check_input: invalid submit sm result");
  509. goto error;
  510.     }
  511.     --smsc->ois_ack_debt;
  512.     time(&smsc->ois_alive);
  513.     break;
  514. case 'M':
  515.     ret = ois_deliver_sm_invoke(smsc, buffer);
  516.     if (ret >= 0) {
  517. ret = ois_deliver_sm_result(smsc, ret, buffer);
  518. if (ret < 0) {
  519.     goto error;
  520. }
  521.     } else {
  522. error(0, "ois_check_input: invalid deliver sm invoke");
  523. goto error;
  524.     }
  525.     time(&smsc->ois_alive);
  526.     break;
  527. default:
  528.     warning(0, "ois_check_input: unexpected message [%s]...",
  529.     ois_debug_str(buffer, ret));
  530.     break;
  531. }
  532.     } else {
  533. if (smsc->socket != -1) {
  534.     time(&now);
  535.     if ((now - smsc->ois_alive) > OIS_MESSAGE_WAITTIME) {
  536. debug("bb.sms.ois", 0, "closing an idle connection");
  537. SAY(4, "ois_check_input: ois_disconnect");
  538. ois_disconnect(smsc);
  539.     }
  540. }
  541.     }
  542.     if (ret < 0) {
  543. error(0, "ois_check_input: malformatted message [%s]",
  544.       ois_debug_str(buffer, -ret));
  545. goto error;
  546.     }
  547.     if (smsc->ois_received_mo != NULL ||
  548. (smsc->ois_flags & OIS_FLAG_ERROR) != 0) {
  549. SAY(2, "ois_check_input has something");
  550. return 1; /* at least one message in the queue or an error pending */
  551.     } else {
  552. return 0; /* no messages this time */
  553.     }
  554.  error:
  555.     smsc->ois_flags |= OIS_FLAG_ERROR;
  556.     return 1;
  557. }
  558. static int ois_check_incoming(SMSCenter *smsc, long wait_usec)
  559. {
  560.     fd_set read_fd;
  561.     struct timeval tv;
  562.     int ret;
  563.     SAY(8, "ois_check_incoming");
  564.     tv.tv_sec = 0;
  565.     tv.tv_usec = wait_usec;
  566.     FD_ZERO(&read_fd);
  567.     FD_SET(smsc->ois_listening_socket, &read_fd);
  568.     ret = select(smsc->ois_listening_socket + 1, &read_fd, NULL, NULL, &tv);
  569.     if (ret == -1) {
  570. if (errno == EINTR || errno == EAGAIN) {
  571.     return 0;
  572. } else {
  573.     error(errno, "ois_check_incoming: select failed");
  574.     smsc->ois_flags |= OIS_FLAG_ERROR;
  575.     return -1;
  576. }
  577.     } else if (ret == 0) {
  578. return 0;
  579.     }
  580.     /* if we end up here, someone is trying to connect */
  581.     if (smsc->socket != -1) {
  582. if ((smsc->ois_flags & OIS_FLAG_MULTIPLE_CALL) == 0) {
  583.     /* if you see lots of these, maybe we should accept */
  584.     /* multiple incoming connections at a time... */
  585.     debug("bb.sms.ois", 0, "letting an incoming call to wait until the old one disconnects");
  586.     smsc->ois_flags |= OIS_FLAG_MULTIPLE_CALL;
  587. }
  588. return 0;
  589.     }
  590.     smsc->ois_flags &= ~OIS_FLAG_MULTIPLE_CALL;
  591.     return ois_open_receiver(smsc);
  592. }
  593. static void ois_append_to_list(ois_listentry **head, Msg *msg)
  594. {
  595.     ois_listentry *item;
  596.     ois_listentry *tail;
  597.     SAY(2, "ois_append_to_list");
  598.     item = gw_malloc(sizeof(ois_listentry));
  599.     item->next = NULL;
  600.     item->msg = msg;
  601.     if (*head == NULL) {
  602. *head = item;
  603.     } else { /* not so bright algorithm, but ok with relatively short lists */
  604. for (tail = *head; tail->next != NULL; tail = tail->next) ;
  605. tail->next = item;
  606.     }
  607.     return;
  608. }
  609. static int ois_int_to_i4(char *raw, int nbr)
  610. {
  611.     int pos;
  612.     SAY(3, "ois_int_to_i4");
  613.     for (pos = 0; pos < 4; ++pos) {
  614. raw[pos] = (char)(nbr % 0x100);
  615. nbr /= 0x100;
  616.     }
  617.     return 4;
  618. }
  619. static int ois_increment_counter(void)
  620. {
  621.     SAY(3, "ois_increment_counter");
  622.     ois_counter = (ois_counter+1) % MAXCOUNTER;
  623.     return ois_counter;
  624. }
  625. static int ois_submit_sm_invoke(SMSCenter *smsc, const Msg *msg)
  626. {
  627.     char body[BUFLEN+1];
  628.     char buffer[BUFLEN+1];
  629.     int len;
  630.     int count;
  631.     int i;
  632.     int ret;
  633.     SAY(2, "ois_submit_sm_invoke");
  634.     /* construct a message */
  635.     ois_increment_counter();                  /* once per invoke */
  636.     len = ois_encode_submit_sm_invoke(body, msg);
  637.     /* the x.25 gear should be capable to fragment large messages, but... */
  638.     /* let's just use an explicit 128 byte blocks */
  639.     count = (len-1) / 121;                    /* 121 = 128 - 6 - 1 */
  640.     /* first part */
  641.     sprintf(buffer, "%c%c%04d%.121s%c",
  642.     'S',                              /* submit sm invoke */
  643.     (char)(0x50|count),               /* ia5 encoding, first part */
  644.     ois_counter,
  645.     &body[0],
  646.     EOL);
  647.     IOTRACE("sending", buffer, strlen(buffer));
  648.     ret = write_to_socket(smsc->socket, buffer);
  649.     if (ret < 0) {
  650. goto error;
  651.     }
  652.     /* additional parts */
  653.     for (i = 1; i <= count; ++i) {
  654. sprintf(buffer, "%c%c%04d%.121s%c",
  655. 'S',                          /* submit sm invoke */
  656. (char)(0x60|(count-i)),       /* ia5, additional part */
  657. ois_counter,
  658. &body[i*121],
  659. EOL);
  660. IOTRACE("sending", buffer, strlen(buffer));
  661. ret = write_to_socket(smsc->socket, buffer);
  662. if (ret < 0) {
  663.     goto error;
  664. }
  665.     }
  666.     SAY(2, "ois_submit_sm_invoke ok");
  667.     return 0;
  668.  error:
  669.     SAY(2, "ois_submit_sm_invoke error");
  670.     return -1;
  671. }
  672. static int ois_encode_submit_sm_invoke(char *str, const Msg *msg)
  673. {
  674.     char raw[BUFLEN];
  675.     int pos;
  676.     int ret;
  677.     SAY(3, "ois_encode_submit_sm_invoke");
  678.     /* construct the submit sm invoke body content */
  679.     pos = 0;
  680.     pos += ois_append_msisdn(&raw[pos], msg);
  681.     pos += ois_append_sme_reference_number(&raw[pos]);
  682.     pos += ois_append_priority(&raw[pos]);
  683.     pos += ois_append_originating_address(&raw[pos]);
  684.     pos += ois_append_validity_period(&raw[pos]);
  685.     pos += ois_append_data_coding_scheme(&raw[pos], msg);
  686.     pos += ois_append_status_report_request(&raw[pos]);
  687.     pos += ois_append_protocol_id(&raw[pos]);
  688.     pos += ois_append_submission_options(&raw[pos], msg);
  689.     pos += ois_append_sm_text(&raw[pos], msg);
  690.     ret = ois_convert_to_ia5(str, raw, pos);
  691.     return ret;
  692. }
  693. static int ois_append_msisdn(char *raw, const Msg *msg)
  694. {
  695.     int len;
  696.     SAY(3, "ois_append_msisdn");
  697.     len = octstr_len(msg->sms.receiver);
  698.     raw[0] = (char) len;
  699.     memcpy(&raw[1], octstr_get_cstr(msg->sms.receiver), len);
  700.     return 1 + len;
  701. }
  702. static int ois_append_sme_reference_number(char *raw)
  703. {
  704.     SAY(3, "ois_append_sme_reference_number");
  705.     /* 1=key, 2=not key (OIS 4.5) */
  706.     /* or 1=reject duplicates, 2=allow duplicates (OIS 5.0) */
  707.     raw[0] = (char) 2;
  708.     return 1 + ois_int_to_i4(&raw[1], ois_counter);
  709. }
  710. static int ois_append_priority(char *raw)
  711. {
  712.     SAY(3, "ois_append_priority");
  713.     raw[0] = (char) 1; /* 0=high, 1=normal */
  714.     return 1;
  715. }
  716. static int ois_append_originating_address(char *raw)
  717. {
  718.     SAY(3, "ois_append_originating_address");
  719.     raw[0] = (char) 2; /* length */
  720.     raw[1] = 'A'; /* A3=address type, actual address is unnecessary */
  721.     raw[2] = '3';
  722.     return 3;
  723. }
  724. static int ois_append_validity_period(char *raw)
  725. {
  726.     SAY(3, "ois_append_validity_period");
  727.     raw[0] = (char) 2; /* 0=none, 1=absolute, 2=relative */
  728.     raw[1] = (char) 1; /* relative, (v+1)*5 minutes, v<144 */
  729.     return 2;
  730. }
  731. static int ois_append_data_coding_scheme(char *raw, const Msg *msg)
  732. {
  733.     SAY(3, "ois_append_data_coding_scheme");
  734.     /* 0x0f is a special code for ASCII text, the SMSC will convert
  735.      * this to GSM and set the DCS to 0.
  736.      * FIXME: Convert to GSM ourselves and use DCS_GSM_TEXT.
  737.      * FIXME: use fields_to_dcs and try to support DC_UCS2 too ;) */
  738.     raw[0] = (char) (msg->sms.coding == DC_8BIT ? DCS_OCTET_DATA : 0x0f);
  739.     return 1;
  740. }
  741. static int ois_append_status_report_request(char *raw)
  742. {
  743.     SAY(3, "ois_append_status_report_request");
  744.     raw[0] = (char) 0x00; /* bit field, bit 0=abandoned, bit 2=delivered */
  745.     return 1;
  746. }
  747. static int ois_append_protocol_id(char *raw)
  748. {
  749.     SAY(3, "ois_append_protocol_id");
  750.     raw[0] = (char) 0; /* 0=default */
  751.     return 1;
  752. }
  753. static int ois_append_submission_options(char *raw, const Msg *msg)
  754. {
  755.     SAY(3, "ois_append_submission_options");
  756.     /* bit field, bit 0=reply path, bit 1=udh, bits 3-4=dcs interpretation */
  757.     raw[0] = (char) 0x00;
  758.     if (octstr_len(msg->sms.udhdata)) {
  759. raw[0] |= (char) 0x02;
  760.     }
  761.     if (msg->sms.coding == DC_8BIT) { /* XXX UCS2? */
  762. raw[0] |= (char) 0x10;
  763.     }
  764.     return 1;
  765. }
  766. static int ois_append_sm_text(char *raw, const Msg *msg)
  767. {
  768.     int udhlen7, udhlen8;
  769.     int msglen7, msglen8;
  770.     int len;
  771.     SAY(3, "ois_append_sm_text");
  772.     if (msg->sms.coding == DC_7BIT) {
  773.         charset_latin1_to_gsm(msg->sms.udhdata);
  774.         charset_latin1_to_gsm(msg->sms.msgdata);
  775.     }
  776.     /* calculate lengths */
  777.     udhlen8 = octstr_len(msg->sms.udhdata);
  778.     msglen8 = octstr_len(msg->sms.msgdata);
  779.     udhlen7 = udhlen8;
  780.     msglen7 = msglen8;
  781.     len = udhlen8 + msglen8;
  782.     /* copy text */
  783.     raw[0] = (char) (len);
  784.     raw[1] = (char) (udhlen7 + msglen7);
  785.     memcpy(&raw[2], octstr_get_cstr(msg->sms.udhdata), udhlen8);
  786.     memcpy(&raw[2+udhlen8], octstr_get_cstr(msg->sms.msgdata), msglen8);
  787.     IOTRACE("encoding", &raw[2], len);
  788.     return 2 + len;
  789. }
  790. static int ois_submit_sm_result(SMSCenter *smsc, const char *buffer)
  791. {
  792.     int status;
  793.     int ret;
  794.     SAY(2, "ois_submit_sm_result");
  795.     ret = ois_decode_submit_sm_result(&status, buffer);
  796.     if (ret < 0) {
  797. goto error;
  798.     }
  799.     return status;
  800.  error:
  801.     return -1;
  802. }
  803. static int ois_decode_submit_sm_result(int *code, const char *str)
  804. {
  805.     int buflen;
  806.     char raw[BUFLEN];
  807.     int len;
  808.     SAY(3, "ois_decode_submit_sm_result");
  809.     buflen = strlen(str) - 1;
  810.     if (buflen < 7 || str[0] != 's' || str[1] != 0x50 || str[buflen] != EOL) {
  811. goto error;
  812.     }
  813.     len = ois_convert_from_ia5(raw, &str[6]);
  814.     if (len <= 0) {
  815. goto error;
  816.     }
  817.     *code = raw[0];
  818.     *code &= 0xff;
  819.     /* there is smsc reference number and accept time, but we ignore them */
  820.     return 0;
  821.  error:
  822.     return -1;
  823. }
  824. static int ois_deliver_sm_invoke(SMSCenter *smsc, const char *buffer)
  825. {
  826.     Msg *msg;
  827.     int ret;
  828.     SAY(2, "ois_deliver_sm_invoke");
  829.     msg = msg_create(sms);
  830.     ret = ois_decode_deliver_sm_invoke(msg, buffer);
  831.     if (ret < 0) {
  832. goto error;
  833.     }
  834.     ois_append_to_list((ois_listentry **) &smsc->ois_received_mo, msg);
  835.     return 0;
  836.     
  837.  error:
  838.     msg_destroy(msg);
  839.     return -1;
  840. }
  841. static int ois_decode_deliver_sm_invoke(Msg *msg, const char *str)
  842. {
  843.     char body[BUFLEN+1];
  844.     char raw[BUFLEN];
  845.     int len;
  846.     int i;
  847.     int pos;
  848.     int ret;
  849.     SAY(3, "ois_decode_deliver_sm_invoke");
  850.     ret = ois_check_deliver_sm_invoke(str);
  851.     if (ret < 0) {
  852. goto error;
  853.     }
  854.     /* extract body */
  855.     len = strlen(str);
  856.     for (pos = 0, i = 6; i < len; ++i) {
  857. if (str[i] != EOL) {
  858.     body[pos++] = str[i];
  859. } else {
  860.     i += 6;
  861. }
  862.     }
  863.     body[pos] = '';
  864.     memset(raw, '', sizeof(raw));
  865.     len = ois_convert_from_ia5(raw, body);
  866.     /* adjust msg values */
  867.     pos = 0;
  868.     pos += ois_adjust_destination_address(msg, &raw[pos]);
  869.     pos += ois_ignore_smsc_reference_number(&raw[pos]);
  870.     pos += ois_adjust_originating_address(msg, &raw[pos]);
  871.     pos += ois_adjust_data_coding_scheme(msg, &raw[pos]);
  872.     pos += ois_ignore_protocol_id(&raw[pos]);
  873.     pos += ois_adjust_additional_information(msg, &raw[pos]);
  874.     pos += ois_adjust_sm_text(msg, &raw[pos]);
  875.     pos += ois_ignore_time(&raw[pos]); /* accept time */
  876.     pos += ois_ignore_time(&raw[pos]); /* invoke time */
  877.     if (pos != len) {
  878. error(0, "ois_decode_deliver_sm_invoke: message parsing error (%d!=%d)",
  879.       pos, len);
  880. goto error;
  881.     }
  882.     return 0;
  883.  error:
  884.     return -1;
  885. }
  886. static int ois_check_deliver_sm_invoke(const char *str)
  887. {
  888.     int buflen;
  889.     char buffer[BUFLEN+1];
  890.     int count;
  891.     SAY(3, "ois_check_deliver_sm_invoke");
  892.     /* check the (initial) header and trailer */
  893.     buflen = strlen(str) - 1;
  894.     if (buflen < 7 || str[0] != 'M' || (str[1] & 0x50) != 0x50
  895. || str[buflen] != EOL) {
  896. goto error;
  897.     }
  898.     count = str[1] & 0x0f;
  899.     while (--count >= 0)
  900.     {
  901. /* check the additional header */
  902. sprintf(buffer, "%c%c%c%.4s",
  903. EOL,
  904. 'M',                      /* deliver sm invoke */
  905. (char)(0x60|count),       /* ia5 encoding, additional part */
  906. &str[2]);
  907. if (strstr(str, buffer) == NULL) {
  908.     goto error;
  909. }
  910.     }
  911.     return 0;
  912.     
  913.  error:
  914.     return -1;
  915. }
  916. static int ois_adjust_destination_address(Msg *msg, const char *raw)
  917. {
  918.     int len;
  919.     SAY(3, "ois_adjust_destination_address");
  920.     len = raw[0] & 0xff;
  921.     msg->sms.receiver = octstr_create_from_data(&raw[1+2], len-2);
  922.     return 1 + len;
  923. }
  924. static int ois_ignore_smsc_reference_number(const char *raw)
  925. {
  926.     int value;
  927.     SAY(3, "ois_ignore_smsc_reference_number");
  928.     value = raw[3] & 0xff;
  929.     value <<= 8;
  930.     value |= raw[2] & 0xff;
  931.     value <<= 8;
  932.     value |= raw[1] & 0xff;
  933.     value <<= 8;
  934.     value |= raw[0] & 0xff;
  935.     return 4;
  936. }
  937. static int ois_adjust_originating_address(Msg *msg, const char *raw)
  938. {
  939.     int len;
  940.     SAY(3, "ois_adjust_originating_address");
  941.     len = raw[0] & 0xff;
  942.     msg->sms.sender = octstr_create_from_data(&raw[1+2], len-2);
  943.     return 1 + len;
  944. }
  945. static int ois_adjust_data_coding_scheme(Msg *msg, const char *raw)
  946. {
  947.     SAY(3, "ois_adjust_data_coding_scheme");
  948.     /* we set the value only temporarily: */
  949.     /* ois_adjust_sm_text will set the correct value */
  950.     msg->sms.coding = (raw[0] & 0xff) + 1;
  951.     return 1;
  952. }
  953. static int ois_ignore_protocol_id(const char *raw)
  954. {
  955.     int value;
  956.     SAY(3, "ois_ignore_protocol_id");
  957.     value = raw[0] & 0xff;
  958.     return 1;
  959. }
  960. static int ois_adjust_additional_information(Msg *msg, const char *raw)
  961. {
  962.     SAY(3, "ois_adjust_additional_information");
  963.     /* we set the value only temporarily: */
  964.     /* ois_adjust_sm_text will set the correct value */
  965.     /* XXX I used mc temporarily. use fields_to_dcs! */
  966.     msg->sms.mclass = raw[0] & 0xff;
  967.     return 1;
  968. }
  969. static int ois_adjust_sm_text(Msg *msg, const char *raw)
  970. {
  971.     int msglen7, msglen8;
  972.     char buffer[BUFLEN+1];
  973.     SAY(3, "ois_adjust_sm_text");
  974.     /* calculate lengths */
  975.     msglen7 = raw[0] & 0xff;
  976.     msglen8 = raw[1] & 0xff;
  977.     /* copy text, note: flag contains temporarily the raw type description */
  978.     switch ((msg->sms.coding - 1) & 0xff) {
  979.     case 0x00: /* gsm7 */
  980. ois_expand_gsm7(buffer, &raw[2], msglen7);
  981. ois_convert_to_iso88591(buffer, msglen7);
  982. if (msg->sms.mclass & 0x02) { /* XXX mclass temporarily */
  983.     msg->sms.msgdata = octstr_create("");
  984.     msg->sms.udhdata = octstr_create_from_data(buffer, msglen7);
  985. } else {
  986.     msg->sms.msgdata = octstr_create_from_data(buffer, msglen7);
  987.     msg->sms.udhdata = octstr_create("");
  988. }
  989. msg->sms.coding = DC_7BIT;
  990. break;
  991.     case 0x0f: /* ia5 */
  992. memcpy(buffer, &raw[2], msglen8);
  993. ois_convert_to_iso88591(buffer, msglen8);
  994. if (msg->sms.mclass & 0x02) { /* XXX mclass temporarily */
  995.     msg->sms.msgdata = octstr_create("");
  996.     msg->sms.udhdata = octstr_create_from_data(buffer, msglen8);
  997. } else {
  998.     msg->sms.msgdata = octstr_create_from_data(buffer, msglen8);
  999.     msg->sms.udhdata = octstr_create("");
  1000. }
  1001. msg->sms.coding = DC_7BIT;
  1002. break;
  1003.     default: /* 0xf4, 0xf5, 0xf6, 0xf7; 8bit to disp, mem, sim or term */ 
  1004. if (msg->sms.mclass & 0x02) { /* XXX mclass temporarily */
  1005.     msg->sms.msgdata = octstr_create("");
  1006.     msg->sms.udhdata = octstr_create_from_data(&raw[2], msglen8);
  1007. } else {
  1008.     msg->sms.msgdata = octstr_create_from_data(&raw[2], msglen8);
  1009.     msg->sms.udhdata = octstr_create("");
  1010. }
  1011. msg->sms.coding = DC_8BIT;
  1012. break;
  1013.     }
  1014.     msg->sms.mclass = MC_UNDEF;
  1015.     if (octstr_len(msg->sms.udhdata)) {
  1016. IOTRACE("decoded udh", octstr_get_cstr(msg->sms.udhdata),
  1017. octstr_len(msg->sms.udhdata));
  1018.     } else {
  1019. IOTRACE("decoded", octstr_get_cstr(msg->sms.msgdata),
  1020. octstr_len(msg->sms.msgdata));
  1021.     }
  1022.     return 2 + msglen8;
  1023. }
  1024. static int ois_ignore_time(const char *raw)
  1025. {
  1026.     char str[15];
  1027.     SAY(3, "ois_ignore_time");
  1028.     strncpy(str, raw, 14); str[14] = '';
  1029.     return 14;
  1030. }
  1031. static int ois_deliver_sm_result(SMSCenter *smsc, int result, const char *str)
  1032. {
  1033.     char body[BUFLEN+1];
  1034.     char buffer[BUFLEN+1];
  1035.     int len;
  1036.     int ret;
  1037.     SAY(2, "ois_deliver_sm_result");
  1038.     /* construct a message */
  1039.     len = ois_encode_deliver_sm_result(body, result);
  1040.     /* first and only part */
  1041.     sprintf(buffer, "%c%c%.4s%.121s%c",
  1042.     'm',                              /* deliver sm result */
  1043.     (char)(0x50),                     /* ia5 encoding, the only part */
  1044.     &str[2],
  1045.     &body[0],
  1046.     EOL);
  1047.     IOTRACE("sending", buffer, strlen(buffer));
  1048.     ret = write_to_socket(smsc->socket, buffer);
  1049.     if (ret < 0) {
  1050. goto error;
  1051.     }
  1052.     return 0;
  1053.  error:
  1054.     return -1;
  1055. }
  1056. static int ois_encode_deliver_sm_result(char *str, int result)
  1057. {
  1058.     char raw[4];
  1059.     SAY(3, "ois_encode_deliver_sm_result");
  1060.     /* construct the deliver sm result body content */
  1061.     raw[0] = (char) result;
  1062.     return ois_convert_to_ia5(str, raw, 1);
  1063. }
  1064. static int ois_expand_gsm7(char *raw8, const char *raw7, int len)
  1065. {
  1066.     int i;
  1067.     char bits[8*(BUFLEN+1)];
  1068.     SAY2(3, "ois_expand_gsm7 len=%d", len);
  1069.     /* yeah, there are also better algorithms, but... */
  1070.     /* well, at least this is fairly portable and ok for small messages... */
  1071.     ois_expand_gsm7_to_bits(bits, raw7, len);
  1072.     for (i = 0; i < len; ++i) {
  1073. raw8[i] = ois_expand_gsm7_from_bits(bits, i);
  1074.     }
  1075.     SAY2(5, "ois_expand_gsm7 gave [%s]", ois_debug_str(raw8, i));
  1076.     return i;
  1077. }
  1078. static int ois_expand_gsm7_to_bits(char *bits, const char *raw7, int len)
  1079. {
  1080.     int i, j, k;
  1081.     char ch;
  1082.     SAY(3, "ois_expand_gsm7_to_bits");
  1083.     len *= 7; /* number of bits in the gms 7-bit msg */
  1084.     for (j = i = 0; j < len; ++i) {
  1085. ch = raw7[i];
  1086. for (k = 0; k < 8; ++k) {
  1087.     bits[j++] = (char) (ch & 0x01);
  1088.     ch >>= 1;
  1089. }
  1090.     }
  1091.     return j;
  1092. }
  1093. static char ois_expand_gsm7_from_bits(const char *bits, int pos)
  1094. {
  1095.     int i;
  1096.     char ch;
  1097.     SAY2(8, "ois_expand_gsm7_from_bits pos=%d", pos);
  1098.     pos *= 7; /* septet position in bits */
  1099.     ch = '';
  1100.     for (i = 6; i >= 0; --i) {
  1101. ch <<= 1;
  1102. ch |= bits[pos+i];
  1103.     }
  1104.     return ch;
  1105. }
  1106. static int ois_convert_to_ia5(char *str, const char *raw, int len)
  1107. {
  1108.     int j;
  1109.     int i;
  1110.     int ch;
  1111.     SAY2(3, "ois_convert_to_ia5 len=%d", len);
  1112.     for (j = i = 0; i < len; ++i) {
  1113. ch = raw[i] & 0xff;
  1114. if (ch == 0x5c || ch == 0x5e || ch == 0x60 || ch == 0x7e) {
  1115.        str[j++] = (char) 0x5c;
  1116.        str[j++] = (char) ch;
  1117. } else if (0x20 <= ch && ch < 0x7f) {
  1118.     str[j++] = (char) ch;
  1119. } else if (0x00 <= ch && ch < 0x20) {
  1120.     str[j++] = (char) 0x5e;
  1121.     str[j++] = (char) ch + 0x40;
  1122. } else if (0xa0 <= ch && ch < 0xff) {
  1123.     str[j++] = (char) 0x60;
  1124.     str[j++] = (char) ch - 0x80;
  1125. } else if (0x80 <= ch && ch < 0xa0) {
  1126.     str[j++] = (char) 0x7e;
  1127.     str[j++] = (char) ch - 0x40;
  1128. } else if (ch == 0x7f) {
  1129.     str[j++] = (char) 0x5e;
  1130.     str[j++] = (char) 0x7e;
  1131. } else { /* ch == 0xff */
  1132.     str[j++] = (char) 0x7e;
  1133.     str[j++] = (char) 0x7e;
  1134. }
  1135.     }
  1136.     str[j] = '';
  1137.     SAY2(5, "ois_convert_to_ia5 gave [%s]", ois_debug_str(str, j));
  1138.     return j;
  1139. }
  1140. static int ois_convert_from_ia5(char *raw, const char *str)
  1141. {
  1142.     int j;
  1143.     int i;
  1144.     int ch;
  1145.     SAY(3, "ois_convert_from_ia5");
  1146.     for (j = i = 0; ; ++i) {
  1147. ch = str[i] & 0xff;
  1148. if (ch < 0x20 || 0x7f <= ch) {
  1149.     break;
  1150. } else if (ch == 0x5c) {
  1151.     ch = str[++i] & 0xff;
  1152.     if (ch == 0x5c || ch == 0x5e || ch == 0x60 || ch == 0x7e) {
  1153. raw[j++] = (char) ch;
  1154.     } else {
  1155. break;
  1156.     }
  1157. } else if (ch == 0x5e) {
  1158.     ch = str[++i] & 0xff;
  1159.     if (0x40 <= ch && ch < 0x60) {
  1160. raw[j++] = (char) ch - 0x40;
  1161.     } else if (ch == 0x7e) {
  1162. raw[j++] = (char) 0x7f;
  1163.     } else {
  1164. break;
  1165.     }
  1166. } else if (ch == 0x60) {
  1167.     ch = str[++i] & 0xff;
  1168.     if (0x20 <= ch && ch < 0x7f) {
  1169. raw[j++] = (char) ch + 0x80;
  1170.     } else {
  1171. break;
  1172.     }
  1173. } else if (ch == 0x7e) {
  1174.     ch = str[++i] & 0xff;
  1175.     if (0x40 <= ch && ch < 0x60) {
  1176. raw[j++] = (char) ch + 0x40;
  1177.     } else if (ch == 0x7e) {
  1178. raw[j++] = (char) 0xff;
  1179.     } else {
  1180. break;
  1181.     }
  1182. } else { /* 0x20 <= ch && ch < 0x7f */
  1183.     raw[j++] = (char) ch;
  1184. }
  1185.     }
  1186.     SAY2(5, "ois_convert_from_ia5 gave [%s]", ois_debug_str(raw, j));
  1187.     return j;
  1188. }
  1189. static int ois_convert_to_iso88591(char *raw, int len)
  1190. {
  1191.     /* a best effort 1-to-1 conversion according to ois appendix a */
  1192.     static const char gsm_to_iso88591[] = {
  1193. '@', 0xa3,'$', 0xa5,0xe8,0xe9,0xf9,0xec, /* 0x00 - 0x07 */
  1194. 0xf2,0xc7,'n',0xd8,0xf8,'r',0xc5,0xe5, /* 0x08 - 0x0f */
  1195. 'D', ' ', 'F', 'G', 'L', 'W', 'P', 'Y',  /* 0x10 - 0x17, poor! */
  1196. 'Y', 'S', 'X', ' ', 0xc6,0xe6,'b', 0xc9, /* 0x18 - 0x1f, poor! */
  1197. ' ', '!', '"', '#', 0xa4, '%', '&', ''',/* 0x20 - 0x27 */
  1198. '(', ')', '*', '+', ',', '-', '.', '/',  /* 0x28 - 0x2f */
  1199. '0', '1', '2', '3', '4', '5', '6', '7',  /* 0x30 - 0x37 */
  1200. '8', '9', ':', ';', '<', '=', '>', '?',  /* 0x38 - 0x3f */
  1201. 0xa1,'A', 'B', 'C', 'D', 'E', 'F', 'G',  /* 0x40 - 0x47 */
  1202. 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',  /* 0x48 - 0x4f */
  1203. 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',  /* 0x50 - 0x57 */
  1204. 'X', 'Y', 'Z', 0xc4,0xd6,0xd1,0xdc,0xa7, /* 0x58 - 0x5f */
  1205. 0xbf,'a', 'b', 'c', 'd', 'e', 'f', 'g',  /* 0x60 - 0x67 */
  1206. 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',  /* 0x68 - 0x6f */
  1207. 'p', 'q', 'r', 's', 't', 'u', 'v', 'w',  /* 0x70 - 0x77 */
  1208. 'x', 'y', 'z', 0xe4,0xf6,0xf1,0xfc,0xe0  /* 0x78 - 0x7f */
  1209.     };
  1210.     int i;
  1211.     SAY2(3, "ois_convert_to_iso88591 len=%d", len);
  1212.     for (i = 0; i < len; ++i) {
  1213. raw[i] = gsm_to_iso88591[raw[i] & 0x7f];
  1214.     }
  1215.     SAY2(5, "ois_convert_to_iso88591 gave [%s]", ois_debug_str(raw, i));
  1216.     return i;
  1217. }
  1218. /*
  1219.  * Extract a message from the internal buffer.
  1220.  */
  1221. static int ois_extract_msg_from_buffer(char *str, SMSCenter *smsc)
  1222. {
  1223.     int len;
  1224.     int count;
  1225.     SAY2(8, "ois_extract_msg_from_buffer buflen=%d", smsc->buflen);
  1226.     str[0] = '';
  1227.     if (smsc->buflen < 7) {             /* 7 = 6 + 1 */
  1228. return 0;              /* we don't have a message yet */
  1229.     }
  1230.     if (strchr("SRDATECQLMPOVsrdatecqlmpov", smsc->buffer[0]) == NULL
  1231. || (smsc->buffer[1] & 0xf0) != 0x50) {
  1232. goto error;
  1233.     }
  1234.     /* a valid message type, find the end of the message */
  1235.     count = smsc->buffer[1] & 0x0f;
  1236.     for (len = 0; (size_t) len < smsc->buflen; ++len) {
  1237. if (smsc->buffer[len] == EOL) {
  1238.     if (--count < 0) {
  1239. ++len;
  1240. break;
  1241.     }
  1242. }
  1243.     }
  1244.     if (count >= 0) {          /* we don't have all the pieces */
  1245. if (len < BUFLEN) {
  1246.     return 0;          /* ...but maybe later */
  1247. }
  1248. goto error;
  1249.     }
  1250.     /* the buffer contains a promising message candidate */
  1251.     memcpy(str, smsc->buffer, len);
  1252.     str[len] = '';
  1253.     smscenter_remove_from_buffer(smsc, len); /* just the message */
  1254.     return len;
  1255.  error:
  1256.     for (len = 0; (size_t) len < smsc->buflen && smsc->buffer[len] != EOL; 
  1257.          ++len) ;
  1258.     if (len > BUFLEN) len = BUFLEN;
  1259.     memcpy(str, smsc->buffer, len);
  1260.     str[len] = '';
  1261.     smscenter_remove_from_buffer(smsc, smsc->buflen); /* everything */
  1262.     return -len;
  1263. }
  1264. /*
  1265.  * Extract a line from the internal buffer.
  1266.  */
  1267. static int ois_extract_line_from_buffer(char *str, SMSCenter *smsc)
  1268. {
  1269.     int len;
  1270.     SAY2(3, "ois_extract_line_from_buffer buflen=%d", smsc->buflen);
  1271.     str[0] = '';
  1272.     for (len = 0; (size_t) len < smsc->buflen && smsc->buffer[len] != 'n'; 
  1273.          ++len) ;
  1274.     if ((size_t) len >= smsc->buflen) {
  1275. return 0;
  1276.     } else {
  1277. ++len;
  1278.     }
  1279.     /* the buffer contains a line */
  1280.     memcpy(str, smsc->buffer, len);
  1281.     str[len] = '';
  1282.     smscenter_remove_from_buffer(smsc, len); /* just the line */
  1283.     return len;
  1284. }
  1285. static void ois_swap_buffering(SMSCenter *smsc)
  1286. {
  1287.     time_t alive;
  1288.     int socket;
  1289.     char *buffer;
  1290.     size_t bufsize;
  1291.     size_t buflen;
  1292.     SAY(8, "ois_swap_buffering");
  1293.     if (smsc->ois_bufsize == 0) {
  1294. smsc->ois_buflen = 0;
  1295. smsc->ois_bufsize = smsc->bufsize;
  1296. smsc->ois_buffer = gw_malloc(smsc->ois_bufsize);
  1297. memset(smsc->ois_buffer, 0, smsc->ois_bufsize);
  1298.     }
  1299.     alive = smsc->ois_alive;
  1300.     smsc->ois_alive = smsc->ois_alive2;
  1301.     smsc->ois_alive2 = alive;
  1302.     socket = smsc->socket;
  1303.     smsc->socket = smsc->ois_socket;
  1304.     smsc->ois_socket = socket;
  1305.     buffer = smsc->buffer;
  1306.     smsc->buffer = smsc->ois_buffer;
  1307.     smsc->ois_buffer = buffer;
  1308.     buflen = smsc->buflen;
  1309.     smsc->buflen = smsc->ois_buflen;
  1310.     smsc->ois_buflen = buflen;
  1311.     bufsize = smsc->bufsize;
  1312.     smsc->bufsize = smsc->ois_bufsize;
  1313.     smsc->ois_bufsize = bufsize;
  1314.     return;
  1315. }
  1316. static const char *ois_debug_str(const char *raw, int len)
  1317. {
  1318.     static const char hex[] = "0123456789abcdef";
  1319.     static char str[4*(BUFLEN+1)+1];
  1320.     int pos;
  1321.     int ch;
  1322.     int i;
  1323.     pos = 0;
  1324.     for (i = 0; i < len; ++i) {
  1325. ch = raw[i] & 0xff;
  1326. if (0x20 <= ch && ch < 0x7f && ch != 0x5c) {
  1327.     str[pos++] = (char) ch;
  1328. } else {
  1329.     str[pos++] = '\';
  1330.     str[pos++] = 'x';
  1331.     str[pos++] = hex[ch/16];
  1332.     str[pos++] = hex[ch%16];
  1333. }
  1334.     }
  1335.     str[pos] = '';
  1336.     return str;
  1337. }