1 /*
2  * signalled-message.c - Source for TpSignalledMessage
3  * Copyright (C) 2006-2010 Collabora Ltd.
4  * Copyright (C) 2006-2008 Nokia Corporation
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19  */
20 
21 /**
22  * SECTION:signalled-message
23  * @title: TpSignalledMessage
24  * @short_description: a message received using the Telepathy message interface
25  *
26  * #TpSignalledMessage is used within Telepathy clients to represent a message
27  * signalled by a connection manager. This can either be a message received from
28  * someone else, confirmation that a message has been sent by the local user,
29  * or a delivery report indicating that delivery of a message has
30  * succeeded or failed.
31  *
32  * Since: 0.13.9
33  */
34 
35 #include "config.h"
36 
37 #include "signalled-message.h"
38 #include "signalled-message-internal.h"
39 #include "message-internal.h"
40 
41 #include <telepathy-glib/dbus.h>
42 #include <telepathy-glib/gtypes.h>
43 #include <telepathy-glib/util.h>
44 
45 /**
46  * TpSignalledMessage:
47  *
48  * Opaque structure representing a received message using the Telepathy
49  * messages interface
50  *
51  * Since: 0.13.9
52  */
53 
54 enum
55 {
56   PROP_SENDER = 1
57 };
58 
59 G_DEFINE_TYPE (TpSignalledMessage, tp_signalled_message, TP_TYPE_MESSAGE)
60 
61 struct _TpSignalledMessagePrivate
62 {
63   TpContact *sender;
64 };
65 
66 static void
tp_signalled_message_get_property(GObject * object,guint property_id,GValue * value,GParamSpec * pspec)67 tp_signalled_message_get_property (GObject *object,
68     guint property_id,
69     GValue *value,
70     GParamSpec *pspec)
71 {
72   TpSignalledMessage *self = (TpSignalledMessage *) object;
73 
74   switch (property_id)
75     {
76       case PROP_SENDER:
77         g_value_set_object (value, self->priv->sender);
78         break;
79 
80       default:
81         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
82         break;
83     }
84 }
85 
86 static void
tp_signalled_message_set_property(GObject * object,guint property_id,const GValue * value,GParamSpec * pspec)87 tp_signalled_message_set_property (GObject *object,
88     guint property_id,
89     const GValue *value,
90     GParamSpec *pspec)
91 {
92   TpSignalledMessage *self = (TpSignalledMessage *) object;
93 
94   switch (property_id)
95     {
96       case PROP_SENDER:
97         g_assert (self->priv->sender == NULL); /* construct only */
98         self->priv->sender = g_value_dup_object (value);
99         break;
100 
101       default:
102         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
103         break;
104     }
105 }
106 
107 static void
tp_signalled_message_dispose(GObject * object)108 tp_signalled_message_dispose (GObject *object)
109 {
110   TpSignalledMessage *self = TP_SIGNALLED_MESSAGE (object);
111   void (*dispose) (GObject *) =
112     G_OBJECT_CLASS (tp_signalled_message_parent_class)->dispose;
113 
114   tp_clear_object (&self->priv->sender);
115 
116   if (dispose != NULL)
117     dispose (object);
118 }
119 
120 static void
tp_signalled_message_class_init(TpSignalledMessageClass * klass)121 tp_signalled_message_class_init (TpSignalledMessageClass *klass)
122 {
123   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
124   GParamSpec *param_spec;
125 
126   gobject_class->get_property = tp_signalled_message_get_property;
127   gobject_class->set_property = tp_signalled_message_set_property;
128   gobject_class->dispose = tp_signalled_message_dispose;
129 
130   /**
131    * TpSignalledMessage:sender:
132    *
133    * A #TpContact representing the sender of the message, if known, or %NULL
134    * otherwise.
135    *
136    * Since: 0.13.9
137    */
138   param_spec = g_param_spec_object ("sender", "TpContact",
139       "The sender of the message",
140       TP_TYPE_CONTACT,
141       G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
142   g_object_class_install_property (gobject_class, PROP_SENDER,
143       param_spec);
144 
145   g_type_class_add_private (gobject_class, sizeof (TpSignalledMessagePrivate));
146 }
147 
148 static void
tp_signalled_message_init(TpSignalledMessage * self)149 tp_signalled_message_init (TpSignalledMessage *self)
150 {
151   self->priv = G_TYPE_INSTANCE_GET_PRIVATE ((self), TP_TYPE_SIGNALLED_MESSAGE,
152       TpSignalledMessagePrivate);
153 
154   self->priv->sender = NULL;
155 }
156 
157 /*
158  * Create a new TpSignalledMessage.
159  *
160  * Any message-sender and message-sender-id in parts[0] will be ignored
161  * completely: the caller is responsible for interpreting those fields
162  * and providing a suitable @sender.
163  *
164  * The message-sender will be removed from the header, and the
165  * message-sender-id will be set to match the #TpContact:identifier of @sender.
166  *
167  * @sender may be %NULL, which means the message wasn't sent by a contact
168  * (this could be used for administrative messages from a chatroom or the
169  * server) or we have no idea who sent it.
170  */
171 TpMessage *
_tp_signalled_message_new(const GPtrArray * parts,TpContact * sender)172 _tp_signalled_message_new (const GPtrArray *parts,
173     TpContact *sender)
174 {
175   TpMessage *self;
176   guint i;
177 
178   g_return_val_if_fail (parts != NULL, NULL);
179   g_return_val_if_fail (parts->len > 0, NULL);
180   g_return_val_if_fail (sender == NULL || TP_IS_CONTACT (sender), NULL);
181 
182   self = g_object_new (TP_TYPE_SIGNALLED_MESSAGE,
183       "sender", sender,
184       NULL);
185 
186   for (i = 0; i < parts->len; i++)
187     {
188       /* First part is automatically created */
189       if (i != 0)
190         tp_message_append_part (self);
191 
192       tp_g_hash_table_update (g_ptr_array_index (self->parts, i),
193           g_ptr_array_index (parts, i),
194           (GBoxedCopyFunc) g_strdup,
195           (GBoxedCopyFunc) tp_g_value_slice_dup);
196     }
197 
198   /* This handle may not be persistent, user should use the TpContact
199    * directly */
200   tp_message_delete_key (self, 0, "message-sender");
201 
202   /* override any message-sender-id that the message might have had */
203   if (sender == NULL)
204     {
205       tp_message_delete_key (self, 0, "message-sender-id");
206     }
207   else
208     {
209       tp_message_set_string (self, 0, "message-sender-id",
210           tp_contact_get_identifier (sender));
211     }
212 
213   _tp_message_set_immutable (self);
214 
215   return self;
216 }
217 
218 /**
219  * tp_signalled_message_get_sender:
220  * @message: a #TpSignalledMessage
221  *
222  * Returns a #TpContact representing the sender of @message if known, %NULL
223  * otherwise.
224  *
225  * Returns: (transfer none): the sender of the message
226  *
227  * Since: 0.13.9
228  */
229 TpContact *
tp_signalled_message_get_sender(TpMessage * message)230 tp_signalled_message_get_sender (TpMessage *message)
231 {
232   TpSignalledMessage *self;
233 
234   g_return_val_if_fail (TP_IS_SIGNALLED_MESSAGE (message), NULL);
235 
236   self = (TpSignalledMessage *) message;
237 
238   return self->priv->sender;
239 }
240 
241 guint
_tp_signalled_message_get_pending_message_id(TpMessage * message,gboolean * valid)242 _tp_signalled_message_get_pending_message_id (TpMessage *message,
243     gboolean *valid)
244 {
245   const GHashTable *part0;
246 
247   g_return_val_if_fail (TP_IS_SIGNALLED_MESSAGE (message), 0);
248   g_return_val_if_fail (valid != NULL, 0);
249 
250   part0 = tp_message_peek (message, 0);
251   if (part0 == NULL)
252     {
253       *valid = FALSE;
254       return 0;
255     }
256 
257   return tp_asv_get_uint32 (part0, "pending-message-id", valid);
258 }
259