1 /* Copyright (c) 2006, Nokia Corporation
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * * Neither the name of the Nokia Corporation nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
18 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
20 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
21 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 #include <modest-tny-send-queue.h>
32 #include <tny-simple-list.h>
33 #include <tny-iterator.h>
34 #include <tny-folder.h>
35 #include <tny-error.h>
36 #include <tny-camel-msg.h>
37 #include <tny-folder-change.h>
38 #include <tny-folder-observer.h>
39 #include <modest-tny-account.h>
40 #include <modest-runtime.h>
41 #include <modest-platform.h>
42 #include <widgets/modest-window-mgr.h>
43 #include <modest-marshal.h>
44 #include <modest-debug.h>
45 #include <string.h> /* strcmp */
47 /* 'private'/'protected' functions */
48 static void modest_tny_send_queue_class_init (ModestTnySendQueueClass *klass);
49 static void modest_tny_send_queue_finalize (GObject *obj);
50 static void modest_tny_send_queue_instance_init (GTypeInstance *instance, gpointer g_class);
53 static void _on_msg_start_sending (TnySendQueue *self,
60 static void _on_msg_has_been_sent (TnySendQueue *self,
67 static void _on_msg_error_happened (TnySendQueue *self,
73 static void _on_queue_start (TnySendQueue *self,
76 static void _on_queue_stop (TnySendQueue *self,
79 static void modest_tny_send_queue_add_async (TnySendQueue *self,
81 TnySendQueueAddCallback callback,
82 TnyStatusCallback status_callback,
85 static TnyFolder* modest_tny_send_queue_get_outbox (TnySendQueue *self);
86 static TnyFolder* modest_tny_send_queue_get_sentbox (TnySendQueue *self);
87 static void modest_tny_send_queue_cancel (TnySendQueue *self,
88 TnySendQueueCancelAction cancel_action,
93 STATUS_CHANGED_SIGNAL,
97 typedef struct _SendInfo SendInfo;
100 ModestTnySendQueueStatus status;
103 typedef struct _ModestTnySendQueuePrivate ModestTnySendQueuePrivate;
104 struct _ModestTnySendQueuePrivate {
108 /* The info that is currently being sent */
111 /* Special folders */
115 /* last was send receive operation?*/
116 gboolean requested_send_receive;
123 #define MODEST_TNY_SEND_QUEUE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
124 MODEST_TYPE_TNY_SEND_QUEUE, \
125 ModestTnySendQueuePrivate))
128 static TnyCamelSendQueueClass *parent_class = NULL;
130 /* uncomment the following if you have defined any signals */
131 static guint signals[LAST_SIGNAL] = {0};
134 * this thread actually tries to send all the mails in the outbox and keeps
135 * track of their state.
139 on_modest_tny_send_queue_compare_id (gconstpointer info, gconstpointer msg_id)
141 g_return_val_if_fail (info && ((SendInfo*)info)->msg_id && msg_id, -1);
143 return strcmp( ((SendInfo*)info)->msg_id, msg_id);
147 modest_tny_send_queue_info_free (SendInfo *info)
149 g_free(info->msg_id);
150 g_slice_free(SendInfo, info);
154 modest_tny_send_queue_lookup_info (ModestTnySendQueue *self, const gchar *msg_id)
156 ModestTnySendQueuePrivate *priv;
157 priv = MODEST_TNY_SEND_QUEUE_GET_PRIVATE (self);
159 return g_queue_find_custom (priv->queue, msg_id, on_modest_tny_send_queue_compare_id);
164 queue_item_to_string (gpointer data, gchar **user_data)
166 SendInfo *info = (SendInfo*)data;
170 if (!(user_data && *user_data))
173 switch (info->status) {
174 case MODEST_TNY_SEND_QUEUE_UNKNOWN: status = "UNKNOWN"; break;
175 case MODEST_TNY_SEND_QUEUE_WAITING: status = "WAITING"; break;
176 case MODEST_TNY_SEND_QUEUE_SUSPENDED: status = "SUSPENDED"; break;
177 case MODEST_TNY_SEND_QUEUE_SENDING: status = "SENDING"; break;
178 case MODEST_TNY_SEND_QUEUE_FAILED: status = "FAILED"; break;
179 default: status= "UNEXPECTED"; break;
182 tmp = g_strdup_printf ("%s\"%s\" => [%s]\n",
183 *user_data, info->msg_id, status);
189 modest_tny_send_queue_to_string (ModestTnySendQueue *self)
192 ModestTnySendQueuePrivate *priv;
194 g_return_val_if_fail (MODEST_IS_TNY_SEND_QUEUE(self), NULL);
195 priv = MODEST_TNY_SEND_QUEUE_GET_PRIVATE (self);
197 str = g_strdup_printf ("items in the send queue: %d\n",
198 g_queue_get_length (priv->queue));
200 g_queue_foreach (priv->queue, (GFunc)queue_item_to_string, &str);
206 TnySendQueueAddCallback callback;
211 _on_added_to_outbox (TnySendQueue *self,
217 ModestTnySendQueuePrivate *priv = MODEST_TNY_SEND_QUEUE_GET_PRIVATE(self);
218 TnyHeader *header = NULL;
219 SendInfo *info = NULL;
220 GList* existing = NULL;
221 gchar* msg_id = NULL;
222 AddAsyncHelper *helper;
224 g_return_if_fail (TNY_IS_SEND_QUEUE(self));
225 g_return_if_fail (TNY_IS_CAMEL_MSG(msg));
227 header = tny_msg_get_header (msg);
228 msg_id = modest_tny_send_queue_get_msg_id (header);
230 g_warning ("%s: No msg_id returned for header", __FUNCTION__);
234 /* Put newly added message in WAITING state */
235 existing = modest_tny_send_queue_lookup_info (MODEST_TNY_SEND_QUEUE(self), msg_id);
236 if(existing != NULL) {
237 info = existing->data;
238 info->status = MODEST_TNY_SEND_QUEUE_WAITING;
240 info = g_slice_new (SendInfo);
241 info->msg_id = msg_id;
242 info->status = MODEST_TNY_SEND_QUEUE_WAITING;
243 g_queue_push_tail (priv->queue, info);
246 g_signal_emit (self, signals[STATUS_CHANGED_SIGNAL], 0, info->msg_id, info->status);
249 g_object_unref (G_OBJECT(header));
251 /* Call the user callback */
252 helper = (AddAsyncHelper *) user_data;
253 if (helper->callback)
254 helper->callback (self, cancelled, msg, err, helper->user_data);
255 g_slice_free (AddAsyncHelper, helper);
259 _add_message (ModestTnySendQueue *self, TnyHeader *header)
261 ModestWindowMgr *mgr = NULL;
262 ModestTnySendQueuePrivate *priv;
263 SendInfo *info = NULL;
264 GList* existing = NULL;
265 gchar* msg_uid = NULL;
266 ModestTnySendQueueStatus status = MODEST_TNY_SEND_QUEUE_UNKNOWN;
267 gboolean editing = FALSE;
269 g_return_if_fail (TNY_IS_SEND_QUEUE(self));
270 g_return_if_fail (TNY_IS_HEADER(header));
271 priv = MODEST_TNY_SEND_QUEUE_GET_PRIVATE (self);
273 /* Check whether the mail is already in the queue */
274 msg_uid = modest_tny_send_queue_get_msg_id (header);
275 status = modest_tny_send_queue_get_msg_status (self, msg_uid);
277 case MODEST_TNY_SEND_QUEUE_UNKNOWN:
278 case MODEST_TNY_SEND_QUEUE_SUSPENDED:
279 case MODEST_TNY_SEND_QUEUE_FAILED:
281 /* Check if it already exists on queue */
282 existing = modest_tny_send_queue_lookup_info (MODEST_TNY_SEND_QUEUE(self), msg_uid);
286 /* Check if its being edited */
287 mgr = modest_runtime_get_window_mgr ();
288 editing = modest_window_mgr_find_registered_header (mgr, header, NULL);
292 /* Add new meesage info */
293 info = g_slice_new0 (SendInfo);
294 info->msg_id = strdup(msg_uid);
295 info->status = MODEST_TNY_SEND_QUEUE_WAITING;
296 g_queue_push_tail (priv->queue, info);
307 modest_tny_send_queue_add_async (TnySendQueue *self,
309 TnySendQueueAddCallback callback,
310 TnyStatusCallback status_callback,
313 AddAsyncHelper *helper = g_slice_new0 (AddAsyncHelper);
314 helper->callback = callback;
315 helper->user_data = user_data;
317 /* Call the superclass passing our own callback */
318 TNY_CAMEL_SEND_QUEUE_CLASS(parent_class)->add_async (self, msg,
326 modest_tny_send_queue_get_sentbox (TnySendQueue *self)
328 ModestTnySendQueuePrivate *priv;
330 g_return_val_if_fail (self, NULL);
332 priv = MODEST_TNY_SEND_QUEUE_GET_PRIVATE (self);
334 return g_object_ref (priv->sentbox);
339 modest_tny_send_queue_get_outbox (TnySendQueue *self)
341 ModestTnySendQueuePrivate *priv;
343 g_return_val_if_fail (self, NULL);
345 priv = MODEST_TNY_SEND_QUEUE_GET_PRIVATE (self);
347 return g_object_ref (priv->outbox);
351 modest_tny_send_queue_cancel (TnySendQueue *self,
352 TnySendQueueCancelAction cancel_action,
355 ModestTnySendQueuePrivate *priv;
357 g_return_if_fail (self);
359 priv = MODEST_TNY_SEND_QUEUE_GET_PRIVATE (self);
361 /* Call the parent */
362 TNY_CAMEL_SEND_QUEUE_CLASS(parent_class)->cancel (self, cancel_action, err);
364 if (cancel_action == TNY_SEND_QUEUE_CANCEL_ACTION_SUSPEND && (err == NULL || *err == NULL))
365 priv->suspend = TRUE;
369 modest_tny_send_queue_get_type (void)
371 static GType my_type = 0;
374 static const GTypeInfo my_info = {
375 sizeof(ModestTnySendQueueClass),
376 NULL, /* base init */
377 NULL, /* base finalize */
378 (GClassInitFunc) modest_tny_send_queue_class_init,
379 NULL, /* class finalize */
380 NULL, /* class data */
381 sizeof(ModestTnySendQueue),
383 (GInstanceInitFunc) modest_tny_send_queue_instance_init,
387 my_type = g_type_register_static (TNY_TYPE_CAMEL_SEND_QUEUE,
388 "ModestTnySendQueue",
396 modest_tny_send_queue_class_init (ModestTnySendQueueClass *klass)
398 GObjectClass *gobject_class;
400 gobject_class = (GObjectClass*) klass;
402 parent_class = g_type_class_peek_parent (klass);
403 gobject_class->finalize = modest_tny_send_queue_finalize;
405 TNY_CAMEL_SEND_QUEUE_CLASS(klass)->add_async = modest_tny_send_queue_add_async;
406 TNY_CAMEL_SEND_QUEUE_CLASS(klass)->get_outbox = modest_tny_send_queue_get_outbox;
407 TNY_CAMEL_SEND_QUEUE_CLASS(klass)->get_sentbox = modest_tny_send_queue_get_sentbox;
408 TNY_CAMEL_SEND_QUEUE_CLASS(klass)->cancel = modest_tny_send_queue_cancel;
409 klass->status_changed = NULL;
411 signals[STATUS_CHANGED_SIGNAL] =
412 g_signal_new ("status_changed",
413 G_TYPE_FROM_CLASS (gobject_class),
415 G_STRUCT_OFFSET (ModestTnySendQueueClass, status_changed),
417 modest_marshal_VOID__STRING_INT,
418 G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_INT);
420 g_type_class_add_private (gobject_class, sizeof(ModestTnySendQueuePrivate));
424 modest_tny_send_queue_instance_init (GTypeInstance *instance, gpointer g_class)
426 ModestTnySendQueuePrivate *priv;
428 priv = MODEST_TNY_SEND_QUEUE_GET_PRIVATE (instance);
429 priv->queue = g_queue_new();
430 priv->current = NULL;
432 priv->sentbox = NULL;
433 priv->sending = FALSE;
434 priv->suspend = FALSE;
435 priv->sighandlers = NULL;
439 modest_tny_send_queue_finalize (GObject *obj)
441 ModestTnySendQueuePrivate *priv;
443 priv = MODEST_TNY_SEND_QUEUE_GET_PRIVATE (obj);
445 modest_signal_mgr_disconnect_all_and_destroy (priv->sighandlers);
446 priv->sighandlers = NULL;
448 g_queue_foreach (priv->queue, (GFunc)modest_tny_send_queue_info_free, NULL);
449 g_queue_free (priv->queue);
451 G_OBJECT_CLASS(parent_class)->finalize (obj);
452 g_object_unref (priv->outbox);
453 g_object_unref (priv->sentbox);
457 TnyCamelTransportAccount *account;
458 ModestTnySendQueue *queue;
462 new_queue_get_headers_async_cb (TnyFolder *folder,
468 ModestTnySendQueue *self;
470 GetHeadersInfo *info;
471 ModestMailOperation *wakeup_op;
473 info = (GetHeadersInfo *) user_data;
474 self = MODEST_TNY_SEND_QUEUE (info->queue);
476 /* In case of error set the transport account anyway */
477 if (cancelled || err)
480 /* Add messages to our internal queue */
481 iter = tny_list_create_iterator (headers);
482 while (!tny_iterator_is_done (iter)) {
483 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
484 _add_message (self, header);
485 g_object_unref (header);
486 tny_iterator_next (iter);
489 /* Reenable suspended items */
490 wakeup_op = modest_mail_operation_new (NULL);
491 modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (),
493 modest_mail_operation_queue_wakeup (wakeup_op, MODEST_TNY_SEND_QUEUE (self));
496 g_object_unref (iter);
497 g_object_unref (headers);
500 /* Do this at the end, because it'll call tny_send_queue_flush
501 which will call tny_send_queue_get_outbox and
502 tny_send_queue_get_sentbox */
503 tny_camel_send_queue_set_transport_account (TNY_CAMEL_SEND_QUEUE(self),
507 g_object_unref (info->account);
508 g_object_unref (info->queue);
509 g_slice_free (GetHeadersInfo, info);
513 modest_tny_send_queue_new (TnyCamelTransportAccount *account)
515 ModestTnySendQueue *self = NULL;
516 ModestTnySendQueuePrivate *priv = NULL;
517 TnyList *headers = NULL;
518 GetHeadersInfo *info;
520 g_return_val_if_fail (TNY_IS_CAMEL_TRANSPORT_ACCOUNT(account), NULL);
522 self = MODEST_TNY_SEND_QUEUE(g_object_new(MODEST_TYPE_TNY_SEND_QUEUE, NULL));
524 /* Set outbox and sentbox */
525 priv = MODEST_TNY_SEND_QUEUE_GET_PRIVATE (self);
526 priv->outbox = modest_tny_account_get_special_folder (TNY_ACCOUNT(account),
527 TNY_FOLDER_TYPE_OUTBOX);
528 priv->sentbox = modest_tny_account_get_special_folder (TNY_ACCOUNT(account),
529 TNY_FOLDER_TYPE_SENT);
531 /* NOTE that this could happen if there was not enough disk
532 space when the account was created */
533 if (!priv->outbox || !priv->sentbox) {
534 g_object_unref (self);
538 /* Connect signals to control when a msg is being or has been sent */
539 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
542 G_CALLBACK(_on_msg_start_sending),
544 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
545 G_OBJECT(self), "msg-sent",
546 G_CALLBACK(_on_msg_has_been_sent),
548 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
549 G_OBJECT(self), "error-happened",
550 G_CALLBACK(_on_msg_error_happened),
552 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
553 G_OBJECT (self), "queue-start",
554 G_CALLBACK (_on_queue_start),
556 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
557 G_OBJECT (self), "queue-stop",
558 G_CALLBACK (_on_queue_stop),
560 priv->requested_send_receive = FALSE;
562 headers = tny_simple_list_new ();
563 info = g_slice_new0 (GetHeadersInfo);
564 info->account = g_object_ref (account);
565 info->queue = g_object_ref (self);
566 tny_folder_get_headers_async (priv->outbox, headers, TRUE,
567 new_queue_get_headers_async_cb,
574 modest_tny_send_queue_msg_is_being_sent (ModestTnySendQueue* self,
577 ModestTnySendQueueStatus status;
579 g_return_val_if_fail (msg_id != NULL, FALSE);
581 status = modest_tny_send_queue_get_msg_status (self, msg_id);
582 return status == MODEST_TNY_SEND_QUEUE_SENDING;
586 modest_tny_send_queue_sending_in_progress (ModestTnySendQueue* self)
588 ModestTnySendQueuePrivate *priv;
590 g_return_val_if_fail (MODEST_IS_TNY_SEND_QUEUE(self), FALSE);
592 priv = MODEST_TNY_SEND_QUEUE_GET_PRIVATE (self);
594 return priv->sending;
597 ModestTnySendQueueStatus
598 modest_tny_send_queue_get_msg_status (ModestTnySendQueue *self, const gchar *msg_id)
602 g_return_val_if_fail (MODEST_IS_TNY_SEND_QUEUE(self), MODEST_TNY_SEND_QUEUE_UNKNOWN);
603 g_return_val_if_fail (msg_id, MODEST_TNY_SEND_QUEUE_UNKNOWN);
605 item = modest_tny_send_queue_lookup_info (self, msg_id);
607 return MODEST_TNY_SEND_QUEUE_UNKNOWN;
609 return ((SendInfo*)item->data)->status;
613 modest_tny_send_queue_get_msg_id (TnyHeader *header)
615 gchar* msg_uid = NULL;
617 time_t date_received;
619 g_return_val_if_fail (header && TNY_IS_HEADER(header), NULL);
621 /* Get message uid */
622 subject = tny_header_dup_subject (header);
623 date_received = tny_header_get_date_received (header);
625 msg_uid = g_strdup_printf ("%s %d", subject, (int) date_received);
633 _on_msg_start_sending (TnySendQueue *self, TnyHeader *header,
634 TnyMsg *msg, int done, int total, gpointer user_data)
636 ModestTnySendQueuePrivate *priv = NULL;
638 SendInfo *info = NULL;
639 gchar *msg_id = NULL;
641 priv = MODEST_TNY_SEND_QUEUE_GET_PRIVATE (self);
643 /* Get message uid */
644 msg_id = modest_tny_send_queue_get_msg_id (header);
646 item = modest_tny_send_queue_lookup_info (MODEST_TNY_SEND_QUEUE (self), msg_id);
648 g_warning ("%s: could not get msg-id for header", __FUNCTION__);
651 /* Set current status item */
653 info->status = MODEST_TNY_SEND_QUEUE_SENDING;
654 g_signal_emit (self, signals[STATUS_CHANGED_SIGNAL], 0, info->msg_id, info->status);
655 priv->current = item;
657 g_warning ("%s: could not find item with id '%s'", __FUNCTION__, msg_id);
664 _on_msg_has_been_sent (TnySendQueue *self,
671 ModestTnySendQueuePrivate *priv;
672 gchar *msg_id = NULL;
675 priv = MODEST_TNY_SEND_QUEUE_GET_PRIVATE (self);
677 /* Get message uid */
678 msg_id = modest_tny_send_queue_get_msg_id (header);
680 tny_header_set_flag (header, TNY_HEADER_FLAG_SEEN);
682 tny_folder_sync_async (priv->sentbox, FALSE, NULL, NULL, NULL);
684 /* Get status info */
685 item = modest_tny_send_queue_lookup_info (MODEST_TNY_SEND_QUEUE (self), msg_id);
688 /* TODO: note that item=NULL must not happen, but I found that
689 tinymail is issuing the message-sent signal twice, because
690 tny_camel_send_queue_update is called twice for each
691 message sent. This must be fixed in tinymail. Sergio */
693 /* Remove status info */
694 modest_tny_send_queue_info_free (item->data);
695 g_queue_delete_link (priv->queue, item);
696 priv->current = NULL;
698 modest_platform_information_banner (NULL, NULL, _("mcen_ib_message_sent"));
706 _on_msg_error_happened (TnySendQueue *self,
712 ModestTnySendQueuePrivate *priv = NULL;
714 priv = MODEST_TNY_SEND_QUEUE_GET_PRIVATE (self);
716 /* Note that header could be NULL. Tinymail notifies about
717 generic send queue errors with this signal as well, and
718 those notifications are not bound to any particular header
720 if (header && TNY_IS_HEADER (header)) {
721 SendInfo *info = NULL;
723 gchar* msg_uid = NULL;
725 /* Get sending info (create new if it doesn not exist) */
726 msg_uid = modest_tny_send_queue_get_msg_id (header);
727 item = modest_tny_send_queue_lookup_info (MODEST_TNY_SEND_QUEUE (self),
730 /* TODO: this should not happen (but it does), so the
731 problem should be located in the way we generate
734 g_warning ("%s: could not find item with id '%s'", __FUNCTION__, msg_uid);
741 /* Keep in queue so that we remember that the opertion has failed */
742 /* and was not just cancelled */
743 if (err->code == TNY_SYSTEM_ERROR_CANCEL) {
744 info->status = MODEST_TNY_SEND_QUEUE_SUSPENDED;
746 info->status = MODEST_TNY_SEND_QUEUE_FAILED;
748 priv->current = NULL;
750 /* Notify status has changed */
751 g_signal_emit (self, signals[STATUS_CHANGED_SIGNAL], 0, info->msg_id, info->status);
759 _on_queue_start (TnySendQueue *self,
762 ModestTnySendQueuePrivate *priv;
763 ModestMailOperation *mail_op;
765 mail_op = modest_mail_operation_new (NULL);
766 modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (),
768 modest_mail_operation_run_queue (mail_op, MODEST_TNY_SEND_QUEUE (self));
769 g_object_unref (mail_op);
771 priv = MODEST_TNY_SEND_QUEUE_GET_PRIVATE (self);
772 priv->sending = TRUE;
776 on_queue_stop_get_headers_async_cb (TnyFolder *folder,
782 ModestTnySendQueue *self = (ModestTnySendQueue *) user_data;
785 if (cancelled || err)
788 /* Update the info about headers */
789 iter = tny_list_create_iterator (headers);
790 while (!tny_iterator_is_done (iter)) {
793 header = (TnyHeader *) tny_iterator_get_current (iter);
795 gchar *msg_id = NULL;
798 /* Get message uid */
799 msg_id = modest_tny_send_queue_get_msg_id (header);
801 item = modest_tny_send_queue_lookup_info (MODEST_TNY_SEND_QUEUE (self), msg_id);
803 g_warning ("%s: could not get msg-id for header", __FUNCTION__);
807 /* Set current status item */
809 if (tny_header_get_flags (header) & TNY_HEADER_FLAG_SUSPENDED) {
810 info->status = MODEST_TNY_SEND_QUEUE_SUSPENDED;
811 g_signal_emit (self, signals[STATUS_CHANGED_SIGNAL], 0,
812 info->msg_id, info->status);
815 g_warning ("%s: could not find item with id '%s'", __FUNCTION__, msg_id);
817 g_object_unref (header);
819 tny_iterator_next (iter);
821 g_object_unref (iter);
825 g_object_unref (headers);
826 g_object_unref (self);
830 _on_queue_stop (TnySendQueue *self,
833 ModestTnySendQueuePrivate *priv;
835 priv = MODEST_TNY_SEND_QUEUE_GET_PRIVATE (self);
836 priv->sending = FALSE;
840 priv->suspend = FALSE;
842 /* Update the state of messages in the queue */
843 headers = tny_simple_list_new ();
844 tny_folder_get_headers_async (priv->outbox, headers, TRUE,
845 on_queue_stop_get_headers_async_cb,
846 NULL, g_object_ref (self));
851 fill_list_of_caches (gpointer key, gpointer value, gpointer userdata)
853 GSList **send_queues = (GSList **) userdata;
854 *send_queues = g_slist_prepend (*send_queues, value);
857 /* This function shouldn't be here. Move it to another place. Sergio */
858 ModestTnySendQueueStatus
859 modest_tny_all_send_queues_get_msg_status (TnyHeader *header)
861 ModestCacheMgr *cache_mgr = NULL;
862 GHashTable *send_queue_cache = NULL;
863 ModestTnyAccountStore *accounts_store = NULL;
864 TnyList *accounts = NULL;
865 TnyIterator *iter = NULL;
866 TnyTransportAccount *account = NULL;
867 GSList *send_queues = NULL, *node;
868 /* get_msg_status returns suspended by default, so we want to detect changes */
869 ModestTnySendQueueStatus status = MODEST_TNY_SEND_QUEUE_UNKNOWN;
870 ModestTnySendQueueStatus queue_status = MODEST_TNY_SEND_QUEUE_UNKNOWN;
871 gchar *msg_uid = NULL;
872 ModestTnySendQueue *send_queue = NULL;
874 g_return_val_if_fail (TNY_IS_HEADER(header), MODEST_TNY_SEND_QUEUE_UNKNOWN);
876 msg_uid = modest_tny_send_queue_get_msg_id (header);
877 cache_mgr = modest_runtime_get_cache_mgr ();
878 send_queue_cache = modest_cache_mgr_get_cache (cache_mgr,
879 MODEST_CACHE_MGR_CACHE_TYPE_SEND_QUEUE);
881 g_hash_table_foreach (send_queue_cache, (GHFunc) fill_list_of_caches, &send_queues);
882 if (send_queues == NULL) {
883 accounts = tny_simple_list_new ();
884 accounts_store = modest_runtime_get_account_store ();
885 tny_account_store_get_accounts (TNY_ACCOUNT_STORE(accounts_store),
887 TNY_ACCOUNT_STORE_TRANSPORT_ACCOUNTS);
889 iter = tny_list_create_iterator (accounts);
890 while (!tny_iterator_is_done (iter)) {
891 account = TNY_TRANSPORT_ACCOUNT(tny_iterator_get_current (iter));
892 send_queue = modest_runtime_get_send_queue(TNY_TRANSPORT_ACCOUNT(account), TRUE);
893 g_object_unref(account);
894 if (TNY_IS_SEND_QUEUE (send_queue)) {
895 queue_status = modest_tny_send_queue_get_msg_status (send_queue, msg_uid);
896 if (queue_status != MODEST_TNY_SEND_QUEUE_UNKNOWN) {
897 status = queue_status;
901 tny_iterator_next (iter);
903 g_object_unref (iter);
904 g_object_unref (accounts);
907 for (node = send_queues; node != NULL; node = g_slist_next (node)) {
908 send_queue = MODEST_TNY_SEND_QUEUE (node->data);
910 queue_status = modest_tny_send_queue_get_msg_status (send_queue, msg_uid);
911 if (queue_status != MODEST_TNY_SEND_QUEUE_UNKNOWN) {
912 status = queue_status;
919 g_slist_free (send_queues);
923 typedef struct _WakeupHelper {
924 ModestTnySendQueue *self;
925 ModestTnySendQueueWakeupFunc callback;
930 wakeup_sync_cb (TnyFolder *self, gboolean cancelled, GError *err, gpointer userdata)
932 WakeupHelper *helper = (WakeupHelper *) userdata;
934 if (helper->callback) {
935 helper->callback (helper->self, cancelled, err, helper->userdata);
937 g_object_unref (helper->self);
938 g_slice_free (WakeupHelper, helper);
942 wakeup_get_headers_async_cb (TnyFolder *folder,
948 ModestTnySendQueue *self;
949 ModestTnySendQueuePrivate *priv;
951 WakeupHelper *helper = (WakeupHelper *) user_data;
953 self = MODEST_TNY_SEND_QUEUE (helper->self);
954 priv = MODEST_TNY_SEND_QUEUE_GET_PRIVATE (self);
956 if (cancelled || err) {
957 g_debug ("Failed to wake up the headers of the send queue");
958 g_object_unref (self);
959 if (helper->callback) {
960 helper->callback (helper->self, cancelled, err, helper->userdata);
962 g_object_unref (helper->self);
963 g_slice_free (WakeupHelper, helper);
967 /* Wake up every single suspended header */
968 iter = tny_list_create_iterator (headers);
969 while (!tny_iterator_is_done (iter)) {
970 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
972 if (tny_header_get_flags (header) & TNY_HEADER_FLAG_SUSPENDED) {
977 /* Unset the suspended flag */
978 tny_header_unset_flag (header, TNY_HEADER_FLAG_SUSPENDED);
981 msg_id = modest_tny_send_queue_get_msg_id (header);
982 item = modest_tny_send_queue_lookup_info (MODEST_TNY_SEND_QUEUE (self), msg_id);
984 info = g_slice_new (SendInfo);
985 info->msg_id = msg_id;
986 g_queue_push_tail (priv->queue, info);
988 info = (SendInfo *) item->data;
991 info->status = MODEST_TNY_SEND_QUEUE_WAITING;
992 g_signal_emit (self, signals[STATUS_CHANGED_SIGNAL], 0, info->msg_id, info->status);
996 g_object_unref (header);
997 tny_iterator_next (iter);
1000 /* Make changes persistent on disk */
1001 tny_folder_sync_async (priv->outbox, FALSE, wakeup_sync_cb, NULL, helper);
1004 g_object_unref (iter);
1005 g_object_unref (headers);
1009 modest_tny_send_queue_wakeup (ModestTnySendQueue *self,
1010 ModestTnySendQueueWakeupFunc callback,
1013 ModestTnySendQueuePrivate *priv;
1015 WakeupHelper *helper;
1017 g_return_if_fail (MODEST_IS_TNY_SEND_QUEUE (self));
1018 priv = MODEST_TNY_SEND_QUEUE_GET_PRIVATE (self);
1020 helper = g_slice_new (WakeupHelper);
1021 helper->self = g_object_ref (self);
1022 helper->callback = callback;
1023 helper->userdata = userdata;
1025 headers = tny_simple_list_new ();
1026 tny_folder_get_headers_async (priv->outbox, headers, TRUE,
1027 wakeup_get_headers_async_cb,
1032 modest_tny_send_queue_get_requested_send_receive (ModestTnySendQueue *self)
1034 ModestTnySendQueuePrivate *priv;
1036 g_return_val_if_fail (MODEST_IS_TNY_SEND_QUEUE (self), FALSE);
1037 priv = MODEST_TNY_SEND_QUEUE_GET_PRIVATE (self);
1039 return priv->requested_send_receive;
1043 modest_tny_send_queue_set_requested_send_receive (ModestTnySendQueue *self, gboolean requested_send_receive)
1045 ModestTnySendQueuePrivate *priv;
1047 g_return_if_fail (MODEST_IS_TNY_SEND_QUEUE (self));
1048 priv = MODEST_TNY_SEND_QUEUE_GET_PRIVATE (self);
1050 priv->requested_send_receive = requested_send_receive;