mirror of git://git.sysmocom.de/ofono
Add utilities for SMS re-assembly
This commit is contained in:
parent
f443493ddb
commit
c5511db5c5
148
src/smsutil.c
148
src/smsutil.c
|
@ -2029,3 +2029,151 @@ char *sms_decode_text(GSList *sms_list)
|
|||
|
||||
return utf8;
|
||||
}
|
||||
|
||||
struct sms_assembly *sms_assembly_new()
|
||||
{
|
||||
return g_new0(struct sms_assembly, 1);
|
||||
}
|
||||
|
||||
void sms_assembly_free(struct sms_assembly *assembly)
|
||||
{
|
||||
GSList *l;
|
||||
|
||||
for (l = assembly->assembly_list; l; l = l->next) {
|
||||
struct sms_assembly_node *node = l->data;
|
||||
|
||||
g_slist_foreach(node->fragment_list, (GFunc)g_free, 0);
|
||||
g_slist_free(node->fragment_list);
|
||||
g_free(node);
|
||||
}
|
||||
|
||||
g_slist_free(assembly->assembly_list);
|
||||
g_free(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)
|
||||
{
|
||||
int offset = seq / 8;
|
||||
int bit = 1 << (seq % 32);
|
||||
GSList *l;
|
||||
GSList *prev;
|
||||
struct sms *newsms;
|
||||
struct sms_assembly_node *node;
|
||||
GSList *completed;
|
||||
int position;
|
||||
int i;
|
||||
int j;
|
||||
|
||||
prev = NULL;
|
||||
|
||||
for (l = assembly->assembly_list; l; prev = l, l = l->next) {
|
||||
node = l->data;
|
||||
|
||||
if (node->addr.number_type != addr->number_type)
|
||||
continue;
|
||||
|
||||
if (node->addr.numbering_plan != addr->numbering_plan)
|
||||
continue;
|
||||
|
||||
if (strcmp(node->addr.address, addr->address))
|
||||
continue;
|
||||
|
||||
if (ref != node->ref)
|
||||
continue;
|
||||
|
||||
/* Message Reference and address the same, but max is not
|
||||
* ignore the SMS completely
|
||||
*/
|
||||
if (max != node->max_fragments)
|
||||
return NULL;
|
||||
|
||||
/* Now check if we already have this seq number */
|
||||
if (node->bitmap[offset] & bit)
|
||||
return NULL;
|
||||
|
||||
position = 0;
|
||||
for (i = 0; i < offset; i++)
|
||||
for (j = 0; j < 32; j++)
|
||||
if (node->bitmap[i] & (1 << j))
|
||||
position += 1;
|
||||
|
||||
for (j = 1; j < bit; j = j << 1)
|
||||
if (node->bitmap[offset] & j)
|
||||
position += 1;
|
||||
|
||||
goto out;
|
||||
}
|
||||
|
||||
node = g_new0(struct sms_assembly_node, 1);
|
||||
memcpy(&node->addr, addr, sizeof(struct sms_address));
|
||||
node->ts = ts;
|
||||
node->ref = ref;
|
||||
node->max_fragments = max;
|
||||
|
||||
assembly->assembly_list = g_slist_prepend(assembly->assembly_list,
|
||||
node);
|
||||
|
||||
prev = NULL;
|
||||
l = assembly->assembly_list;
|
||||
position = 0;
|
||||
|
||||
out:
|
||||
newsms = g_new(struct sms, 1);
|
||||
|
||||
memcpy(newsms, sms, sizeof(struct sms));
|
||||
node->fragment_list = g_slist_insert(node->fragment_list,
|
||||
newsms, position);
|
||||
node->bitmap[offset] |= bit;
|
||||
node->num_fragments += 1;
|
||||
|
||||
if (node->num_fragments < node->max_fragments)
|
||||
return NULL;
|
||||
|
||||
completed = node->fragment_list;
|
||||
|
||||
if (prev)
|
||||
prev->next = l->next;
|
||||
else
|
||||
assembly->assembly_list = l->next;
|
||||
|
||||
g_free(node);
|
||||
return completed;
|
||||
}
|
||||
|
||||
/*!
|
||||
* Expires all incomplete messages that have been received at time prior
|
||||
* to one given by before argument. The fragment list is freed and the
|
||||
* SMSes are vaporized.
|
||||
*/
|
||||
void sms_assembly_expire(struct sms_assembly *assembly, time_t before)
|
||||
{
|
||||
GSList *cur;
|
||||
GSList *prev;
|
||||
|
||||
prev = NULL;
|
||||
cur = assembly->assembly_list;
|
||||
|
||||
while (cur) {
|
||||
struct sms_assembly_node *node = cur->data;
|
||||
|
||||
if (node->ts > before) {
|
||||
prev = cur;
|
||||
cur = cur->next;
|
||||
continue;
|
||||
}
|
||||
|
||||
g_slist_foreach(node->fragment_list, (GFunc)g_free, 0);
|
||||
g_slist_free(node->fragment_list);
|
||||
g_free(node);
|
||||
|
||||
if (prev)
|
||||
prev->next = cur->next;
|
||||
else
|
||||
assembly->assembly_list = cur->next;
|
||||
|
||||
cur = cur->next;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -321,6 +321,20 @@ struct sms_udh_iter {
|
|||
guint8 offset;
|
||||
};
|
||||
|
||||
struct sms_assembly_node {
|
||||
struct sms_address addr;
|
||||
time_t ts;
|
||||
GSList *fragment_list;
|
||||
guint8 ref;
|
||||
guint8 max_fragments;
|
||||
guint8 num_fragments;
|
||||
unsigned int bitmap[8];
|
||||
};
|
||||
|
||||
struct sms_assembly {
|
||||
GSList *assembly_list;
|
||||
};
|
||||
|
||||
gboolean sms_decode(const unsigned char *pdu, int len, gboolean outgoing,
|
||||
int tpdu_len, struct sms *out);
|
||||
|
||||
|
@ -360,4 +374,11 @@ gboolean sms_extract_concatenation(const struct sms *sms, guint16 *ref_num,
|
|||
unsigned char *sms_decode_datagram(GSList *sms_list, long *out_len);
|
||||
char *sms_decode_text(GSList *sms_list);
|
||||
|
||||
struct sms_assembly *sms_assembly_new();
|
||||
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);
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue