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);
90 STATUS_CHANGED_SIGNAL,
94 typedef struct _SendInfo SendInfo;
97 ModestTnySendQueueStatus status;
100 typedef struct _ModestTnySendQueuePrivate ModestTnySendQueuePrivate;
101 struct _ModestTnySendQueuePrivate {
105 /* The info that is currently being sent */
108 /* Special folders */
112 /* last was send receive operation?*/
113 gboolean requested_send_receive;
118 #define MODEST_TNY_SEND_QUEUE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
119 MODEST_TYPE_TNY_SEND_QUEUE, \
120 ModestTnySendQueuePrivate))
123 static TnyCamelSendQueueClass *parent_class = NULL;
125 /* uncomment the following if you have defined any signals */
126 static guint signals[LAST_SIGNAL] = {0};
129 * this thread actually tries to send all the mails in the outbox and keeps
130 * track of their state.
134 on_modest_tny_send_queue_compare_id (gconstpointer info, gconstpointer msg_id)
136 g_return_val_if_fail (info && ((SendInfo*)info)->msg_id && msg_id, -1);
138 return strcmp( ((SendInfo*)info)->msg_id, msg_id);
142 modest_tny_send_queue_info_free (SendInfo *info)
144 g_free(info->msg_id);
145 g_slice_free(SendInfo, info);
149 modest_tny_send_queue_lookup_info (ModestTnySendQueue *self, const gchar *msg_id)
151 ModestTnySendQueuePrivate *priv;
152 priv = MODEST_TNY_SEND_QUEUE_GET_PRIVATE (self);
154 return g_queue_find_custom (priv->queue, msg_id, on_modest_tny_send_queue_compare_id);
159 queue_item_to_string (gpointer data, gchar **user_data)
161 SendInfo *info = (SendInfo*)data;
165 if (!(user_data && *user_data))
168 switch (info->status) {
169 case MODEST_TNY_SEND_QUEUE_UNKNOWN: status = "UNKNOWN"; break;
170 case MODEST_TNY_SEND_QUEUE_WAITING: status = "WAITING"; break;
171 case MODEST_TNY_SEND_QUEUE_SUSPENDED: status = "SUSPENDED"; break;
172 case MODEST_TNY_SEND_QUEUE_SENDING: status = "SENDING"; break;
173 case MODEST_TNY_SEND_QUEUE_FAILED: status = "FAILED"; break;
174 default: status= "UNEXPECTED"; break;
177 tmp = g_strdup_printf ("%s\"%s\" => [%s]\n",
178 *user_data, info->msg_id, status);
184 modest_tny_send_queue_to_string (ModestTnySendQueue *self)
187 ModestTnySendQueuePrivate *priv;
189 g_return_val_if_fail (MODEST_IS_TNY_SEND_QUEUE(self), NULL);
190 priv = MODEST_TNY_SEND_QUEUE_GET_PRIVATE (self);
192 str = g_strdup_printf ("items in the send queue: %d\n",
193 g_queue_get_length (priv->queue));
195 g_queue_foreach (priv->queue, (GFunc)queue_item_to_string, &str);
201 TnySendQueueAddCallback callback;
206 _on_added_to_outbox (TnySendQueue *self,
212 ModestTnySendQueuePrivate *priv = MODEST_TNY_SEND_QUEUE_GET_PRIVATE(self);
213 TnyHeader *header = NULL;
214 SendInfo *info = NULL;
215 GList* existing = NULL;
216 gchar* msg_id = NULL;
217 AddAsyncHelper *helper;
219 g_return_if_fail (TNY_IS_SEND_QUEUE(self));
220 g_return_if_fail (TNY_IS_CAMEL_MSG(msg));
222 header = tny_msg_get_header (msg);
223 msg_id = modest_tny_send_queue_get_msg_id (header);
225 g_warning ("%s: No msg_id returned for header", __FUNCTION__);
229 /* Put newly added message in WAITING state */
230 existing = modest_tny_send_queue_lookup_info (MODEST_TNY_SEND_QUEUE(self), msg_id);
231 if(existing != NULL) {
232 info = existing->data;
233 info->status = MODEST_TNY_SEND_QUEUE_WAITING;
235 info = g_slice_new (SendInfo);
236 info->msg_id = msg_id;
237 info->status = MODEST_TNY_SEND_QUEUE_WAITING;
238 g_queue_push_tail (priv->queue, info);
241 g_signal_emit (self, signals[STATUS_CHANGED_SIGNAL], 0, info->msg_id, info->status);
244 g_object_unref (G_OBJECT(header));
246 /* Call the user callback */
247 helper = (AddAsyncHelper *) user_data;
248 if (helper->callback)
249 helper->callback (self, cancelled, msg, err, helper->user_data);
250 g_slice_free (AddAsyncHelper, helper);
254 _add_message (ModestTnySendQueue *self, TnyHeader *header)
256 ModestWindowMgr *mgr = NULL;
257 ModestTnySendQueuePrivate *priv;
258 SendInfo *info = NULL;
259 GList* existing = NULL;
260 gchar* msg_uid = NULL;
261 ModestTnySendQueueStatus status = MODEST_TNY_SEND_QUEUE_UNKNOWN;
262 gboolean editing = FALSE;
264 g_return_if_fail (TNY_IS_SEND_QUEUE(self));
265 g_return_if_fail (TNY_IS_HEADER(header));
266 priv = MODEST_TNY_SEND_QUEUE_GET_PRIVATE (self);
268 /* Check whether the mail is already in the queue */
269 msg_uid = modest_tny_send_queue_get_msg_id (header);
270 status = modest_tny_send_queue_get_msg_status (self, msg_uid);
272 case MODEST_TNY_SEND_QUEUE_UNKNOWN:
273 case MODEST_TNY_SEND_QUEUE_SUSPENDED:
274 case MODEST_TNY_SEND_QUEUE_FAILED:
276 /* Check if it already exists on queue */
277 existing = modest_tny_send_queue_lookup_info (MODEST_TNY_SEND_QUEUE(self), msg_uid);
281 /* Check if its being edited */
282 mgr = modest_runtime_get_window_mgr ();
283 editing = modest_window_mgr_find_registered_header (mgr, header, NULL);
287 /* Add new meesage info */
288 info = g_slice_new0 (SendInfo);
289 info->msg_id = strdup(msg_uid);
290 info->status = MODEST_TNY_SEND_QUEUE_WAITING;
291 g_queue_push_tail (priv->queue, info);
302 modest_tny_send_queue_add_async (TnySendQueue *self,
304 TnySendQueueAddCallback callback,
305 TnyStatusCallback status_callback,
308 AddAsyncHelper *helper = g_slice_new0 (AddAsyncHelper);
309 helper->callback = callback;
310 helper->user_data = user_data;
312 /* Call the superclass passing our own callback */
313 TNY_CAMEL_SEND_QUEUE_CLASS(parent_class)->add_async (self, msg,
321 modest_tny_send_queue_get_sentbox (TnySendQueue *self)
323 ModestTnySendQueuePrivate *priv;
325 g_return_val_if_fail (self, NULL);
327 priv = MODEST_TNY_SEND_QUEUE_GET_PRIVATE (self);
329 return g_object_ref (priv->sentbox);
334 modest_tny_send_queue_get_outbox (TnySendQueue *self)
336 ModestTnySendQueuePrivate *priv;
338 g_return_val_if_fail (self, NULL);
340 priv = MODEST_TNY_SEND_QUEUE_GET_PRIVATE (self);
342 return g_object_ref (priv->outbox);
346 modest_tny_send_queue_get_type (void)
348 static GType my_type = 0;
351 static const GTypeInfo my_info = {
352 sizeof(ModestTnySendQueueClass),
353 NULL, /* base init */
354 NULL, /* base finalize */
355 (GClassInitFunc) modest_tny_send_queue_class_init,
356 NULL, /* class finalize */
357 NULL, /* class data */
358 sizeof(ModestTnySendQueue),
360 (GInstanceInitFunc) modest_tny_send_queue_instance_init,
364 my_type = g_type_register_static (TNY_TYPE_CAMEL_SEND_QUEUE,
365 "ModestTnySendQueue",
373 modest_tny_send_queue_class_init (ModestTnySendQueueClass *klass)
375 GObjectClass *gobject_class;
377 gobject_class = (GObjectClass*) klass;
379 parent_class = g_type_class_peek_parent (klass);
380 gobject_class->finalize = modest_tny_send_queue_finalize;
382 TNY_CAMEL_SEND_QUEUE_CLASS(klass)->add_async = modest_tny_send_queue_add_async;
383 TNY_CAMEL_SEND_QUEUE_CLASS(klass)->get_outbox = modest_tny_send_queue_get_outbox;
384 TNY_CAMEL_SEND_QUEUE_CLASS(klass)->get_sentbox = modest_tny_send_queue_get_sentbox;
385 klass->status_changed = NULL;
387 signals[STATUS_CHANGED_SIGNAL] =
388 g_signal_new ("status_changed",
389 G_TYPE_FROM_CLASS (gobject_class),
391 G_STRUCT_OFFSET (ModestTnySendQueueClass, status_changed),
393 modest_marshal_VOID__STRING_INT,
394 G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_INT);
396 g_type_class_add_private (gobject_class, sizeof(ModestTnySendQueuePrivate));
400 modest_tny_send_queue_instance_init (GTypeInstance *instance, gpointer g_class)
402 ModestTnySendQueuePrivate *priv;
404 priv = MODEST_TNY_SEND_QUEUE_GET_PRIVATE (instance);
405 priv->queue = g_queue_new();
406 priv->current = NULL;
408 priv->sentbox = NULL;
409 priv->sending = FALSE;
413 modest_tny_send_queue_finalize (GObject *obj)
415 ModestTnySendQueuePrivate *priv;
417 priv = MODEST_TNY_SEND_QUEUE_GET_PRIVATE (obj);
419 g_queue_foreach (priv->queue, (GFunc)modest_tny_send_queue_info_free, NULL);
420 g_queue_free (priv->queue);
422 G_OBJECT_CLASS(parent_class)->finalize (obj);
423 g_object_unref (priv->outbox);
424 g_object_unref (priv->sentbox);
428 TnyCamelTransportAccount *account;
429 ModestTnySendQueue *queue;
433 new_queue_get_headers_async_cb (TnyFolder *folder,
439 ModestTnySendQueue *self;
441 GetHeadersInfo *info;
442 ModestMailOperation *wakeup_op;
444 info = (GetHeadersInfo *) user_data;
445 self = MODEST_TNY_SEND_QUEUE (info->queue);
447 /* In case of error set the transport account anyway */
448 if (cancelled || err)
451 /* Add messages to our internal queue */
452 iter = tny_list_create_iterator (headers);
453 while (!tny_iterator_is_done (iter)) {
454 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
455 _add_message (self, header);
456 g_object_unref (header);
457 tny_iterator_next (iter);
460 /* Reenable suspended items */
461 wakeup_op = modest_mail_operation_new (NULL);
462 modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (),
464 modest_mail_operation_queue_wakeup (wakeup_op, MODEST_TNY_SEND_QUEUE (self));
467 g_object_unref (iter);
468 g_object_unref (headers);
471 /* Do this at the end, because it'll call tny_send_queue_flush
472 which will call tny_send_queue_get_outbox and
473 tny_send_queue_get_sentbox */
474 tny_camel_send_queue_set_transport_account (TNY_CAMEL_SEND_QUEUE(self),
478 g_object_unref (info->account);
479 g_object_unref (info->queue);
480 g_slice_free (GetHeadersInfo, info);
484 modest_tny_send_queue_new (TnyCamelTransportAccount *account)
486 ModestTnySendQueue *self = NULL;
487 ModestTnySendQueuePrivate *priv = NULL;
488 TnyList *headers = NULL;
489 GetHeadersInfo *info;
491 g_return_val_if_fail (TNY_IS_CAMEL_TRANSPORT_ACCOUNT(account), NULL);
493 self = MODEST_TNY_SEND_QUEUE(g_object_new(MODEST_TYPE_TNY_SEND_QUEUE, NULL));
495 /* Set outbox and sentbox */
496 priv = MODEST_TNY_SEND_QUEUE_GET_PRIVATE (self);
497 priv->outbox = modest_tny_account_get_special_folder (TNY_ACCOUNT(account),
498 TNY_FOLDER_TYPE_OUTBOX);
499 priv->sentbox = modest_tny_account_get_special_folder (TNY_ACCOUNT(account),
500 TNY_FOLDER_TYPE_SENT);
502 /* NOTE that this could happen if there was not enough disk
503 space when the account was created */
504 if (!priv->outbox || !priv->sentbox) {
505 g_object_unref (self);
509 /* Connect signals to control when a msg is being or has been sent */
510 g_signal_connect (G_OBJECT(self), "msg-sending",
511 G_CALLBACK(_on_msg_start_sending),
513 g_signal_connect (G_OBJECT(self), "msg-sent",
514 G_CALLBACK(_on_msg_has_been_sent),
516 g_signal_connect (G_OBJECT(self), "error-happened",
517 G_CALLBACK(_on_msg_error_happened),
520 g_signal_connect (G_OBJECT (self), "queue-start",
521 G_CALLBACK (_on_queue_start),
524 g_signal_connect (G_OBJECT (self), "queue-stop",
525 G_CALLBACK (_on_queue_stop),
528 priv->requested_send_receive = FALSE;
530 headers = tny_simple_list_new ();
531 info = g_slice_new0 (GetHeadersInfo);
532 info->account = g_object_ref (account);
533 info->queue = g_object_ref (self);
534 tny_folder_get_headers_async (priv->outbox, headers, TRUE,
535 new_queue_get_headers_async_cb,
542 modest_tny_send_queue_msg_is_being_sent (ModestTnySendQueue* self,
545 ModestTnySendQueueStatus status;
547 g_return_val_if_fail (msg_id != NULL, FALSE);
549 status = modest_tny_send_queue_get_msg_status (self, msg_id);
550 return status == MODEST_TNY_SEND_QUEUE_SENDING;
554 modest_tny_send_queue_sending_in_progress (ModestTnySendQueue* self)
556 ModestTnySendQueuePrivate *priv;
558 g_return_val_if_fail (MODEST_IS_TNY_SEND_QUEUE(self), FALSE);
560 priv = MODEST_TNY_SEND_QUEUE_GET_PRIVATE (self);
562 return priv->sending;
565 ModestTnySendQueueStatus
566 modest_tny_send_queue_get_msg_status (ModestTnySendQueue *self, const gchar *msg_id)
570 g_return_val_if_fail (MODEST_IS_TNY_SEND_QUEUE(self), MODEST_TNY_SEND_QUEUE_UNKNOWN);
571 g_return_val_if_fail (msg_id, MODEST_TNY_SEND_QUEUE_UNKNOWN);
573 item = modest_tny_send_queue_lookup_info (self, msg_id);
575 return MODEST_TNY_SEND_QUEUE_UNKNOWN;
577 return ((SendInfo*)item->data)->status;
581 modest_tny_send_queue_get_msg_id (TnyHeader *header)
583 gchar* msg_uid = NULL;
585 time_t date_received;
587 g_return_val_if_fail (header && TNY_IS_HEADER(header), NULL);
589 /* Get message uid */
590 subject = tny_header_dup_subject (header);
591 date_received = tny_header_get_date_received (header);
593 msg_uid = g_strdup_printf ("%s %d", subject, (int) date_received);
601 _on_msg_start_sending (TnySendQueue *self, TnyHeader *header,
602 TnyMsg *msg, int done, int total, gpointer user_data)
604 ModestTnySendQueuePrivate *priv = NULL;
606 SendInfo *info = NULL;
607 gchar *msg_id = NULL;
609 priv = MODEST_TNY_SEND_QUEUE_GET_PRIVATE (self);
611 /* Get message uid */
612 msg_id = modest_tny_send_queue_get_msg_id (header);
614 item = modest_tny_send_queue_lookup_info (MODEST_TNY_SEND_QUEUE (self), msg_id);
616 g_warning ("%s: could not get msg-id for header", __FUNCTION__);
619 /* Set current status item */
621 info->status = MODEST_TNY_SEND_QUEUE_SENDING;
622 g_signal_emit (self, signals[STATUS_CHANGED_SIGNAL], 0, info->msg_id, info->status);
623 priv->current = item;
625 g_warning ("%s: could not find item with id '%s'", __FUNCTION__, msg_id);
632 _on_msg_has_been_sent (TnySendQueue *self,
639 ModestTnySendQueuePrivate *priv;
640 gchar *msg_id = NULL;
643 priv = MODEST_TNY_SEND_QUEUE_GET_PRIVATE (self);
645 /* Get message uid */
646 msg_id = modest_tny_send_queue_get_msg_id (header);
648 tny_header_set_flag (header, TNY_HEADER_FLAG_SEEN);
650 tny_folder_sync_async (priv->sentbox, FALSE, NULL, NULL, NULL);
652 /* Get status info */
653 item = modest_tny_send_queue_lookup_info (MODEST_TNY_SEND_QUEUE (self), msg_id);
656 /* TODO: note that item=NULL must not happen, but I found that
657 tinymail is issuing the message-sent signal twice, because
658 tny_camel_send_queue_update is called twice for each
659 message sent. This must be fixed in tinymail. Sergio */
661 /* Remove status info */
662 modest_tny_send_queue_info_free (item->data);
663 g_queue_delete_link (priv->queue, item);
664 priv->current = NULL;
666 modest_platform_information_banner (NULL, NULL, _("mcen_ib_message_sent"));
674 _on_msg_error_happened (TnySendQueue *self,
680 ModestTnySendQueuePrivate *priv = NULL;
682 priv = MODEST_TNY_SEND_QUEUE_GET_PRIVATE (self);
684 /* Note that header could be NULL. Tinymail notifies about
685 generic send queue errors with this signal as well, and
686 those notifications are not bound to any particular header
688 if (header && TNY_IS_HEADER (header)) {
689 SendInfo *info = NULL;
691 gchar* msg_uid = NULL;
693 /* Get sending info (create new if it doesn not exist) */
694 msg_uid = modest_tny_send_queue_get_msg_id (header);
695 item = modest_tny_send_queue_lookup_info (MODEST_TNY_SEND_QUEUE (self),
698 /* TODO: this should not happen (but it does), so the
699 problem should be located in the way we generate
702 g_warning ("%s: could not find item with id '%s'", __FUNCTION__, msg_uid);
709 /* Keep in queue so that we remember that the opertion has failed */
710 /* and was not just cancelled */
711 if (err->code == TNY_SYSTEM_ERROR_CANCEL) {
712 info->status = MODEST_TNY_SEND_QUEUE_SUSPENDED;
714 info->status = MODEST_TNY_SEND_QUEUE_FAILED;
716 priv->current = NULL;
718 /* Notify status has changed */
719 g_signal_emit (self, signals[STATUS_CHANGED_SIGNAL], 0, info->msg_id, info->status);
727 _on_queue_start (TnySendQueue *self,
730 ModestTnySendQueuePrivate *priv;
731 ModestMailOperation *mail_op;
733 mail_op = modest_mail_operation_new (NULL);
734 modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (),
736 modest_mail_operation_run_queue (mail_op, MODEST_TNY_SEND_QUEUE (self));
737 g_object_unref (mail_op);
739 priv = MODEST_TNY_SEND_QUEUE_GET_PRIVATE (self);
740 priv->sending = TRUE;
744 _on_queue_stop (TnySendQueue *self,
747 ModestTnySendQueuePrivate *priv;
749 priv = MODEST_TNY_SEND_QUEUE_GET_PRIVATE (self);
750 priv->sending = FALSE;
754 fill_list_of_caches (gpointer key, gpointer value, gpointer userdata)
756 GSList **send_queues = (GSList **) userdata;
757 *send_queues = g_slist_prepend (*send_queues, value);
760 /* This function shouldn't be here. Move it to another place. Sergio */
761 ModestTnySendQueueStatus
762 modest_tny_all_send_queues_get_msg_status (TnyHeader *header)
764 ModestCacheMgr *cache_mgr = NULL;
765 GHashTable *send_queue_cache = NULL;
766 ModestTnyAccountStore *accounts_store = NULL;
767 TnyList *accounts = NULL;
768 TnyIterator *iter = NULL;
769 TnyTransportAccount *account = NULL;
770 GSList *send_queues = NULL, *node;
771 /* get_msg_status returns suspended by default, so we want to detect changes */
772 ModestTnySendQueueStatus status = MODEST_TNY_SEND_QUEUE_UNKNOWN;
773 ModestTnySendQueueStatus queue_status = MODEST_TNY_SEND_QUEUE_UNKNOWN;
774 gchar *msg_uid = NULL;
775 ModestTnySendQueue *send_queue = NULL;
777 g_return_val_if_fail (TNY_IS_HEADER(header), MODEST_TNY_SEND_QUEUE_UNKNOWN);
779 msg_uid = modest_tny_send_queue_get_msg_id (header);
780 cache_mgr = modest_runtime_get_cache_mgr ();
781 send_queue_cache = modest_cache_mgr_get_cache (cache_mgr,
782 MODEST_CACHE_MGR_CACHE_TYPE_SEND_QUEUE);
784 g_hash_table_foreach (send_queue_cache, (GHFunc) fill_list_of_caches, &send_queues);
785 if (send_queues == NULL) {
786 accounts = tny_simple_list_new ();
787 accounts_store = modest_runtime_get_account_store ();
788 tny_account_store_get_accounts (TNY_ACCOUNT_STORE(accounts_store),
790 TNY_ACCOUNT_STORE_TRANSPORT_ACCOUNTS);
792 iter = tny_list_create_iterator (accounts);
793 while (!tny_iterator_is_done (iter)) {
794 account = TNY_TRANSPORT_ACCOUNT(tny_iterator_get_current (iter));
795 send_queue = modest_runtime_get_send_queue(TNY_TRANSPORT_ACCOUNT(account), TRUE);
796 g_object_unref(account);
797 if (TNY_IS_SEND_QUEUE (send_queue)) {
798 queue_status = modest_tny_send_queue_get_msg_status (send_queue, msg_uid);
799 if (queue_status != MODEST_TNY_SEND_QUEUE_UNKNOWN) {
800 status = queue_status;
804 tny_iterator_next (iter);
806 g_object_unref (iter);
807 g_object_unref (accounts);
810 for (node = send_queues; node != NULL; node = g_slist_next (node)) {
811 send_queue = MODEST_TNY_SEND_QUEUE (node->data);
813 queue_status = modest_tny_send_queue_get_msg_status (send_queue, msg_uid);
814 if (queue_status != MODEST_TNY_SEND_QUEUE_UNKNOWN) {
815 status = queue_status;
822 g_slist_free (send_queues);
826 typedef struct _WakeupHelper {
827 ModestTnySendQueue *self;
828 ModestTnySendQueueWakeupFunc callback;
833 wakeup_sync_cb (TnyFolder *self, gboolean cancelled, GError *err, gpointer userdata)
835 WakeupHelper *helper = (WakeupHelper *) userdata;
837 if (helper->callback) {
838 helper->callback (helper->self, cancelled, err, helper->userdata);
840 g_object_unref (helper->self);
841 g_slice_free (WakeupHelper, helper);
845 wakeup_get_headers_async_cb (TnyFolder *folder,
851 ModestTnySendQueue *self;
852 ModestTnySendQueuePrivate *priv;
854 WakeupHelper *helper = (WakeupHelper *) user_data;
856 self = MODEST_TNY_SEND_QUEUE (helper->self);
857 priv = MODEST_TNY_SEND_QUEUE_GET_PRIVATE (self);
859 if (cancelled || err) {
860 g_debug ("Failed to wake up the headers of the send queue");
861 g_object_unref (self);
862 if (helper->callback) {
863 helper->callback (helper->self, cancelled, err, helper->userdata);
865 g_object_unref (helper->self);
866 g_slice_free (WakeupHelper, helper);
870 /* Wake up every single suspended header */
871 iter = tny_list_create_iterator (headers);
872 while (!tny_iterator_is_done (iter)) {
873 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
875 if (tny_header_get_flags (header) & TNY_HEADER_FLAG_SUSPENDED) {
880 /* Unset the suspended flag */
881 tny_header_unset_flag (header, TNY_HEADER_FLAG_SUSPENDED);
884 msg_id = modest_tny_send_queue_get_msg_id (header);
885 item = modest_tny_send_queue_lookup_info (MODEST_TNY_SEND_QUEUE (self), msg_id);
887 info = g_slice_new (SendInfo);
888 info->msg_id = msg_id;
889 g_queue_push_tail (priv->queue, info);
891 info = (SendInfo *) item->data;
894 info->status = MODEST_TNY_SEND_QUEUE_WAITING;
895 g_signal_emit (self, signals[STATUS_CHANGED_SIGNAL], 0, info->msg_id, info->status);
899 g_object_unref (header);
900 tny_iterator_next (iter);
903 /* Make changes persistent on disk */
904 tny_folder_sync_async (priv->outbox, FALSE, wakeup_sync_cb, NULL, helper);
907 g_object_unref (iter);
908 g_object_unref (headers);
912 modest_tny_send_queue_wakeup (ModestTnySendQueue *self,
913 ModestTnySendQueueWakeupFunc callback,
916 ModestTnySendQueuePrivate *priv;
918 WakeupHelper *helper;
920 g_return_if_fail (MODEST_IS_TNY_SEND_QUEUE (self));
921 priv = MODEST_TNY_SEND_QUEUE_GET_PRIVATE (self);
923 helper = g_slice_new (WakeupHelper);
924 helper->self = g_object_ref (self);
925 helper->callback = callback;
926 helper->userdata = userdata;
928 headers = tny_simple_list_new ();
929 tny_folder_get_headers_async (priv->outbox, headers, TRUE,
930 wakeup_get_headers_async_cb,
935 modest_tny_send_queue_get_requested_send_receive (ModestTnySendQueue *self)
937 ModestTnySendQueuePrivate *priv;
939 g_return_val_if_fail (MODEST_IS_TNY_SEND_QUEUE (self), FALSE);
940 priv = MODEST_TNY_SEND_QUEUE_GET_PRIVATE (self);
942 return priv->requested_send_receive;
946 modest_tny_send_queue_set_requested_send_receive (ModestTnySendQueue *self, gboolean requested_send_receive)
948 ModestTnySendQueuePrivate *priv;
950 g_return_if_fail (MODEST_IS_TNY_SEND_QUEUE (self));
951 priv = MODEST_TNY_SEND_QUEUE_GET_PRIVATE (self);
953 priv->requested_send_receive = requested_send_receive;