128 #define RESPONSE_TIMEOUT (60 * 1000000)   264     for (i = 0; 
parameters[i].name != NULL; i++) {
   326     return isdigit(c) || c == 
'+' || c == 
'-';
   351     { 
"Login", 
LOGIN, 1, 0 },
   352     { 
"Logout", 
LOGOUT, 1, 0 },
   357     { 
"Set parameter", 
SET_REQ, 1, 0 },
   358     { 
"Get parameter", 
GET_REQ, 1, 0 },
   363     { 
"Alive", 
ALIVE, 1, 1 },
   365     { 
"NACK", 
NACK, 1, 1 },
   375     for (i = 0; 
operations[i].name != NULL; i++) {
   466 #define STX_str "\02"   467 #define ETX_str "\03"   468 #define TAB_str "\011"   471 #define BOGUS_SEQUENCE 0   557     if (stx >= 0 && stx < etx) {
   558         warning(0, 
"CIMD2[%s]: packet without end marker",
   720         warning(0, 
"CIMD2[%s]: packet header in wrong format",
   748         warning(0, 
"CIMD2[%s]: parameter at offset %ld in wrong format",
   761     dlen = len - (dpos - pos);
   769         warning(0, 
"CIMD2[%s]: packet contains unknown parameter %ld", 
   776         warning(0, 
"CIMD2[%s]: packet has '%s' parameter with length %ld, spec says max %d",
   788             warning(0, 
"CIMD2[%s]: packet has '%s' parameter with non-integer contents", 
   795             warning(0, 
"CIMD2[%s]: packet has '%s' parameter out of range (value %ld, min %d, max %d)",
   804             warning(0, 
"CIMD2[%s]: packet has '%s' parameter with non-digit contents", 
   812             warning(0, 
"CIMD2[%s]: packet has '%s' parameter with non phone number contents", 
   820             warning(0, 
"CIMD2[%s]: packet has '%s' parameter with non-hex contents", 
   826             warning(0, 
"CIMD2[%s]: packet has odd-length '%s' parameter", 
   857         warning(0, 
"CIMD2[%s]: packet contains NULs",
   874     for ( ; pos >= 0; pos = next) {
   888                 warning(0, 
"CIMD2[%s]: packet checksum in wrong format",
   910         warning(0, 
"CIMD2[%s]: SMSC sent us %s request",
   925     { 1, 
"Unexpected operation" },
   926     { 2, 
"Syntax error" },
   927     { 3, 
"Unsupported parameter error" },
   928     { 4, 
"Connection to message center lost" },
   929     { 5, 
"No response from message center" },
   930     { 6, 
"General system error" },
   931     { 7, 
"Cannot find information" },
   932     { 8, 
"Parameter formatting error" },
   933     { 9, 
"Requested operation failed" },
   935     { 100, 
"Invalid login" },
   936     { 101, 
"Incorrect access type" },
   937     { 102, 
"Too many users with this login id" },
   938     { 103, 
"Login refused by message center" },
   940     { 300, 
"Incorrect destination address" },
   941     { 301, 
"Incorrect number of destination addresses" },
   942     { 302, 
"Syntax error in user data parameter" },
   943     { 303, 
"Incorrect bin/head/normal user data parameter combination" },
   944     { 304, 
"Incorrect data coding scheme parameter usage" },
   945     { 305, 
"Incorrect validity period parameters usage" },
   946     { 306, 
"Incorrect originator address usage" },
   947     { 307, 
"Incorrect pid paramterer usage" },
   948     { 308, 
"Incorrect first delivery parameter usage" },
   949     { 309, 
"Incorrect reply path usage" },
   950     { 310, 
"Incorrect status report request parameter usage" },
   951     { 311, 
"Incorrect cancel enabled parameter usage" },
   952     { 312, 
"Incorrect priority parameter usage" },
   953     { 313, 
"Incorrect tariff class parameter usage" },
   954     { 314, 
"Incorrect service description parameter usage" },
   955     { 315, 
"Incorrect transport type parameter usage" },
   956     { 316, 
"Incorrect message type parameter usage" },
   957     { 318, 
"Incorrect mms parameter usage" },
   958     { 319, 
"Incorrect operation timer parameter usage" },
   960     { 400, 
"Incorrect address parameter usage" },
   961     { 401, 
"Incorrect scts parameter usage" },
   963     { 500, 
"Incorrect scts parameter usage" },
   964     { 501, 
"Incorrect mode parameter usage" },
   965     { 502, 
"Incorrect parameter combination" },
   967     { 600, 
"Incorrect scts parameter usage" },
   968     { 601, 
"Incorrect address parameter usage" },
   969     { 602, 
"Incorrect mode parameter usage" },
   970     { 603, 
"Incorrect parameter combination" },
   972     { 800, 
"Changing password failed" },
   973     { 801, 
"Changing password not allowed" },
   975     { 900, 
"Unsupported item requested" },
  1010     error(0, 
"CIMD2[%s]: %s contained error message:",
  1097     for (pos = 0; pos < len; pos++) {
  1107         else if (c == 
'_' && pos + 2 < len) {
  1116                 warning(0, 
"CIMD2[%s]: Encountered unknown "  1117                         "escape code _%c%c, ignoring.",
  1139     for (pos = 0; pos < len; pos++) {
  1160         } 
else if (c == 2) {
  1179     char minpacket[
sizeof(
"sOO:SSSte")];
  1194     char parmh[
sizeof(
"tPPP:")];
  1205         warning(0, 
"CIMD2[%s]: %s parameter too long, truncating from "  1206                 "%ld to %ld characters",
  1219     sprintf(parmh, 
TAB_str "%03d:", parmno);
  1268     sprintf(buf, 
"%ld", value);
  1298     sprintf(buf, 
"%02X", checksum);
  1310     sprintf(buf, 
"%03d", 
seq);
  1327     int setvalidity = 0;
  1335     if (
msg->sms.sender == NULL)
  1339         warning(0, 
"CIMD2[%s]: non-digits in destination phone number '%s', discarded",
  1371                 warning(0, 
"CIMD2[%s]: Sending message with originating address <%s>, "  1372                         "which does not start with the sender-prefix.",
  1396         long val = (
msg->sms.validity - time(NULL)) / 60;
  1399         if (val >= 50400 && val <= 635040)
  1400             setvalidity = (val - 1) / 7 / 24 / 60 + 192 + 1;
  1401         if (val > 43200 && val < 50400)
  1403         if (val >= 2880 && val <= 43200)
  1404             setvalidity = (val - 1) / 24 / 60 + 166 + 1;
  1405         if (val > 1440 && val < 2880)
  1407         if (val >= 750 && val <= 1440)
  1408             setvalidity = (val - 720 - 1) / 30 + 143 + 1;
  1409         if (val > 720 && val < 750)
  1411         if (val >= 5 && val <= 720)
  1412             setvalidity = (val - 1) / 5 - 1 + 1;
  1431         warning(0, 
"CIMD2[%s]: dlr request make no sense while no-dlr set to true",
  1437     if (
msg->sms.rpi > 0)
  1447     if (
msg->sms.pid > 0)
  1454     if (
msg->sms.msg_left > 0)
  1468         spaceleft = spaceleft * 8 / 7;
  1475         warning(0, 
"CIMD2[%s]: message filled up with UDH, no room for message text",
  1496     if (truncated > 0) {
  1497         warning(0, 
"CIMD2[%s]: truncating message text to fit in %d characters.", 
  1537             warning(0, 
"CIMD2[%s]: SMSC is not responding",
  1543             error(0, 
"CIMD2[%s]: cimd2_get_packet: read failed",
  1553     debug(
"bb.sms.cimd2", 0, 
"CIMD2[%s]: received: <%s>",
  1577     debug(
"bb.sms.cimd2", 0, 
"CIMD2[%s]: sending <%s>",
  1590     Msg *message = NULL;
  1591     Octstr *destination = NULL;
  1631     if (!destination || 
octstr_len(destination) == 0) {
  1632         info(0, 
"CIMD2[%s]: Got SMS without receiver, discarding.",
  1637         info(0, 
"CIMD2[%s]: Got SMS without sender, discarding.",
  1643         info(0, 
"CIMD2[%s]: Got empty SMS, ignoring.",
  1651         debug(
"bb.sms.cimd2", 0, 
"CIMD2[%s]: Invalid DCS",
  1655     time(&message->sms.time);
  1656     message->sms.sender = origin;
  1657     message->sms.receiver = destination;
  1659         message->sms.udhdata = UDH;
  1661     message->sms.msgdata = 
text;
  1677     Msg *message = NULL;
  1681         warning(0, 
"CIMD2[%s]: request had same sequence number as previous.",
  1731         warning(0, 
"CIMD2[%s]: cimd2_request: socket not open.",
  1740     debug(
"bb.sms.cimd2", 0, 
"CIMD2[%s]: sending <%s>",
  1757         warning(0, 
"CIMD2[%s]: received NACK",
  1763             warning(0, 
"CIMD2[%s]: correcting sequence number from %ld to %ld.",
  1773         error(0, 
"CIMD2[%s]: received general error response",
  1788         warning(0, 
"CIMD2[%s]: response had unexpected sequence number; ignoring.",
  1797         warning(0, 
"CIMD2[%s]: %s request got a %s",
  1826         warning(0, 
"CIMD2[%s]: Retransmitting (take %d)", 
  1831     warning(0, 
"CIMD2[%s]: Giving up.",
  1844     if (close(pdata->
socket) < 0)
  1845         warning(errno, 
"CIMD2[%s]: error closing socket",
  1862     if (pdata->
socket >= 0) {
  1863         warning(0, 
"CIMD2[%s]: login: socket was already open; closing",
  1873     if (pdata->
socket != -1) {
  1883             info(0, 
"CIMD2[%s] logged in.",
  1888     error(0, 
"CIMD2[%s] login failed.",
  1906         info(0, 
"CIMD2[%s] logged out.",
  1922         warning(0, 
"CIMD2[%s]: SMSC not alive.",
  1944         warning(0, 
"CIMD2[%s]: discarded %d received messages",
  1964     debug(
"bb.sms.cimd2", 0, 
"CIMD2[%s]: sending message",
  1988     else if (ret == -2) {
  2033         warning(errno, 
"CIMD2[%s]: cimd2_receive_msg: read_available failed",
  2042         warning(0, 
"CIMD2[%s]: cimd2_receive_msg: service center closed connection.",
  2047         warning(0, 
"CIMD2[%s]: cimd2_receive_msg: read failed",
  2060         debug(
"bb.sms.cimd2", 0, 
"CIMD2[%s]: received: <%s>",
  2067             error(0, 
"CIMD2[%s]: cimd2_receive_msg: unexpected response packet",
  2088     Octstr *destination = NULL;
  2089     Octstr *timestamp = NULL;
  2090     Octstr *statuscode = NULL;
  2126         if (!
msg->sms.msgdata) {
  2127             msg->sms.msgdata = statuscode;
  2151     else if (ret == 0) { 
  2169     double    sleep = 0.0001;
  2182                 error(0, 
"CIMD2[%s]: Couldn't connect to SMSC (retrying in %ld seconds).",
  2203                 debug(
"bb.sms.cimd2", 0, 
"CIMD2[%s]: new message received",
  2256     debug(
"bb.sms", 0, 
"Shutting down SMSCConn CIMD2 %s (%s)",
  2258           finish_sending ? 
"slow" : 
"instant");
  2266     if (finish_sending == 0) {
  2287     debug(
"bb.sms", 0, 
"SMSCConn CIMD2 %s shut down.",  
  2301     debug(
"bb.sms", 0, 
"SMSCConn CIMD2 %s, start called",
  2309     debug(
"bb.sms", 0, 
"SMSCConn CIMD2 %s, stop called",
  2327     pdata = gw_malloc(
sizeof(
PrivData));
  2360     if (pdata->
host == NULL) {
  2361         error(0,
"CIMD2[%s]: Configuration file doesn't specify host",
  2365     if (pdata->
port == 0) {
  2366         error(0,
"CIMD2[%s]: Configuration file doesn't specify port",
  2371         error(0, 
"CIMD2[%s]: Configuration file doesn't specify username.",
  2376         error(0, 
"CIMD2[%s]: Configuration file doesn't specify password.",
  2393       debug(
"bb.sms.cimd2", 0, 
"CIMD2[%s]: Keepalive set to %ld seconds", 
  2402         warning(0, 
"CIMD2[%s]: Truncating username to %d chars", 
  2410         warning(0, 
"CIMD2[%s]: Truncating password to %d chars", 
  2419         error(0,
"CIMD2[%s]: Couldn't start I/O thread.",
 
void error(int err, const char *fmt,...)
 
void info(int err, const char *fmt,...)
 
int octstr_write_to_socket(int socket, Octstr *ostr)
 
Msg * msg_duplicate(Msg *msg)
 
void bb_smscconn_connected(SMSCConn *conn)
 
static Octstr * packet_get_sms_parm(struct packet *packet, int parmno)
 
static int packet_check_parameter(struct packet *packet, long pos, long len, SMSCConn *conn)
 
static Octstr * packet_get_hex_parm(struct packet *packet, int parmno)
 
int smsc_cimd2_create(SMSCConn *conn, CfgGroup *grp)
 
gw_assert(wtls_machine->packet_to_send !=NULL)
 
void gwlist_append(List *list, void *item)
 
void bb_smscconn_killed(void)
 
static void cimd2_send_response(struct packet *request, PrivData *pdata)
 
int octstr_check_range(Octstr *ostr, long pos, long len, octstr_func_t filter)
 
static void packet_add_parm(struct packet *packet, int parmtype, int parmno, Octstr *value, SMSCConn *conn)
 
void gwlist_produce(List *list, void *item)
 
void gwthread_join(long thread)
 
long gwlist_len(List *list)
 
static Octstr * packet_get_parm(struct packet *packet, int parmno)
 
int octstr_append_from_socket(Octstr *ostr, int socket)
 
static int parm_valid_address(Octstr *value)
 
static void packet_parse_header(struct packet *packet)
 
void(* stop_conn)(SMSCConn *conn)
 
static void packet_check_can_receive(struct packet *packet, SMSCConn *conn)
 
static int parm_maxlen(int parmno)
 
void charset_utf8_to_gsm(Octstr *ostr)
 
static void cimd2_handle_request(struct packet *request, SMSCConn *conn)
 
#define cfg_get(grp, varname)
 
static struct packet * cimd2_get_packet(PrivData *pdata, Octstr **ts)
 
static Octstr * packet_get_address_parm(struct packet *packet, int parmno)
 
static void packet_set_checksum(struct packet *packet)
 
static void packet_add_sms_parm(struct packet *packet, int parmno, Octstr *value, SMSCConn *conn)
 
static int cimd2_shutdown_cb(SMSCConn *conn, int finish_sending)
 
void octstr_append_cstr(Octstr *ostr, const char *cstr)
 
void octstr_insert_data(Octstr *ostr, long pos, const char *data, long len)
 
Msg * dlr_find(const Octstr *smsc, const Octstr *ts, const Octstr *dst, int typ, int use_dst)
 
void dlr_add(const Octstr *smsc, const Octstr *ts, Msg *msg, int use_dst)
 
#define octstr_get_cstr(ostr)
 
#define octstr_copy(ostr, from, len)
 
void octstr_binary_to_hex(Octstr *ostr, int uppercase)
 
void(* start_conn)(SMSCConn *conn)
 
long octstr_search_char(const Octstr *ostr, int ch, long pos)
 
void log_thread_to(int idx)
 
static void cimd2_logout(SMSCConn *conn)
 
static int packet_display_error(struct packet *packet, SMSCConn *conn)
 
static void io_thread(void *arg)
 
static const char * parm_name(int parmno)
 
static int operation_can_send(int operation)
 
static void packet_set_send_sequence(struct packet *packet, PrivData *pdata)
 
static Msg * cimd2_accept_delivery_report_message(struct packet *request, SMSCConn *conn)
 
smscconn_killed_t why_killed
 
static void cimd2_close_socket(PrivData *pdata)
 
static int cimd2_request(struct packet *request, SMSCConn *conn, Octstr **ts)
 
static long packet_get_int_parm(struct packet *packet, int parmno)
 
void msg_destroy_item(void *msg)
 
Octstr * octstr_imm(const char *cstr)
 
static void packet_set_sequence(struct packet *packet, int seq)
 
void octstr_insert(Octstr *ostr1, const Octstr *ostr2, long pos)
 
static int parm_index(int parmno)
 
static void cimd2_start_cb(SMSCConn *conn)
 
static int cimd2_send_alive(SMSCConn *conn)
 
void * gwlist_extract_first(List *list)
 
void octstr_delete(Octstr *ostr1, long pos, long len)
 
void gwlist_remove_producer(List *list)
 
static int cimd2_receive_msg(SMSCConn *conn, Msg **msg)
 
long bb_smscconn_receive(SMSCConn *conn, Msg *sms)
 
static Octstr * operation_name(int operation)
 
static int isphonedigit(int c)
 
static void packet_add_string_parm(struct packet *packet, int parmno, Octstr *value, SMSCConn *conn)
 
int octstr_ncompare(const Octstr *ostr1, const Octstr *ostr2, long n)
 
static const struct @19 parameters[]
 
#define octstr_duplicate(ostr)
 
#define octstr_dump(ostr, level,...)
 
static void packet_add_hex_parm(struct packet *packet, int parmno, Octstr *value, SMSCConn *conn)
 
void msg_destroy(Msg *msg)
 
static Msg * sms_receive(SMSCConn *conn)
 
void warning(int err, const char *fmt,...)
 
int tcpip_connect_to_server_with_port(char *hostname, int port, int our_port, const char *source_addr)
 
Octstr * octstr_format(const char *fmt,...)
 
void octstr_destroy(Octstr *ostr)
 
#define gwthread_create(func, arg)
 
#define octstr_create(cstr)
 
static int parm_type(int parmno)
 
int fields_to_dcs(Msg *msg, int mode)
 
void gwthread_sleep(double seconds)
 
static Msg * cimd2_accept_message(struct packet *request, SMSCConn *conn)
 
volatile sig_atomic_t is_stopped
 
static int operation_can_receive(int operation)
 
static void packet_add_int_parm(struct packet *packet, int parmno, long value, SMSCConn *conn)
 
static void packet_destroy(struct packet *packet)
 
long octstr_len(const Octstr *ostr)
 
static void convert_gsm_to_cimd2(Octstr *text)
 
int cfg_get_bool(int *n, CfgGroup *grp, Octstr *varname)
 
void bb_smscconn_sent(SMSCConn *conn, Msg *sms, Octstr *reply)
 
static int packet_check(struct packet *packet, SMSCConn *conn)
 
void * gwlist_consume(List *list)
 
static int cimd2_add_msg_cb(SMSCConn *conn, Msg *sms)
 
int read_available(int fd, long wait_usec)
 
int(* shutdown)(SMSCConn *conn, int finish_sending)
 
static void packet_add_address_parm(struct packet *packet, int parmno, Octstr *value, SMSCConn *conn)
 
static int parm_in_range(int parmno, long value)
 
void debug(const char *place, int err, const char *fmt,...)
 
int cfg_get_integer(long *n, CfgGroup *grp, Octstr *varname)
 
static int cimd2_submit_msg(SMSCConn *conn, Msg *msg)
 
void gwthread_wakeup(long thread)
 
static long cimd2_queued_cb(SMSCConn *conn)
 
#define MSG_PARAM_UNDEFINED
 
static struct @21 cimd2_errors[]
 
int octstr_hex_to_binary(Octstr *ostr)
 
long octstr_parse_long(long *nump, Octstr *ostr, long pos, int base)
 
long(* queued)(SMSCConn *conn)
 
void octstr_truncate(Octstr *ostr, int new_len)
 
int(* send_msg)(SMSCConn *conn, Msg *msg)
 
void bb_smscconn_send_failed(SMSCConn *conn, Msg *sms, int reason, Octstr *reply)
 
int dcs_to_fields(Msg **msg, int dcs)
 
static const struct @22 cimd_combinations[]
 
static void convert_cimd2_to_gsm(Octstr *text, SMSCConn *conn)
 
static int cimd2_login(SMSCConn *conn)
 
static struct packet * packet_encode_message(Msg *msg, Octstr *sender_prefix, SMSCConn *conn)
 
static struct packet * packet_parse(Octstr *packet_data)
 
void gwlist_add_producer(List *list)
 
static int response(List *push_headers, Octstr **username, Octstr **password)
 
int octstr_get_char(const Octstr *ostr, long pos)
 
static struct packet * packet_extract(Octstr *in, SMSCConn *conn)
 
void octstr_set_char(Octstr *ostr, long pos, int ch)
 
static int packet_check_header(struct packet *packet, SMSCConn *conn)
 
static int operation_find(int operation)
 
#define DLR_IS_SUCCESS_OR_FAIL(dlr)
 
static XMLRPCDocument * msg
 
int charset_gsm_truncate(Octstr *gsm, long max)
 
static void cimd2_destroy(PrivData *pdata)
 
static void cimd2_stop_cb(SMSCConn *conn)
 
static Octstr * packet_get_string_parm(struct packet *packet, int parmno)
 
static void reply(HTTPClient *c, List *push_headers)
 
static const struct @20 operations[]
 
int octstr_compare(const Octstr *ostr1, const Octstr *ostr2)
 
void charset_gsm_to_utf8(Octstr *ostr)
 
static struct packet * packet_create(int operation, int seq)
 
void gwlist_destroy(List *list, gwlist_item_destructor_t *destructor)