⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 smsc_cimd2.c

📁 The Kannel Open Source WAP and SMS gateway works as both an SMS gateway, for implementing keyword b
💻 C
📖 第 1 页 / 共 5 页
字号:
    unsigned char minpacket[sizeof("sOO:SSSte")];    packet = gw_malloc(sizeof(*packet));    packet->operation = operation;    packet->seq = seq;    sprintf(minpacket, STX_str "%02d:%03d" TAB_str ETX_str, operation, seq);    packet->data = octstr_create(minpacket);    return packet;}/* Add a parameter to the end of packet */static void packet_add_parm(struct packet *packet, int parmtype,                            int parmno, Octstr *value, SMSCConn *conn){    unsigned char parmh[sizeof("tPPP:")];    long position;    long len;    int copied = 0;    len = octstr_len(value);    gw_assert(packet != NULL);    gw_assert(parm_type(parmno) == parmtype);    if (len > parm_maxlen(parmno)) {        warning(0, "CIMD2[%s]: %s parameter too long, truncating from "                "%ld to %ld characters",                octstr_get_cstr(conn->id),                 parm_name(parmno),                len,                 (long) parm_maxlen(parmno));        value = octstr_copy(value, 0, parm_maxlen(parmno));        copied = 1;    }    /* There's a TAB and ETX at the end; insert it before those.     * The new parameter will come with a new starting TAB. */    position = octstr_len(packet->data) - 2;    sprintf(parmh, TAB_str "%03d:", parmno);    octstr_insert_data(packet->data, position, parmh, strlen(parmh));    octstr_insert(packet->data, value, position + strlen(parmh));    if (copied)        octstr_destroy(value);}/* Add a String parameter to the packet */static void packet_add_string_parm(struct packet *packet, int parmno, Octstr *value, SMSCConn *conn){    packet_add_parm(packet, P_STRING, parmno, value, conn);}/* Add an Address parameter to the packet */static void packet_add_address_parm(struct packet *packet, int parmno, Octstr *value, SMSCConn *conn){    gw_assert(octstr_check_range(value, 0, octstr_len(value), isphonedigit));    packet_add_parm(packet, P_ADDRESS, parmno, value, conn);}/* Add an SMS parameter to the packet.  The caller is expected to have done * the translation to the GSM character set already.  */static void packet_add_sms_parm(struct packet *packet, int parmno, Octstr *value, SMSCConn *conn){    packet_add_parm(packet, P_SMS, parmno, value, conn);}/* There is no function for adding a Time parameter to the packet, because * the format makes Time parameters useless for us.  If you find that you * need to use them, then also add code for querying the SMS center timestamp * and using that for synchronization.  And beware of DST changes. *//* Add a Hexadecimal parameter to the packet */static void packet_add_hex_parm(struct packet *packet, int parmno, Octstr *value, SMSCConn *conn){    value = octstr_duplicate(value);    octstr_binary_to_hex(value, 1);   /* 1 for uppercase hex, i.e. A .. F */    packet_add_parm(packet, P_HEX, parmno, value, conn);    octstr_destroy(value);}/* Add an Integer parameter to the packet */static void packet_add_int_parm(struct packet *packet, int parmno, long value, SMSCConn *conn){    unsigned char buf[128];    Octstr *valuestr;    gw_assert(parm_in_range(parmno, value));    sprintf(buf, "%ld", value);    valuestr = octstr_create(buf);    packet_add_parm(packet, P_INT, parmno, valuestr, conn);    octstr_destroy(valuestr);}static void packet_set_checksum(struct packet *packet){    Octstr *data;    int checksum;    long pos, len;    unsigned char buf[16];    gw_assert(packet != NULL);    data = packet->data;    if (octstr_get_char(data, octstr_len(data) - 2) != TAB) {        /* Packet already has checksum; kill it. */        octstr_delete(data, octstr_len(data) - 3, 2);    }    gw_assert(octstr_get_char(data, octstr_len(data) - 2) == TAB);    /* Sum all the way up to the last TAB */    checksum = 0;    for (pos = 0, len = octstr_len(data); pos < len - 1; pos++) {        checksum += octstr_get_char(data, pos);        checksum &= 0xff;    }    sprintf(buf, "%02X", checksum);    octstr_insert_data(data, len - 1, buf, 2);}static void packet_set_sequence(struct packet *packet, int seq){    unsigned char buf[16];    gw_assert(packet != NULL);    gw_assert(seq >= 0);    gw_assert(seq < 256);    sprintf(buf, "%03d", seq);    /* Start at 4 to skip the <STX> ZZ: part of the header. */    octstr_set_char(packet->data, 4, buf[0]);    octstr_set_char(packet->data, 5, buf[1]);    octstr_set_char(packet->data, 6, buf[2]);    packet->seq = seq;}static struct packet *packet_encode_message(Msg *msg, Octstr *sender_prefix, SMSCConn *conn){    struct packet *packet;    PrivData *pdata = conn->data;    Octstr *text;    int spaceleft;    long truncated;    int dcs = 0;    int setvalidity = 0;    gw_assert(msg != NULL);    gw_assert(msg->type == sms);    gw_assert(msg->sms.receiver != NULL);    dcs = fields_to_dcs(msg, (msg->sms.alt_dcs != -1 ?         msg->sms.alt_dcs : conn->alt_dcs));    if (msg->sms.sender == NULL)        msg->sms.sender = octstr_create("");    if (!parm_valid_address(msg->sms.receiver)) {        warning(0, "CIMD2[%s]: non-digits in destination phone number '%s', discarded",                octstr_get_cstr(conn->id),                octstr_get_cstr(msg->sms.receiver));        return NULL;    }    packet = packet_create(SUBMIT_MESSAGE, BOGUS_SEQUENCE);    packet_add_address_parm(packet, P_DESTINATION_ADDRESS, msg->sms.receiver, conn);    /* CIMD2 interprets the originating address as a sub-address to     * our connection number (so if the connection is "400" and we     * fill in "600" as the sender number, the user sees "400600").     * Since we have no way to ask what this number is, it has to     * be configured. */    /* Quick and dirty check to see if we are using alphanumeric sender */    if (parm_valid_address(msg->sms.sender)) {        /* We are not, so send in the usual way */        /* Speed up the default case */        if (octstr_len(sender_prefix) == 0) {            packet_add_address_parm(packet, P_ORIGINATING_ADDRESS,msg->sms.sender, conn);        }        else if (octstr_compare(sender_prefix, octstr_imm("never")) != 0) {            if (octstr_ncompare(sender_prefix, msg->sms.sender,                                octstr_len(sender_prefix)) == 0) {                Octstr *sender;                sender = octstr_copy(msg->sms.sender,                                     octstr_len(sender_prefix), octstr_len(msg->sms.sender));                packet_add_address_parm(packet, P_ORIGINATING_ADDRESS, sender, conn);                octstr_destroy(sender);            } else {                warning(0, "CIMD2[%s]: Sending message with originating address <%s>, "                        "which does not start with the sender-prefix.",                        octstr_get_cstr(conn->id),                        octstr_get_cstr(msg->sms.sender));            }        }    }    else {        /* The test above to check if sender was all digits failed, so assume we want alphanumeric sender */        packet_add_string_parm(packet, P_ALPHANUMERIC_ORIGINATING_ADDRESS,msg->sms.sender, conn);    }    /* Add the validity period if necessary.  This sets the relative validity     * period as this is the description of the "validity" parameter of the     * sendsms interface.     *     * Convert from minutes to GSM 03.40 specification (section 9.2.3.12).     * 0-143   = 0 to 12 hours in 5 minute increments.     * 144-167 = 12hrs30min to 24hrs in 30 minute increments.     * 168-196 = 2days to 30days in 1 day increments.     * 197-255 = 5weeks to 63weeks in 1 week increments.     *     * This code was copied from smsc_at2.c.     */    if (msg->sms.validity >= 0) {      if (msg->sms.validity > 635040)	setvalidity = 255;      if (msg->sms.validity >= 50400 && msg->sms.validity <= 635040)	setvalidity = (msg->sms.validity - 1) / 7 / 24 / 60 + 192 + 1;      if (msg->sms.validity > 43200 && msg->sms.validity < 50400)	setvalidity = 197;      if (msg->sms.validity >= 2880 && msg->sms.validity <= 43200)	setvalidity = (msg->sms.validity - 1) / 24 / 60 + 166 + 1;      if (msg->sms.validity > 1440 && msg->sms.validity < 2880)	setvalidity = 168;      if (msg->sms.validity >= 750 && msg->sms.validity <= 1440)	setvalidity = (msg->sms.validity - 720 - 1) / 30 + 143 + 1;      if (msg->sms.validity > 720 && msg->sms.validity < 750)	setvalidity = 144;      if (msg->sms.validity >= 5 && msg->sms.validity <= 720)	setvalidity = (msg->sms.validity - 1) / 5 - 1 + 1;      if (msg->sms.validity < 5)	setvalidity = 0;      packet_add_int_parm(packet, P_VALIDITY_PERIOD_RELATIVE, setvalidity, conn);    }    /* Explicitly ask not to get status reports.     * If we do not do this, the server's default might be to     * send status reports in some cases, and we don't do anything     * with those reports anyway. */    /* ask for the delivery reports if needed*/    if (!pdata->no_dlr)        if (DLR_IS_SUCCESS_OR_FAIL(msg->sms.dlr_mask))            packet_add_int_parm(packet, P_STATUS_REPORT_REQUEST, 14, conn);    	else            packet_add_int_parm(packet, P_STATUS_REPORT_REQUEST, 0, conn);    else if( pdata->no_dlr && DLR_IS_SUCCESS_OR_FAIL(msg->sms.dlr_mask))     	warning(0, "CIMD2[%s]: dlr request make no sense while no-dlr set to true",    		 octstr_get_cstr(conn->id));    /* Turn off reply path as default.     * This avoids phones automatically asking for a reply     */    if (msg->sms.rpi > 0)	packet_add_int_parm(packet, P_REPLY_PATH, 1, conn);    else    	packet_add_int_parm(packet, P_REPLY_PATH, 0, conn);    /* Use binfo to set the tariff class */    if (octstr_len(msg->sms.binfo))	packet_add_parm(packet, P_INT, P_TARIFF_CLASS, msg->sms.binfo, conn);    /* Set the protocol identifier if requested */    if (msg->sms.pid > 0)        packet_add_int_parm(packet, P_PROTOCOL_IDENTIFIER, msg->sms.pid, conn); 	/* If there are more messages to the same destination, then set the	* More Messages to Send flag. This allow faster delivery of many messages 	* to the same destination	*/    if (msg->sms.msg_left > 0)        packet_add_int_parm(packet, P_MORE_MESSAGES_TO_SEND, 1, conn);    else        packet_add_int_parm(packet, P_MORE_MESSAGES_TO_SEND, 0, conn);	    truncated = 0;    spaceleft = 140;    if (octstr_len(msg->sms.udhdata)) {        /* udhdata will be truncated and warned about if         * it does not fit. */        packet_add_hex_parm(packet, P_USER_DATA_HEADER, msg->sms.udhdata, conn);    }    if (msg->sms.coding == DC_7BIT || msg->sms.coding == DC_UNDEF)        spaceleft = spaceleft * 8 / 7;    if (spaceleft < 0)        spaceleft = 0;    text = octstr_duplicate(msg->sms.msgdata);    if (octstr_len(text) > 0 && spaceleft == 0) {        warning(0, "CIMD2[%s]: message filled up with UDH, no room for message text",                octstr_get_cstr(conn->id));    } else if (msg->sms.coding == DC_8BIT || msg->sms.coding == DC_UCS2) {        if (octstr_len(text) > spaceleft) {            truncated = octstr_len(text) - spaceleft;            octstr_truncate(text, spaceleft);        }        packet_add_hex_parm(packet, P_USER_DATA_BINARY, text, conn);    } else {        /* Going from latin1 to GSM to CIMD2 may seem like a         * detour, but it's the only way to get all the escape         * codes right. */        charset_latin1_to_gsm(text);        truncated = charset_gsm_truncate(text, spaceleft);        convert_gsm_to_cimd2(text);        packet_add_sms_parm(packet, P_USER_DATA, text, conn);    }    if (dcs != 0)        packet_add_int_parm(packet, P_DATA_CODING_SCHEME, dcs, conn);    if (truncated > 0) {        warning(0, "CIMD2[%s]: truncating message text to fit in %d characters.",                 octstr_get_cstr(conn->id),                spaceleft);    }    octstr_destroy(text);    return packet;}/***************************************************************************//* Protocol functions.  These implement various transactions.              *//***************************************************************************//* Give this packet a proper sequence number for sending. */static void packet_set_send_sequence(struct packet *packet, PrivData *pdata){    gw_assert(pdata != NULL);    /* LOGIN packets always have sequence number 001 */    if (packet->operation == LOGIN)        pdata->send_seq = 1;    /* Send sequence numbers are always odd, receiving are always even */    gw_assert(pdata->send_seq % 2 == 1);    packet_set_sequence(packet, pdata->send_seq);    pdata->send_seq += 2;    if (pdata->send_seq > 256)        pdata->send_seq = 1;}static struct packet *cimd2_get_packet(PrivData *pdata, Octstr **ts){    struct packet *packet = NULL;    gw_assert(pdata != NULL);    /* If packet is already available, don't try to read anything */    packet = packet_extract(pdata->inbuffer, pdata->conn);    while (packet == NULL) {        if (read_available(pdata->socket, RESPONSE_TIMEOUT) != 1) {            warning(0, "CIMD2[%s]: SMSC is not responding",                    octstr_get_cstr(pdata->conn->id));            return NULL;        }        if (octstr_append_from_socket(pdata->inbuffer, pdata->socket) <= 0) {            error(0, "CIMD2[%s]: cimd2_get_packet: read failed",                  octstr_get_cstr(pdata->conn->id));            return NULL;        }        packet = packet_extract(pdata->inbuffer, pdata->conn);    }    packet_check(packet,pdata->conn);    packet_check_can_receive(packet,pdata->conn);    debug("bb.sms.cimd2", 0, "CIMD2[%s]: received: <%s>",          octstr_get_cstr(pdata->conn->id),           octstr_get_cstr(packet->data));    if (ts)        *ts = packet_get_parm(packet,P_MC_TIMESTAMP);    if (pdata->keepalive > 0)        pdata->next_ping = time(NULL) + pdata->keepalive;    return packet;}/* Acknowledge a request.  The CIMD 2 spec only defines positive responses * to the server, because the server is perfect. */static void cimd2_send_response(struct packet *request, PrivData *pdata){    struct packet *response;    gw_assert(request != NULL);    gw_assert(request->operation < RESPONSE);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -