diff options
-rw-r--r-- | src/smsutil.c | 148 | ||||
-rw-r--r-- | src/smsutil.h | 21 |
2 files changed, 169 insertions, 0 deletions
diff --git a/src/smsutil.c b/src/smsutil.c index 20654cc2..d45fbc40 100644 --- a/src/smsutil.c +++ b/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; + } +} diff --git a/src/smsutil.h b/src/smsutil.h index 8b86352b..64d7800d 100644 --- a/src/smsutil.h +++ b/src/smsutil.h @@ -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 |