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 if (err->code == TNY_SERVICE_ERROR_CONNECT) {
715 TnyCamelTransportAccount* transport;
716 TnyTransportAccount *conn_specific;
718 transport = tny_camel_send_queue_get_transport_account (TNY_CAMEL_SEND_QUEUE (self));
721 ModestTnyAccountStore *acc_store;
722 const gchar *acc_name;
724 acc_store = modest_runtime_get_account_store();
725 acc_name = modest_tny_account_get_parent_modest_account_name_for_server_account (TNY_ACCOUNT (transport));
726 conn_specific = (TnyTransportAccount *)
727 modest_tny_account_store_get_transport_account_for_open_connection (acc_store, acc_name);
729 message = g_strdup_printf (_("emev_ib_ui_smtp_server_invalid"),
730 tny_account_get_hostname (TNY_ACCOUNT (conn_specific)));
731 g_object_unref (conn_specific);
733 message = g_strdup_printf (_("emev_ib_ui_smtp_server_invalid"),
734 tny_account_get_hostname (TNY_ACCOUNT (transport)));
736 modest_platform_run_alert_dialog (message, FALSE);
738 g_object_unref (transport);
741 info->status = MODEST_TNY_SEND_QUEUE_FAILED;
743 priv->current = NULL;
745 /* Notify status has changed */
746 g_signal_emit (self, signals[STATUS_CHANGED_SIGNAL], 0, info->msg_id, info->status);
754 _on_queue_start (TnySendQueue *self,
757 ModestTnySendQueuePrivate *priv;
758 ModestMailOperation *mail_op;
760 mail_op = modest_mail_operation_new (NULL);
761 modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (),
763 modest_mail_operation_run_queue (mail_op, MODEST_TNY_SEND_QUEUE (self));
764 g_object_unref (mail_op);
766 priv = MODEST_TNY_SEND_QUEUE_GET_PRIVATE (self);
767 priv->sending = TRUE;
771 _on_queue_stop (TnySendQueue *self,
774 ModestTnySendQueuePrivate *priv;
776 priv = MODEST_TNY_SEND_QUEUE_GET_PRIVATE (self);
777 priv->sending = FALSE;
781 fill_list_of_caches (gpointer key, gpointer value, gpointer userdata)
783 GSList **send_queues = (GSList **) userdata;
784 *send_queues = g_slist_prepend (*send_queues, value);
787 /* This function shouldn't be here. Move it to another place. Sergio */
788 ModestTnySendQueueStatus
789 modest_tny_all_send_queues_get_msg_status (TnyHeader *header)
791 ModestCacheMgr *cache_mgr = NULL;
792 GHashTable *send_queue_cache = NULL;
793 ModestTnyAccountStore *accounts_store = NULL;
794 TnyList *accounts = NULL;
795 TnyIterator *iter = NULL;
796 TnyTransportAccount *account = NULL;
797 GSList *send_queues = NULL, *node;
798 /* get_msg_status returns suspended by default, so we want to detect changes */
799 ModestTnySendQueueStatus status = MODEST_TNY_SEND_QUEUE_UNKNOWN;
800 ModestTnySendQueueStatus queue_status = MODEST_TNY_SEND_QUEUE_UNKNOWN;
801 gchar *msg_uid = NULL;
802 ModestTnySendQueue *send_queue = NULL;
804 g_return_val_if_fail (TNY_IS_HEADER(header), MODEST_TNY_SEND_QUEUE_UNKNOWN);
806 msg_uid = modest_tny_send_queue_get_msg_id (header);
807 cache_mgr = modest_runtime_get_cache_mgr ();
808 send_queue_cache = modest_cache_mgr_get_cache (cache_mgr,
809 MODEST_CACHE_MGR_CACHE_TYPE_SEND_QUEUE);
811 g_hash_table_foreach (send_queue_cache, (GHFunc) fill_list_of_caches, &send_queues);
812 if (send_queues == NULL) {
813 accounts = tny_simple_list_new ();
814 accounts_store = modest_runtime_get_account_store ();
815 tny_account_store_get_accounts (TNY_ACCOUNT_STORE(accounts_store),
817 TNY_ACCOUNT_STORE_TRANSPORT_ACCOUNTS);
819 iter = tny_list_create_iterator (accounts);
820 while (!tny_iterator_is_done (iter)) {
821 account = TNY_TRANSPORT_ACCOUNT(tny_iterator_get_current (iter));
822 send_queue = modest_runtime_get_send_queue(TNY_TRANSPORT_ACCOUNT(account), TRUE);
823 g_object_unref(account);
824 if (TNY_IS_SEND_QUEUE (send_queue)) {
825 queue_status = modest_tny_send_queue_get_msg_status (send_queue, msg_uid);
826 if (queue_status != MODEST_TNY_SEND_QUEUE_UNKNOWN) {
827 status = queue_status;
831 tny_iterator_next (iter);
833 g_object_unref (iter);
834 g_object_unref (accounts);
837 for (node = send_queues; node != NULL; node = g_slist_next (node)) {
838 send_queue = MODEST_TNY_SEND_QUEUE (node->data);
840 queue_status = modest_tny_send_queue_get_msg_status (send_queue, msg_uid);
841 if (queue_status != MODEST_TNY_SEND_QUEUE_UNKNOWN) {
842 status = queue_status;
849 g_slist_free (send_queues);
853 typedef struct _WakeupHelper {
854 ModestTnySendQueue *self;
855 ModestTnySendQueueWakeupFunc callback;
860 wakeup_sync_cb (TnyFolder *self, gboolean cancelled, GError *err, gpointer userdata)
862 WakeupHelper *helper = (WakeupHelper *) userdata;
864 if (helper->callback) {
865 helper->callback (helper->self, cancelled, err, helper->userdata);
867 g_object_unref (helper->self);
868 g_slice_free (WakeupHelper, helper);
872 wakeup_get_headers_async_cb (TnyFolder *folder,
878 ModestTnySendQueue *self;
879 ModestTnySendQueuePrivate *priv;
881 WakeupHelper *helper = (WakeupHelper *) user_data;
883 self = MODEST_TNY_SEND_QUEUE (helper->self);
884 priv = MODEST_TNY_SEND_QUEUE_GET_PRIVATE (self);
886 if (cancelled || err) {
887 g_debug ("Failed to wake up the headers of the send queue");
888 g_object_unref (self);
889 if (helper->callback) {
890 helper->callback (helper->self, cancelled, err, helper->userdata);
892 g_object_unref (helper->self);
893 g_slice_free (WakeupHelper, helper);
897 /* Wake up every single suspended header */
898 iter = tny_list_create_iterator (headers);
899 while (!tny_iterator_is_done (iter)) {
900 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
902 if (tny_header_get_flags (header) & TNY_HEADER_FLAG_SUSPENDED) {
907 /* Unset the suspended flag */
908 tny_header_unset_flag (header, TNY_HEADER_FLAG_SUSPENDED);
911 msg_id = modest_tny_send_queue_get_msg_id (header);
912 item = modest_tny_send_queue_lookup_info (MODEST_TNY_SEND_QUEUE (self), msg_id);
914 info = g_slice_new (SendInfo);
915 info->msg_id = msg_id;
916 g_queue_push_tail (priv->queue, info);
918 info = (SendInfo *) item->data;
921 info->status = MODEST_TNY_SEND_QUEUE_WAITING;
922 g_signal_emit (self, signals[STATUS_CHANGED_SIGNAL], 0, info->msg_id, info->status);
926 g_object_unref (header);
927 tny_iterator_next (iter);
930 /* Make changes persistent on disk */
931 tny_folder_sync_async (priv->outbox, FALSE, wakeup_sync_cb, NULL, helper);
934 g_object_unref (iter);
935 g_object_unref (headers);
936 g_object_unref (self);
940 modest_tny_send_queue_wakeup (ModestTnySendQueue *self,
941 ModestTnySendQueueWakeupFunc callback,
944 ModestTnySendQueuePrivate *priv;
946 WakeupHelper *helper;
948 g_return_if_fail (MODEST_IS_TNY_SEND_QUEUE (self));
949 priv = MODEST_TNY_SEND_QUEUE_GET_PRIVATE (self);
951 helper = g_slice_new (WakeupHelper);
952 helper->self = g_object_ref (self);
953 helper->callback = callback;
954 helper->userdata = userdata;
956 headers = tny_simple_list_new ();
957 tny_folder_get_headers_async (priv->outbox, headers, TRUE,
958 wakeup_get_headers_async_cb,
963 modest_tny_send_queue_get_requested_send_receive (ModestTnySendQueue *self)
965 ModestTnySendQueuePrivate *priv;
967 g_return_val_if_fail (MODEST_IS_TNY_SEND_QUEUE (self), FALSE);
968 priv = MODEST_TNY_SEND_QUEUE_GET_PRIVATE (self);
970 return priv->requested_send_receive;
974 modest_tny_send_queue_set_requested_send_receive (ModestTnySendQueue *self, gboolean requested_send_receive)
976 ModestTnySendQueuePrivate *priv;
978 g_return_if_fail (MODEST_IS_TNY_SEND_QUEUE (self));
979 priv = MODEST_TNY_SEND_QUEUE_GET_PRIVATE (self);
981 priv->requested_send_receive = requested_send_receive;