Main Page | Alphabetical List | Data Structures | Directories | File List | Data Fields | Globals

smsc_cimd2.c File Reference

#include <ctype.h>
#include <time.h>
#include <errno.h>
#include <limits.h>
#include <string.h>
#include <unistd.h>
#include "gwlib/gwlib.h"
#include "smscconn.h"
#include "smscconn_p.h"
#include "bb_smscconn_cb.h"
#include "shared.h"
#include "sms.h"
#include "dlr.h"

Include dependency graph for smsc_cimd2.c:

Include dependency graph

Go to the source code of this file.

Data Structures

struct  privdata
struct  packet

Defines

#define RESPONSE_TIMEOUT   (60 * 1000000)
#define STX   2
#define ETX   3
#define TAB   9
#define STX_str   "\02"
#define ETX_str   "\03"
#define TAB_str   "\011"
#define BOGUS_SEQUENCE   0

Typedefs

typedef privdata PrivData

Enumerations

enum  {
  LOGIN = 1, LOGOUT = 2, SUBMIT_MESSAGE = 3, ENQUIRE_MESSAGE_STATUS = 4,
  DELIVERY_REQUEST = 5, CANCEL_MESSAGE = 6, SET_REQ = 8, GET_REQ = 9,
  DELIVER_MESSAGE = 20, DELIVER_STATUS_REPORT = 23, ALIVE = 40, RESPONSE = 50,
  GENERAL_ERROR_RESPONSE = 98, NACK = 99
}
enum  {
  P_USER_IDENTITY = 10, P_PASSWORD = 11, P_DESTINATION_ADDRESS = 21, P_ORIGINATING_ADDRESS = 23,
  P_ORIGINATING_IMSI = 26, P_ALPHANUMERIC_ORIGINATING_ADDRESS = 27, P_ORIGINATED_VISITED_MSC = 28, P_DATA_CODING_SCHEME = 30,
  P_USER_DATA_HEADER = 32, P_USER_DATA = 33, P_USER_DATA_BINARY = 34, P_MORE_MESSAGES_TO_SEND = 44,
  P_VALIDITY_PERIOD_RELATIVE = 50, P_VALIDITY_PERIOD_ABSOLUTE = 51, P_PROTOCOL_IDENTIFIER = 52, P_FIRST_DELIVERY_TIME_RELATIVE = 53,
  P_FIRST_DELIVERY_TIME_ABSOLUTE = 54, P_REPLY_PATH = 55, P_STATUS_REPORT_REQUEST = 56, P_CANCEL_ENABLED = 58,
  P_CANCEL_MODE = 59, P_MC_TIMESTAMP = 60, P_STATUS_CODE = 61, P_STATUS_ERROR_CODE = 62,
  P_DISCHARGE_TIME = 63, P_TARIFF_CLASS = 64, P_SERVICE_DESCRIPTION = 65, P_MESSAGE_COUNT = 66,
  P_PRIORITY = 67, P_DELIVERY_REQUEST_MODE = 68, P_SERVICE_CENTER_ADDRESS = 69, P_GET_PARAMETER = 500,
  P_MC_TIME = 501, P_ERROR_CODE = 900, P_ERROR_TEXT = 901
}
enum  {
  P_INT, P_STRING, P_ADDRESS, P_TIME,
  P_HEX, P_SMS
}

Functions

int parm_index (int parmno)
int parm_type (int parmno)
int parm_maxlen (int parmno)
const char * parm_name (int parmno)
int parm_in_range (int parmno, long value)
int isphonedigit (int c)
int parm_valid_address (Octstr *value)
int operation_find (int operation)
Octstroperation_name (int operation)
int operation_can_send (int operation)
int operation_can_receive (int operation)
Msgcimd2_accept_delivery_report_message (struct packet *request, SMSCConn *conn)
void packet_parse_header (struct packet *packet)
packetpacket_parse (Octstr *packet_data)
void packet_destroy (struct packet *packet)
packetpacket_extract (Octstr *in, SMSCConn *conn)
Octstrpacket_get_parm (struct packet *packet, int parmno)
long packet_get_int_parm (struct packet *packet, int parmno)
Octstrpacket_get_string_parm (struct packet *packet, int parmno)
Octstrpacket_get_address_parm (struct packet *packet, int parmno)
Octstrpacket_get_sms_parm (struct packet *packet, int parmno)
Octstrpacket_get_hex_parm (struct packet *packet, int parmno)
int packet_check_header (struct packet *packet, SMSCConn *conn)
int packet_check_parameter (struct packet *packet, long pos, long len, SMSCConn *conn)
int packet_check (struct packet *packet, SMSCConn *conn)
void packet_check_can_receive (struct packet *packet, SMSCConn *conn)
int packet_display_error (struct packet *packet, SMSCConn *conn)
void convert_cimd2_to_gsm (Octstr *text, SMSCConn *conn)
void convert_gsm_to_cimd2 (Octstr *text)
packetpacket_create (int operation, int seq)
void packet_add_parm (struct packet *packet, int parmtype, int parmno, Octstr *value, SMSCConn *conn)
void packet_add_string_parm (struct packet *packet, int parmno, Octstr *value, SMSCConn *conn)
void packet_add_address_parm (struct packet *packet, int parmno, Octstr *value, SMSCConn *conn)
void packet_add_sms_parm (struct packet *packet, int parmno, Octstr *value, SMSCConn *conn)
void packet_add_hex_parm (struct packet *packet, int parmno, Octstr *value, SMSCConn *conn)
void packet_add_int_parm (struct packet *packet, int parmno, long value, SMSCConn *conn)
void packet_set_checksum (struct packet *packet)
void packet_set_sequence (struct packet *packet, int seq)
packetpacket_encode_message (Msg *msg, Octstr *sender_prefix, SMSCConn *conn)
void packet_set_send_sequence (struct packet *packet, PrivData *pdata)
packetcimd2_get_packet (PrivData *pdata, Octstr **ts)
void cimd2_send_response (struct packet *request, PrivData *pdata)
Msgcimd2_accept_message (struct packet *request, SMSCConn *conn)
void cimd2_handle_request (struct packet *request, SMSCConn *conn)
int cimd2_request (struct packet *request, SMSCConn *conn, Octstr **ts)
void cimd2_close_socket (PrivData *pdata)
int cimd2_login (SMSCConn *conn)
void cimd2_logout (SMSCConn *conn)
int cimd2_send_alive (SMSCConn *conn)
void cimd2_destroy (PrivData *pdata)
int cimd2_submit_msg (SMSCConn *conn, Msg *msg)
int cimd2_receive_msg (SMSCConn *conn, Msg **msg)
Msgsms_receive (SMSCConn *conn)
void io_thread (void *arg)
int cimd2_add_msg_cb (SMSCConn *conn, Msg *sms)
int cimd2_shutdown_cb (SMSCConn *conn, int finish_sending)
void cimd2_start_cb (SMSCConn *conn)
void cimd2_stop_cb (SMSCConn *conn)
long cimd2_queued_cb (SMSCConn *conn)
int smsc_cimd2_create (SMSCConn *conn, CfgGroup *grp)

Variables

struct {
   char *   name
   int   number
   int   maxlen
   int   type
   int   minval
   int   maxval
parameters []
struct {
   char *   name
   int   code
   int   can_send
   int   can_receive
operations []
struct {
   int   code
   char *   text
cimd2_errors []
struct {
   unsigned char   cimd1
   unsigned char   cimd2
   unsigned char   gsm
cimd_combinations []


Define Documentation

#define BOGUS_SEQUENCE   0
 

Definition at line 471 of file smsc_cimd2.c.

Referenced by cimd2_login(), cimd2_logout(), cimd2_send_alive(), oisd_send_delivery_request(), and packet_encode_message().

#define ETX   3
 

Definition at line 462 of file smsc_cimd2.c.

Referenced by packet_extract(), parse_data(), pretty_print(), random_message(), and send_packet().

#define ETX_str   "\03"
 

Definition at line 467 of file smsc_cimd2.c.

Referenced by packet_create(), and packet_extract().

#define RESPONSE_TIMEOUT   (60 * 1000000)
 

Definition at line 128 of file smsc_cimd2.c.

Referenced by cimd2_get_packet(), and oisd_get_packet().

#define STX   2
 

Definition at line 461 of file smsc_cimd2.c.

Referenced by packet_extract(), parse_data(), pretty_print(), random_message(), and send_packet().

#define STX_str   "\02"
 

Definition at line 466 of file smsc_cimd2.c.

Referenced by packet_create().

#define TAB   9
 

Definition at line 463 of file smsc_cimd2.c.

Referenced by eat_string_parm(), packet_check(), packet_get_parm(), packet_set_checksum(), pretty_print(), and send_packet().

#define TAB_str   "\011"
 

Definition at line 468 of file smsc_cimd2.c.

Referenced by packet_add_parm(), and packet_create().


Typedef Documentation

typedef struct privdata PrivData
 


Enumeration Type Documentation

anonymous enum
 

Enumeration values:
LOGIN 
LOGOUT 
SUBMIT_MESSAGE 
ENQUIRE_MESSAGE_STATUS 
DELIVERY_REQUEST 
CANCEL_MESSAGE 
SET_REQ 
GET_REQ 
DELIVER_MESSAGE 
DELIVER_STATUS_REPORT 
ALIVE 
RESPONSE 
GENERAL_ERROR_RESPONSE 
NACK 

Definition at line 132 of file smsc_cimd2.c.

00132      {
00133     /* Requests from client */
00134     LOGIN = 1,
00135     LOGOUT = 2,
00136     SUBMIT_MESSAGE = 3,
00137     ENQUIRE_MESSAGE_STATUS = 4,
00138     DELIVERY_REQUEST = 5,
00139     CANCEL_MESSAGE = 6,
00140     SET_REQ = 8,
00141     GET_REQ = 9,
00142 
00143     /* Requests from server */
00144     DELIVER_MESSAGE = 20,
00145     DELIVER_STATUS_REPORT = 23,
00146 
00147     /* Requests from either */
00148     ALIVE = 40,
00149 
00150     /* Not a request; add to any request to make it a response */
00151     RESPONSE = 50,
00152 
00153     /* Responses not related to requests */
00154     GENERAL_ERROR_RESPONSE = 98,
00155     NACK = 99
00156 };

anonymous enum
 

Enumeration values:
P_USER_IDENTITY 
P_PASSWORD 
P_DESTINATION_ADDRESS 
P_ORIGINATING_ADDRESS 
P_ORIGINATING_IMSI 
P_ALPHANUMERIC_ORIGINATING_ADDRESS 
P_ORIGINATED_VISITED_MSC 
P_DATA_CODING_SCHEME 
P_USER_DATA_HEADER 
P_USER_DATA 
P_USER_DATA_BINARY 
P_MORE_MESSAGES_TO_SEND 
P_VALIDITY_PERIOD_RELATIVE 
P_VALIDITY_PERIOD_ABSOLUTE 
P_PROTOCOL_IDENTIFIER 
P_FIRST_DELIVERY_TIME_RELATIVE 
P_FIRST_DELIVERY_TIME_ABSOLUTE 
P_REPLY_PATH 
P_STATUS_REPORT_REQUEST 
P_CANCEL_ENABLED 
P_CANCEL_MODE 
P_MC_TIMESTAMP 
P_STATUS_CODE 
P_STATUS_ERROR_CODE 
P_DISCHARGE_TIME 
P_TARIFF_CLASS 
P_SERVICE_DESCRIPTION 
P_MESSAGE_COUNT 
P_PRIORITY 
P_DELIVERY_REQUEST_MODE 
P_SERVICE_CENTER_ADDRESS 
P_GET_PARAMETER 
P_MC_TIME 
P_ERROR_CODE 
P_ERROR_TEXT 

Definition at line 160 of file smsc_cimd2.c.

00160      {
00161     P_USER_IDENTITY = 10,
00162     P_PASSWORD = 11,
00163     P_DESTINATION_ADDRESS = 21,
00164     P_ORIGINATING_ADDRESS = 23,
00165     P_ORIGINATING_IMSI = 26,
00166     P_ALPHANUMERIC_ORIGINATING_ADDRESS = 27,
00167     P_ORIGINATED_VISITED_MSC = 28,
00168     P_DATA_CODING_SCHEME = 30,
00169     P_USER_DATA_HEADER = 32,
00170     P_USER_DATA = 33,
00171     P_USER_DATA_BINARY = 34,
00172     P_MORE_MESSAGES_TO_SEND = 44,
00173     P_VALIDITY_PERIOD_RELATIVE = 50,
00174     P_VALIDITY_PERIOD_ABSOLUTE = 51,
00175     P_PROTOCOL_IDENTIFIER = 52,
00176     P_FIRST_DELIVERY_TIME_RELATIVE = 53,
00177     P_FIRST_DELIVERY_TIME_ABSOLUTE = 54,
00178     P_REPLY_PATH = 55,
00179     P_STATUS_REPORT_REQUEST = 56,
00180     P_CANCEL_ENABLED = 58,
00181     P_CANCEL_MODE = 59,
00182     P_MC_TIMESTAMP = 60,
00183     P_STATUS_CODE = 61,
00184     P_STATUS_ERROR_CODE = 62,
00185     P_DISCHARGE_TIME = 63,
00186     P_TARIFF_CLASS = 64,
00187     P_SERVICE_DESCRIPTION = 65,
00188     P_MESSAGE_COUNT = 66,
00189     P_PRIORITY = 67,
00190     P_DELIVERY_REQUEST_MODE = 68,
00191     P_SERVICE_CENTER_ADDRESS = 69,
00192     P_GET_PARAMETER = 500,
00193     P_MC_TIME = 501,
00194     P_ERROR_CODE = 900,
00195     P_ERROR_TEXT = 901
00196 };

anonymous enum
 

Enumeration values:
P_INT 
P_STRING 
P_ADDRESS 
P_TIME 
P_HEX 
P_SMS 

Definition at line 205 of file smsc_cimd2.c.

00205 { P_INT, P_STRING, P_ADDRESS, P_TIME, P_HEX, P_SMS };


Function Documentation

Msg * cimd2_accept_delivery_report_message struct packet request,
SMSCConn conn
[static]
 

Definition at line 2084 of file smsc_cimd2.c.

References code, dlr_find(), smscconn::name, octstr_destroy(), octstr_get_cstr, P_DESTINATION_ADDRESS, P_MC_TIMESTAMP, P_STATUS_CODE, P_USER_DATA, packet_get_parm(), and SMSCConn.

Referenced by cimd2_handle_request().

02086 {
02087     Msg *msg = NULL;
02088     Octstr *destination = NULL;
02089     Octstr *timestamp = NULL;
02090     Octstr *statuscode = NULL;
02091     int st_code;
02092     int code;
02093 
02094     destination = packet_get_parm(request, P_DESTINATION_ADDRESS);
02095     timestamp = packet_get_parm(request, P_MC_TIMESTAMP);
02096     statuscode = packet_get_parm(request, P_STATUS_CODE);
02097 
02098     st_code = atoi(octstr_get_cstr(statuscode));
02099 
02100     switch(st_code)
02101     {
02102     case 2:  /* validity period expired */
02103     case 3:  /* delivery failed */
02104     case 6: /* last no response */
02105     case 7: /* message cancelled */
02106     case 8: /* message deleted */
02107     case 9: /* message deleted by cancel */
02108     code = DLR_FAIL;
02109         break;
02110     case 4: /* delivery successful */
02111         code = DLR_SUCCESS;
02112         break;
02113     default:
02114         code = 0;
02115     }
02116     if(code)
02117         msg = dlr_find(conn->name, timestamp, destination, code);
02118     else
02119         msg = NULL;
02120 
02121     /* recode the body into msgdata */
02122     if (msg) {
02123         msg->sms.msgdata = packet_get_parm(request, P_USER_DATA);
02124         if (!msg->sms.msgdata) {
02125             msg->sms.msgdata = statuscode;
02126             statuscode = NULL;
02127         }
02128     }
02129 
02130     octstr_destroy(statuscode);
02131     octstr_destroy(destination);
02132     octstr_destroy(timestamp);
02133 
02134     return msg;
02135  }

Here is the call graph for this function:

Msg* cimd2_accept_message struct packet request,
SMSCConn conn
[static]
 

Definition at line 1588 of file smsc_cimd2.c.

References charset_gsm_to_utf8(), convert_cimd2_to_gsm(), dcs_to_fields(), debug(), error(), smscconn::id, info(), message, msg_create, msg_destroy(), octstr_destroy(), octstr_get_cstr, octstr_len(), P_DATA_CODING_SCHEME, P_DESTINATION_ADDRESS, P_ORIGINATING_ADDRESS, P_USER_DATA, P_USER_DATA_BINARY, P_USER_DATA_HEADER, packet_get_address_parm(), packet_get_hex_parm(), packet_get_int_parm(), packet_get_sms_parm(), sms, SMSCConn, and text.

Referenced by cimd2_handle_request().

01589 {
01590     Msg *message = NULL;
01591     Octstr *destination = NULL;
01592     Octstr *origin = NULL;
01593     Octstr *UDH = NULL;
01594     Octstr *text = NULL;
01595     int DCS;
01596 
01597     /* See GSM 03.38.  The bit patterns we can handle are:
01598      *   000xyyxx  Uncompressed text, yy indicates alphabet.
01599      *                   yy = 00, default alphabet
01600      *                   yy = 01, 8-bit data
01601      *                   yy = 10, UCS-2
01602      *                   yy = 11, reserved
01603      *   1111xyxx  Data, y indicates alphabet.
01604      *                   y = 0, default alphabet
01605      *                   y = 1, 8-bit data
01606      */
01607     DCS = packet_get_int_parm(request, P_DATA_CODING_SCHEME);
01608 
01609     destination = packet_get_address_parm(request, P_DESTINATION_ADDRESS);
01610     origin = packet_get_address_parm(request, P_ORIGINATING_ADDRESS);
01611     UDH = packet_get_hex_parm(request, P_USER_DATA_HEADER);
01612     /* Text is either in User Data or User Data Binary field. */
01613     text = packet_get_sms_parm(request, P_USER_DATA);
01614     if (text != NULL) {
01615         convert_cimd2_to_gsm(text,conn);
01616         charset_gsm_to_utf8(text);
01617     } else {
01618         /*
01619          * FIXME: If DCS indicates GSM charset, and we get it in binary,
01620          * then it's probably bit-packed.  We'll have to undo it because
01621          * our "charset_gsm" means one gsm character per octet.  This is
01622          * not currently supported. -- RB
01623          */
01624         text = packet_get_hex_parm(request, P_USER_DATA_BINARY);
01625     }
01626 
01627     /* Code elsewhere in the gateway always expects the sender and
01628      * receiver fields to be filled, so we discard messages that
01629      * lack them.  If they should not be discarded, then the code
01630      * handling sms messages should be reviewed.  -- RB */
01631     if (!destination || octstr_len(destination) == 0) {
01632         info(0, "CIMD2[%s]: Got SMS without receiver, discarding.",
01633               octstr_get_cstr(conn->id));
01634         goto error;
01635     }
01636     if (!origin || octstr_len(origin) == 0) {
01637         info(0, "CIMD2[%s]: Got SMS without sender, discarding.",
01638               octstr_get_cstr(conn->id));
01639         goto error;
01640     }
01641 
01642     if (!text && (!UDH || octstr_len(UDH) == 0)) {
01643         info(0, "CIMD2[%s]: Got empty SMS, ignoring.",
01644               octstr_get_cstr(conn->id));
01645         goto error;
01646     }
01647     
01648     message = msg_create(sms);
01649     if (! dcs_to_fields(&message, DCS)) {
01650     /* XXX Should reject this message ? */
01651         debug("bb.sms.cimd2", 0, "CIMD2[%s]: Invalid DCS",
01652               octstr_get_cstr(conn->id));
01653     dcs_to_fields(&message, 0);
01654     }
01655     time(&message->sms.time);
01656     message->sms.sender = origin;
01657     message->sms.receiver = destination;
01658     if (UDH) {
01659         message->sms.udhdata = UDH;
01660     }
01661     message->sms.msgdata = text;
01662     return message;
01663 
01664 error:
01665     msg_destroy(message);
01666     octstr_destroy(destination);
01667     octstr_destroy(origin);
01668     octstr_destroy(UDH);
01669     octstr_destroy(text);
01670     return NULL;
01671 }

Here is the call graph for this function:

int cimd2_add_msg_cb SMSCConn conn,
Msg sms
[static]
 

Definition at line 2237 of file smsc_cimd2.c.

References smscconn::data, gwlist_produce(), gwthread_wakeup(), privdata::io_thread, msg_duplicate(), privdata::outgoing_queue, PrivData, sms, and SMSCConn.

02238 {
02239     PrivData *pdata = conn->data;
02240     Msg *copy;
02241 
02242     copy = msg_duplicate(sms);
02243     gwlist_produce(pdata->outgoing_queue, copy);
02244     gwthread_wakeup(pdata->io_thread);
02245 
02246     return 0;
02247 }

Here is the call graph for this function:

void cimd2_close_socket PrivData pdata  )  [static]
 

Definition at line 1837 of file smsc_cimd2.c.

References privdata::conn, gw_assert, smscconn::id, octstr_get_cstr, PrivData, privdata::socket, and warning().

Referenced by cimd2_login(), cimd2_shutdown_cb(), cimd2_submit_msg(), and sms_receive().

01838 {
01839     gw_assert(pdata != NULL);
01840 
01841     if (pdata->socket < 0)
01842         return;
01843 
01844     if (close(pdata->socket) < 0)
01845         warning(errno, "CIMD2[%s]: error closing socket",
01846                 octstr_get_cstr(pdata->conn->id));
01847     pdata->socket = -1;
01848 }

Here is the call graph for this function:

void cimd2_destroy PrivData pdata  )  [static]
 

Definition at line 1929 of file smsc_cimd2.c.

References privdata::conn, gwlist_destroy(), gwlist_len(), privdata::host, smscconn::id, privdata::inbuffer, msg_destroy_item(), privdata::my_number, octstr_destroy(), octstr_get_cstr, privdata::outgoing_queue, privdata::password, PrivData, privdata::received, privdata::stopped, privdata::username, and warning().

Referenced by cimd2_shutdown_cb(), and smsc_cimd2_create().

01930 {
01931     int discarded;
01932 
01933     if (pdata == NULL) 
01934         return;
01935         
01936     octstr_destroy(pdata->host);
01937     octstr_destroy(pdata->username);
01938     octstr_destroy(pdata->password);
01939     octstr_destroy(pdata->inbuffer);
01940     octstr_destroy(pdata->my_number);
01941 
01942     discarded = gwlist_len(pdata->received);
01943     if (discarded > 0)
01944         warning(0, "CIMD2[%s]: discarded %d received messages",
01945                 octstr_get_cstr(pdata->conn->id), 
01946                 discarded);
01947 
01948     gwlist_destroy(pdata->received, msg_destroy_item);
01949     gwlist_destroy(pdata->outgoing_queue, NULL);
01950     gwlist_destroy(pdata->stopped, NULL);
01951 
01952     gw_free(pdata);
01953 }

Here is the call graph for this function:

struct packet* cimd2_get_packet PrivData pdata,
Octstr **  ts
[static]
 

Definition at line 1526 of file smsc_cimd2.c.

References privdata::conn, packet::data, debug(), error(), gw_assert, smscconn::id, privdata::inbuffer, privdata::keepalive, privdata::next_ping, octstr_append_from_socket(), octstr_get_cstr, P_MC_TIMESTAMP, packet_check(), packet_check_can_receive(), packet_extract(), packet_get_parm(), PrivData, read_available(), RESPONSE_TIMEOUT, privdata::socket, and warning().

Referenced by cimd2_request().

01527 {
01528     struct packet *packet = NULL;
01529 
01530     gw_assert(pdata != NULL);
01531 
01532     /* If packet is already available, don't try to read anything */
01533     packet = packet_extract(pdata->inbuffer, pdata->conn);
01534 
01535     while (packet == NULL) {
01536         if (read_available(pdata->socket, RESPONSE_TIMEOUT) != 1) {
01537             warning(0, "CIMD2[%s]: SMSC is not responding",
01538                     octstr_get_cstr(pdata->conn->id));
01539             return NULL;
01540         }
01541 
01542         if (octstr_append_from_socket(pdata->inbuffer, pdata->socket) <= 0) {
01543             error(0, "CIMD2[%s]: cimd2_get_packet: read failed",
01544                   octstr_get_cstr(pdata->conn->id));
01545             return NULL;
01546         }
01547 
01548         packet = packet_extract(pdata->inbuffer, pdata->conn);
01549     }
01550 
01551     packet_check(packet,pdata->conn);
01552     packet_check_can_receive(packet,pdata->conn);
01553     debug("bb.sms.cimd2", 0, "CIMD2[%s]: received: <%s>",
01554           octstr_get_cstr(pdata->conn->id), 
01555           octstr_get_cstr(packet->data));
01556     if (ts)
01557         *ts = packet_get_parm(packet,P_MC_TIMESTAMP);
01558 
01559     if (pdata->keepalive > 0)
01560         pdata->next_ping = time(NULL) + pdata->keepalive;
01561 
01562     return packet;
01563 }

Here is the call graph for this function:

void cimd2_handle_request struct packet request,
SMSCConn conn
[static]
 

Definition at line 1674 of file smsc_cimd2.c.

References cimd2_accept_delivery_report_message(), cimd2_accept_message(), cimd2_send_response(), smscconn::data, gwlist_append(), smscconn::id, message, octstr_get_cstr, packet::operation, PrivData, privdata::receive_seq, privdata::received, packet::seq, SMSCConn, and warning().

Referenced by cimd2_receive_msg(), and cimd2_request().

01675 {
01676     PrivData *pdata = conn->data;
01677     Msg *message = NULL;
01678 
01679     if ((request->seq == 254 && pdata->receive_seq == 0) ||
01680             request->seq == pdata->receive_seq - 2) {
01681         warning(0, "CIMD2[%s]: request had same sequence number as previous.",
01682                 octstr_get_cstr(conn->id));
01683     }
01684     else {
01685         pdata->receive_seq = request->seq + 2;
01686         if (pdata->receive_seq > 254)
01687             pdata->receive_seq = 0;
01688 
01689         if (request->operation == DELIVER_STATUS_REPORT) {
01690             message = cimd2_accept_delivery_report_message(request, conn);
01691             if (message)
01692                 gwlist_append(pdata->received, message);
01693         }
01694         else if (request->operation == DELIVER_MESSAGE) {
01695             message = cimd2_accept_message(request,conn);
01696             if (message)
01697                 gwlist_append(pdata->received, message);
01698         }
01699     }
01700 
01701     cimd2_send_response(request, pdata);
01702 }

Here is the call graph for this function:

int cimd2_login SMSCConn conn  )  [static]
 

Definition at line 1854 of file smsc_cimd2.c.

References BOGUS_SEQUENCE, cimd2_close_socket(), cimd2_request(), smscconn::data, error(), gw_assert, privdata::host, smscconn::id, info(), LOGIN, octstr_get_cstr, smscconn::our_host, privdata::our_port, P_PASSWORD, P_USER_IDENTITY, packet_add_string_parm(), packet_create(), packet_destroy(), privdata::password, privdata::port, PrivData, SMSCConn, privdata::socket, tcpip_connect_to_server_with_port(), privdata::username, and warning().

Referenced by io_thread().

01855 {
01856     PrivData *pdata = conn->data;
01857     int ret;
01858     struct packet *packet = NULL;
01859 
01860     gw_assert(pdata != NULL);
01861 
01862     if (pdata->socket >= 0) {
01863         warning(0, "CIMD2[%s]: login: socket was already open; closing",
01864                 octstr_get_cstr(conn->id));
01865         cimd2_close_socket(pdata);
01866     }
01867     
01868     pdata->socket = tcpip_connect_to_server_with_port(
01869                                             octstr_get_cstr(pdata->host),
01870                                             pdata->port,
01871                                             pdata->our_port,
01872                                             (conn->our_host ? octstr_get_cstr(conn->our_host) : NULL)); 
01873     if (pdata->socket != -1) {
01874     
01875         packet = packet_create(LOGIN, BOGUS_SEQUENCE);
01876         packet_add_string_parm(packet, P_USER_IDENTITY, pdata->username, conn);
01877         packet_add_string_parm(packet, P_PASSWORD, pdata->password, conn);
01878         
01879         ret = cimd2_request(packet, conn, NULL);
01880         
01881         if (ret >= 0) {
01882             packet_destroy(packet);
01883             info(0, "CIMD2[%s] logged in.",
01884                  octstr_get_cstr(conn->id));
01885             return 0;
01886         }
01887     }
01888     error(0, "CIMD2[%s] login failed.",
01889           octstr_get_cstr(conn->id));
01890     cimd2_close_socket(pdata);
01891     packet_destroy(packet);
01892     return -1;
01893 }

Here is the call graph for this function:

void cimd2_logout SMSCConn conn  )  [static]
 

Definition at line 1895 of file smsc_cimd2.c.

References BOGUS_SEQUENCE, cimd2_request(), smscconn::id, info(), LOGOUT, octstr_get_cstr, packet_create(), packet_destroy(), and SMSCConn.

Referenced by cimd2_shutdown_cb().

01896 {
01897     struct packet *packet = NULL;
01898     int ret;
01899 
01900     packet = packet_create(LOGOUT, BOGUS_SEQUENCE);
01901 
01902     /* TODO: Don't wait very long for a response in this case. */
01903     ret = cimd2_request(packet, conn, NULL);
01904 
01905     if (ret == 0) {
01906         info(0, "CIMD2[%s] logged out.",
01907              octstr_get_cstr(conn->id));
01908     }
01909     packet_destroy(packet);
01910 }

Here is the call graph for this function:

long cimd2_queued_cb SMSCConn conn  )  [static]
 

Definition at line 2311 of file smsc_cimd2.c.

References smscconn::data, gwlist_len(), smscconn::load, privdata::outgoing_queue, PrivData, SMSCConn, SMSCCONN_DEAD, and smscconn::status.

02312 {
02313     PrivData *pdata = conn->data;
02314     conn->load = (pdata ? (conn->status != SMSCCONN_DEAD ? 
02315                   gwlist_len(pdata->outgoing_queue) : 0) : 0);
02316     return conn->load; 
02317 }

Here is the call graph for this function:

int cimd2_receive_msg SMSCConn conn,
Msg **  msg
[static]
 

Definition at line 2002 of file smsc_cimd2.c.

References cimd2_handle_request(), cimd2_send_alive(), privdata::conn, packet::data, smscconn::data, debug(), error(), gw_assert, gwlist_consume(), gwlist_len(), smscconn::id, privdata::inbuffer, privdata::keepalive, privdata::next_ping, octstr_append_from_socket(), octstr_dump, octstr_get_cstr, packet::operation, packet_check(), packet_check_can_receive(), packet_destroy(), packet_extract(), PrivData, read_available(), privdata::received, SMSCConn, privdata::socket, and warning().

Referenced by sms_receive().

02003 {
02004     PrivData *pdata = conn->data;
02005     long ret;
02006     struct packet *packet;
02007 
02008     gw_assert(pdata != NULL);
02009 
02010     if (gwlist_len(pdata->received) > 0) {
02011         *msg = gwlist_consume(pdata->received);
02012         return 1;
02013     }
02014 
02015     if (pdata->socket < 0) {
02016         /* XXX We have to assume that smsc_send_message is
02017          * currently trying to reopen, so we have to make
02018          * this thread wait.  It should be done in a nicer
02019          * way. */
02020         return 0;
02021     }
02022     
02023     ret = read_available(pdata->socket, 0);
02024     if (ret == 0) {
02025         if (pdata->keepalive > 0 && pdata->next_ping < time(NULL)) {
02026             if (cimd2_send_alive(conn) < 0)
02027         return -1;
02028         }
02029         return 0;
02030     }
02031 
02032     if (ret < 0) {
02033         warning(errno, "CIMD2[%s]: cimd2_receive_msg: read_available failed",
02034                 octstr_get_cstr(conn->id));
02035         return -1;
02036     }
02037 
02038     /* We have some data waiting... see if it is an sms delivery. */
02039     ret = octstr_append_from_socket(pdata->inbuffer, pdata->socket);
02040 
02041     if (ret == 0) {
02042         warning(0, "CIMD2[%s]: cimd2_receive_msg: service center closed connection.",
02043                 octstr_get_cstr(conn->id));
02044         return -1;
02045     }
02046     if (ret < 0) {
02047         warning(0, "CIMD2[%s]: cimd2_receive_msg: read failed",
02048                 octstr_get_cstr(conn->id));
02049         return -1;
02050     }
02051 
02052 
02053     for (;;) {
02054         packet = packet_extract(pdata->inbuffer,conn);
02055         if (!packet)
02056             break;
02057 
02058         packet_check(packet,conn);
02059         packet_check_can_receive(packet,conn);
02060         debug("bb.sms.cimd2", 0, "CIMD2[%s]: received: <%s>",
02061               octstr_get_cstr(pdata->conn->id), 
02062               octstr_get_cstr(packet->data));
02063 
02064         if (packet->operation < RESPONSE)
02065             cimd2_handle_request(packet, conn);
02066         else {
02067             error(0, "CIMD2[%s]: cimd2_receive_msg: unexpected response packet",
02068                 octstr_get_cstr(conn->id));
02069             octstr_dump(packet->data, 0);
02070         }
02071 
02072         packet_destroy(packet);
02073     }
02074 
02075     if (gwlist_len(pdata->received) > 0) {
02076     *msg = gwlist_consume(pdata->received);
02077         return 1;
02078     }
02079     return 0;
02080 }

Here is the call graph for this function:

int cimd2_request struct packet request,
SMSCConn conn,
Octstr **  ts
[static]
 

Definition at line 1718 of file smsc_cimd2.c.

References cimd2_get_packet(), cimd2_handle_request(), packet::data, smscconn::data, debug(), error(), gw_assert, smscconn::id, octstr_destroy(), octstr_dump, octstr_get_cstr, octstr_write_to_socket(), packet::operation, operation_can_send(), operation_name(), packet_destroy(), packet_display_error(), packet_set_checksum(), packet_set_send_sequence(), PrivData, privdata::send_seq, packet::seq, SMSCConn, privdata::socket, and warning().

Referenced by cimd2_login(), cimd2_logout(), cimd2_send_alive(), and cimd2_submit_msg().

01719 {
01720     PrivData *pdata = conn->data;
01721     int ret;
01722     struct packet *reply = NULL;
01723     int errorcode;
01724     int tries = 0;
01725 
01726     gw_assert(pdata != NULL);
01727     gw_assert(request != NULL);
01728     gw_assert(operation_can_send(request->operation));
01729 
01730     if (pdata->socket < 0) {
01731         warning(0, "CIMD2[%s]: cimd2_request: socket not open.",
01732                 octstr_get_cstr(conn->id));
01733         return -2;        
01734     }
01735     
01736 retransmit:
01737     packet_set_send_sequence(request, pdata);
01738     packet_set_checksum(request);
01739 
01740     debug("bb.sms.cimd2", 0, "CIMD2[%s]: sending <%s>",
01741           octstr_get_cstr(conn->id),
01742           octstr_get_cstr(request->data));
01743 
01744     ret = octstr_write_to_socket(pdata->socket, request->data);
01745     if (ret < 0)
01746         goto io_error;
01747 
01748 next_reply:
01749     packet_destroy(reply);  /* destroy old, if any */
01750     reply = cimd2_get_packet(pdata, ts);
01751     if (!reply)
01752         goto io_error;
01753 
01754     errorcode = packet_display_error(reply,conn);
01755 
01756     if (reply->operation == NACK) {
01757         warning(0, "CIMD2[%s]: received NACK",
01758                 octstr_get_cstr(conn->id));
01759         octstr_dump(reply->data, 0);
01760         /* Correct sequence number if server says it was wrong,
01761          * but only if server's number is sane. */
01762         if (reply->seq != request->seq && (reply->seq % 2) == 1) {
01763             warning(0, "CIMD2[%s]: correcting sequence number from %ld to %ld.",
01764                     octstr_get_cstr(conn->id),
01765                     (long) pdata->send_seq, 
01766                     (long) reply->seq);
01767             pdata->send_seq = reply->seq;
01768         }
01769         goto retry;
01770     }
01771 
01772     if (reply->operation == GENERAL_ERROR_RESPONSE) {
01773         error(0, "CIMD2[%s]: received general error response",
01774               octstr_get_cstr(conn->id));
01775         goto io_error;
01776     }
01777 
01778     /* The server sent us a request.  Handle it, then wait for
01779      * a new reply. */
01780     if (reply->operation < RESPONSE) {
01781         cimd2_handle_request(reply, conn);
01782         goto next_reply;
01783     }
01784 
01785     if (reply->seq != request->seq) {
01786         /* We got a response to a different request number than
01787          * what we send.  Strange. */
01788         warning(0, "CIMD2[%s]: response had unexpected sequence number; ignoring.",
01789                 octstr_get_cstr(conn->id));
01790         goto next_reply;
01791     }
01792 
01793     if (reply->operation != request->operation + RESPONSE) {
01794         /* We got a response that didn't match our request */
01795         Octstr *request_name = operation_name(request->operation);
01796         Octstr *reply_name = operation_name(reply->operation);
01797         warning(0, "CIMD2[%s]: %s request got a %s",
01798                 octstr_get_cstr(conn->id),
01799                 octstr_get_cstr(request_name),
01800                 octstr_get_cstr(reply_name));
01801 
01802         octstr_destroy(request_name);
01803         octstr_destroy(reply_name);
01804         octstr_dump(reply->data, 0);
01805         goto retry;
01806     }
01807 
01808     if (errorcode > 0)
01809         goto error;
01810 
01811     /* The reply passed all the checks... looks like the SMSC accepted
01812      * our request! */
01813     packet_destroy(reply);
01814     return 0;
01815 
01816 io_error:
01817     packet_destroy(reply);
01818     return -2;
01819 
01820 error:
01821     packet_destroy(reply);
01822     return -1;
01823 
01824 retry:
01825     if (++tries < 3) {
01826         warning(0, "CIMD2[%s]: Retransmitting (take %d)", 
01827                 octstr_get_cstr(conn->id),
01828                 tries);
01829         goto retransmit;
01830     }
01831     warning(0, "CIMD2[%s]: Giving up.",
01832             octstr_get_cstr(conn->id));
01833     goto io_error;
01834 }

Here is the call graph for this function:

int cimd2_send_alive SMSCConn conn  )  [static]
 

Definition at line 1912 of file smsc_cimd2.c.

References ALIVE, BOGUS_SEQUENCE, cimd2_request(), smscconn::id, octstr_get_cstr, packet_create(), packet_destroy(), SMSCConn, and warning().

Referenced by cimd2_receive_msg().

01913 {
01914     struct packet *packet = NULL;
01915     int ret;
01916 
01917     packet = packet_create(ALIVE, BOGUS_SEQUENCE);
01918     ret = cimd2_request(packet, conn, NULL);
01919     packet_destroy(packet);
01920 
01921     if (ret < 0)
01922         warning(0, "CIMD2[%s]: SMSC not alive.",
01923                 octstr_get_cstr(conn->id));
01924 
01925     return ret;
01926 }

Here is the call graph for this function:

void cimd2_send_response struct packet request,
PrivData pdata
[static]
 

Definition at line 1567 of file smsc_cimd2.c.

References privdata::conn, packet::data, debug(), gw_assert, smscconn::id, octstr_get_cstr, octstr_write_to_socket(), packet::operation, packet_create(), packet_destroy(), packet_set_checksum(), PrivData, response, RESPONSE, packet::seq, and privdata::socket.

Referenced by cimd2_handle_request().

01568 {
01569     struct packet *response;
01570 
01571     gw_assert(request != NULL);
01572     gw_assert(request->operation < RESPONSE);
01573 
01574     response = packet_create(request->operation + RESPONSE, request->seq);
01575     packet_set_checksum(response);
01576 
01577     debug("bb.sms.cimd2", 0, "CIMD2[%s]: sending <%s>",
01578           octstr_get_cstr(pdata->conn->id),
01579           octstr_get_cstr(response->data));
01580 
01581     /* Don't check errors here because if there is something
01582      * wrong with the socket, the main loop will detect it. */
01583     octstr_write_to_socket(pdata->socket, response->data);
01584 
01585     packet_destroy(response);
01586 }

Here is the call graph for this function:

int cimd2_shutdown_cb SMSCConn conn,
int  finish_sending
[static]
 

Definition at line 2250 of file smsc_cimd2.c.

References bb_smscconn_killed(), bb_smscconn_send_failed(), cimd2_close_socket(), cimd2_destroy(), cimd2_logout(), smscconn::data, debug(), gwlist_extract_first(), gwlist_remove_producer(), gwthread_join(), gwthread_wakeup(), smscconn::id, privdata::io_thread, smscconn::is_stopped, octstr_get_cstr, privdata::outgoing_queue, PrivData, privdata::quitting, SMSCConn, SMSCCONN_FAILED_SHUTDOWN, smscconn::status, privdata::stopped, and smscconn::why_killed.

02251 {
02252     PrivData *pdata = conn->data;
02253     
02254     debug("bb.sms", 0, "Shutting down SMSCConn CIMD2 %s (%s)",
02255           octstr_get_cstr(conn->id), 
02256           finish_sending ? "slow" : "instant");
02257 
02258     /* Documentation claims this would have been done by smscconn.c,
02259        but isn't when this code is being written. */
02260     conn->why_killed = SMSCCONN_KILLED_SHUTDOWN;
02261     pdata->quitting = 1;     /* Separate from why_killed to avoid locking, as
02262                               * why_killed may be changed from outside? */
02263 
02264     if (finish_sending == 0) {
02265         Msg *msg;
02266         while ((msg = gwlist_extract_first(pdata->outgoing_queue)) != NULL) {
02267             bb_smscconn_send_failed(conn, msg, SMSCCONN_FAILED_SHUTDOWN, NULL);
02268         }
02269     }
02270 
02271     cimd2_logout(conn);
02272     if (conn->is_stopped) {
02273         gwlist_remove_producer(pdata->stopped);
02274         conn->is_stopped = 0;
02275     }
02276 
02277     if (pdata->io_thread != -1) {
02278         gwthread_wakeup(pdata->io_thread);
02279         gwthread_join(pdata->io_thread);
02280     }
02281 
02282     cimd2_close_socket(pdata);
02283     cimd2_destroy(pdata); 
02284      
02285     debug("bb.sms", 0, "SMSCConn CIMD2 %s shut down.",  
02286           octstr_get_cstr(conn->id)); 
02287     conn->status = SMSCCONN_DEAD; 
02288     bb_smscconn_killed(); 
02289     return 0;
02290 }    

Here is the call graph for this function:

void cimd2_start_cb SMSCConn conn  )  [static]
 

Definition at line 2292 of file smsc_cimd2.c.

References smscconn::data, debug(), gwlist_remove_producer(), gwthread_wakeup(), smscconn::id, privdata::io_thread, octstr_get_cstr, PrivData, SMSCConn, and privdata::stopped.

02293 {
02294     PrivData *pdata = conn->data;
02295 
02296     gwlist_remove_producer(pdata->stopped);
02297     /* in case there are messages in the buffer already */
02298     gwthread_wakeup(pdata->io_thread);
02299     debug("bb.sms", 0, "SMSCConn CIMD2 %s, start called",
02300           octstr_get_cstr(conn->id));
02301 }

Here is the call graph for this function:

void cimd2_stop_cb SMSCConn conn  )  [static]
 

Definition at line 2303 of file smsc_cimd2.c.

References smscconn::data, debug(), gwlist_add_producer(), smscconn::id, octstr_get_cstr, PrivData, SMSCConn, and privdata::stopped.

02304 {
02305     PrivData *pdata = conn->data;
02306     gwlist_add_producer(pdata->stopped);
02307     debug("bb.sms", 0, "SMSCConn CIMD2 %s, stop called",
02308           octstr_get_cstr(conn->id));
02309 }

Here is the call graph for this function:

int cimd2_submit_msg SMSCConn conn,
Msg msg
[static]
 

Definition at line 1956 of file smsc_cimd2.c.

References bb_smscconn_send_failed(), bb_smscconn_sent(), cimd2_close_socket(), cimd2_request(), smscconn::data, debug(), dlr_add(), DLR_IS_SUCCESS_OR_FAIL, smscconn::flow_mutex, gw_assert, smscconn::id, mutex_lock, mutex_unlock, privdata::my_number, smscconn::name, privdata::no_dlr, octstr_create, octstr_destroy(), octstr_get_cstr, packet_destroy(), packet_encode_message(), PrivData, SMSCConn, SMSCCONN_FAILED_MALFORMED, SMSCCONN_FAILED_REJECTED, SMSCCONN_FAILED_TEMPORARILY, and smscconn::status.

Referenced by io_thread().

01957 {
01958     PrivData *pdata = conn->data;
01959     struct packet *packet;
01960     Octstr *ts = NULL;
01961     int ret;
01962 
01963     gw_assert(pdata != NULL);
01964     debug("bb.sms.cimd2", 0, "CIMD2[%s]: sending message",
01965         octstr_get_cstr(conn->id));
01966 
01967     packet = packet_encode_message(msg, pdata->my_number,conn);
01968     if (!packet) {
01969         /* This is a protocol error. Does this help? I doubt..
01970          * But nevermind that.
01971          */
01972         bb_smscconn_send_failed(conn, msg,
01973                 SMSCCONN_FAILED_MALFORMED, octstr_create("MALFORMED"));
01974         return -1;
01975     }
01976 
01977     ret = cimd2_request(packet, conn, &ts);
01978     if((ret == 0) && (ts) && DLR_IS_SUCCESS_OR_FAIL(msg->sms.dlr_mask) && !pdata->no_dlr) {
01979         dlr_add(conn->name, ts, msg);
01980     }
01981     octstr_destroy(ts);
01982     packet_destroy(packet);
01983     
01984     if (ret == -1) {
01985         bb_smscconn_send_failed(conn, msg,
01986                 SMSCCONN_FAILED_REJECTED, octstr_create("REJECTED"));
01987     }
01988     else if (ret == -2) {
01989         cimd2_close_socket(pdata);
01990         bb_smscconn_send_failed(conn, msg, SMSCCONN_FAILED_TEMPORARILY, NULL);
01991         mutex_lock(conn->flow_mutex);
01992         conn->status = SMSCCONN_DISCONNECTED;
01993         mutex_unlock(conn->flow_mutex);
01994     }
01995     else {
01996         bb_smscconn_sent(conn,msg, NULL);
01997     }
01998 
01999     return ret;
02000 }

Here is the call graph for this function:

void convert_cimd2_to_gsm Octstr text,
SMSCConn conn
[static]
 

Definition at line 1082 of file smsc_cimd2.c.

References cimd1, cimd2, cimd_combinations, gsm, smscconn::id, octstr_delete(), octstr_get_char(), octstr_get_cstr, octstr_len(), octstr_set_char(), SMSCConn, text, and warning().

Referenced by cimd2_accept_message().

01083 {
01084     long pos, len;
01085     int cimd1, cimd2;
01086     int c;
01087     int i;
01088 
01089     /* CIMD2 uses four single-character mappings that do not map
01090      * to themselves:
01091      * '@' from 64 to 0, '$' from 36 to 2, ']' from 93 to 14 (A-ring),
01092      * and '}' from 125 to 15 (a-ring).
01093      * Other than those, we only have to worry about the escape
01094      * sequences introduced by _ (underscore).
01095      */
01096 
01097     len = octstr_len(text);
01098     for (pos = 0; pos < len; pos++) {
01099         c = octstr_get_char(text, pos);
01100         if (c == '@')
01101             octstr_set_char(text, pos, 0);
01102         else if (c == '$')
01103             octstr_set_char(text, pos, 2);
01104         else if (c == ']')
01105             octstr_set_char(text, pos, 14);
01106         else if (c == '}')
01107             octstr_set_char(text, pos, 15);
01108         else if (c == '_' && pos + 2 < len) {
01109             cimd1 = octstr_get_char(text, pos + 1);
01110             cimd2 = octstr_get_char(text, pos + 2);
01111             for (i = 0; cimd_combinations[i].cimd1 != 0; i++) {
01112                 if (cimd_combinations[i].cimd1 == cimd1 &&
01113                     cimd_combinations[i].cimd2 == cimd2)
01114                     break;
01115             }
01116             if (cimd_combinations[i].cimd1 == 0)
01117                 warning(0, "CIMD2[%s]: Encountered unknown "
01118                         "escape code _%c%c, ignoring.",
01119                         octstr_get_cstr(conn->id),
01120                         cimd1, cimd2);
01121             else {
01122                 octstr_delete(text, pos, 2);
01123                 octstr_set_char(text, pos, cimd_combinations[i].gsm);
01124                 len = octstr_len(text);
01125             }
01126         }
01127     }
01128 }

Here is the call graph for this function:

void convert_gsm_to_cimd2 Octstr text  )  [static]
 

Definition at line 1135 of file smsc_cimd2.c.

References cimd1, cimd2, cimd_combinations, gw_assert, octstr_get_char(), octstr_insert_data(), octstr_len(), octstr_set_char(), and text.

Referenced by packet_encode_message().

01136 {
01137     long pos, len;
01138 
01139     len = octstr_len(text);
01140     for (pos = 0; pos < len; pos++) {
01141         int c, i;
01142 
01143         c = octstr_get_char(text, pos);
01144         /* If c is not in the GSM alphabet at this point,
01145          * the caller did something badly wrong. */
01146         gw_assert(c >= 0);
01147         gw_assert(c < 128);
01148 
01149         for (i = 0; cimd_combinations[i].cimd1 != 0; i++) {
01150             if (cimd_combinations[i].gsm == c)
01151                 break;
01152         }
01153 
01154         if (cimd_combinations[i].gsm == c) {
01155             /* Escape sequence */
01156             octstr_insert_data(text, pos, "_ ", 2);
01157             pos += 2;
01158             len += 2;
01159             octstr_set_char(text, pos - 1, cimd_combinations[i].cimd1);
01160             octstr_set_char(text, pos, cimd_combinations[i].cimd2);
01161         } else if (c == 2) {
01162             /* The dollar sign is the only GSM character that
01163                  * does not have a CIMD escape sequence and does not
01164              * map to itself. */
01165             octstr_set_char(text, pos, '$');
01166         }
01167     }
01168 }

Here is the call graph for this function:

void io_thread void *  arg  )  [static]
 

Definition at line 2162 of file smsc_cimd2.c.

References bb_smscconn_connected(), bb_smscconn_receive(), cimd2_login(), cimd2_submit_msg(), smscconn::connect_time, smscconn::data, debug(), error(), smscconn::flow_mutex, gwlist_consume(), gwlist_extract_first(), gwthread_sleep(), smscconn::id, smscconn::log_idx, log_thread_to(), mutex_lock, mutex_unlock, octstr_get_cstr, privdata::outgoing_queue, PrivData, privdata::quitting, smscconn::reconnect_delay, sms_receive(), SMSCConn, smscconn::status, and privdata::stopped.

Referenced by smsc_cimd2_create().

02163 {
02164     Msg       *msg;
02165     SMSCConn  *conn = arg;
02166     PrivData *pdata = conn->data;
02167     double    sleep = 0.0001;
02168 
02169     /* Make sure we log into our own log-file if defined */
02170     log_thread_to(conn->log_idx);
02171 
02172     /* remove messages from SMSC until we are killed */
02173     while (!pdata->quitting) {
02174     
02175         gwlist_consume(pdata->stopped); /* block here if suspended/isolated */
02176       
02177         /* check that connection is active */
02178         if (conn->status != SMSCCONN_ACTIVE) {
02179             if (cimd2_login(conn) != 0) { 
02180                 error(0, "CIMD2[%s]: Couldn't connect to SMSC (retrying in %ld seconds).",
02181                       octstr_get_cstr(conn->id), 
02182                       conn->reconnect_delay);
02183                 gwthread_sleep(conn->reconnect_delay);
02184                 mutex_lock(conn->flow_mutex);
02185                 conn->status = SMSCCONN_RECONNECTING; 
02186                 mutex_unlock(conn->flow_mutex);
02187                 continue; 
02188             } 
02189             mutex_lock(conn->flow_mutex);
02190             conn->status = SMSCCONN_ACTIVE;
02191             conn->connect_time = time(NULL);
02192             bb_smscconn_connected(conn);
02193             mutex_unlock(conn->flow_mutex);
02194         }
02195 
02196         /* receive messages */
02197         do { 
02198             msg = sms_receive(conn);
02199             if (msg) {
02200                 sleep = 0;
02201                 debug("bb.sms.cimd2", 0, "CIMD2[%s]: new message received",
02202                       octstr_get_cstr(conn->id));
02203                 bb_smscconn_receive(conn, msg);
02204             }
02205         } while (msg);
02206  
02207         /* send messages */
02208         do {
02209             msg = gwlist_extract_first(pdata->outgoing_queue);
02210             if (msg) {
02211                 sleep = 0;
02212                 if (cimd2_submit_msg(conn,msg) != 0) break;
02213             }
02214         } while (msg);
02215  
02216         if (sleep > 0) {
02217 
02218             /* note that this implementations means that we sleep even
02219              * when we fail connection.. but time is very short, anyway
02220              */
02221             gwthread_sleep(sleep);
02222             /* gradually sleep longer and longer times until something starts to
02223              * happen - this of course reduces response time, but that's better than
02224              * extensive CPU usage when it is not used
02225              */
02226             sleep *= 2;
02227             if (sleep >= 2.0)
02228                 sleep = 1.999999;
02229         }
02230         else {
02231             sleep = 0.0001;
02232         }
02233     }
02234 }

Here is the call graph for this function:

int isphonedigit int  c  )  [static]
 

Definition at line 324 of file smsc_cimd2.c.

Referenced by packet_add_address_parm(), packet_check_parameter(), and parm_valid_address().

00325 {
00326     return isdigit(c) || c == '+' || c == '-';
00327 }

int operation_can_receive int  operation  )  [static]
 

Definition at line 422 of file smsc_cimd2.c.

References operation_can_send(), operation_find(), operations, and RESPONSE.

00423 {
00424     int i = operation_find(operation);
00425 
00426     if (i >= 0)
00427         return operations[i].can_receive;
00428 
00429     /* If we can send the request, then we can receive the response. */
00430     if (operation >= RESPONSE)
00431         return operation_can_send(operation - RESPONSE);
00432 
00433     return 0;
00434 }

Here is the call graph for this function:

int operation_can_send int  operation  )  [static]
 

Definition at line 406 of file smsc_cimd2.c.

References operation_can_receive(), operation_find(), operations, and RESPONSE.

00407 {
00408     int i = operation_find(operation);
00409 
00410     if (i >= 0)
00411         return operations[i].can_send;
00412 
00413     /* If we can receive the request, then we can send the response. */
00414     if (operation >= RESPONSE)
00415         return operation_can_receive(operation - RESPONSE);
00416 
00417     return 0;
00418 }

Here is the call graph for this function:

int operation_find int  operation  )  [static]
 

Definition at line 371 of file smsc_cimd2.c.

References operations.

00372 {
00373     int i;
00374 
00375     for (i = 0; operations[i].name != NULL; i++) {
00376         if (operations[i].code == operation)
00377             return i;
00378     }
00379 
00380     return -1;
00381 }

Octstr * operation_name int  operation  )  [static]
 

Definition at line 384 of file smsc_cimd2.c.

References name, octstr_append_cstr(), octstr_create, operation_find(), operations, and RESPONSE.

00385 {
00386     int i;
00387 
00388     i = operation_find(operation);
00389     if (i >= 0)
00390         return octstr_create(operations[i].name);
00391 
00392     if (operation >= RESPONSE) {
00393         i = operation_find(operation - RESPONSE);
00394         if (i >= 0) {
00395             Octstr *name = octstr_create(operations[i].name);
00396             octstr_append_cstr(name, " response");
00397             return name;
00398         }
00399     }
00400 
00401     /* Put the operation number here when we have octstr_format */
00402     return octstr_create("(unknown)");
00403 }

Here is the call graph for this function:

void packet_add_address_parm struct packet packet,
int  parmno,
Octstr value,
SMSCConn conn
[static]
 

Definition at line 1234 of file smsc_cimd2.c.

References gw_assert, isphonedigit(), octstr_check_range(), octstr_len(), P_ADDRESS, packet_add_parm(), and SMSCConn.

Referenced by packet_encode_message().

01235 {
01236     gw_assert(octstr_check_range(value, 0, octstr_len(value), isphonedigit));
01237     packet_add_parm(packet, P_ADDRESS, parmno, value, conn);
01238 }

Here is the call graph for this function:

void packet_add_hex_parm struct packet packet,
int  parmno,
Octstr value,
SMSCConn conn
[static]
 

Definition at line 1253 of file smsc_cimd2.c.

References octstr_binary_to_hex(), octstr_destroy(), octstr_duplicate, P_HEX, packet_add_parm(), and SMSCConn.

Referenced by packet_encode_message().

01254 {
01255     value = octstr_duplicate(value);
01256     octstr_binary_to_hex(value, 1);   /* 1 for uppercase hex, i.e. A .. F */
01257     packet_add_parm(packet, P_HEX, parmno, value, conn);
01258     octstr_destroy(value);
01259 }

Here is the call graph for this function:

void packet_add_int_parm struct packet packet,
int  parmno,
long  value,
SMSCConn conn
[static]
 

Definition at line 1262 of file smsc_cimd2.c.

References gw_assert, octstr_create, octstr_destroy(), P_INT, packet_add_parm(), parm_in_range(), and SMSCConn.

Referenced by packet_encode_message().

01263 {
01264     char buf[128];
01265     Octstr *valuestr;
01266 
01267     gw_assert(parm_in_range(parmno, value));
01268 
01269     sprintf(buf, "%ld", value);
01270     valuestr = octstr_create(buf);
01271     packet_add_parm(packet, P_INT, parmno, valuestr, conn);
01272     octstr_destroy(valuestr);
01273 }

Here is the call graph for this function:

void packet_add_parm struct packet packet,
int  parmtype,
int  parmno,
Octstr value,
SMSCConn conn
[static]
 

Definition at line 1192 of file smsc_cimd2.c.

References packet::data, gw_assert, smscconn::id, octstr_copy, octstr_destroy(), octstr_get_cstr, octstr_insert(), octstr_insert_data(), octstr_len(), parm_maxlen(), parm_name(), parm_type(), SMSCConn, TAB_str, and warning().

Referenced by packet_add_address_parm(), packet_add_hex_parm(), packet_add_int_parm(), packet_add_sms_parm(), packet_add_string_parm(), and packet_encode_message().

01194 {
01195     char parmh[sizeof("tPPP:")];
01196     long position;
01197     long len;
01198     int copied = 0;
01199 
01200     len = octstr_len(value);
01201 
01202     gw_assert(packet != NULL);
01203     gw_assert(parm_type(parmno) == parmtype);
01204 
01205     if (len > parm_maxlen(parmno)) {
01206         warning(0, "CIMD2[%s]: %s parameter too long, truncating from "
01207                 "%ld to %ld characters",
01208                 octstr_get_cstr(conn->id), 
01209                 parm_name(parmno),
01210                 len, 
01211                 (long) parm_maxlen(parmno));
01212         value = octstr_copy(value, 0, parm_maxlen(parmno));
01213         copied = 1;
01214     }
01215 
01216     /* There's a TAB and ETX at the end; insert it before those.
01217      * The new parameter will come with a new starting TAB. */
01218     position = octstr_len(packet->data) - 2;
01219 
01220     sprintf(parmh, TAB_str "%03d:", parmno);
01221     octstr_insert_data(packet->data, position, parmh, strlen(parmh));
01222     octstr_insert(packet->data, value, position + strlen(parmh));
01223     if (copied)
01224         octstr_destroy(value);
01225 }

Here is the call graph for this function:

void packet_add_sms_parm struct packet packet,
int  parmno,
Octstr value,
SMSCConn conn
[static]
 

Definition at line 1242 of file smsc_cimd2.c.

References P_SMS, packet_add_parm(), and SMSCConn.

Referenced by packet_encode_message().

01243 {
01244     packet_add_parm(packet, P_SMS, parmno, value, conn);
01245 }

Here is the call graph for this function:

void packet_add_string_parm struct packet packet,
int  parmno,
Octstr value,
SMSCConn conn
[static]
 

Definition at line 1228 of file smsc_cimd2.c.

References P_STRING, packet_add_parm(), and SMSCConn.

Referenced by cimd2_login(), and packet_encode_message().

01229 {
01230     packet_add_parm(packet, P_STRING, parmno, value, conn);
01231 }

Here is the call graph for this function:

int packet_check struct packet packet,
SMSCConn conn
[static]
 

Definition at line 846 of file smsc_cimd2.c.

References packet::data, data, gw_assert, gw_isxdigit(), smscconn::id, octstr_check_range(), octstr_dump, octstr_get_cstr, octstr_len(), octstr_search_char(), packet_check_header(), packet_check_parameter(), SMSCConn, TAB, and warning().

Referenced by cimd2_get_packet(), and cimd2_receive_msg().

00847 {
00848     int errors = 0;
00849     long pos, len, next;
00850     Octstr *data;
00851 
00852     gw_assert(packet != NULL);
00853     data = packet->data;
00854 
00855     if (octstr_search_char(data, 0, 0) >= 0) {
00856         /* CIMD2 spec does not allow NUL bytes in a packet */
00857         warning(0, "CIMD2[%s]: packet contains NULs",
00858                 octstr_get_cstr(conn->id));
00859         errors++;
00860     }
00861 
00862     /* Assume the packet starts with STX and ends with ETX,
00863      * because we parsed it that way in the first place. */
00864 
00865     errors += (packet_check_header(packet,conn) < 0);
00866 
00867     /* Parameters are separated by tabs.  After the last parameter
00868      * there is a tab, an optional two-digit checksum, and the ETX.
00869      * Check each parameter in turn, by skipping from tab to tab.
00870      */
00871     len = octstr_len(data);
00872     /* Start at the first tab, wherever it is, so that we can still
00873      * check parameters if the header was weird. */
00874     pos = octstr_search_char(data, TAB, 0);
00875     for ( ; pos >= 0; pos = next) {
00876         next = octstr_search_char(data, TAB, pos + 1);
00877         if (next >= 0) {
00878             errors += (packet_check_parameter(packet, pos, next - pos, conn) < 0);
00879         } else {
00880             /* Check if the checksum has the right format.  Don't
00881              * check the sum itself here, that will be done in a
00882              * separate call later. */
00883             /* There are two valid formats: TAB ETX (no checksum)
00884              * and TAB digit digit ETX.  We already know the TAB
00885              * and the ETX are there. */
00886             if (!(octstr_len(data) - pos == 2 ||
00887                   (octstr_len(data) - pos == 4 &&
00888                    octstr_check_range(data, pos + 1, 2, gw_isxdigit)))) {
00889                 warning(0, "CIMD2[%s]: packet checksum in wrong format",
00890                         octstr_get_cstr(conn->id));
00891                 errors++;
00892             }
00893         }
00894     }
00895 
00896 
00897     if (errors > 0) {
00898         octstr_dump(packet->data, 0);
00899         return -1;
00900     }
00901 
00902     return 0;
00903 }

Here is the call graph for this function:

void packet_check_can_receive struct packet packet,
SMSCConn conn
[static]
 

Definition at line 905 of file smsc_cimd2.c.

References gw_assert, smscconn::id, name, octstr_destroy(), octstr_get_cstr, packet::operation, operation_can_receive(), operation_name(), SMSCConn, and warning().

00906 {
00907     gw_assert(packet != NULL);
00908 
00909     if (!operation_can_receive(packet->operation)) {
00910         Octstr *name = operation_name(packet->operation);
00911         warning(0, "CIMD2[%s]: SMSC sent us %s request",
00912                 octstr_get_cstr(conn->id),
00913                 octstr_get_cstr(name));
00914         octstr_destroy(name);
00915     }
00916 }

Here is the call graph for this function:

int packet_check_header struct packet packet,
SMSCConn conn
[static]
 

Definition at line 705 of file smsc_cimd2.c.

References packet::data, data, gw_assert, gw_isdigit(), smscconn::id, octstr_check_range(), octstr_get_char(), octstr_get_cstr, octstr_len(), SMSCConn, and warning().

Referenced by packet_check().

00706 {
00707     Octstr *data;
00708 
00709     gw_assert(packet != NULL);
00710     data = packet->data;
00711 
00712     /* The header must have a two-digit operation code, a colon,
00713      * and a three-digit sequence number, followed by a tab.
00714      * (CIMD2, 3.1) */
00715     if (octstr_len(data) < 8 ||
00716         !octstr_check_range(data, 1, 2, gw_isdigit) ||
00717         octstr_get_char(data, 3) != ':' ||
00718         !octstr_check_range(data, 4, 3, gw_isdigit) ||
00719         octstr_get_char(data, 7) != TAB) {
00720         warning(0, "CIMD2[%s]: packet header in wrong format",
00721                 octstr_get_cstr(conn->id));
00722         return -1;
00723     }
00724 
00725     return 0;
00726 }

Here is the call graph for this function:

int packet_check_parameter struct packet packet,
long  pos,
long  len,
SMSCConn conn
[static]
 

Definition at line 728 of file smsc_cimd2.c.

References packet::data, data, gw_assert, gw_isdigit(), gw_isxdigit(), smscconn::id, isphonedigit(), octstr_check_range(), octstr_get_char(), octstr_get_cstr, octstr_parse_long(), P_ADDRESS, P_HEX, P_INT, P_SMS, P_STRING, P_TIME, parameters, parm_index(), SMSCConn, and warning().

Referenced by packet_check().

00729 {
00730     Octstr *data;
00731     long parm;
00732     long dpos, dlen;
00733     int negative;
00734     long value;
00735     int i;
00736     int errors = 0;
00737 
00738     gw_assert(packet != NULL);
00739     data = packet->data;
00740 
00741     /* The parameter header should be TAB, followed by a three-digit
00742      * parameter number, a colon, and the data.  We already know about
00743      * the tab. */
00744 
00745     if (len < 5 ||
00746         !octstr_check_range(data, pos + 1, 3, gw_isdigit) ||
00747         octstr_get_char(data, pos + 4) != ':') {
00748         warning(0, "CIMD2[%s]: parameter at offset %ld in wrong format",
00749                 octstr_get_cstr(conn->id),
00750                 pos);
00751         errors++;
00752     }
00753 
00754     /* If we can't parse a parameter number, there's nothing more
00755      * that we can check. */
00756     dpos = octstr_parse_long(&parm, data, pos + 1, 10);
00757     if (dpos < 0)
00758         return -1;
00759     if (octstr_get_char(data, dpos) == ':')
00760         dpos++;
00761     dlen = len - (dpos - pos);
00762     /* dlen can not go negative because octstr_parse_long must have
00763      * been stopped by the TAB at the end of the parameter data. */
00764     gw_assert(dlen >= 0);
00765 
00766     i = parm_index(parm);
00767 
00768     if (i < 0) {
00769         warning(0, "CIMD2[%s]: packet contains unknown parameter %ld", 
00770                 octstr_get_cstr(conn->id),
00771                 parm);
00772         return -1;
00773     }
00774 
00775     if (dlen > parameters[i].maxlen) {
00776         warning(0, "CIMD2[%s]: packet has '%s' parameter with length %ld, spec says max %d",
00777                 octstr_get_cstr(conn->id),
00778                 parameters[i].name, len, parameters[i].maxlen);
00779         errors++;
00780     }
00781 
00782     switch (parameters[i].type) {
00783     case P_INT:
00784         /* Allow a leading - */
00785         negative = (octstr_get_char(data, dpos) == '-');
00786         if (!octstr_check_range(data, dpos + negative,
00787                                 dlen - negative, gw_isdigit)) {
00788             warning(0, "CIMD2[%s]: packet has '%s' parameter with non-integer contents", 
00789                     octstr_get_cstr(conn->id),
00790                     parameters[i].name);
00791             errors++;
00792         }
00793         if (octstr_parse_long(&value, data, dpos, 10) >= 0 &&
00794             (value < parameters[i].minval || value > parameters[i].maxval)) {
00795             warning(0, "CIMD2[%s]: packet has '%s' parameter out of range (value %ld, min %d, max %d)",
00796                     octstr_get_cstr(conn->id),
00797                     parameters[i].name, value,
00798                     parameters[i].minval, parameters[i].maxval);
00799             errors++;
00800         }
00801         break;
00802     case P_TIME:
00803         if (!octstr_check_range(data, dpos, dlen, gw_isdigit)) {
00804             warning(0, "CIMD2[%s]: packet has '%s' parameter with non-digit contents", 
00805                     octstr_get_cstr(conn->id),
00806                     parameters[i].name);
00807             errors++;
00808         }
00809         break;
00810     case P_ADDRESS:
00811         if (!octstr_check_range(data, dpos, dlen, isphonedigit)) {
00812             warning(0, "CIMD2[%s]: packet has '%s' parameter with non phone number contents", 
00813                     octstr_get_cstr(conn->id),
00814                     parameters[i].name);
00815             errors++;
00816         }
00817         break;
00818     case P_HEX:
00819         if (!octstr_check_range(data, dpos, dlen, gw_isxdigit)) {
00820             warning(0, "CIMD2[%s]: packet has '%s' parameter with non-hex contents", 
00821                     octstr_get_cstr(conn->id),
00822                     parameters[i].name);
00823             errors++;
00824         }
00825         if (dlen % 2 != 0) {
00826             warning(0, "CIMD2[%s]: packet has odd-length '%s' parameter", 
00827                     octstr_get_cstr(conn->id),
00828                     parameters[i].name);
00829             errors++;
00830         }
00831         break;
00832     case P_SMS:
00833     case P_STRING:  /* nothing to check */
00834         break;
00835     }
00836 
00837     if (errors > 0)
00838         return -1;
00839     return 0;
00840 }

Here is the call graph for this function:

struct packet* packet_create int  operation,
int  seq
[static]
 

Definition at line 1177 of file smsc_cimd2.c.

References packet::data, ETX_str, octstr_create, packet::operation, packet::seq, STX_str, and TAB_str.

01178 {
01179     struct packet *packet;
01180     char minpacket[sizeof("sOO:SSSte")];
01181 
01182     packet = gw_malloc(sizeof(*packet));
01183     packet->operation = operation;
01184     packet->seq = seq;
01185     sprintf(minpacket, STX_str "%02d:%03d" TAB_str ETX_str, operation, seq);
01186     packet->data = octstr_create(minpacket);
01187 
01188     return packet;
01189 }

void packet_destroy struct packet packet  )  [static]
 

Definition at line 521 of file smsc_cimd2.c.

References packet::data, and octstr_destroy().

00522 {
00523     if (packet != NULL) {
00524         octstr_destroy(packet->data);
00525         gw_free(packet);
00526     }
00527 }

Here is the call graph for this function:

int packet_display_error struct packet packet,
SMSCConn conn
[static]
 

Definition at line 980 of file smsc_cimd2.c.

References cimd2_errors, code, error(), smscconn::id, octstr_create, octstr_destroy(), octstr_get_cstr, packet::operation, operation_name(), P_ERROR_CODE, P_ERROR_TEXT, packet_get_int_parm(), packet_get_string_parm(), SMSCConn, and text.

Referenced by cimd2_request().

00981 {
00982     int code;
00983     Octstr *text = NULL;
00984     Octstr *opname = NULL;
00985 
00986     code = packet_get_int_parm(packet, P_ERROR_CODE);
00987     text = packet_get_string_parm(packet, P_ERROR_TEXT);
00988 
00989     if (code <= 0) {
00990         octstr_destroy(text);
00991         return 0;
00992     }
00993 
00994     if (text == NULL) {
00995         /* No error text.  Try to find it in the table. */
00996         int i;
00997         for (i = 0; cimd2_errors[i].text != NULL; i++) {
00998             if (cimd2_errors[i].code == code) {
00999                 text = octstr_create(cimd2_errors[i].text);
01000                 break;
01001             }
01002         }
01003     }
01004 
01005     if (text == NULL) {
01006         /* Still no error text.  Make one up. */
01007         text = octstr_create("Unknown error");
01008     }
01009 
01010     opname = operation_name(packet->operation);
01011     error(0, "CIMD2[%s]: %s contained error message:",
01012           octstr_get_cstr(conn->id),
01013           octstr_get_cstr(opname));
01014     error(0, "code %03d: %s", code, octstr_get_cstr(text));
01015     octstr_destroy(opname);
01016     octstr_destroy(text);
01017     return code;
01018 }

Here is the call graph for this function:

struct packet* packet_encode_message Msg msg,
Octstr sender_prefix,
SMSCConn conn
[static]
 

Definition at line 1320 of file smsc_cimd2.c.

References smscconn::alt_dcs, BOGUS_SEQUENCE, charset_gsm_truncate(), charset_utf8_to_gsm(), convert_gsm_to_cimd2(), smscconn::data, DC_7BIT, DC_8BIT, DLR_IS_SUCCESS_OR_FAIL, fields_to_dcs(), gw_assert, smscconn::id, privdata::no_dlr, octstr_compare(), octstr_copy, octstr_create, octstr_destroy(), octstr_duplicate, octstr_get_cstr, octstr_imm(), octstr_len(), octstr_ncompare(), octstr_truncate(), P_ALPHANUMERIC_ORIGINATING_ADDRESS, P_DATA_CODING_SCHEME, P_DESTINATION_ADDRESS, P_INT, P_MORE_MESSAGES_TO_SEND, P_ORIGINATING_ADDRESS, P_PROTOCOL_IDENTIFIER, P_REPLY_PATH, P_STATUS_REPORT_REQUEST, P_TARIFF_CLASS, P_USER_DATA, P_USER_DATA_BINARY, P_USER_DATA_HEADER, P_VALIDITY_PERIOD_RELATIVE, packet_add_address_parm(), packet_add_hex_parm(), packet_add_int_parm(), packet_add_parm(), packet_add_sms_parm(), packet_add_string_parm(), packet_create(), parm_valid_address(), PrivData, sms, SMSCConn, SUBMIT_MESSAGE, text, and warning().

01321 {
01322     struct packet *packet;
01323     PrivData *pdata = conn->data;
01324     Octstr *text;
01325     int spaceleft;
01326     long truncated;
01327     int dcs = 0;
01328     int setvalidity = 0;
01329 
01330     gw_assert(msg != NULL);
01331     gw_assert(msg->type == sms);
01332     gw_assert(msg->sms.receiver != NULL);
01333 
01334     dcs = fields_to_dcs(msg, (msg->sms.alt_dcs != -1 ? 
01335         msg->sms.alt_dcs : conn->alt_dcs));
01336     if (msg->sms.sender == NULL)
01337         msg->sms.sender = octstr_create("");
01338 
01339     if (!parm_valid_address(msg->sms.receiver)) {
01340         warning(0, "CIMD2[%s]: non-digits in destination phone number '%s', discarded",
01341                 octstr_get_cstr(conn->id),
01342                 octstr_get_cstr(msg->sms.receiver));
01343         return NULL;
01344     }
01345 
01346     packet = packet_create(SUBMIT_MESSAGE, BOGUS_SEQUENCE);
01347 
01348     packet_add_address_parm(packet, P_DESTINATION_ADDRESS, msg->sms.receiver, conn);
01349 
01350     /* CIMD2 interprets the originating address as a sub-address to
01351      * our connection number (so if the connection is "400" and we
01352      * fill in "600" as the sender number, the user sees "400600").
01353      * Since we have no way to ask what this number is, it has to
01354      * be configured. */
01355 
01356     /* Quick and dirty check to see if we are using alphanumeric sender */
01357     if (parm_valid_address(msg->sms.sender)) {
01358         /* We are not, so send in the usual way */
01359         /* Speed up the default case */
01360         if (octstr_len(sender_prefix) == 0) {
01361             packet_add_address_parm(packet, P_ORIGINATING_ADDRESS,msg->sms.sender, conn);
01362         }
01363         else if (octstr_compare(sender_prefix, octstr_imm("never")) != 0) {
01364             if (octstr_ncompare(sender_prefix, msg->sms.sender,
01365                                 octstr_len(sender_prefix)) == 0) {
01366                 Octstr *sender;
01367                 sender = octstr_copy(msg->sms.sender,
01368                                      octstr_len(sender_prefix), octstr_len(msg->sms.sender));
01369                 packet_add_address_parm(packet, P_ORIGINATING_ADDRESS, sender, conn);
01370                 octstr_destroy(sender);
01371             } else {
01372                 warning(0, "CIMD2[%s]: Sending message with originating address <%s>, "
01373                         "which does not start with the sender-prefix.",
01374                         octstr_get_cstr(conn->id),
01375                         octstr_get_cstr(msg->sms.sender));
01376             }
01377         }
01378     }
01379     else {
01380         /* The test above to check if sender was all digits failed, so assume we want alphanumeric sender */
01381         packet_add_string_parm(packet, P_ALPHANUMERIC_ORIGINATING_ADDRESS,msg->sms.sender, conn);
01382     }
01383 
01384     /* Add the validity period if necessary.  This sets the relative validity
01385      * period as this is the description of the "validity" parameter of the
01386      * sendsms interface.
01387      *
01388      * Convert from minutes to GSM 03.40 specification (section 9.2.3.12).
01389      * 0-143   = 0 to 12 hours in 5 minute increments.
01390      * 144-167 = 12hrs30min to 24hrs in 30 minute increments.
01391      * 168-196 = 2days to 30days in 1 day increments.
01392      * 197-255 = 5weeks to 63weeks in 1 week increments.
01393      *
01394      * This code was copied from smsc_at2.c.
01395      */
01396     if (msg->sms.validity >= 0) {
01397       if (msg->sms.validity > 635040)
01398     setvalidity = 255;
01399       if (msg->sms.validity >= 50400 && msg->sms.validity <= 635040)
01400     setvalidity = (msg->sms.validity - 1) / 7 / 24 / 60 + 192 + 1;
01401       if (msg->sms.validity > 43200 && msg->sms.validity < 50400)
01402     setvalidity = 197;
01403       if (msg->sms.validity >= 2880 && msg->sms.validity <= 43200)
01404     setvalidity = (msg->sms.validity - 1) / 24 / 60 + 166 + 1;
01405       if (msg->sms.validity > 1440 && msg->sms.validity < 2880)
01406     setvalidity = 168;
01407       if (msg->sms.validity >= 750 && msg->sms.validity <= 1440)
01408     setvalidity = (msg->sms.validity - 720 - 1) / 30 + 143 + 1;
01409       if (msg->sms.validity > 720 && msg->sms.validity < 750)
01410     setvalidity = 144;
01411       if (msg->sms.validity >= 5 && msg->sms.validity <= 720)
01412     setvalidity = (msg->sms.validity - 1) / 5 - 1 + 1;
01413       if (msg->sms.validity < 5)
01414     setvalidity = 0;
01415 
01416       packet_add_int_parm(packet, P_VALIDITY_PERIOD_RELATIVE, setvalidity, conn);
01417     }
01418 
01419     /* Explicitly ask not to get status reports.
01420      * If we do not do this, the server's default might be to
01421      * send status reports in some cases, and we don't do anything
01422      * with those reports anyway. */
01423     /* ask for the delivery reports if needed*/
01424 
01425     if (!pdata->no_dlr)
01426         if (DLR_IS_SUCCESS_OR_FAIL(msg->sms.dlr_mask))
01427             packet_add_int_parm(packet, P_STATUS_REPORT_REQUEST, 14, conn);
01428         else
01429             packet_add_int_parm(packet, P_STATUS_REPORT_REQUEST, 0, conn);
01430     else if( pdata->no_dlr && DLR_IS_SUCCESS_OR_FAIL(msg->sms.dlr_mask)) 
01431         warning(0, "CIMD2[%s]: dlr request make no sense while no-dlr set to true",
01432              octstr_get_cstr(conn->id));
01433 
01434     /* Turn off reply path as default.
01435      * This avoids phones automatically asking for a reply
01436      */
01437     if (msg->sms.rpi > 0)
01438     packet_add_int_parm(packet, P_REPLY_PATH, 1, conn);
01439     else
01440         packet_add_int_parm(packet, P_REPLY_PATH, 0, conn);
01441 
01442     /* Use binfo to set the tariff class */
01443     if (octstr_len(msg->sms.binfo))
01444     packet_add_parm(packet, P_INT, P_TARIFF_CLASS, msg->sms.binfo, conn);
01445 
01446     /* Set the protocol identifier if requested */
01447     if (msg->sms.pid > 0)
01448         packet_add_int_parm(packet, P_PROTOCOL_IDENTIFIER, msg->sms.pid, conn);
01449  
01450     /* If there are more messages to the same destination, then set the
01451     * More Messages to Send flag. This allow faster delivery of many messages 
01452     * to the same destination
01453     */
01454     if (msg->sms.msg_left > 0)
01455         packet_add_int_parm(packet, P_MORE_MESSAGES_TO_SEND, 1, conn);
01456     else
01457         packet_add_int_parm(packet, P_MORE_MESSAGES_TO_SEND, 0, conn);
01458     
01459     truncated = 0;
01460 
01461     spaceleft = 140;
01462     if (octstr_len(msg->sms.udhdata)) {
01463         /* udhdata will be truncated and warned about if
01464          * it does not fit. */
01465         packet_add_hex_parm(packet, P_USER_DATA_HEADER, msg->sms.udhdata, conn);
01466     }
01467     if (msg->sms.coding == DC_7BIT || msg->sms.coding == DC_UNDEF)
01468         spaceleft = spaceleft * 8 / 7;
01469     if (spaceleft < 0)
01470         spaceleft = 0;
01471 
01472     text = octstr_duplicate(msg->sms.msgdata);
01473 
01474     if (octstr_len(text) > 0 && spaceleft == 0) {
01475         warning(0, "CIMD2[%s]: message filled up with UDH, no room for message text",
01476                 octstr_get_cstr(conn->id));
01477     } else if (msg->sms.coding == DC_8BIT || msg->sms.coding == DC_UCS2) {
01478         if (octstr_len(text) > spaceleft) {
01479             truncated = octstr_len(text) - spaceleft;
01480             octstr_truncate(text, spaceleft);
01481         }
01482         packet_add_hex_parm(packet, P_USER_DATA_BINARY, text, conn);
01483     } else {
01484         /* Going from latin1 to GSM to CIMD2 may seem like a
01485          * detour, but it's the only way to get all the escape
01486          * codes right. */
01487         charset_utf8_to_gsm(text);
01488         truncated = charset_gsm_truncate(text, spaceleft);
01489         convert_gsm_to_cimd2(text);
01490         packet_add_sms_parm(packet, P_USER_DATA, text, conn);
01491     }
01492 
01493     if (dcs != 0)
01494         packet_add_int_parm(packet, P_DATA_CODING_SCHEME, dcs, conn);
01495 
01496     if (truncated > 0) {
01497         warning(0, "CIMD2[%s]: truncating message text to fit in %d characters.", 
01498                 octstr_get_cstr(conn->id),
01499                 spaceleft);
01500     }
01501 
01502     octstr_destroy(text);
01503     return packet;
01504 }

Here is the call graph for this function:

struct packet* packet_extract Octstr in,
SMSCConn conn
[static]
 

Definition at line 533 of file smsc_cimd2.c.

References ETX, ETX_str, smscconn::id, octstr_append_cstr(), octstr_copy, octstr_delete(), octstr_get_cstr, octstr_len(), octstr_search_char(), packet_parse(), SMSCConn, STX, and warning().

00534 {
00535     int stx, etx;
00536     Octstr *packet;
00537 
00538     /* Find STX, and delete everything up to it */
00539     stx = octstr_search_char(in, STX, 0);
00540     if (stx < 0) {
00541         octstr_delete(in, 0, octstr_len(in));
00542         return NULL;
00543     } else {
00544         octstr_delete(in, 0, stx);
00545     }
00546 
00547     /* STX is now in position 0.  Find ETX. */
00548     etx = octstr_search_char(in, ETX, 1);
00549     if (etx < 0)
00550         return NULL;
00551 
00552     /* What shall we do with STX data... STX data... ETX?
00553      * Either skip to the second STX, or assume an ETX marker before
00554      * the STX.  Doing the latter has a chance of succeeding, and
00555      * will at least allow good logging of the error. */
00556     stx = octstr_search_char(in, STX, 1);
00557     if (stx >= 0 && stx < etx) {
00558         warning(0, "CIMD2[%s]: packet without end marker",
00559                 octstr_get_cstr(conn->id));
00560         packet = octstr_copy(in, 0, stx);
00561         octstr_delete(in, 0, stx);
00562         octstr_append_cstr(packet, ETX_str);
00563     } else {
00564         /* Normal case. Copy packet, and cut it from the source. */
00565         packet = octstr_copy(in, 0, etx + 1);
00566         octstr_delete(in, 0, etx + 1);
00567     }
00568 
00569     return packet_parse(packet);
00570 }

Here is the call graph for this function:

Octstr* packet_get_address_parm struct packet packet,
int  parmno
[static]
 

Definition at line 653 of file smsc_cimd2.c.

References gw_assert, P_ADDRESS, packet_get_parm(), and parm_type().

Referenced by cimd2_accept_message().

00654 {
00655     /* Our code should never even try a bad parameter access. */
00656     gw_assert(parm_type(parmno) == P_ADDRESS);
00657 
00658     return packet_get_parm(packet, parmno);
00659 }

Here is the call graph for this function:

Octstr* packet_get_hex_parm struct packet packet,
int  parmno
[static]
 

Definition at line 681 of file smsc_cimd2.c.

References error(), gw_assert, octstr_destroy(), octstr_hex_to_binary(), P_HEX, packet_get_parm(), and parm_type().

Referenced by cimd2_accept_message().

00682 {
00683     Octstr *value = NULL;
00684 
00685     /* Our code should never even try a bad parameter access. */
00686     gw_assert(parm_type(parmno) == P_HEX);
00687 
00688     value = packet_get_parm(packet, parmno);
00689     if (!value)
00690         goto error;
00691 
00692     if (octstr_hex_to_binary(value) < 0)
00693         goto error;
00694 
00695     return value;
00696 
00697 error:
00698     octstr_destroy(value);
00699     return NULL;
00700 }

Here is the call graph for this function:

long packet_get_int_parm struct packet packet,
int  parmno
[static]
 

Definition at line 616 of file smsc_cimd2.c.

References error(), gw_assert, octstr_destroy(), octstr_parse_long(), P_INT, packet_get_parm(), and parm_type().

Referenced by cimd2_accept_message(), and packet_display_error().

00617 {
00618     Octstr *valuestr = NULL;
00619     long value;
00620 
00621     /* Our code should never even try a bad parameter access. */
00622     gw_assert(parm_type(parmno) == P_INT);
00623 
00624     valuestr = packet_get_parm(packet, parmno);
00625     if (!valuestr)
00626         goto error;
00627 
00628     if (octstr_parse_long(&value, valuestr, 0, 10) < 0)
00629         goto error;
00630 
00631     octstr_destroy(valuestr);
00632     return value;
00633 
00634 error:
00635     octstr_destroy(valuestr);
00636     return INT_MIN;
00637 }

Here is the call graph for this function:

Octstr* packet_get_parm struct packet packet,
int  parmno
[static]
 

Definition at line 579 of file smsc_cimd2.c.

References packet::data, gw_assert, number, octstr_copy, octstr_parse_long(), octstr_search_char(), and TAB.

Referenced by cimd2_accept_delivery_report_message(), cimd2_get_packet(), packet_get_address_parm(), packet_get_hex_parm(), packet_get_int_parm(), packet_get_sms_parm(), and packet_get_string_parm().

00580 {
00581     long pos, next;
00582     long valuepos;
00583     long number;
00584 
00585     gw_assert(packet != NULL);
00586     pos = octstr_search_char(packet->data, TAB, 0);
00587     if (pos < 0)
00588         return NULL;  /* Bad packet, nothing we can do */
00589 
00590     /* Parameters have a tab on each end.  If we don't find the
00591      * closing tab, we're at the checksum, so we stop. */
00592     for ( ;
00593           (next = octstr_search_char(packet->data, TAB, pos + 1)) >= 0;
00594           pos = next) {
00595         if (octstr_parse_long(&number, packet->data, pos + 1, 10) < 0)
00596             continue;
00597         if (number != parmno)
00598             continue;
00599         valuepos = octstr_search_char(packet->data, ':', pos + 1);
00600         if (valuepos < 0)
00601             continue;  /* badly formatted parm */
00602         valuepos++;  /* skip the ':' */
00603 
00604         /* Found the right parameter */
00605         return octstr_copy(packet->data, valuepos, next - valuepos);
00606     }
00607 
00608     return NULL;
00609 }

Here is the call graph for this function:

Octstr* packet_get_sms_parm struct packet packet,
int  parmno
[static]
 

Definition at line 665 of file smsc_cimd2.c.

References gw_assert, P_SMS, packet_get_parm(), and parm_type().

Referenced by cimd2_accept_message().

00666 {
00667     /* Our code should never even try a bad parameter access. */
00668     gw_assert(parm_type(parmno) == P_SMS);
00669 
00670     return packet_get_parm(packet, parmno);
00671 }

Here is the call graph for this function:

Octstr* packet_get_string_parm struct packet packet,
int  parmno
[static]
 

Definition at line 642 of file smsc_cimd2.c.

References gw_assert, P_STRING, packet_get_parm(), and parm_type().

Referenced by packet_display_error().

00643 {
00644     /* Our code should never even try a bad parameter access. */
00645     gw_assert(parm_type(parmno) == P_STRING);
00646 
00647     return packet_get_parm(packet, parmno);
00648 }

Here is the call graph for this function:

struct packet* packet_parse Octstr packet_data  )  [static]
 

Definition at line 507 of file smsc_cimd2.c.

References packet::data, and packet_parse_header().

00508 {
00509     struct packet *packet;
00510 
00511     packet = gw_malloc(sizeof(*packet));
00512     packet->data = packet_data;
00513 
00514     /* Fill in packet->operation and packet->seq */
00515     packet_parse_header(packet);
00516 
00517     return packet;
00518 }

Here is the call graph for this function:

void packet_parse_header struct packet packet  )  [static]
 

Definition at line 480 of file smsc_cimd2.c.

References packet::data, number, octstr_get_char(), octstr_parse_long(), packet::operation, and packet::seq.

00481 {
00482     int pos;
00483     long number;
00484 
00485     /* Set default values, in case we can't parse the fields */
00486     packet->operation = -1;
00487     packet->seq = -1;
00488 
00489     pos = octstr_parse_long(&number, packet->data, 1, 10);
00490     if (pos < 0)
00491         return;
00492     packet->operation = number;
00493 
00494     if (octstr_get_char(packet->data, pos++) != ':')
00495         return;
00496 
00497     pos = octstr_parse_long(&number, packet->data, pos, 10);
00498     if (pos < 0)
00499         return;
00500     packet->seq = number;
00501 }

Here is the call graph for this function:

void packet_set_checksum struct packet packet  )  [static]
 

Definition at line 1275 of file smsc_cimd2.c.

References packet::data, data, gw_assert, octstr_delete(), octstr_get_char(), octstr_insert_data(), octstr_len(), and TAB.

Referenced by cimd2_request(), and cimd2_send_response().

01276 {
01277     Octstr *data;
01278     int checksum;
01279     long pos, len;
01280     char buf[16];
01281 
01282     gw_assert(packet != NULL);
01283 
01284     data = packet->data;
01285     if (octstr_get_char(data, octstr_len(data) - 2) != TAB) {
01286         /* Packet already has checksum; kill it. */
01287         octstr_delete(data, octstr_len(data) - 3, 2);
01288     }
01289 
01290     gw_assert(octstr_get_char(data, octstr_len(data) - 2) == TAB);
01291 
01292     /* Sum all the way up to the last TAB */
01293     checksum = 0;
01294     for (pos = 0, len = octstr_len(data); pos < len - 1; pos++) {
01295         checksum += octstr_get_char(data, pos);
01296         checksum &= 0xff;
01297     }
01298 
01299     sprintf(buf, "%02X", checksum);
01300     octstr_insert_data(data, len - 1, buf, 2);
01301 }

Here is the call graph for this function:

void packet_set_send_sequence struct packet packet,
PrivData pdata
[static]
 

Definition at line 1511 of file smsc_cimd2.c.

References gw_assert, packet::operation, packet_set_sequence(), PrivData, and privdata::send_seq.

01512 {
01513     gw_assert(pdata != NULL);
01514     /* LOGIN packets always have sequence number 001 */
01515     if (packet->operation == LOGIN)
01516         pdata->send_seq = 1;
01517     /* Send sequence numbers are always odd, receiving are always even */
01518     gw_assert(pdata->send_seq % 2 == 1);
01519 
01520     packet_set_sequence(packet, pdata->send_seq);
01521     pdata->send_seq += 2;
01522     if (pdata->send_seq > 256)
01523         pdata->send_seq = 1;
01524 }

Here is the call graph for this function:

void packet_set_sequence struct packet packet,
int  seq
[static]
 

Definition at line 1303 of file smsc_cimd2.c.

References packet::data, gw_assert, octstr_set_char(), and packet::seq.

01304 {
01305     char buf[16];
01306 
01307     gw_assert(packet != NULL);
01308     gw_assert(seq >= 0);
01309     gw_assert(seq < 256);
01310 
01311     sprintf(buf, "%03d", seq);
01312 
01313     /* Start at 4 to skip the <STX> ZZ: part of the header. */
01314     octstr_set_char(packet->data, 4, buf[0]);
01315     octstr_set_char(packet->data, 5, buf[1]);
01316     octstr_set_char(packet->data, 6, buf[2]);
01317     packet->seq = seq;
01318 }

Here is the call graph for this function:

int parm_in_range int  parmno,
long  value
[static]
 

Definition at line 310 of file smsc_cimd2.c.

References parameters, and parm_index().

Referenced by packet_add_int_parm().

00311 {
00312     int i;
00313 
00314     i = parm_index(parmno);
00315 
00316     if (i < 0)
00317         return -1;
00318 
00319     return (value >= parameters[i].minval && value <= parameters[i].maxval);
00320 }

Here is the call graph for this function:

int parm_index int  parmno  )  [static]
 

Definition at line 260 of file smsc_cimd2.c.

References parameters.

Referenced by packet_check_parameter(), parm_in_range(), parm_maxlen(), parm_name(), and parm_type().

00261 {
00262     int i;
00263 
00264     for (i = 0; parameters[i].name != NULL; i++) {
00265         if (parameters[i].number == parmno)
00266             return i;
00267     }
00268 
00269     return -1;
00270 }

int parm_maxlen int  parmno  )  [static]
 

Definition at line 287 of file smsc_cimd2.c.

References parameters, and parm_index().

Referenced by packet_add_parm(), and smsc_cimd2_create().

00288 {
00289     int i = parm_index(parmno);
00290 
00291     if (i < 0)
00292         return -1;
00293 
00294     return parameters[i].maxlen;
00295 }

Here is the call graph for this function:

const char* parm_name int  parmno  )  [static]
 

Definition at line 297 of file smsc_cimd2.c.

References parameters, and parm_index().

Referenced by packet_add_parm().

00298 {
00299     int i = parm_index(parmno);
00300 
00301     if (i < 0)
00302         return NULL;
00303 
00304     return parameters[i].name;
00305 }

Here is the call graph for this function:

int parm_type int  parmno  )  [static]
 

Definition at line 274 of file smsc_cimd2.c.

References parameters, and parm_index().

Referenced by packet_add_parm(), packet_get_address_parm(), packet_get_hex_parm(), packet_get_int_parm(), packet_get_sms_parm(), and packet_get_string_parm().

00275 {
00276     int i = parm_index(parmno);
00277 
00278     if (i < 0)
00279         return -1;
00280 
00281     return parameters[i].type;
00282 }

Here is the call graph for this function:

int parm_valid_address Octstr value  )  [static]
 

Definition at line 329 of file smsc_cimd2.c.

References isphonedigit(), octstr_check_range(), and octstr_len().

00330 {
00331     return octstr_check_range(value, 0, octstr_len(value), isphonedigit);
00332 }

Here is the call graph for this function:

Msg* sms_receive SMSCConn conn  )  [static]
 

Definition at line 2137 of file smsc_cimd2.c.

References cimd2_close_socket(), cimd2_receive_msg(), smscconn::data, smscconn::flow_mutex, smscconn::id, msg_destroy(), mutex_lock, mutex_unlock, octstr_duplicate, PrivData, SMSCConn, and smscconn::status.

02138 {
02139     PrivData *pdata = conn->data;
02140     int ret;
02141     Msg *newmsg = NULL;
02142 
02143     ret = cimd2_receive_msg(conn, &newmsg);
02144     if (ret == 1) {
02145         /* if any smsc_id available, use it */
02146         newmsg->sms.smsc_id = octstr_duplicate(conn->id);
02147         return newmsg;
02148     } 
02149     else if (ret == 0) { /* no message, just retry... */
02150         return NULL;
02151     } 
02152     /* error. reconnect. */
02153     msg_destroy(newmsg);
02154     mutex_lock(conn->flow_mutex);
02155     cimd2_close_socket(pdata);
02156     conn->status = SMSCCONN_DISCONNECTED;
02157     mutex_unlock(conn->flow_mutex);
02158     return NULL;
02159 }

Here is the call graph for this function:

int smsc_cimd2_create SMSCConn conn,
CfgGroup grp
 

Definition at line 2319 of file smsc_cimd2.c.

References cfg_get, cfg_get_bool(), cfg_get_integer(), cimd2_destroy(), privdata::conn, smscconn::data, debug(), error(), gwlist_add_producer(), gwlist_create, gwthread_create, gwthread_join(), gwthread_wakeup(), privdata::host, smscconn::id, privdata::inbuffer, privdata::io_thread, io_thread(), smscconn::is_stopped, privdata::keepalive, maxlen, privdata::my_number, smscconn::name, privdata::next_ping, privdata::no_dlr, octstr_create, octstr_format(), octstr_get_cstr, octstr_imm(), octstr_len(), octstr_truncate(), ok, privdata::our_port, privdata::outgoing_queue, P_PASSWORD, P_USER_IDENTITY, parm_maxlen(), privdata::password, privdata::port, PrivData, smscconn::queued, privdata::quitting, privdata::receive_seq, privdata::received, smscconn::send_msg, privdata::send_seq, smscconn::shutdown, SMSCConn, privdata::socket, smscconn::start_conn, smscconn::stop_conn, privdata::stopped, privdata::username, and warning().

Referenced by smscconn_create().

02320 {
02321     PrivData *pdata;
02322     int ok;
02323     int maxlen;
02324 
02325     pdata = gw_malloc(sizeof(PrivData));
02326     conn->data = pdata;
02327     pdata->conn = conn;
02328    
02329     pdata->no_dlr = 0;
02330     pdata->quitting = 0;
02331     pdata->socket = -1;
02332     pdata->received = gwlist_create();
02333     pdata->inbuffer = octstr_create("");
02334     pdata->send_seq = 1;
02335     pdata->receive_seq = 0;
02336     pdata->outgoing_queue = gwlist_create();
02337     pdata->stopped = gwlist_create();
02338     gwlist_add_producer(pdata->outgoing_queue);
02339 
02340     if (conn->is_stopped)
02341       gwlist_add_producer(pdata->stopped);
02342 
02343     pdata->host = cfg_get(grp, octstr_imm("host"));
02344     if (cfg_get_integer(&(pdata->port), grp, octstr_imm("port")) == -1)
02345       pdata->port = 0;
02346     if (cfg_get_integer(&(pdata->our_port), grp, octstr_imm("our-port")) == -1)
02347       pdata->our_port = 0;
02348     pdata->username = cfg_get(grp, octstr_imm("smsc-username"));
02349     pdata->password = cfg_get(grp, octstr_imm("smsc-password"));
02350     pdata->my_number = cfg_get(grp, octstr_imm("my-number"));
02351     if (cfg_get_integer(&(pdata->keepalive), grp,octstr_imm("keepalive")) == -1)
02352         pdata->keepalive = 0;
02353 
02354     cfg_get_bool(&pdata->no_dlr, grp, octstr_imm("no-dlr"));
02355     
02356     /* Check that config is OK */
02357     ok = 1;
02358     if (pdata->host == NULL) {
02359         error(0,"CIMD2[%s]: Configuration file doesn't specify host",
02360               octstr_get_cstr(conn->id));
02361         ok = 0;
02362     }
02363     if (pdata->port == 0) {
02364         error(0,"CIMD2[%s]: Configuration file doesn't specify port",
02365               octstr_get_cstr(conn->id));
02366         ok = 0;
02367     }
02368     if (pdata->username == NULL) {
02369         error(0, "CIMD2[%s]: Configuration file doesn't specify username.",
02370               octstr_get_cstr(conn->id));
02371         ok = 0;
02372     }
02373     if (pdata->password == NULL) {
02374         error(0, "CIMD2[%s]: Configuration file doesn't specify password.",
02375               octstr_get_cstr(conn->id));
02376         ok = 0;
02377     }
02378 
02379     if (!ok) {
02380         cimd2_destroy(pdata);
02381         return -1;
02382     }
02383 
02384     conn->name = octstr_format("CIMD2:%s:%d:%s",
02385                      octstr_get_cstr(pdata->host),
02386                      pdata->port,
02387                      octstr_get_cstr(pdata->username));
02388 
02389 
02390     if (pdata->keepalive > 0) {
02391       debug("bb.sms.cimd2", 0, "CIMD2[%s]: Keepalive set to %ld seconds", 
02392             octstr_get_cstr(conn->id),
02393             pdata->keepalive);
02394         pdata->next_ping = time(NULL) + pdata->keepalive;
02395     }
02396 
02397     maxlen = parm_maxlen(P_USER_IDENTITY);
02398     if (octstr_len(pdata->username) > maxlen) {
02399         octstr_truncate(pdata->username, maxlen);
02400         warning(0, "CIMD2[%s]: Truncating username to %d chars", 
02401                 octstr_get_cstr(conn->id),
02402                 maxlen);
02403     }
02404 
02405     maxlen = parm_maxlen(P_PASSWORD);
02406     if (octstr_len(pdata->password) > maxlen) {
02407         octstr_truncate(pdata->password, maxlen);
02408         warning(0, "CIMD2[%s]: Truncating password to %d chars", 
02409                 octstr_get_cstr(conn->id),
02410                 maxlen);
02411     }
02412 
02413     pdata->io_thread = gwthread_create(io_thread, conn);
02414 
02415     if (pdata->io_thread == -1) {  
02416 
02417         error(0,"CIMD2[%s]: Couldn't start I/O thread.",
02418               octstr_get_cstr(conn->id));
02419         pdata->quitting = 1;
02420         gwthread_wakeup(pdata->io_thread);
02421         gwthread_join(pdata->io_thread);
02422         cimd2_destroy(pdata);
02423         return -1;  
02424     } 
02425 
02426     conn->send_msg = cimd2_add_msg_cb;
02427     conn->shutdown = cimd2_shutdown_cb;
02428     conn->queued = cimd2_queued_cb;
02429     conn->start_conn = cimd2_start_cb;
02430     conn->stop_conn = cimd2_stop_cb;
02431 
02432     return 0;
02433 }

Here is the call graph for this function:


Variable Documentation

int can_receive
 

Definition at line 348 of file smsc_cimd2.c.

int can_send
 

Definition at line 347 of file smsc_cimd2.c.

unsigned char cimd1
 

Definition at line 1025 of file smsc_cimd2.c.

Referenced by convert_cimd2_to_gsm(), and convert_gsm_to_cimd2().

unsigned char cimd2
 

Definition at line 1025 of file smsc_cimd2.c.

Referenced by convert_cimd2_to_gsm(), and convert_gsm_to_cimd2().

struct { ... } cimd2_errors[] [static]
 

Referenced by packet_display_error().

const { ... } cimd_combinations[] [static]
 

Referenced by convert_cimd2_to_gsm(), and convert_gsm_to_cimd2().

int code
 

Definition at line 921 of file smsc_cimd2.c.

Referenced by abort_delivery(), cimd2_accept_delivery_report_message(), convert_html_entity(), http_status_class(), octstr_url_decode(), ois_decode_submit_sm_result(), oisd_accept_delivery_report_message(), packet_display_error(), remove_session_data(), response_push_message(), send_bad_message_response(), tell_fatal_error(), ws_bc_add_function(), and xidris_parse_reply().

unsigned char gsm
 

Definition at line 1026 of file smsc_cimd2.c.

Referenced by charset_gsm_truncate(), and convert_cimd2_to_gsm().

int maxlen
 

Definition at line 214 of file smsc_cimd2.c.

Referenced by eat_int_parm(), octstr_set_bits(), and smsc_cimd2_create().

int maxval
 

Definition at line 216 of file smsc_cimd2.c.

int minval
 

Definition at line 216 of file smsc_cimd2.c.

name
 

Referenced by add_group(), cfg_dump(), cfg_get_multi_group(), cfg_get_single_group(), cfg_read(), cgwop_add(), cgwop_get(), change_header_value(), check_do_elements(), check_variable_name(), config_reload(), decode_bearer_indication(), do_pidfile(), drop_optional_header(), emi2_emimsg_send(), get_cookies(), get_do_element_name(), get_x_kannel_from_headers(), grp_dump(), gw_gethostbyname(), gwthread_create_real(), gwthread_shutdown(), header_is_called(), http_cgi_variable(), http_header_add(), http_header_combine(), http_header_find_all(), http_header_find_first_real(), http_header_get(), http_header_pack(), http_header_remove_all(), http_header_value(), lookup_keyword(), main(), octstr_dump_short(), open_file(), operation_name(), ota_tokenize_bookmarks(), packet_check_can_receive(), parse_array_element(), parse_attribute(), parse_data_element(), parse_document(), parse_element(), parse_fault_element(), parse_headers(), parse_member_element(), parse_methodcall_element(), parse_methodresponse_element(), parse_ota_syncsettings(), parse_param_element(), parse_params_element(), parse_signal(), parse_struct_element(), parse_url_value(), parse_value_element(), pass_field_name(), pass_optional_header(), read_test_ppg_config(), set_group_name(), smsbox_sendota_post(), soap_convert_token(), spawn_thread(), split_header_list(), type_is(), urltrans_find_username(), ws_bc_add_function(), ws_bc_add_pragma_user_agent_property(), ws_bc_add_pragma_user_agent_property_and_scheme(), ws_expr_call(), ws_function(), ws_function_hash(), ws_hash_get(), ws_hash_put(), ws_stdlib_function(), ws_variable_define(), ws_variable_lookup(), wsp_cap_count(), wsp_cap_get_data(), wsp_cap_unpack_list(), xmlrpc_add_member(), xmlrpc_add_member_scalar(), xmlrpc_call_create(), xmlrpc_doc_create_call(), xmlrpc_get_member(), xmlrpc_get_member_content(), xmlrpc_get_member_type(), and yyparse().

int number
 

Definition at line 213 of file smsc_cimd2.c.

Referenced by blacklisted(), check_startmark(), does_prefix_match(), gwthread_shutdown(), handle_get(), normalize_number(), number_to_cstr(), number_to_string(), octstr_parse_double(), octstr_parse_long(), packet_get_parm(), packet_parse_header(), parse_charset(), prefix_allowed(), startmark(), wap_push_ppg_pushuser_client_phone_number_acceptable(), and whitelisted().

const { ... } operations[] [static]
 

Referenced by operation_can_receive(), operation_can_send(), operation_find(), and operation_name().

const { ... } parameters[] [static]
 

Referenced by packet_check_parameter(), parm_in_range(), parm_index(), parm_maxlen(), parm_name(), and parm_type().

char* text
 

Definition at line 922 of file smsc_cimd2.c.

Referenced by at2_pdu_decode_deliver_sm(), bb_alog_sms(), brunet_receive_sms(), cimd2_accept_message(), cimd_receive_msg(), clickatell_receive_sms(), convert_cimd2_to_gsm(), convert_gsm_to_cimd2(), create_onetrans(), get_pattern(), get_variable(), get_x_kannel_from_xml(), handle_submit(), hash_create(), kannel_receive_sms(), obey_request_thread(), octstr_shrink_blanks(), octstr_strip_blanks(), octstr_strip_char(), octstr_strip_crlfs(), octstr_strip_nonalphanums(), only_blanks(), pack_quoted_string(), packet_display_error(), packet_encode_message(), parse_variable(), set_charset(), smsbox_req_handle(), smsbox_req_sendsms(), smsbox_sendsms_post(), wml_init(), wsp_pack_constrained_value(), wsp_pack_quoted_text(), wsp_pack_text(), and xidris_receive_sms().

int type
 

Definition at line 215 of file smsc_cimd2.c.

Referenced by add_accept_headers(), at2_pdu_decode(), at2_pdu_decode_report_sm(), brunet_receive_sms(), error_converting(), get_x_kannel_from_xml(), handle_operation(), handle_push_message(), handle_reply(), http_header_get_content_type(), http_type_accepted(), main(), memorybuffer_has_rawmessage(), mime_entity_dump_real(), msg_to_bb(), numhash_create(), obey_request(), pap_convert_content(), parse_ext_qualifiers(), qualifiers(), radius_pdu_unpack(), radius_type_convert(), receive_reply(), send_abort(), smasi_pdu_unpack(), smpp_pdu_unpack(), smsbox_sendota_post(), smsbox_sendsms_post(), smsbox_xmlrpc_post(), smsc_http_create(), smsc_open(), store_init(), transform_message(), unpack_parameter(), unpack_tpis(), update_table(), update_tables(), url_result_thread(), wap_event_create_real(), wap_event_name(), wbmp_create(), ws_expr_unary(), ws_yy_lex(), xmlrpc_add_element_scalar(), xmlrpc_add_member_scalar(), xmlrpc_create_scalar_value(), xmlrpc_doc_add_scalar(), and xmlrpc_value_get_type_smart().

See file LICENSE for details about the license agreement for using, modifying, copying or deriving work from this software.