gint tx_source;
struct ofono_message_waiting *mw;
unsigned int mw_watch;
+ struct ofono_sim *sim;
+ unsigned int sim_watch;
+ unsigned int imsi_watch;
const struct ofono_sms_driver *driver;
void *driver_data;
struct ofono_atom *atom;
__ofono_modem_remove_atom_watch(modem, sms->mw_watch);
sms->mw_watch = 0;
}
+
+ if (sms->sim_watch) {
+ if (sms->imsi_watch) {
+ ofono_sim_remove_ready_watch(sms->sim,
+ sms->imsi_watch);
+ sms->imsi_watch = 0;
+ }
+
+ __ofono_modem_remove_atom_watch(modem, sms->sim_watch);
+ sms->sim_watch = 0;
+ }
}
static void sms_remove(struct ofono_atom *atom)
sms->sca.type = 129;
sms->ref = 1;
- sms->assembly = sms_assembly_new();
sms->txq = g_queue_new();
sms->atom = __ofono_modem_add_atom(modem, OFONO_ATOM_TYPE_SMS,
sms_remove, sms);
sms->mw = __ofono_atom_get_data(atom);
}
+static void sms_got_imsi(void *data)
+{
+ struct ofono_sms *sms = data;
+ const char *imsi = ofono_sim_get_imsi(sms->sim);
+
+ sms->assembly = sms_assembly_new(imsi);
+}
+
+static void sim_watch(struct ofono_atom *atom,
+ enum ofono_atom_watch_condition cond, void *data)
+{
+ struct ofono_sms *sms = data;
+
+ if (cond == OFONO_ATOM_WATCH_CONDITION_UNREGISTERED) {
+ sms->imsi_watch = 0;
+
+ if (sms->assembly) {
+ sms_assembly_free(sms->assembly);
+ sms->assembly = NULL;
+ }
+
+ return;
+ }
+
+ sms->sim = __ofono_atom_get_data(atom);
+ sms->imsi_watch = ofono_sim_add_ready_watch(sms->sim, sms_got_imsi,
+ sms, NULL);
+
+ if (ofono_sim_get_ready(sms->sim))
+ sms_got_imsi(sms);
+}
+
void ofono_sms_register(struct ofono_sms *sms)
{
DBusConnection *conn = ofono_dbus_get_connection();
struct ofono_modem *modem = __ofono_atom_get_modem(sms->atom);
const char *path = __ofono_atom_get_path(sms->atom);
struct ofono_atom *mw_atom;
+ struct ofono_atom *sim_atom;
if (!g_dbus_register_interface(conn, path,
SMS_MANAGER_INTERFACE,
if (mw_atom && __ofono_atom_get_registered(mw_atom))
mw_watch(mw_atom, OFONO_ATOM_WATCH_CONDITION_REGISTERED, sms);
+ sms->sim_watch = __ofono_modem_add_atom_watch(modem,
+ OFONO_ATOM_TYPE_SIM,
+ sim_watch, sms, NULL);
+
+ sim_atom = __ofono_modem_find_atom(modem, OFONO_ATOM_TYPE_SIM);
+
+ if (sim_atom && __ofono_atom_get_registered(sim_atom))
+ sim_watch(sim_atom,
+ OFONO_ATOM_WATCH_CONDITION_REGISTERED, sms);
+
__ofono_atom_register(sms->atom, sms_unregister);
}
#include <config.h>
#endif
+#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <dirent.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
#include <glib.h>
+#include "types.h"
+#include "common.h"
#include "util.h"
+#include "storage.h"
#include "smsutil.h"
#define uninitialized_var(x) x = x
+#define SMS_BACKUP_MODE 0600
+#define SMS_BACKUP_PATH STORAGEDIR "/%s/sms"
+#define SMS_BACKUP_PATH_DIR SMS_BACKUP_PATH "/%s-%i-%i"
+#define SMS_BACKUP_PATH_FILE SMS_BACKUP_PATH_DIR "/%03i"
+
+#define SMS_ADDR_FMT "%21[0-9+*#]"
+
+static GSList *sms_assembly_add_fragment_backup(struct sms_assembly *assembly,
+ const struct sms *sms, time_t ts,
+ const struct sms_address *addr,
+ guint16 ref, guint8 max, guint8 seq,
+ gboolean backup);
+
void extract_bcd_number(const unsigned char *buf, int len, char *out)
{
static const char digit_lut[] = "0123456789*#abc\0";
return utf8;
}
-struct sms_assembly *sms_assembly_new()
+static int sms_serialize(unsigned char *buf, const struct sms *sms)
+{
+ int len, tpdu_len;
+
+ sms_encode(sms, &len, &tpdu_len, buf + 1);
+ buf[0] = tpdu_len;
+
+ return len;
+}
+
+static gboolean sms_deserialize(const unsigned char *buf,
+ struct sms *sms, int len)
+{
+ if (len < 1)
+ return FALSE;
+
+ return sms_decode(buf + 1, len - 1, FALSE, buf[0], sms);
+}
+
+static void sms_assembly_load(struct sms_assembly *assembly,
+ const struct dirent *dir)
+{
+ struct sms_address addr;
+ char straddr[sizeof(addr.address) + 1];
+ guint16 ref;
+ guint8 max;
+ guint8 seq;
+ char *path;
+ int len;
+ struct stat segment_stat;
+ struct dirent **segments;
+ char *endp;
+ int r;
+ int i;
+ unsigned char buf[177];
+ struct sms segment;
+
+ if (dir->d_type != DT_DIR)
+ return;
+
+ if (sscanf(dir->d_name, SMS_ADDR_FMT "-%hi-%hhi",
+ straddr, &ref, &max) < 3)
+ return;
+ sms_address_from_string(&addr, straddr);
+
+ path = g_strdup_printf(SMS_BACKUP_PATH "/%s",
+ assembly->imsi, dir->d_name);
+ len = scandir(path, &segments, NULL, versionsort);
+ g_free(path);
+
+ if (len < 0)
+ return;
+
+ for (i = 0; i < len; i++) {
+ if (segments[i]->d_type != DT_REG)
+ continue;
+
+ seq = strtol(segments[i]->d_name, &endp, 10);
+ if (*endp != '\0')
+ continue;
+
+ r = read_file(buf, sizeof(buf), SMS_BACKUP_PATH "/%s/%s",
+ assembly->imsi,
+ dir->d_name, segments[i]->d_name);
+ if (r < 0)
+ continue;
+
+ if (!sms_deserialize(buf, &segment, r))
+ continue;
+
+ path = g_strdup_printf(SMS_BACKUP_PATH "/%s/%s",
+ assembly->imsi,
+ dir->d_name, segments[i]->d_name);
+ r = stat(path, &segment_stat);
+ g_free(path);
+
+ if (r != 0)
+ continue;
+
+ if (sms_assembly_add_fragment_backup(assembly, &segment,
+ segment_stat.st_mtime,
+ &addr, ref, max, seq, FALSE)) {
+ /* This should not happen */
+ }
+ }
+
+ for (i = 0; i < len; i++)
+ free(segments[i]);
+
+ free(segments);
+}
+
+static gboolean sms_assembly_store(struct sms_assembly *assembly,
+ struct sms_assembly_node *node,
+ const struct sms *sms, guint8 seq)
+{
+ unsigned char buf[177];
+ int len;
+
+ if (!assembly->imsi)
+ return FALSE;
+
+ len = sms_serialize(buf, sms);
+
+ if (write_file(buf, len, SMS_BACKUP_MODE,
+ SMS_BACKUP_PATH_FILE, assembly->imsi,
+ sms_address_to_string(&node->addr),
+ node->ref, node->max_fragments, seq) != len)
+ return FALSE;
+
+ return TRUE;
+}
+
+static void sms_assembly_backup_free(struct sms_assembly *assembly,
+ struct sms_assembly_node *node)
+{
+ char *path;
+ int seq;
+
+ if (!assembly->imsi)
+ return;
+
+ for (seq = 0; seq < node->max_fragments; seq++) {
+ int offset = seq / 32;
+ int bit = 1 << (seq % 32);
+
+ if (node->bitmap[offset] & bit) {
+ path = g_strdup_printf(SMS_BACKUP_PATH_FILE,
+ assembly->imsi,
+ sms_address_to_string(&node->addr),
+ node->ref, node->max_fragments, seq);
+ unlink(path);
+ g_free(path);
+ }
+ }
+
+ path = g_strdup_printf(SMS_BACKUP_PATH_DIR, assembly->imsi,
+ sms_address_to_string(&node->addr),
+ node->ref, node->max_fragments);
+ rmdir(path);
+ g_free(path);
+}
+
+struct sms_assembly *sms_assembly_new(const char *imsi)
{
- return g_new0(struct sms_assembly, 1);
+ struct sms_assembly *ret = g_new0(struct sms_assembly, 1);
+ char *path;
+ struct dirent **entries;
+ int len;
+
+ if (imsi) {
+ ret->imsi = imsi;
+
+ /* Restore state from backup */
+
+ path = g_strdup_printf(SMS_BACKUP_PATH, imsi);
+ len = scandir(path, &entries, NULL, alphasort);
+ g_free(path);
+
+ if (len < 0)
+ return ret;
+
+ while (len--) {
+ sms_assembly_load(ret, entries[len]);
+ free(entries[len]);
+ }
+
+ free(entries);
+ }
+
+ return ret;
}
void sms_assembly_free(struct sms_assembly *assembly)
const struct sms_address *addr,
guint16 ref, guint8 max, guint8 seq)
{
+ return sms_assembly_add_fragment_backup(assembly, sms,
+ ts, addr, ref, max, seq, TRUE);
+}
+
+static GSList *sms_assembly_add_fragment_backup(struct sms_assembly *assembly,
+ const struct sms *sms, time_t ts,
+ const struct sms_address *addr,
+ guint16 ref, guint8 max, guint8 seq,
+ gboolean backup)
+{
int offset = seq / 32;
int bit = 1 << (seq % 32);
GSList *l;
node->bitmap[offset] |= bit;
node->num_fragments += 1;
- if (node->num_fragments < node->max_fragments)
+ if (node->num_fragments < node->max_fragments) {
+ if (backup)
+ sms_assembly_store(assembly, node, sms, seq);
+
return NULL;
+ }
completed = node->fragment_list;
+ sms_assembly_backup_free(assembly, node);
+
if (prev)
prev->next = l->next;
else
continue;
}
+ sms_assembly_backup_free(assembly, node);
+
g_slist_foreach(node->fragment_list, (GFunc)g_free, 0);
g_slist_free(node->fragment_list);
g_free(node);