ofono/src/smsutil.h

601 lines
16 KiB
C

/*
*
* oFono - Open Source Telephony
*
* Copyright (C) 2008-2011 Intel Corporation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#define CBS_MAX_GSM_CHARS 93
#define SMS_MSGID_LEN 20
enum sms_type {
SMS_TYPE_DELIVER = 0,
SMS_TYPE_DELIVER_REPORT_ACK,
SMS_TYPE_DELIVER_REPORT_ERROR,
SMS_TYPE_STATUS_REPORT,
SMS_TYPE_SUBMIT,
SMS_TYPE_SUBMIT_REPORT_ACK,
SMS_TYPE_SUBMIT_REPORT_ERROR,
SMS_TYPE_COMMAND
};
/* 23.040 Section 9.1.2.5 */
enum sms_number_type {
SMS_NUMBER_TYPE_UNKNOWN = 0,
SMS_NUMBER_TYPE_INTERNATIONAL = 1,
SMS_NUMBER_TYPE_NATIONAL = 2,
SMS_NUMBER_TYPE_NETWORK_SPECIFIC = 3,
SMS_NUMBER_TYPE_SUBSCRIBER = 4,
SMS_NUMBER_TYPE_ALPHANUMERIC = 5,
SMS_NUMBER_TYPE_ABBREVIATED = 6,
SMS_NUMBER_TYPE_RESERVED = 7
};
/* 23.040 Section 9.1.2.5 */
enum sms_numbering_plan {
SMS_NUMBERING_PLAN_UNKNOWN = 0,
SMS_NUMBERING_PLAN_ISDN = 1,
SMS_NUMBERING_PLAN_DATA = 3,
SMS_NUMBERING_PLAN_TELEX = 4,
SMS_NUMBERING_PLAN_SC1 = 5,
SMS_NUMBERING_PLAN_SC2 = 6,
SMS_NUMBERING_PLAN_NATIONAL = 8,
SMS_NUMBERING_PLAN_PRIVATE = 9,
SMS_NUMBERING_PLAN_ERMES = 10,
SMS_NUMBERING_PLAN_RESERVED = 15
};
enum sms_validity_period_format {
SMS_VALIDITY_PERIOD_FORMAT_ABSENT = 0,
SMS_VALIDITY_PERIOD_FORMAT_ENHANCED = 1,
SMS_VALIDITY_PERIOD_FORMAT_RELATIVE = 2,
SMS_VALIDITY_PERIOD_FORMAT_ABSOLUTE = 3,
};
enum sms_st {
SMS_ST_COMPLETED_RECEIVED = 0x0,
SMS_ST_COMPLETED_UNABLE_TO_CONFIRM = 0x1,
SMS_ST_COMPLETED_REPLACED = 0x2,
SMS_ST_COMPLETED_LAST = 0x1F,
SMS_ST_TEMPORARY_CONGESTION = 0x20,
SMS_ST_TEMPORARY_SME_BUSY = 0x21,
SMS_ST_TEMPORARY_NO_RESPONSE = 0x22,
SMS_ST_TEMPORARY_SERVICE_REJECTED = 0x23,
SMS_ST_TEMPORARY_QOS_UNAVAILABLE = 0x24,
SMS_ST_TEMPORARY_SME_ERROR = 0x25,
SMS_ST_TEMPORARY_LAST = 0x2F,
SMS_ST_PERMANENT_RP_ERROR = 0x40,
SMS_ST_PERMANENT_INVALID_DESTINATION = 0x41,
SMS_ST_PERMANENT_CONNECTION_REJECTED = 0x42,
SMS_ST_PERMANENT_NOT_OBTAINABLE = 0x43,
SMS_ST_PERMANENT_QOS_UNAVAILABLE = 0x44,
SMS_ST_PERMANENT_INTERWORKING_UNAVAILABLE = 0x45,
SMS_ST_PERMANENT_VALIDITY_PERIOD_EXPIRED = 0x46,
SMS_ST_PERMANENT_DELETED = 0x47,
SMS_ST_PERMANENT_SC_ADMIN_DELETED = 0x48,
SMS_ST_PERMANENT_SM_DOES_NOT_EXIST = 0x49,
SMS_ST_PERMANENT_LAST = 0x4F,
SMS_ST_TEMPFINAL_CONGESTION = 0x60,
SMS_ST_TEMPFINAL_SME_BUSY = 0x61,
SMS_ST_TEMPFINAL_NO_RESPONSE = 0x62,
SMS_ST_TEMPFINAL_SERVICE_REJECTED = 0x63,
SMS_ST_TEMPFINAL_QOS_UNAVAILABLE = 0x64,
SMS_ST_TEMPFINAL_SME_ERROR = 0x65,
SMS_ST_TEMPFINAL_LAST = 0x6F,
};
enum sms_ct {
SMS_CT_ENQUIRY = 0,
SMS_CT_CANCEL_SRR = 1,
SMS_CT_DELETE_SM = 2,
SMS_CT_ENABLE_SRR = 3
};
enum sms_iei {
SMS_IEI_CONCATENATED_8BIT = 0x00,
SMS_IEI_SPECIAL_MESSAGE_INDICATION = 0x01,
SMS_IEI_APPLICATION_ADDRESS_8BIT = 0x04,
SMS_IEI_APPLICATION_ADDRESS_16BIT = 0x05,
SMS_IEI_SMSC_CONTROL_PARAMETERS = 0x06,
SMS_IEI_UDH_SOURCE_INDICATOR = 0x07,
SMS_IEI_CONCATENATED_16BIT = 0x08,
SMS_IEI_WCMP = 0x09,
SMS_IEI_TEXT_FORMAT = 0x0A,
SMS_IEI_PREDEFINED_SOUND = 0x0B,
SMS_IEI_USER_DEFINED_SOUND = 0x0C,
SMS_IEI_PREDEFINED_ANIMATION = 0x0D,
SMS_IEI_LARGE_ANIMATION = 0x0E,
SMS_IEI_SMALL_ANIMATION = 0x0F,
SMS_IEI_LARGE_PICTURE = 0x10,
SMS_IEI_SMALL_PICTURE = 0x11,
SMS_IEI_VARIABLE_PICTURE = 0x12,
SMS_IEI_USER_PROMPT_INDICATOR = 0x13,
SMS_IEI_EXTENDED_OBJECT = 0x14,
SMS_IEI_REUSED_EXTENDED_OBJECT = 0x15,
SMS_IEI_COMPRESSION_CONTROL = 0x16,
SMS_IEI_OBJECT_DISTRIBUTION_INDICATOR = 0x17,
SMS_IEI_STANDARD_WVG_OBJECT = 0x18,
SMS_IEI_CHARACTER_SIZE_WVG_OBJECT = 0x19,
SMS_IEI_EXTENDED_OBJECT_DATA_REQUEST_COMMAND = 0x1A,
SMS_IEI_RFC822_EMAIL_HEADER = 0x20,
SMS_IEI_HYPERLINK_ELEMENT = 0x21,
SMS_IEI_REPLY_ADDRESS_ELEMENT = 0x22,
SMS_IEI_ENHANCED_VOICE_MAIL_INFORMATION = 0x23,
SMS_IEI_NATIONAL_LANGUAGE_SINGLE_SHIFT = 0x24,
SMS_IEI_NATIONAL_LANGUAGE_LOCKING_SHIFT = 0x25,
SMS_IEI_INVALID = 0xFFF
};
enum sms_class {
SMS_CLASS_0 = 0,
SMS_CLASS_1 = 1,
SMS_CLASS_2 = 2,
SMS_CLASS_3 = 3,
SMS_CLASS_UNSPECIFIED = 4,
};
enum sms_charset {
SMS_CHARSET_7BIT = 0,
SMS_CHARSET_8BIT = 1,
SMS_CHARSET_UCS2 = 2,
};
enum sms_alphabet {
SMS_ALPHABET_DEFAULT = 0,
SMS_ALPHABET_TURKISH,
SMS_ALPHABET_SPANISH,
SMS_ALPHABET_PORTUGUESE,
SMS_ALPHABET_BENGALI,
SMS_ALPHABET_GUJARATI,
SMS_ALPHABET_HINDI,
SMS_ALPHABET_KANNADA,
SMS_ALPHABET_MALAYALAM,
SMS_ALPHABET_ORIYA,
SMS_ALPHABET_PUNJABI,
SMS_ALPHABET_TAMIL,
SMS_ALPHABET_TELUGU,
SMS_ALPHABET_URDU,
};
enum sms_mwi_type {
SMS_MWI_TYPE_VOICE = 0,
SMS_MWI_TYPE_FAX = 1,
SMS_MWI_TYPE_EMAIL = 2,
SMS_MWI_TYPE_OTHER = 3,
SMS_MWI_TYPE_VIDEO = 4,
};
enum sms_pid_type {
SMS_PID_TYPE_SM_TYPE_0 = 0x40,
SMS_PID_TYPE_REPLACE_SM_TYPE_1 = 0x41,
SMS_PID_TYPE_REPLACE_SM_TYPE_2 = 0x42,
SMS_PID_TYPE_REPLACE_SM_TYPE_3 = 0x43,
SMS_PID_TYPE_REPLACE_SM_TYPE_4 = 0x44,
SMS_PID_TYPE_REPLACE_SM_TYPE_5 = 0x45,
SMS_PID_TYPE_REPLACE_SM_TYPE_6 = 0x46,
SMS_PID_TYPE_REPLACE_SM_TYPE_7 = 0x47,
SMS_PID_TYPE_ENHANCED_MESSAGE_SERVICE = 0x5e,
SMS_PID_TYPE_RETURN_CALL = 0x5f,
SMS_PID_TYPE_ANSI136 = 0x7c,
SMS_PID_TYPE_ME_DOWNLOAD = 0x7d,
SMS_PID_TYPE_ME_DEPERSONALIZATION = 0x7e,
SMS_PID_TYPE_USIM_DOWNLOAD = 0x7f,
};
enum cbs_language {
CBS_LANGUAGE_GERMAN = 0x0,
CBS_LANGUAGE_ENGLISH = 0x1,
CBS_LANGUAGE_ITALIAN = 0x2,
CBS_LANGUAGE_FRENCH = 0x3,
CBS_LANGUAGE_SPANISH = 0x4,
CBS_LANGUAGE_DUTCH = 0x5,
CBS_LANGUAGE_SWEDISH = 0x6,
CBS_LANGUAGE_DANISH = 0x7,
CBS_LANGUAGE_PORTUGESE = 0x8,
CBS_LANGUAGE_FINNISH = 0x9,
CBS_LANGUAGE_NORWEGIAN = 0xA,
CBS_LANGUAGE_GREEK = 0xB,
CBS_LANGUAGE_TURKISH = 0xC,
CBS_LANGUAGE_HUNGARIAN = 0xD,
CBS_LANGUAGE_POLISH = 0xE,
CBS_LANGUAGE_UNSPECIFIED = 0xF,
CBS_LANGUAGE_CZECH = 0x20,
CBS_LANGUAGE_HEBREW = 0x21,
CBS_LANGUAGE_ARABIC = 0x22,
CBS_LANGUAGE_RUSSIAN = 0x23,
CBS_LANGUAGE_ICELANDIC = 0x24
};
enum cbs_geo_scope {
CBS_GEO_SCOPE_CELL_IMMEDIATE,
CBS_GEO_SCOPE_PLMN,
CBS_GEO_SCOPE_SERVICE_AREA,
CBS_GEO_SCOPE_CELL_NORMAL
};
struct sms_address {
enum sms_number_type number_type;
enum sms_numbering_plan numbering_plan;
/*
* An alphanum TP-OA is 10 7-bit coded octets, which can carry
* 11 8-bit characters. 22 bytes + terminator in UTF-8.
*/
char address[23];
};
struct sms_scts {
guint8 year;
guint8 month;
guint8 day;
guint8 hour;
guint8 minute;
guint8 second;
gboolean has_timezone;
gint8 timezone;
};
struct sms_validity_period {
union {
guint8 relative;
struct sms_scts absolute;
guint8 enhanced[7];
};
};
struct sms_deliver {
gboolean mms;
gboolean sri;
gboolean udhi;
gboolean rp;
struct sms_address oaddr;
guint8 pid;
guint8 dcs;
struct sms_scts scts;
guint8 udl;
guint8 ud[140];
};
struct sms_deliver_err_report {
gboolean udhi;
guint8 fcs;
guint8 pi;
guint8 pid;
guint8 dcs;
guint8 udl;
guint8 ud[158];
};
struct sms_deliver_ack_report {
gboolean udhi;
guint8 pi;
guint8 pid;
guint8 dcs;
guint8 udl;
guint8 ud[159];
};
struct sms_command {
gboolean udhi;
gboolean srr;
guint8 mr;
guint8 pid;
enum sms_ct ct;
guint8 mn;
struct sms_address daddr;
guint8 cdl;
guint8 cd[156];
};
struct sms_status_report {
gboolean udhi;
gboolean mms;
gboolean srq;
guint8 mr;
struct sms_address raddr;
struct sms_scts scts;
struct sms_scts dt;
enum sms_st st;
guint8 pi;
guint8 pid;
guint8 dcs;
guint8 udl;
guint8 ud[143];
};
struct sms_submit {
gboolean rd;
enum sms_validity_period_format vpf;
gboolean rp;
gboolean udhi;
gboolean srr;
guint8 mr;
struct sms_address daddr;
guint8 pid;
guint8 dcs;
struct sms_validity_period vp;
guint8 udl;
guint8 ud[140];
};
struct sms_submit_ack_report {
gboolean udhi;
guint8 pi;
struct sms_scts scts;
guint8 pid;
guint8 dcs;
guint8 udl;
guint8 ud[152];
};
struct sms_submit_err_report {
gboolean udhi;
guint8 fcs;
guint8 pi;
struct sms_scts scts;
guint8 pid;
guint8 dcs;
guint8 udl;
guint8 ud[151];
};
struct sms {
struct sms_address sc_addr;
enum sms_type type;
union {
struct sms_deliver deliver;
struct sms_deliver_ack_report deliver_ack_report;
struct sms_deliver_err_report deliver_err_report;
struct sms_submit submit;
struct sms_submit_ack_report submit_ack_report;
struct sms_submit_err_report submit_err_report;
struct sms_command command;
struct sms_status_report status_report;
};
};
struct sms_udh_iter {
const guint8 *data;
guint8 offset;
};
struct sms_assembly_node {
struct sms_address addr;
time_t ts;
GSList *fragment_list;
guint16 ref;
guint8 max_fragments;
guint8 num_fragments;
unsigned int bitmap[8];
};
struct sms_assembly {
const char *imsi;
GSList *assembly_list;
};
struct id_table_node {
unsigned int mrs[8];
time_t expiration;
unsigned char total_mrs;
unsigned char sent_mrs;
gboolean deliverable;
} __attribute__((packed));
struct status_report_assembly {
const char *imsi;
GHashTable *assembly_table;
};
struct cbs {
enum cbs_geo_scope gs; /* 2 bits */
guint16 message_code; /* 10 bits */
guint8 update_number; /* 4 bits */
guint16 message_identifier; /* 16 bits */
guint8 dcs; /* 8 bits */
guint8 max_pages; /* 4 bits */
guint8 page; /* 4 bits */
guint8 udlen;
guint8 ud[82];
};
struct cbs_assembly_node {
guint32 serial;
guint16 bitmap;
GSList *pages;
};
struct cbs_assembly {
GSList *assembly_list;
GSList *recv_plmn;
GSList *recv_loc;
GSList *recv_cell;
};
struct cbs_topic_range {
unsigned short min;
unsigned short max;
};
struct txq_backup_entry {
GSList *msg_list;
unsigned char uuid[SMS_MSGID_LEN];
unsigned long flags;
};
static inline gboolean is_bit_set(unsigned char oct, int bit)
{
int mask = 1 << bit;
return oct & mask ? TRUE : FALSE;
}
static inline unsigned char bit_field(unsigned char oct, int start, int num)
{
unsigned char mask = (1 << num) - 1;
return (oct >> start) & mask;
}
void extract_bcd_number(const unsigned char *buf, int len, char *out);
void encode_bcd_number(const char *number, unsigned char *out);
gboolean sms_decode(const unsigned char *pdu, int len, gboolean outgoing,
int tpdu_len, struct sms *out);
gboolean sms_decode_unpacked_stk_pdu(const unsigned char *pdu, int len,
struct sms *out);
gboolean sms_encode(const struct sms *in, int *len, int *tpdu_len,
unsigned char *pdu);
/*
* Length is based on the address being 12 hex characters plus a
* terminating NUL char. See sms_assembly_extract_address().
*/
#define DECLARE_SMS_ADDR_STR(a) char a[25]
gboolean sms_decode_address_field(const unsigned char *pdu, int len,
int *offset, gboolean sc,
struct sms_address *out);
gboolean sms_encode_address_field(const struct sms_address *in, gboolean sc,
unsigned char *pdu, int *offset);
guint8 sms_decode_semi_octet(guint8 in);
gboolean sms_decode_scts(const unsigned char *pdu, int len,
int *offset, struct sms_scts *out);
gboolean sms_encode_scts(const struct sms_scts *in, unsigned char *pdu,
int *offset);
int sms_udl_in_bytes(guint8 ud_len, guint8 dcs);
time_t sms_scts_to_time(const struct sms_scts *scts, struct tm *remote);
const char *sms_address_to_string(const struct sms_address *addr);
void sms_address_from_string(struct sms_address *addr, const char *str);
const guint8 *sms_extract_common(const struct sms *sms, gboolean *out_udhi,
guint8 *out_dcs, guint8 *out_udl,
guint8 *out_max);
gboolean sms_udh_iter_init(const struct sms *sms, struct sms_udh_iter *iter);
gboolean sms_udh_iter_init_from_cbs(const struct cbs *cbs,
struct sms_udh_iter *iter);
guint8 sms_udh_iter_get_udh_length(struct sms_udh_iter *iter);
const guint8 *sms_udh_iter_get_ud_after_header(struct sms_udh_iter *iter);
enum sms_iei sms_udh_iter_get_ie_type(struct sms_udh_iter *iter);
guint8 sms_udh_iter_get_ie_length(struct sms_udh_iter *iter);
void sms_udh_iter_get_ie_data(struct sms_udh_iter *iter, guint8 *data);
gboolean sms_udh_iter_has_next(struct sms_udh_iter *iter);
gboolean sms_udh_iter_next(struct sms_udh_iter *iter);
gboolean sms_dcs_decode(guint8 dcs, enum sms_class *cls,
enum sms_charset *charset,
gboolean *compressed, gboolean *autodelete);
gboolean sms_mwi_dcs_decode(guint8 dcs, enum sms_mwi_type *type,
enum sms_charset *charset,
gboolean *active, gboolean *discard);
gboolean sms_extract_app_port(const struct sms *sms, int *dst, int *src,
gboolean *is_8bit);
gboolean sms_extract_concatenation(const struct sms *sms, guint16 *ref_num,
guint8 *max_msgs, guint8 *seq_num);
gboolean sms_extract_language_variant(const struct sms *sms, guint8 *locking,
guint8 *single);
unsigned char *sms_decode_datagram(GSList *sms_list, long *out_len);
char *sms_decode_text(GSList *sms_list);
struct sms_assembly *sms_assembly_new(const char *imsi);
void sms_assembly_free(struct sms_assembly *assembly);
GSList *sms_assembly_add_fragment(struct sms_assembly *assembly,
const struct sms *sms, time_t ts,
const struct sms_address *addr,
guint16 ref, guint8 max, guint8 seq);
void sms_assembly_expire(struct sms_assembly *assembly, time_t before);
gboolean sms_address_to_hex_string(const struct sms_address *in, char *straddr);
struct status_report_assembly *status_report_assembly_new(const char *imsi);
void status_report_assembly_free(struct status_report_assembly *assembly);
gboolean status_report_assembly_report(struct status_report_assembly *assembly,
const struct sms *status_report,
unsigned char *out_msgid,
gboolean *msg_delivered);
void status_report_assembly_add_fragment(struct status_report_assembly
*assembly, const unsigned char *msgid,
const struct sms_address *to,
unsigned char mr, time_t expiration,
unsigned char total_mrs);
void status_report_assembly_expire(struct status_report_assembly *assembly,
time_t before);
gboolean sms_tx_backup_store(const char *imsi, unsigned long id,
unsigned long flags, const char *uuid,
guint8 seq, const unsigned char *pdu,
int pdu_len, int tpdu_len);
void sms_tx_backup_remove(const char *imsi, unsigned long id,
unsigned long flags, const char *uuid,
guint8 seq);
void sms_tx_backup_free(const char *imsi, unsigned long id,
unsigned long flags, const char *uuid);
GQueue *sms_tx_queue_load(const char *imsi);
GSList *sms_text_prepare(const char *to, const char *utf8, guint16 ref,
gboolean use_16bit,
gboolean use_delivery_reports);
GSList *sms_text_prepare_with_alphabet(const char *to, const char *utf8,
guint16 ref, gboolean use_16bit,
gboolean use_delivery_reports,
enum sms_alphabet alphabet);
GSList *sms_datagram_prepare(const char *to,
const unsigned char *data, unsigned int len,
guint16 ref, gboolean use_16bit_ref,
unsigned short src, unsigned short dst,
gboolean use_16bit_port,
gboolean use_delivery_reports);
gboolean cbs_dcs_decode(guint8 dcs, gboolean *udhi, enum sms_class *cls,
enum sms_charset *charset, gboolean *compressed,
enum cbs_language *language, gboolean *iso639);
gboolean iso639_2_from_language(enum cbs_language lang, char *iso639);
gboolean cbs_decode(const unsigned char *pdu, int len, struct cbs *out);
gboolean cbs_encode(const struct cbs *cbs, int *len, unsigned char *pdu);
gboolean cbs_extract_app_port(const struct cbs *cbs, int *dst, int *src,
gboolean *is_8bit);
char *cbs_decode_text(GSList *cbs_list, char *iso639_lang);
struct cbs_assembly *cbs_assembly_new(void);
void cbs_assembly_free(struct cbs_assembly *assembly);
GSList *cbs_assembly_add_page(struct cbs_assembly *assembly,
const struct cbs *cbs);
void cbs_assembly_location_changed(struct cbs_assembly *assembly, gboolean plmn,
gboolean lac, gboolean ci);
char *cbs_topic_ranges_to_string(GSList *ranges);
GSList *cbs_extract_topic_ranges(const char *ranges);
GSList *cbs_optimize_ranges(GSList *ranges);
gboolean cbs_topic_in_range(unsigned int topic, GSList *ranges);
char *ussd_decode(int dcs, int len, const unsigned char *data);
gboolean ussd_encode(const char *str, long *items_written, unsigned char *pdu);