diff options
author | Aleksander Morgado <aleksander@lanedo.com> | 2012-02-01 09:49:47 +0100 |
---|---|---|
committer | Aleksander Morgado <aleksander@lanedo.com> | 2012-03-15 14:14:59 +0100 |
commit | ad8fbcd1a6b37aabc18b14864eecc17f48a1b927 (patch) | |
tree | a2626ba94e62b9b6a193135c301cd8ee958302fe | |
parent | d41f4226f43fa12a54794497fb54dcbaa72a69ef (diff) |
sms: new object to handle single-part and multi-part messages
-rw-r--r-- | src/Makefile.am | 2 | ||||
-rw-r--r-- | src/mm-sms.c | 415 | ||||
-rw-r--r-- | src/mm-sms.h | 71 |
3 files changed, 488 insertions, 0 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index 3f94dfc8..c76b50d7 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -142,6 +142,8 @@ modem_manager_SOURCES = \ mm-base-modem.c \ mm-sms-part.h \ mm-sms-part.c \ + mm-sms.h \ + mm-sms.c \ mm-iface-modem.h \ mm-iface-modem.c \ mm-iface-modem-3gpp.h \ diff --git a/src/mm-sms.c b/src/mm-sms.c new file mode 100644 index 00000000..841469f1 --- /dev/null +++ b/src/mm-sms.c @@ -0,0 +1,415 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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: + * + * Copyright (C) 2008 - 2009 Novell, Inc. + * Copyright (C) 2009 - 2012 Red Hat, Inc. + * Copyright (C) 2012 Google, Inc. + */ + +#include <config.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <ctype.h> + +#include <ModemManager.h> +#include <libmm-common.h> + +#include "mm-iface-modem.h" +#include "mm-sms.h" +#include "mm-base-modem-at.h" +#include "mm-base-modem.h" +#include "mm-utils.h" +#include "mm-log.h" +#include "mm-modem-helpers.h" + +G_DEFINE_TYPE (MMSms, mm_sms, MM_GDBUS_TYPE_SMS_SKELETON); + +enum { + PROP_0, + PROP_PATH, + PROP_CONNECTION, + PROP_MODEM, + PROP_IS_MULTIPART, + PROP_MAX_PARTS, + PROP_MULTIPART_REFERENCE, + PROP_LAST +}; + +static GParamSpec *properties[PROP_LAST]; + +struct _MMSmsPrivate { + /* The connection to the system bus */ + GDBusConnection *connection; + /* The modem which owns this SMS */ + MMBaseModem *modem; + /* The path where the SMS object is exported */ + gchar *path; + + /* Multipart SMS specific stuff */ + gboolean is_multipart; + guint multipart_reference; + + /* List of SMS parts */ + guint max_parts; + GList *parts; +}; + +/*****************************************************************************/ + +void +mm_sms_export (MMSms *self) +{ + static guint id = 0; + gchar *path; + + path = g_strdup_printf (MM_DBUS_SMS_PREFIX "/%d", id++); + g_object_set (self, + MM_SMS_PATH, path, + NULL); + g_free (path); +} + +/*****************************************************************************/ + +static void +mm_sms_dbus_export (MMSms *self) +{ + GError *error = NULL; + + /* TODO: Handle method invocations */ + + if (!g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (self), + self->priv->connection, + self->priv->path, + &error)) { + mm_warn ("couldn't export SMS at '%s': '%s'", + self->priv->path, + error->message); + g_error_free (error); + } +} + +static void +mm_sms_dbus_unexport (MMSms *self) +{ + /* Only unexport if currently exported */ + if (g_dbus_interface_skeleton_get_object_path (G_DBUS_INTERFACE_SKELETON (self))) + g_dbus_interface_skeleton_unexport (G_DBUS_INTERFACE_SKELETON (self)); +} + +/*****************************************************************************/ + +const gchar * +mm_sms_get_path (MMSms *self) +{ + return self->priv->path; +} + +gboolean +mm_sms_is_multipart (MMSms *self) +{ + return self->priv->is_multipart; +} + +/*****************************************************************************/ + +static guint +cmp_sms_part_sequence (MMSmsPart *a, + MMSmsPart *b) +{ + return (mm_sms_part_get_concat_sequence (a) - mm_sms_part_get_concat_sequence (b)); +} + +gboolean +mm_sms_multipart_take_part (MMSms *self, + MMSmsPart *part, + GError **error) +{ + if (!self->priv->is_multipart) { + g_set_error (error, + MM_CORE_ERROR, + MM_CORE_ERROR_FAILED, + "This SMS is not a multipart message"); + return FALSE; + } + + if (g_list_length (self->priv->parts) >= self->priv->max_parts) { + g_set_error (error, + MM_CORE_ERROR, + MM_CORE_ERROR_FAILED, + "Already took %u parts, cannot take more", + g_list_length (self->priv->parts)); + return FALSE; + } + + if (g_list_find_custom (self->priv->parts, + part, + (GCompareFunc)cmp_sms_part_sequence)) { + g_set_error (error, + MM_CORE_ERROR, + MM_CORE_ERROR_FAILED, + "Cannot take part, sequence %u already taken", + mm_sms_part_get_concat_sequence (part)); + return FALSE; + } + + if (mm_sms_part_get_concat_sequence (part) > self->priv->max_parts) { + g_set_error (error, + MM_CORE_ERROR, + MM_CORE_ERROR_FAILED, + "Cannot take part with sequence %u, maximum is %u", + mm_sms_part_get_concat_sequence (part), + self->priv->max_parts); + return FALSE; + } + + /* Insert sorted by concat sequence */ + self->priv->parts = g_list_insert_sorted (self->priv->parts, + part, + (GCompareFunc)cmp_sms_part_sequence); + + if (g_list_length (self->priv->parts) == self->priv->max_parts) { + /* TODO: Multipart SMS completed */ + } + + return TRUE; +} + +MMSms * +mm_sms_new (MMSmsPart *part) +{ + MMSms *self; + + self = g_object_new (MM_TYPE_SMS, NULL); + + /* Keep the single part in the list */ + self->priv->parts = g_list_prepend (self->priv->parts, part); + + /* Only export once properly created */ + mm_sms_export (self); + + return self; +} + +MMSms * +mm_sms_multipart_new (guint reference, + guint max_parts, + MMSmsPart *first_part) +{ + MMSms *self; + + self = g_object_new (MM_TYPE_SMS, + MM_SMS_IS_MULTIPART, TRUE, + MM_SMS_MAX_PARTS, max_parts, + MM_SMS_MULTIPART_REFERENCE, reference, + NULL); + + /* Add the first part to the list */ + self->priv->parts = g_list_prepend (self->priv->parts, first_part); + + /* Only export once properly created */ + mm_sms_export (self); + + return self; +} + +/*****************************************************************************/ + +static void +set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + MMSms *self = MM_SMS (object); + + switch (prop_id) { + case PROP_PATH: + g_free (self->priv->path); + self->priv->path = g_value_dup_string (value); + + /* Export when we get a DBus connection AND we have a path */ + if (self->priv->path && + self->priv->connection) + mm_sms_dbus_export (self); + break; + case PROP_CONNECTION: + g_clear_object (&self->priv->connection); + self->priv->connection = g_value_dup_object (value); + + /* Export when we get a DBus connection AND we have a path */ + if (!self->priv->connection) + mm_sms_dbus_unexport (self); + else if (self->priv->path) + mm_sms_dbus_export (self); + break; + case PROP_MODEM: + g_clear_object (&self->priv->modem); + self->priv->modem = g_value_dup_object (value); + if (self->priv->modem) { + /* Bind the modem's connection (which is set when it is exported, + * and unset when unexported) to the SMS's connection */ + g_object_bind_property (self->priv->modem, MM_BASE_MODEM_CONNECTION, + self, MM_SMS_CONNECTION, + G_BINDING_DEFAULT | G_BINDING_SYNC_CREATE); + } + break; + case PROP_IS_MULTIPART: + self->priv->is_multipart = g_value_get_boolean (value); + break; + case PROP_MAX_PARTS: + self->priv->max_parts = g_value_get_uint (value); + break; + case PROP_MULTIPART_REFERENCE: + self->priv->multipart_reference = g_value_get_uint (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + MMSms *self = MM_SMS (object); + + switch (prop_id) { + case PROP_PATH: + g_value_set_string (value, self->priv->path); + break; + case PROP_CONNECTION: + g_value_set_object (value, self->priv->connection); + break; + case PROP_MODEM: + g_value_set_object (value, self->priv->modem); + break; + case PROP_IS_MULTIPART: + g_value_set_boolean (value, self->priv->is_multipart); + break; + case PROP_MAX_PARTS: + g_value_set_uint (value, self->priv->max_parts); + break; + case PROP_MULTIPART_REFERENCE: + g_value_set_uint (value, self->priv->multipart_reference); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +mm_sms_init (MMSms *self) +{ + /* Initialize private data */ + self->priv = G_TYPE_INSTANCE_GET_PRIVATE ((self), + MM_TYPE_SMS, + MMSmsPrivate); + /* Defaults */ + self->priv->max_parts = 1; +} + +static void +finalize (GObject *object) +{ + MMSms *self = MM_SMS (object); + + g_list_free_full (self->priv->parts, (GDestroyNotify)mm_sms_part_free); + g_free (self->priv->path); + + G_OBJECT_CLASS (mm_sms_parent_class)->finalize (object); +} + +static void +dispose (GObject *object) +{ + MMSms *self = MM_SMS (object); + + if (self->priv->connection) { + /* If we arrived here with a valid connection, make sure we unexport + * the object */ + mm_sms_dbus_unexport (self); + g_clear_object (&self->priv->connection); + } + + g_clear_object (&self->priv->modem); + + G_OBJECT_CLASS (mm_sms_parent_class)->dispose (object); +} + +static void +mm_sms_class_init (MMSmsClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + g_type_class_add_private (object_class, sizeof (MMSmsPrivate)); + + /* Virtual methods */ + object_class->get_property = get_property; + object_class->set_property = set_property; + object_class->finalize = finalize; + object_class->dispose = dispose; + + properties[PROP_CONNECTION] = + g_param_spec_object (MM_SMS_CONNECTION, + "Connection", + "GDBus connection to the system bus.", + G_TYPE_DBUS_CONNECTION, + G_PARAM_READWRITE); + g_object_class_install_property (object_class, PROP_CONNECTION, properties[PROP_CONNECTION]); + + properties[PROP_PATH] = + g_param_spec_string (MM_SMS_PATH, + "Path", + "DBus path of the SMS", + NULL, + G_PARAM_READWRITE); + g_object_class_install_property (object_class, PROP_PATH, properties[PROP_PATH]); + + properties[PROP_MODEM] = + g_param_spec_object (MM_SMS_MODEM, + "Modem", + "The Modem which owns this SMS", + MM_TYPE_BASE_MODEM, + G_PARAM_READWRITE); + g_object_class_install_property (object_class, PROP_MODEM, properties[PROP_MODEM]); + + properties[PROP_IS_MULTIPART] = + g_param_spec_boolean (MM_SMS_IS_MULTIPART, + "Is multipart", + "Flag specifying if the SMS is multipart", + FALSE, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); + g_object_class_install_property (object_class, PROP_IS_MULTIPART, properties[PROP_IS_MULTIPART]); + + properties[PROP_MAX_PARTS] = + g_param_spec_uint (MM_SMS_MAX_PARTS, + "Max parts", + "Maximum number of parts composing this SMS", + 1,255, 1, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); + g_object_class_install_property (object_class, PROP_MAX_PARTS, properties[PROP_MAX_PARTS]); + + properties[PROP_MULTIPART_REFERENCE] = + g_param_spec_uint (MM_SMS_MULTIPART_REFERENCE, + "Multipart reference", + "Common reference for all parts in the multipart SMS", + 0, G_MAXUINT, 0, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); + g_object_class_install_property (object_class, PROP_MULTIPART_REFERENCE, properties[PROP_MULTIPART_REFERENCE]); +} diff --git a/src/mm-sms.h b/src/mm-sms.h new file mode 100644 index 00000000..172c10d4 --- /dev/null +++ b/src/mm-sms.h @@ -0,0 +1,71 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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: + * + * Author: Aleksander Morgado <aleksander@lanedo.com> + * + * Copyright (C) 2012 Google, Inc. + */ + +#ifndef MM_SMS_H +#define MM_SMS_H + +#include <glib.h> +#include <glib-object.h> + +#include <libmm-common.h> + +#include "mm-sms-part.h" +#include "mm-base-modem.h" + +#define MM_TYPE_SMS (mm_sms_get_type ()) +#define MM_SMS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_SMS, MMSms)) +#define MM_SMS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_SMS, MMSmsClass)) +#define MM_IS_SMS(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_SMS)) +#define MM_IS_SMS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MM_TYPE_SMS)) +#define MM_SMS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_SMS, MMSmsClass)) + +typedef struct _MMSms MMSms; +typedef struct _MMSmsClass MMSmsClass; +typedef struct _MMSmsPrivate MMSmsPrivate; + +#define MM_SMS_PATH "sms-path" +#define MM_SMS_CONNECTION "sms-connection" +#define MM_SMS_MODEM "sms-modem" +#define MM_SMS_IS_MULTIPART "sms-is-multipart" +#define MM_SMS_MAX_PARTS "sms-max-parts" +#define MM_SMS_MULTIPART_REFERENCE "sms-multipart-reference" + +struct _MMSms { + MmGdbusSmsSkeleton parent; + MMSmsPrivate *priv; +}; + +struct _MMSmsClass { + MmGdbusSmsSkeletonClass parent; +}; + +GType mm_sms_get_type (void); + +MMSms *mm_sms_new (MMSmsPart *part); + +MMSms *mm_sms_multipart_new (guint reference, + guint max_parts, + MMSmsPart *first_part); +gboolean mm_sms_multipart_take_part (MMSms *self, + MMSmsPart *part, + GError **error); + +void mm_sms_export (MMSms *self); +const gchar *mm_sms_get_path (MMSms *self); +gboolean mm_sms_is_multipart (MMSms *self); + +#endif /* MM_SMS_H */ |