summaryrefslogtreecommitdiffstats
path: root/src/smsutil.c
diff options
context:
space:
mode:
authorPetteri Tikander <petteri.tikander@ixonos.com>2010-09-01 18:59:30 +0300
committerDenis Kenzior <denkenz@gmail.com>2010-09-01 13:32:28 -0500
commit95fc8bee7282e70db3acffaf3b0ff1a28695645d (patch)
tree9ef68dda34a8090d059b0c1ac66de0c7fc9c9595 /src/smsutil.c
parent2a96c7cf29ab05ed2fd8fc8f3116663a8ba0590f (diff)
downloadofono-95fc8bee7282e70db3acffaf3b0ff1a28695645d.tar.bz2
smsutil: storing/loading sms status report over reboot
Diffstat (limited to 'src/smsutil.c')
-rw-r--r--src/smsutil.c159
1 files changed, 156 insertions, 3 deletions
diff --git a/src/smsutil.c b/src/smsutil.c
index 2e49a66a..0de420be 100644
--- a/src/smsutil.c
+++ b/src/smsutil.c
@@ -45,6 +45,9 @@
#define SMS_BACKUP_PATH_DIR SMS_BACKUP_PATH "/%s-%i-%i"
#define SMS_BACKUP_PATH_FILE SMS_BACKUP_PATH_DIR "/%03i"
+#define SMS_SR_BACKUP_PATH STORAGEDIR "/%s/sms_sr"
+#define SMS_SR_BACKUP_PATH_FILE SMS_SR_BACKUP_PATH "/%s-%i"
+
#define SMS_ADDR_FMT "%24[0-9A-F]"
static GSList *sms_assembly_add_fragment_backup(struct sms_assembly *assembly,
@@ -2643,20 +2646,152 @@ void sms_assembly_expire(struct sms_assembly *assembly, time_t before)
}
}
+static void sr_assembly_load_backup(GHashTable *assembly_table,
+ const char *imsi,
+ const struct dirent *addr_dir)
+{
+ struct sms_address addr;
+ DECLARE_SMS_ADDR_STR(straddr);
+ struct id_table_node *node;
+ GHashTable *id_table;
+ int r;
+ char *assembly_table_key;
+ unsigned int *id_table_key;
+ unsigned int msg_id;
+
+ if (addr_dir->d_type != DT_REG)
+ return;
+
+ /*
+ * All SMS-messages under the same IMSI-code are
+ * included in the same directory.
+ * So, SMS-address and message ID are included in the same file name
+ * Max of SMS address size is 12 bytes, hex encoded
+ */
+ if (sscanf(addr_dir->d_name, SMS_ADDR_FMT "-%u",
+ straddr, &msg_id) < 2)
+ return;
+
+ if (sms_assembly_extract_address(straddr, &addr) == FALSE)
+ return;
+
+ node = g_new0(struct id_table_node, 1);
+
+ r = read_file((unsigned char *) node,
+ sizeof(struct id_table_node),
+ SMS_SR_BACKUP_PATH "/%s",
+ imsi, addr_dir->d_name);
+
+ if (r < 0) {
+ g_free(node);
+ return;
+ }
+
+ id_table = g_hash_table_lookup(assembly_table,
+ sms_address_to_string(&addr));
+
+ /* Create hashtable keyed by the to address if required */
+ if (id_table == NULL) {
+ id_table = g_hash_table_new_full(g_int_hash, g_int_equal,
+ g_free, g_free);
+
+ assembly_table_key = g_strdup(sms_address_to_string(&addr));
+ g_hash_table_insert(assembly_table, assembly_table_key,
+ id_table);
+ }
+
+ /* Node ready, create key and add them to the table */
+ id_table_key = g_new0(unsigned int, 1);
+ *id_table_key = msg_id;
+
+ g_hash_table_insert(id_table, id_table_key, node);
+}
+
struct status_report_assembly *status_report_assembly_new(const char *imsi)
{
+ char *path;
+ int len;
+ struct dirent **addresses;
struct status_report_assembly *ret =
g_new0(struct status_report_assembly, 1);
ret->assembly_table = g_hash_table_new_full(g_str_hash, g_str_equal,
g_free, (GDestroyNotify)g_hash_table_destroy);
- if (imsi)
+ if (imsi) {
ret->imsi = imsi;
+ /* Restore state from backup */
+ path = g_strdup_printf(SMS_SR_BACKUP_PATH, imsi);
+ len = scandir(path, &addresses, NULL, alphasort);
+
+ g_free(path);
+
+ if (len < 0)
+ return ret;
+
+ /*
+ * Go through different addresses. Each address can relate to
+ * 1-n msg_ids.
+ */
+
+ while (len--) {
+ sr_assembly_load_backup(ret->assembly_table, imsi,
+ addresses[len]);
+ g_free(addresses[len]);
+ }
+
+ g_free(addresses);
+ }
+
return ret;
}
+static gboolean sr_assembly_add_fragment_backup(const char *imsi,
+ const struct id_table_node *node,
+ const struct sms_address *addr,
+ unsigned int msg_id)
+{
+ int len = sizeof(struct id_table_node);
+ DECLARE_SMS_ADDR_STR(straddr);
+
+ if (!imsi)
+ return FALSE;
+
+ if (sms_address_to_hex_string(addr, straddr) == FALSE)
+ return FALSE;
+
+ /* storagedir/%s/sms_sr/%s-%i */
+ if (write_file((unsigned char *) node, len, SMS_BACKUP_MODE,
+ SMS_SR_BACKUP_PATH_FILE, imsi,
+ straddr, msg_id) != len)
+ return FALSE;
+
+ return TRUE;
+}
+
+static gboolean sr_assembly_remove_fragment_backup(const char *imsi,
+ const struct id_table_node *node,
+ const struct sms_address *addr,
+ unsigned int msg_id)
+{
+ char *path;
+ DECLARE_SMS_ADDR_STR(straddr);
+
+ if (!imsi)
+ return FALSE;
+
+ if (sms_address_to_hex_string(addr, straddr) == FALSE)
+ return FALSE;
+
+ path = g_strdup_printf(SMS_SR_BACKUP_PATH_FILE, imsi, straddr, msg_id);
+
+ unlink(path);
+ g_free(path);
+
+ return TRUE;
+}
+
void status_report_assembly_free(struct status_report_assembly *assembly)
{
g_hash_table_destroy(assembly->assembly_table);
@@ -2699,6 +2834,7 @@ gboolean status_report_assembly_report(struct status_report_assembly *assembly,
GHashTableIter iter;
gboolean pending;
int i;
+ unsigned int msg_id;
/* We ignore temporary or tempfinal status reports */
if (sr_st_to_delivered(status_report->status_report.st,
@@ -2744,14 +2880,30 @@ gboolean status_report_assembly_report(struct status_report_assembly *assembly,
}
}
- if (pending == TRUE && node->deliverable == TRUE)
+ msg_id = *(unsigned int *) key;
+
+ if (pending == TRUE && node->deliverable == TRUE) {
+ /*
+ * More status reports expected, and already received
+ * reports completed. Update backup file.
+ */
+ sr_assembly_add_fragment_backup(
+ assembly->imsi, node,
+ &status_report->status_report.raddr,
+ msg_id);
+
return FALSE;
+ }
if (out_delivered)
*out_delivered = node->deliverable;
if (out_id)
- *out_id = *((unsigned int *) key);
+ *out_id = msg_id;
+
+ sr_assembly_remove_fragment_backup(assembly->imsi, node,
+ &status_report->status_report.raddr,
+ msg_id);
g_hash_table_iter_remove(&iter);
@@ -2805,6 +2957,7 @@ void status_report_assembly_add_fragment(
node->mrs[offset] |= bit;
node->expiration = expiration;
node->sent_mrs++;
+ sr_assembly_add_fragment_backup(assembly->imsi, node, to, msg_id);
}
void status_report_assembly_expire(struct status_report_assembly *assembly,