Extending test-client-custom-summary to try e_book_client_get_contacts_uids()
[platform/upstream/evolution-data-server.git] / camel / camel-transport.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /* camel-transport.c : Abstract class for an email transport */
3
4 /*
5  *
6  * Author :
7  *  Dan Winship <danw@ximian.com>
8  *
9  * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
10  *
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of version 2 of the GNU Lesser General Public
13  * License as published by the Free Software Foundation.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License for more details.
19  *
20  * You should have received a copy of the GNU Lesser General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
23  * USA
24  */
25
26 #ifdef HAVE_CONFIG_H
27 #include <config.h>
28 #endif
29
30 #include "camel-address.h"
31 #include "camel-debug.h"
32 #include "camel-mime-message.h"
33 #include "camel-transport.h"
34
35 #define CAMEL_TRANSPORT_GET_PRIVATE(obj) \
36         (G_TYPE_INSTANCE_GET_PRIVATE \
37         ((obj), CAMEL_TYPE_TRANSPORT, CamelTransportPrivate))
38
39 typedef struct _AsyncContext AsyncContext;
40
41 struct _CamelTransportPrivate {
42         GMutex send_lock;   /* for locking send operations */
43 };
44
45 struct _AsyncContext {
46         /* arguments */
47         CamelAddress *from;
48         CamelAddress *recipients;
49         CamelMimeMessage *message;
50 };
51
52 G_DEFINE_ABSTRACT_TYPE (CamelTransport, camel_transport, CAMEL_TYPE_SERVICE)
53
54 static void
55 async_context_free (AsyncContext *async_context)
56 {
57         if (async_context->from != NULL)
58                 g_object_unref (async_context->from);
59
60         if (async_context->recipients != NULL)
61                 g_object_unref (async_context->recipients);
62
63         if (async_context->message != NULL)
64                 g_object_unref (async_context->message);
65
66         g_slice_free (AsyncContext, async_context);
67 }
68
69 static void
70 transport_finalize (GObject *object)
71 {
72         CamelTransportPrivate *priv;
73
74         priv = CAMEL_TRANSPORT_GET_PRIVATE (object);
75
76         g_mutex_clear (&priv->send_lock);
77
78         /* Chain up to parent's finalize() method. */
79         G_OBJECT_CLASS (camel_transport_parent_class)->finalize (object);
80 }
81
82 static void
83 transport_send_to_thread (GSimpleAsyncResult *simple,
84                           GObject *object,
85                           GCancellable *cancellable)
86 {
87         AsyncContext *async_context;
88         GError *error = NULL;
89
90         async_context = g_simple_async_result_get_op_res_gpointer (simple);
91
92         camel_transport_send_to_sync (
93                 CAMEL_TRANSPORT (object), async_context->message,
94                 async_context->from, async_context->recipients,
95                 cancellable, &error);
96
97         if (error != NULL)
98                 g_simple_async_result_take_error (simple, error);
99 }
100
101 static void
102 transport_send_to (CamelTransport *transport,
103                    CamelMimeMessage *message,
104                    CamelAddress *from,
105                    CamelAddress *recipients,
106                    gint io_priority,
107                    GCancellable *cancellable,
108                    GAsyncReadyCallback callback,
109                    gpointer user_data)
110 {
111         GSimpleAsyncResult *simple;
112         AsyncContext *async_context;
113
114         async_context = g_slice_new0 (AsyncContext);
115         async_context->from = g_object_ref (from);
116         async_context->recipients = g_object_ref (recipients);
117         async_context->message = g_object_ref (message);
118
119         simple = g_simple_async_result_new (
120                 G_OBJECT (transport), callback, user_data, transport_send_to);
121
122         g_simple_async_result_set_check_cancellable (simple, cancellable);
123
124         g_simple_async_result_set_op_res_gpointer (
125                 simple, async_context, (GDestroyNotify) async_context_free);
126
127         g_simple_async_result_run_in_thread (
128                 simple, transport_send_to_thread, io_priority, cancellable);
129
130         g_object_unref (simple);
131 }
132
133 static gboolean
134 transport_send_to_finish (CamelTransport *transport,
135                           GAsyncResult *result,
136                           GError **error)
137 {
138         GSimpleAsyncResult *simple;
139
140         g_return_val_if_fail (
141                 g_simple_async_result_is_valid (
142                 result, G_OBJECT (transport), transport_send_to), FALSE);
143
144         simple = G_SIMPLE_ASYNC_RESULT (result);
145
146         /* Assume success unless a GError is set. */
147         return !g_simple_async_result_propagate_error (simple, error);
148 }
149
150 static void
151 camel_transport_class_init (CamelTransportClass *class)
152 {
153         GObjectClass *object_class;
154
155         g_type_class_add_private (class, sizeof (CamelTransportPrivate));
156
157         object_class = G_OBJECT_CLASS (class);
158         object_class->finalize = transport_finalize;
159
160         class->send_to = transport_send_to;
161         class->send_to_finish = transport_send_to_finish;
162 }
163
164 static void
165 camel_transport_init (CamelTransport *transport)
166 {
167         transport->priv = CAMEL_TRANSPORT_GET_PRIVATE (transport);
168
169         g_mutex_init (&transport->priv->send_lock);
170 }
171
172 /**
173  * camel_transport_lock:
174  * @transport: a #CamelTransport
175  * @lock: lock type to lock
176  *
177  * Locks %transport's %lock. Unlock it with camel_transport_unlock().
178  *
179  * Since: 2.32
180  **/
181 void
182 camel_transport_lock (CamelTransport *transport,
183                       CamelTransportLock lock)
184 {
185         g_return_if_fail (CAMEL_IS_TRANSPORT (transport));
186
187         switch (lock) {
188                 case CAMEL_TRANSPORT_SEND_LOCK:
189                         g_mutex_lock (&transport->priv->send_lock);
190                         break;
191                 default:
192                         g_return_if_reached ();
193         }
194 }
195
196 /**
197  * camel_transport_unlock:
198  * @transport: a #CamelTransport
199  * @lock: lock type to unlock
200  *
201  * Unlocks %transport's %lock, previously locked with camel_transport_lock().
202  *
203  * Since: 2.32
204  **/
205 void
206 camel_transport_unlock (CamelTransport *transport,
207                         CamelTransportLock lock)
208 {
209         g_return_if_fail (CAMEL_IS_TRANSPORT (transport));
210
211         switch (lock) {
212                 case CAMEL_TRANSPORT_SEND_LOCK:
213                         g_mutex_unlock (&transport->priv->send_lock);
214                         break;
215                 default:
216                         g_return_if_reached ();
217         }
218 }
219
220 /**
221  * camel_transport_send_to_sync:
222  * @transport: a #CamelTransport
223  * @message: a #CamelMimeMessage to send
224  * @from: a #CamelAddress to send from
225  * @recipients: a #CamelAddress containing all recipients
226  * @cancellable: optional #GCancellable object, or %NULL
227  * @error: return location for a #GError, or %NULL
228  *
229  * Sends the message to the given recipients, regardless of the contents
230  * of @message.  If the message contains a "Bcc" header, the transport
231  * is responsible for stripping it.
232  *
233  * Returns: %TRUE on success or %FALSE on error
234  *
235  * Since: 3.0
236  **/
237 gboolean
238 camel_transport_send_to_sync (CamelTransport *transport,
239                               CamelMimeMessage *message,
240                               CamelAddress *from,
241                               CamelAddress *recipients,
242                               GCancellable *cancellable,
243                               GError **error)
244 {
245         CamelTransportClass *class;
246         gboolean success;
247
248         g_return_val_if_fail (CAMEL_IS_TRANSPORT (transport), FALSE);
249         g_return_val_if_fail (CAMEL_IS_MIME_MESSAGE (message), FALSE);
250         g_return_val_if_fail (CAMEL_IS_ADDRESS (from), FALSE);
251         g_return_val_if_fail (CAMEL_IS_ADDRESS (recipients), FALSE);
252
253         class = CAMEL_TRANSPORT_GET_CLASS (transport);
254         g_return_val_if_fail (class->send_to_sync != NULL, FALSE);
255
256         camel_transport_lock (transport, CAMEL_TRANSPORT_SEND_LOCK);
257
258         /* Check for cancellation after locking. */
259         if (g_cancellable_set_error_if_cancelled (cancellable, error)) {
260                 camel_transport_unlock (transport, CAMEL_TRANSPORT_SEND_LOCK);
261                 return FALSE;
262         }
263
264         success = class->send_to_sync (
265                 transport, message, from, recipients, cancellable, error);
266         CAMEL_CHECK_GERROR (transport, send_to_sync, success, error);
267
268         camel_transport_unlock (transport, CAMEL_TRANSPORT_SEND_LOCK);
269
270         return success;
271 }
272
273 /**
274  * camel_transport_send_to:
275  * @transport: a #CamelTransport
276  * @message: a #CamelMimeMessage to send
277  * @from: a #CamelAddress to send from
278  * @recipients: a #CamelAddress containing all recipients
279  * @io_priority: the I/O priority of the request
280  * @cancellable: optional #GCancellable object, or %NULL
281  * @callback: a #GAsyncReadyCallback to call when the request is satisfied
282  * @user_data: data to pass to the callback function
283  *
284  * Sends the message asynchronously to the given recipients, regardless of
285  * the contents of @message.  If the message contains a "Bcc" header, the
286  * transport is responsible for stripping it.
287  *
288  * When the operation is finished, @callback will be called.  You can then
289  * call camel_transport_send_to_finish() to get the result of the operation.
290  *
291  * Since: 3.0
292  **/
293 void
294 camel_transport_send_to (CamelTransport *transport,
295                          CamelMimeMessage *message,
296                          CamelAddress *from,
297                          CamelAddress *recipients,
298                          gint io_priority,
299                          GCancellable *cancellable,
300                          GAsyncReadyCallback callback,
301                          gpointer user_data)
302 {
303         CamelTransportClass *class;
304
305         g_return_if_fail (CAMEL_IS_TRANSPORT (transport));
306         g_return_if_fail (CAMEL_IS_MIME_MESSAGE (message));
307         g_return_if_fail (CAMEL_IS_ADDRESS (from));
308         g_return_if_fail (CAMEL_IS_ADDRESS (recipients));
309
310         class = CAMEL_TRANSPORT_GET_CLASS (transport);
311         g_return_if_fail (class->send_to != NULL);
312
313         class->send_to (
314                 transport, message, from, recipients, io_priority,
315                 cancellable, callback, user_data);
316 }
317
318 /**
319  * camel_transport_send_to_finish:
320  * @transport: a #CamelTransport
321  * @result: a #GAsyncResult
322  * @error: return locaton for a #GError, or %NULL
323  *
324  * Finishes the operation started with camel_transport_send_to().
325  *
326  * Returns: %TRUE on success, %FALSE on error
327  *
328  * Since: 3.0
329  **/
330 gboolean
331 camel_transport_send_to_finish (CamelTransport *transport,
332                                 GAsyncResult *result,
333                                 GError **error)
334 {
335         CamelTransportClass *class;
336
337         g_return_val_if_fail (CAMEL_IS_TRANSPORT (transport), FALSE);
338         g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE);
339
340         class = CAMEL_TRANSPORT_GET_CLASS (transport);
341         g_return_val_if_fail (class->send_to_finish != NULL, FALSE);
342
343         return class->send_to_finish (transport, result, error);
344 }