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;
120 #define MODEST_TNY_SEND_QUEUE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
121 MODEST_TYPE_TNY_SEND_QUEUE, \
122 ModestTnySendQueuePrivate))
125 static TnyCamelSendQueueClass *parent_class = NULL;
127 /* uncomment the following if you have defined any signals */
128 static guint signals[LAST_SIGNAL] = {0};
131 * this thread actually tries to send all the mails in the outbox and keeps
132 * track of their state.
136 on_modest_tny_send_queue_compare_id (gconstpointer info, gconstpointer msg_id)
138 g_return_val_if_fail (info && ((SendInfo*)info)->msg_id && msg_id, -1);
140 return strcmp( ((SendInfo*)info)->msg_id, msg_id);
144 modest_tny_send_queue_info_free (SendInfo *info)
146 g_free(info->msg_id);
147 g_slice_free(SendInfo, info);
151 modest_tny_send_queue_lookup_info (ModestTnySendQueue *self, const gchar *msg_id)
153 ModestTnySendQueuePrivate *priv;
154 priv = MODEST_TNY_SEND_QUEUE_GET_PRIVATE (self);
156 return g_queue_find_custom (priv->queue, msg_id, on_modest_tny_send_queue_compare_id);
161 queue_item_to_string (gpointer data, gchar **user_data)
163 SendInfo *info = (SendInfo*)data;
167 if (!(user_data && *user_data))
170 switch (info->status) {
171 case MODEST_TNY_SEND_QUEUE_UNKNOWN: status = "UNKNOWN"; break;
172 case MODEST_TNY_SEND_QUEUE_WAITING: status = "WAITING"; break;
173 case MODEST_TNY_SEND_QUEUE_SUSPENDED: status = "SUSPENDED"; break;
174 case MODEST_TNY_SEND_QUEUE_SENDING: status = "SENDING"; break;
175 case MODEST_TNY_SEND_QUEUE_FAILED: status = "FAILED"; break;
176 default: status= "UNEXPECTED"; break;
179 tmp = g_strdup_printf ("%s\"%s\" => [%s]\n",
180 *user_data, info->msg_id, status);
186 modest_tny_send_queue_to_string (ModestTnySendQueue *self)
189 ModestTnySendQueuePrivate *priv;
191 g_return_val_if_fail (MODEST_IS_TNY_SEND_QUEUE(self), NULL);
192 priv = MODEST_TNY_SEND_QUEUE_GET_PRIVATE (self);
194 str = g_strdup_printf ("items in the send queue: %d\n",
195 g_queue_get_length (priv->queue));
197 g_queue_foreach (priv->queue, (GFunc)queue_item_to_string, &str);
203 TnySendQueueAddCallback callback;
208 _on_added_to_outbox (TnySendQueue *self,
214 ModestTnySendQueuePrivate *priv = MODEST_TNY_SEND_QUEUE_GET_PRIVATE(self);
215 TnyHeader *header = NULL;
216 SendInfo *info = NULL;
217 GList* existing = NULL;
218 gchar* msg_id = NULL;
219 AddAsyncHelper *helper;
221 g_return_if_fail (TNY_IS_SEND_QUEUE(self));
222 g_return_if_fail (TNY_IS_CAMEL_MSG(msg));
224 header = tny_msg_get_header (msg);
225 msg_id = modest_tny_send_queue_get_msg_id (header);
227 g_warning ("%s: No msg_id returned for header", __FUNCTION__);
231 /* Put newly added message in WAITING state */
232 existing = modest_tny_send_queue_lookup_info (MODEST_TNY_SEND_QUEUE(self), msg_id);
233 if(existing != NULL) {
234 info = existing->data;
235 info->status = MODEST_TNY_SEND_QUEUE_WAITING;
237 info = g_slice_new (SendInfo);
238 info->msg_id = msg_id;
239 info->status = MODEST_TNY_SEND_QUEUE_WAITING;
240 g_queue_push_tail (priv->queue, info);
243 g_signal_emit (self, signals[STATUS_CHANGED_SIGNAL], 0, info->msg_id, info->status);
246 g_object_unref (G_OBJECT(header));
248 /* Call the user callback */
249 helper = (AddAsyncHelper *) user_data;
250 if (helper->callback)
251 helper->callback (self, cancelled, msg, err, helper->user_data);
252 g_slice_free (AddAsyncHelper, helper);
256 _add_message (ModestTnySendQueue *self, TnyHeader *header)
258 ModestWindowMgr *mgr = NULL;
259 ModestTnySendQueuePrivate *priv;
260 SendInfo *info = NULL;
261 GList* existing = NULL;
262 gchar* msg_uid = NULL;
263 ModestTnySendQueueStatus status = MODEST_TNY_SEND_QUEUE_UNKNOWN;
264 gboolean editing = FALSE;
266 g_return_if_fail (TNY_IS_SEND_QUEUE(self));
267 g_return_if_fail (TNY_IS_HEADER(header));
268 priv = MODEST_TNY_SEND_QUEUE_GET_PRIVATE (self);
270 /* Check whether the mail is already in the queue */
271 msg_uid = modest_tny_send_queue_get_msg_id (header);
272 status = modest_tny_send_queue_get_msg_status (self, msg_uid);
274 case MODEST_TNY_SEND_QUEUE_UNKNOWN:
275 case MODEST_TNY_SEND_QUEUE_SUSPENDED:
276 case MODEST_TNY_SEND_QUEUE_FAILED:
278 /* Check if it already exists on queue */
279 existing = modest_tny_send_queue_lookup_info (MODEST_TNY_SEND_QUEUE(self), msg_uid);
283 /* Check if its being edited */
284 mgr = modest_runtime_get_window_mgr ();
285 editing = modest_window_mgr_find_registered_header (mgr, header, NULL);
289 /* Add new meesage info */
290 info = g_slice_new0 (SendInfo);
291 info->msg_id = strdup(msg_uid);
292 info->status = MODEST_TNY_SEND_QUEUE_WAITING;
293 g_queue_push_tail (priv->queue, info);
304 modest_tny_send_queue_add_async (TnySendQueue *self,
306 TnySendQueueAddCallback callback,
307 TnyStatusCallback status_callback,
310 AddAsyncHelper *helper = g_slice_new0 (AddAsyncHelper);
311 helper->callback = callback;
312 helper->user_data = user_data;
314 /* Call the superclass passing our own callback */
315 TNY_CAMEL_SEND_QUEUE_CLASS(parent_class)->add_async (self, msg,
323 modest_tny_send_queue_get_sentbox (TnySendQueue *self)
325 ModestTnySendQueuePrivate *priv;
327 g_return_val_if_fail (self, NULL);
329 priv = MODEST_TNY_SEND_QUEUE_GET_PRIVATE (self);
331 return g_object_ref (priv->sentbox);
336 modest_tny_send_queue_get_outbox (TnySendQueue *self)
338 ModestTnySendQueuePrivate *priv;
340 g_return_val_if_fail (self, NULL);
342 priv = MODEST_TNY_SEND_QUEUE_GET_PRIVATE (self);
344 return g_object_ref (priv->outbox);
348 modest_tny_send_queue_get_type (void)
350 static GType my_type = 0;
353 static const GTypeInfo my_info = {
354 sizeof(ModestTnySendQueueClass),
355 NULL, /* base init */
356 NULL, /* base finalize */
357 (GClassInitFunc) modest_tny_send_queue_class_init,
358 NULL, /* class finalize */
359 NULL, /* class data */
360 sizeof(ModestTnySendQueue),
362 (GInstanceInitFunc) modest_tny_send_queue_instance_init,
366 my_type = g_type_register_static (TNY_TYPE_CAMEL_SEND_QUEUE,
367 "ModestTnySendQueue",
375 modest_tny_send_queue_class_init (ModestTnySendQueueClass *klass)
377 GObjectClass *gobject_class;
379 gobject_class = (GObjectClass*) klass;
381 parent_class = g_type_class_peek_parent (klass);
382 gobject_class->finalize = modest_tny_send_queue_finalize;
384 TNY_CAMEL_SEND_QUEUE_CLASS(klass)->add_async = modest_tny_send_queue_add_async;
385 TNY_CAMEL_SEND_QUEUE_CLASS(klass)->get_outbox = modest_tny_send_queue_get_outbox;
386 TNY_CAMEL_SEND_QUEUE_CLASS(klass)->get_sentbox = modest_tny_send_queue_get_sentbox;
387 klass->status_changed = NULL;
389 signals[STATUS_CHANGED_SIGNAL] =
390 g_signal_new ("status_changed",
391 G_TYPE_FROM_CLASS (gobject_class),
393 G_STRUCT_OFFSET (ModestTnySendQueueClass, status_changed),
395 modest_marshal_VOID__STRING_INT,
396 G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_INT);
398 g_type_class_add_private (gobject_class, sizeof(ModestTnySendQueuePrivate));
402 modest_tny_send_queue_instance_init (GTypeInstance *instance, gpointer g_class)
404 ModestTnySendQueuePrivate *priv;
406 priv = MODEST_TNY_SEND_QUEUE_GET_PRIVATE (instance);
407 priv->queue = g_queue_new();
408 priv->current = NULL;
410 priv->sentbox = NULL;
411 priv->sending = FALSE;
412 priv->sighandlers = NULL;
416 modest_tny_send_queue_finalize (GObject *obj)
418 ModestTnySendQueuePrivate *priv;
420 priv = MODEST_TNY_SEND_QUEUE_GET_PRIVATE (obj);
422 modest_signal_mgr_disconnect_all_and_destroy (priv->sighandlers);
423 priv->sighandlers = NULL;
425 g_queue_foreach (priv->queue, (GFunc)modest_tny_send_queue_info_free, NULL);
426 g_queue_free (priv->queue);
428 G_OBJECT_CLASS(parent_class)->finalize (obj);
429 g_object_unref (priv->outbox);
430 g_object_unref (priv->sentbox);
434 TnyCamelTransportAccount *account;
435 ModestTnySendQueue *queue;
439 new_queue_get_headers_async_cb (TnyFolder *folder,
445 ModestTnySendQueue *self;
447 GetHeadersInfo *info;
448 ModestMailOperation *wakeup_op;
450 info = (GetHeadersInfo *) user_data;
451 self = MODEST_TNY_SEND_QUEUE (info->queue);
453 /* In case of error set the transport account anyway */
454 if (cancelled || err)
457 /* Add messages to our internal queue */
458 iter = tny_list_create_iterator (headers);
459 while (!tny_iterator_is_done (iter)) {
460 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
461 _add_message (self, header);
462 g_object_unref (header);
463 tny_iterator_next (iter);
466 /* Reenable suspended items */
467 wakeup_op = modest_mail_operation_new (NULL);
468 modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (),
470 modest_mail_operation_queue_wakeup (wakeup_op, MODEST_TNY_SEND_QUEUE (self));
473 g_object_unref (iter);
474 g_object_unref (headers);
477 /* Do this at the end, because it'll call tny_send_queue_flush
478 which will call tny_send_queue_get_outbox and
479 tny_send_queue_get_sentbox */
480 tny_camel_send_queue_set_transport_account (TNY_CAMEL_SEND_QUEUE(self),
484 g_object_unref (info->account);
485 g_object_unref (info->queue);
486 g_slice_free (GetHeadersInfo, info);
490 modest_tny_send_queue_new (TnyCamelTransportAccount *account)
492 ModestTnySendQueue *self = NULL;
493 ModestTnySendQueuePrivate *priv = NULL;
494 TnyList *headers = NULL;
495 GetHeadersInfo *info;
497 g_return_val_if_fail (TNY_IS_CAMEL_TRANSPORT_ACCOUNT(account), NULL);
499 self = MODEST_TNY_SEND_QUEUE(g_object_new(MODEST_TYPE_TNY_SEND_QUEUE, NULL));
501 /* Set outbox and sentbox */
502 priv = MODEST_TNY_SEND_QUEUE_GET_PRIVATE (self);
503 priv->outbox = modest_tny_account_get_special_folder (TNY_ACCOUNT(account),
504 TNY_FOLDER_TYPE_OUTBOX);
505 priv->sentbox = modest_tny_account_get_special_folder (TNY_ACCOUNT(account),
506 TNY_FOLDER_TYPE_SENT);
508 /* NOTE that this could happen if there was not enough disk
509 space when the account was created */
510 if (!priv->outbox || !priv->sentbox) {
511 g_object_unref (self);
515 /* Connect signals to control when a msg is being or has been sent */
516 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
519 G_CALLBACK(_on_msg_start_sending),
521 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
522 G_OBJECT(self), "msg-sent",
523 G_CALLBACK(_on_msg_has_been_sent),
525 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
526 G_OBJECT(self), "error-happened",
527 G_CALLBACK(_on_msg_error_happened),
529 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
530 G_OBJECT (self), "queue-start",
531 G_CALLBACK (_on_queue_start),
533 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
534 G_OBJECT (self), "queue-stop",
535 G_CALLBACK (_on_queue_stop),
537 priv->requested_send_receive = FALSE;
539 headers = tny_simple_list_new ();
540 info = g_slice_new0 (GetHeadersInfo);
541 info->account = g_object_ref (account);
542 info->queue = g_object_ref (self);
543 tny_folder_get_headers_async (priv->outbox, headers, TRUE,
544 new_queue_get_headers_async_cb,
551 modest_tny_send_queue_msg_is_being_sent (ModestTnySendQueue* self,
554 ModestTnySendQueueStatus status;
556 g_return_val_if_fail (msg_id != NULL, FALSE);
558 status = modest_tny_send_queue_get_msg_status (self, msg_id);
559 return status == MODEST_TNY_SEND_QUEUE_SENDING;
563 modest_tny_send_queue_sending_in_progress (ModestTnySendQueue* self)
565 ModestTnySendQueuePrivate *priv;
567 g_return_val_if_fail (MODEST_IS_TNY_SEND_QUEUE(self), FALSE);
569 priv = MODEST_TNY_SEND_QUEUE_GET_PRIVATE (self);
571 return priv->sending;
574 ModestTnySendQueueStatus
575 modest_tny_send_queue_get_msg_status (ModestTnySendQueue *self, const gchar *msg_id)
579 g_return_val_if_fail (MODEST_IS_TNY_SEND_QUEUE(self), MODEST_TNY_SEND_QUEUE_UNKNOWN);
580 g_return_val_if_fail (msg_id, MODEST_TNY_SEND_QUEUE_UNKNOWN);
582 item = modest_tny_send_queue_lookup_info (self, msg_id);
584 return MODEST_TNY_SEND_QUEUE_UNKNOWN;
586 return ((SendInfo*)item->data)->status;
590 modest_tny_send_queue_get_msg_id (TnyHeader *header)
592 gchar* msg_uid = NULL;
594 time_t date_received;
596 g_return_val_if_fail (header && TNY_IS_HEADER(header), NULL);
598 /* Get message uid */
599 subject = tny_header_dup_subject (header);
600 date_received = tny_header_get_date_received (header);
602 msg_uid = g_strdup_printf ("%s %d", subject, (int) date_received);
610 _on_msg_start_sending (TnySendQueue *self, TnyHeader *header,
611 TnyMsg *msg, int done, int total, gpointer user_data)
613 ModestTnySendQueuePrivate *priv = NULL;
615 SendInfo *info = NULL;
616 gchar *msg_id = NULL;
618 priv = MODEST_TNY_SEND_QUEUE_GET_PRIVATE (self);
620 /* Get message uid */
621 msg_id = modest_tny_send_queue_get_msg_id (header);
623 item = modest_tny_send_queue_lookup_info (MODEST_TNY_SEND_QUEUE (self), msg_id);
625 g_warning ("%s: could not get msg-id for header", __FUNCTION__);
628 /* Set current status item */
630 info->status = MODEST_TNY_SEND_QUEUE_SENDING;
631 g_signal_emit (self, signals[STATUS_CHANGED_SIGNAL], 0, info->msg_id, info->status);
632 priv->current = item;
634 g_warning ("%s: could not find item with id '%s'", __FUNCTION__, msg_id);
641 _on_msg_has_been_sent (TnySendQueue *self,
648 ModestTnySendQueuePrivate *priv;
649 gchar *msg_id = NULL;
652 priv = MODEST_TNY_SEND_QUEUE_GET_PRIVATE (self);
654 /* Get message uid */
655 msg_id = modest_tny_send_queue_get_msg_id (header);
657 tny_header_set_flag (header, TNY_HEADER_FLAG_SEEN);
659 tny_folder_sync_async (priv->sentbox, FALSE, NULL, NULL, NULL);
661 /* Get status info */
662 item = modest_tny_send_queue_lookup_info (MODEST_TNY_SEND_QUEUE (self), msg_id);
665 /* TODO: note that item=NULL must not happen, but I found that
666 tinymail is issuing the message-sent signal twice, because
667 tny_camel_send_queue_update is called twice for each
668 message sent. This must be fixed in tinymail. Sergio */
670 /* Remove status info */
671 modest_tny_send_queue_info_free (item->data);
672 g_queue_delete_link (priv->queue, item);
673 priv->current = NULL;
675 modest_platform_information_banner (NULL, NULL, _("mcen_ib_message_sent"));
683 _on_msg_error_happened (TnySendQueue *self,
689 ModestTnySendQueuePrivate *priv = NULL;
691 priv = MODEST_TNY_SEND_QUEUE_GET_PRIVATE (self);
693 /* Note that header could be NULL. Tinymail notifies about
694 generic send queue errors with this signal as well, and
695 those notifications are not bound to any particular header
697 if (header && TNY_IS_HEADER (header)) {
698 SendInfo *info = NULL;
700 gchar* msg_uid = NULL;
702 /* Get sending info (create new if it doesn not exist) */
703 msg_uid = modest_tny_send_queue_get_msg_id (header);
704 item = modest_tny_send_queue_lookup_info (MODEST_TNY_SEND_QUEUE (self),
707 /* TODO: this should not happen (but it does), so the
708 problem should be located in the way we generate
711 g_warning ("%s: could not find item with id '%s'", __FUNCTION__, msg_uid);
718 /* Keep in queue so that we remember that the opertion has failed */
719 /* and was not just cancelled */
720 if (err->code == TNY_SYSTEM_ERROR_CANCEL) {
721 info->status = MODEST_TNY_SEND_QUEUE_SUSPENDED;
723 info->status = MODEST_TNY_SEND_QUEUE_FAILED;
725 priv->current = NULL;
727 /* Notify status has changed */
728 g_signal_emit (self, signals[STATUS_CHANGED_SIGNAL], 0, info->msg_id, info->status);
736 _on_queue_start (TnySendQueue *self,
739 ModestTnySendQueuePrivate *priv;
740 ModestMailOperation *mail_op;
742 mail_op = modest_mail_operation_new (NULL);
743 modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (),
745 modest_mail_operation_run_queue (mail_op, MODEST_TNY_SEND_QUEUE (self));
746 g_object_unref (mail_op);
748 priv = MODEST_TNY_SEND_QUEUE_GET_PRIVATE (self);
749 priv->sending = TRUE;
753 _on_queue_stop (TnySendQueue *self,
756 ModestTnySendQueuePrivate *priv;
758 priv = MODEST_TNY_SEND_QUEUE_GET_PRIVATE (self);
759 priv->sending = FALSE;
763 fill_list_of_caches (gpointer key, gpointer value, gpointer userdata)
765 GSList **send_queues = (GSList **) userdata;
766 *send_queues = g_slist_prepend (*send_queues, value);
769 /* This function shouldn't be here. Move it to another place. Sergio */
770 ModestTnySendQueueStatus
771 modest_tny_all_send_queues_get_msg_status (TnyHeader *header)
773 ModestCacheMgr *cache_mgr = NULL;
774 GHashTable *send_queue_cache = NULL;
775 ModestTnyAccountStore *accounts_store = NULL;
776 TnyList *accounts = NULL;
777 TnyIterator *iter = NULL;
778 TnyTransportAccount *account = NULL;
779 GSList *send_queues = NULL, *node;
780 /* get_msg_status returns suspended by default, so we want to detect changes */
781 ModestTnySendQueueStatus status = MODEST_TNY_SEND_QUEUE_UNKNOWN;
782 ModestTnySendQueueStatus queue_status = MODEST_TNY_SEND_QUEUE_UNKNOWN;
783 gchar *msg_uid = NULL;
784 ModestTnySendQueue *send_queue = NULL;
786 g_return_val_if_fail (TNY_IS_HEADER(header), MODEST_TNY_SEND_QUEUE_UNKNOWN);
788 msg_uid = modest_tny_send_queue_get_msg_id (header);
789 cache_mgr = modest_runtime_get_cache_mgr ();
790 send_queue_cache = modest_cache_mgr_get_cache (cache_mgr,
791 MODEST_CACHE_MGR_CACHE_TYPE_SEND_QUEUE);
793 g_hash_table_foreach (send_queue_cache, (GHFunc) fill_list_of_caches, &send_queues);
794 if (send_queues == NULL) {
795 accounts = tny_simple_list_new ();
796 accounts_store = modest_runtime_get_account_store ();
797 tny_account_store_get_accounts (TNY_ACCOUNT_STORE(accounts_store),
799 TNY_ACCOUNT_STORE_TRANSPORT_ACCOUNTS);
801 iter = tny_list_create_iterator (accounts);
802 while (!tny_iterator_is_done (iter)) {
803 account = TNY_TRANSPORT_ACCOUNT(tny_iterator_get_current (iter));
804 send_queue = modest_runtime_get_send_queue(TNY_TRANSPORT_ACCOUNT(account), TRUE);
805 g_object_unref(account);
806 if (TNY_IS_SEND_QUEUE (send_queue)) {
807 queue_status = modest_tny_send_queue_get_msg_status (send_queue, msg_uid);
808 if (queue_status != MODEST_TNY_SEND_QUEUE_UNKNOWN) {
809 status = queue_status;
813 tny_iterator_next (iter);
815 g_object_unref (iter);
816 g_object_unref (accounts);
819 for (node = send_queues; node != NULL; node = g_slist_next (node)) {
820 send_queue = MODEST_TNY_SEND_QUEUE (node->data);
822 queue_status = modest_tny_send_queue_get_msg_status (send_queue, msg_uid);
823 if (queue_status != MODEST_TNY_SEND_QUEUE_UNKNOWN) {
824 status = queue_status;
831 g_slist_free (send_queues);
835 typedef struct _WakeupHelper {
836 ModestTnySendQueue *self;
837 ModestTnySendQueueWakeupFunc callback;
842 wakeup_sync_cb (TnyFolder *self, gboolean cancelled, GError *err, gpointer userdata)
844 WakeupHelper *helper = (WakeupHelper *) userdata;
846 if (helper->callback) {
847 helper->callback (helper->self, cancelled, err, helper->userdata);
849 g_object_unref (helper->self);
850 g_slice_free (WakeupHelper, helper);
854 wakeup_get_headers_async_cb (TnyFolder *folder,
860 ModestTnySendQueue *self;
861 ModestTnySendQueuePrivate *priv;
863 WakeupHelper *helper = (WakeupHelper *) user_data;
865 self = MODEST_TNY_SEND_QUEUE (helper->self);
866 priv = MODEST_TNY_SEND_QUEUE_GET_PRIVATE (self);
868 if (cancelled || err) {
869 g_debug ("Failed to wake up the headers of the send queue");
870 g_object_unref (self);
871 if (helper->callback) {
872 helper->callback (helper->self, cancelled, err, helper->userdata);
874 g_object_unref (helper->self);
875 g_slice_free (WakeupHelper, helper);
879 /* Wake up every single suspended header */
880 iter = tny_list_create_iterator (headers);
881 while (!tny_iterator_is_done (iter)) {
882 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
884 if (tny_header_get_flags (header) & TNY_HEADER_FLAG_SUSPENDED) {
889 /* Unset the suspended flag */
890 tny_header_unset_flag (header, TNY_HEADER_FLAG_SUSPENDED);
893 msg_id = modest_tny_send_queue_get_msg_id (header);
894 item = modest_tny_send_queue_lookup_info (MODEST_TNY_SEND_QUEUE (self), msg_id);
896 info = g_slice_new (SendInfo);
897 info->msg_id = msg_id;
898 g_queue_push_tail (priv->queue, info);
900 info = (SendInfo *) item->data;
903 info->status = MODEST_TNY_SEND_QUEUE_WAITING;
904 g_signal_emit (self, signals[STATUS_CHANGED_SIGNAL], 0, info->msg_id, info->status);
908 g_object_unref (header);
909 tny_iterator_next (iter);
912 /* Make changes persistent on disk */
913 tny_folder_sync_async (priv->outbox, FALSE, wakeup_sync_cb, NULL, helper);
916 g_object_unref (iter);
917 g_object_unref (headers);
921 modest_tny_send_queue_wakeup (ModestTnySendQueue *self,
922 ModestTnySendQueueWakeupFunc callback,
925 ModestTnySendQueuePrivate *priv;
927 WakeupHelper *helper;
929 g_return_if_fail (MODEST_IS_TNY_SEND_QUEUE (self));
930 priv = MODEST_TNY_SEND_QUEUE_GET_PRIVATE (self);
932 helper = g_slice_new (WakeupHelper);
933 helper->self = g_object_ref (self);
934 helper->callback = callback;
935 helper->userdata = userdata;
937 headers = tny_simple_list_new ();
938 tny_folder_get_headers_async (priv->outbox, headers, TRUE,
939 wakeup_get_headers_async_cb,
944 modest_tny_send_queue_get_requested_send_receive (ModestTnySendQueue *self)
946 ModestTnySendQueuePrivate *priv;
948 g_return_val_if_fail (MODEST_IS_TNY_SEND_QUEUE (self), FALSE);
949 priv = MODEST_TNY_SEND_QUEUE_GET_PRIVATE (self);
951 return priv->requested_send_receive;
955 modest_tny_send_queue_set_requested_send_receive (ModestTnySendQueue *self, gboolean requested_send_receive)
957 ModestTnySendQueuePrivate *priv;
959 g_return_if_fail (MODEST_IS_TNY_SEND_QUEUE (self));
960 priv = MODEST_TNY_SEND_QUEUE_GET_PRIVATE (self);
962 priv->requested_send_receive = requested_send_receive;