📄 smsc_cimd2.c
字号:
dlen - negative, gw_isdigit)) { warning(0, "CIMD2[%s]: packet has '%s' parameter with non-integer contents", octstr_get_cstr(conn->id), parameters[i].name); errors++; } if (octstr_parse_long(&value, data, dpos, 10) >= 0 && (value < parameters[i].minval || value > parameters[i].maxval)) { warning(0, "CIMD2[%s]: packet has '%s' parameter out of range (value %ld, min %d, max %d)", octstr_get_cstr(conn->id), parameters[i].name, value, parameters[i].minval, parameters[i].maxval); errors++; } break; case P_TIME: if (!octstr_check_range(data, dpos, dlen, gw_isdigit)) { warning(0, "CIMD2[%s]: packet has '%s' parameter with non-digit contents", octstr_get_cstr(conn->id), parameters[i].name); errors++; } break; case P_ADDRESS: if (!octstr_check_range(data, dpos, dlen, isphonedigit)) { warning(0, "CIMD2[%s]: packet has '%s' parameter with non phone number contents", octstr_get_cstr(conn->id), parameters[i].name); errors++; } break; case P_HEX: if (!octstr_check_range(data, dpos, dlen, gw_isxdigit)) { warning(0, "CIMD2[%s]: packet has '%s' parameter with non-hex contents", octstr_get_cstr(conn->id), parameters[i].name); errors++; } if (dlen % 2 != 0) { warning(0, "CIMD2[%s]: packet has odd-length '%s' parameter", octstr_get_cstr(conn->id), parameters[i].name); errors++; } break; case P_SMS: case P_STRING: /* nothing to check */ break; } if (errors > 0) return -1; return 0;}/* Check the packet against the CIMD 2 spec, generating log entries as * necessary. Return -1 if anything was wrong, otherwise 0. *//* TODO: Check if parameters found actually belong in the packet type */static int packet_check(struct packet *packet, SMSCConn *conn){ int errors = 0; long pos, len, next; Octstr *data; gw_assert(packet != NULL); data = packet->data; if (octstr_search_char(data, 0, 0) >= 0) { /* CIMD2 spec does not allow NUL bytes in a packet */ warning(0, "CIMD2[%s]: packet contains NULs", octstr_get_cstr(conn->id)); errors++; } /* Assume the packet starts with STX and ends with ETX, * because we parsed it that way in the first place. */ errors += (packet_check_header(packet,conn) < 0); /* Parameters are separated by tabs. After the last parameter * there is a tab, an optional two-digit checksum, and the ETX. * Check each parameter in turn, by skipping from tab to tab. */ len = octstr_len(data); /* Start at the first tab, wherever it is, so that we can still * check parameters if the header was weird. */ pos = octstr_search_char(data, TAB, 0); for ( ; pos >= 0; pos = next) { next = octstr_search_char(data, TAB, pos + 1); if (next >= 0) { errors += (packet_check_parameter(packet, pos, next - pos, conn) < 0); } else { /* Check if the checksum has the right format. Don't * check the sum itself here, that will be done in a * separate call later. */ /* There are two valid formats: TAB ETX (no checksum) * and TAB digit digit ETX. We already know the TAB * and the ETX are there. */ if (!(octstr_len(data) - pos == 2 || (octstr_len(data) - pos == 4 && octstr_check_range(data, pos + 1, 2, gw_isxdigit)))) { warning(0, "CIMD2[%s]: packet checksum in wrong format", octstr_get_cstr(conn->id)); errors++; } } } if (errors > 0) { octstr_dump(packet->data, 0); return -1; } return 0;}static void packet_check_can_receive(struct packet *packet, SMSCConn *conn){ gw_assert(packet != NULL); if (!operation_can_receive(packet->operation)) { Octstr *name = operation_name(packet->operation); warning(0, "CIMD2[%s]: SMSC sent us %s request", octstr_get_cstr(conn->id), octstr_get_cstr(name)); octstr_destroy(name); }}/* Table of known error codes */static struct{ int code; unsigned char *text;}cimd2_errors[] = { { 0, "No error" }, { 1, "Unexpected operation" }, { 2, "Syntax error" }, { 3, "Unsupported parameter error" }, { 4, "Connection to message center lost" }, { 5, "No response from message center" }, { 6, "General system error" }, { 7, "Cannot find information" }, { 8, "Parameter formatting error" }, { 9, "Requested operation failed" }, /* LOGIN error codes */ { 100, "Invalid login" }, { 101, "Incorrect access type" }, { 102, "Too many users with this login id" }, { 103, "Login refused by message center" }, /* SUBMIT MESSAGE error codes */ { 300, "Incorrect destination address" }, { 301, "Incorrect number of destination addresses" }, { 302, "Syntax error in user data parameter" }, { 303, "Incorrect bin/head/normal user data parameter combination" }, { 304, "Incorrect data coding scheme parameter usage" }, { 305, "Incorrect validity period parameters usage" }, { 306, "Incorrect originator address usage" }, { 307, "Incorrect pid paramterer usage" }, { 308, "Incorrect first delivery parameter usage" }, { 309, "Incorrect reply path usage" }, { 310, "Incorrect status report request parameter usage" }, { 311, "Incorrect cancel enabled parameter usage" }, { 312, "Incorrect priority parameter usage" }, { 313, "Incorrect tariff class parameter usage" }, { 314, "Incorrect service description parameter usage" }, { 315, "Incorrect transport type parameter usage" }, { 316, "Incorrect message type parameter usage" }, { 318, "Incorrect mms parameter usage" }, { 319, "Incorrect operation timer parameter usage" }, /* ENQUIRE MESSAGE STATUS error codes */ { 400, "Incorrect address parameter usage" }, { 401, "Incorrect scts parameter usage" }, /* DELIVERY REQUEST error codes */ { 500, "Incorrect scts parameter usage" }, { 501, "Incorrect mode parameter usage" }, { 502, "Incorrect parameter combination" }, /* CANCEL MESSAGE error codes */ { 600, "Incorrect scts parameter usage" }, { 601, "Incorrect address parameter usage" }, { 602, "Incorrect mode parameter usage" }, { 603, "Incorrect parameter combination" }, /* SET error codes */ { 800, "Changing password failed" }, { 801, "Changing password not allowed" }, /* GET error codes */ { 900, "Unsupported item requested" }, { -1, NULL }};static int packet_display_error(struct packet *packet, SMSCConn *conn){ int code; Octstr *text = NULL; Octstr *opname = NULL; code = packet_get_int_parm(packet, P_ERROR_CODE); text = packet_get_string_parm(packet, P_ERROR_TEXT); if (code <= 0) { octstr_destroy(text); return 0; } if (text == NULL) { /* No error text. Try to find it in the table. */ int i; for (i = 0; cimd2_errors[i].text != NULL; i++) { if (cimd2_errors[i].code == code) { text = octstr_create(cimd2_errors[i].text); break; } } } if (text == NULL) { /* Still no error text. Make one up. */ text = octstr_create("Unknown error"); } opname = operation_name(packet->operation); error(0, "CIMD2[%s]: %s contained error message:", octstr_get_cstr(conn->id), octstr_get_cstr(opname)); error(0, "code %03d: %s", code, octstr_get_cstr(text)); octstr_destroy(opname); octstr_destroy(text); return code;}/* Table of special combinations, for convert_gsm_to_latin1. *//* Each cimd1, cimd2 pair is mapped to a character in the GSM default * character set. */static const struct{ unsigned char cimd1, cimd2; unsigned char gsm;}cimd_combinations[] = { { 'O', 'a', 0 }, /* @ */ { 'L', '-', 1 }, /* Pounds sterling */ { 'Y', '-', 3 }, /* Yen */ { 'e', '`', 4 }, /* egrave */ { 'e', '\'', 5 }, /* eacute */ { 'u', '`', 6 }, /* ugrave */ { 'i', '`', 7 }, /* igrave */ { 'o', '`', 8 }, /* ograve */ { 'C', ',', 9 }, /* C cedilla */ { 'O', '/', 11 }, /* Oslash */ { 'o', '/', 12 }, /* oslash */ { 'A', '*', 14 }, /* Aring */ { 'a', '*', 15 }, /* aring */ { 'g', 'd', 16 }, /* greek delta */ { '-', '-', 17 }, /* underscore */ { 'g', 'f', 18 }, /* greek phi */ { 'g', 'g', 19 }, /* greek gamma */ { 'g', 'l', 20 }, /* greek lambda */ { 'g', 'o', 21 }, /* greek omega */ { 'g', 'p', 22 }, /* greek pi */ { 'g', 'i', 23 }, /* greek psi */ { 'g', 's', 24 }, /* greek sigma */ { 'g', 't', 25 }, /* greek theta */ { 'g', 'x', 26 }, /* greek xi */ { 'X', 'X', 27 }, /* escape */ { 'A', 'E', 28 }, /* AE ligature */ { 'a', 'e', 29 }, /* ae ligature */ { 's', 's', 30 }, /* german double s */ { 'E', '\'', 31 }, /* Eacute */ { 'q', 'q', '"' }, { 'o', 'x', 36 }, /* international currency symbol */ { '!', '!', 64 }, /* inverted ! */ { 'A', '"', 91 }, /* Adieresis */ { 'O', '"', 92 }, /* Odieresis */ { 'N', '~', 93 }, /* N tilde */ { 'U', '"', 94 }, /* Udieresis */ { 's', 'o', 95 }, /* section mark */ { '?', '?', 96 }, /* inverted ? */ { 'a', '"', 123 }, /* adieresis */ { 'o', '"', 124 }, /* odieresis */ { 'n', '~', 125 }, /* n tilde */ { 'u', '"', 126 }, /* udieresis */ { 'a', '`', 127 }, /* agrave */ { 0, 0, 0 }};/* Convert text in the CIMD2 User Data format to the GSM default * character set. * CIMD2 allows 8-bit characters in this format; they map directly * to the corresponding ISO-8859-1 characters. Since we are heading * toward that character set in the end, we don't bother converting * those to GSM. */static void convert_cimd2_to_gsm(Octstr *text, SMSCConn *conn){ long pos, len; int cimd1, cimd2; int c; int i; /* CIMD2 uses four single-character mappings that do not map * to themselves: * '@' from 64 to 0, '$' from 36 to 2, ']' from 93 to 14 (A-ring), * and '}' from 125 to 15 (a-ring). * Other than those, we only have to worry about the escape * sequences introduced by _ (underscore). */ len = octstr_len(text); for (pos = 0; pos < len; pos++) { c = octstr_get_char(text, pos); if (c == '@') octstr_set_char(text, pos, 0); else if (c == '$') octstr_set_char(text, pos, 2); else if (c == ']') octstr_set_char(text, pos, 14); else if (c == '}') octstr_set_char(text, pos, 15); else if (c == '_' && pos + 2 < len) { cimd1 = octstr_get_char(text, pos + 1); cimd2 = octstr_get_char(text, pos + 2); for (i = 0; cimd_combinations[i].cimd1 != 0; i++) { if (cimd_combinations[i].cimd1 == cimd1 && cimd_combinations[i].cimd2 == cimd2) break; } if (cimd_combinations[i].cimd1 == 0) warning(0, "CIMD2[%s]: Encountered unknown " "escape code _%c%c, ignoring.", octstr_get_cstr(conn->id), cimd1, cimd2); else { octstr_delete(text, pos, 2); octstr_set_char(text, pos, cimd_combinations[i].gsm); len = octstr_len(text); } } }}/* Convert text in the GSM default character set to the CIMD2 User Data * format, which is a representation of the GSM default character set * in the lower 7 bits of ISO-8859-1. (8-bit characters are also * allowed, but it's just as easy not to use them.) */static void convert_gsm_to_cimd2(Octstr *text){ long pos, len; len = octstr_len(text); for (pos = 0; pos < len; pos++) { int c, i; c = octstr_get_char(text, pos); /* If c is not in the GSM alphabet at this point, * the caller did something badly wrong. */ gw_assert(c >= 0); gw_assert(c < 128); for (i = 0; cimd_combinations[i].cimd1 != 0; i++) { if (cimd_combinations[i].gsm == c) break; } if (cimd_combinations[i].gsm == c) { /* Escape sequence */ octstr_insert_data(text, pos, "_ ", 2); pos += 2; len += 2; octstr_set_char(text, pos - 1, cimd_combinations[i].cimd1); octstr_set_char(text, pos, cimd_combinations[i].cimd2); } else if (c == 2) { /* The dollar sign is the only GSM character that * does not have a CIMD escape sequence and does not * map to itself. */ octstr_set_char(text, pos, '$'); } }}/***************************************************************************//* Packet encoding functions. They do not allow the creation of invalid *//* CIMD 2 packets. *//***************************************************************************//* Build a new packet struct with this operation code and sequence number. */static struct packet *packet_create(int operation, int seq){ struct packet *packet;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -