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 modest_platform_emit_msg_read_changed_signal (msg_id, TRUE);
684 tny_folder_sync_async (priv->sentbox, FALSE, NULL, NULL, NULL);
686 /* Get status info */
687 item = modest_tny_send_queue_lookup_info (MODEST_TNY_SEND_QUEUE (self), msg_id);
690 /* TODO: note that item=NULL must not happen, but I found that
691 tinymail is issuing the message-sent signal twice, because
692 tny_camel_send_queue_update is called twice for each
693 message sent. This must be fixed in tinymail. Sergio */
695 /* Remove status info */
696 modest_tny_send_queue_info_free (item->data);
697 g_queue_delete_link (priv->queue, item);
698 priv->current = NULL;
700 modest_platform_information_banner (NULL, NULL, _("mcen_ib_message_sent"));
708 _on_msg_error_happened (TnySendQueue *self,
714 ModestTnySendQueuePrivate *priv = NULL;
716 priv = MODEST_TNY_SEND_QUEUE_GET_PRIVATE (self);
718 /* Note that header could be NULL. Tinymail notifies about
719 generic send queue errors with this signal as well, and
720 those notifications are not bound to any particular header
722 if (header && TNY_IS_HEADER (header)) {
723 SendInfo *info = NULL;
725 gchar* msg_uid = NULL;
727 /* Get sending info (create new if it doesn not exist) */
728 msg_uid = modest_tny_send_queue_get_msg_id (header);
729 item = modest_tny_send_queue_lookup_info (MODEST_TNY_SEND_QUEUE (self),
732 /* TODO: this should not happen (but it does), so the
733 problem should be located in the way we generate
736 g_warning ("%s: could not find item with id '%s'", __FUNCTION__, msg_uid);
743 /* Keep in queue so that we remember that the opertion has failed */
744 /* and was not just cancelled */
745 if (err->code == TNY_SYSTEM_ERROR_CANCEL) {
746 info->status = MODEST_TNY_SEND_QUEUE_SUSPENDED;
748 info->status = MODEST_TNY_SEND_QUEUE_FAILED;
750 priv->current = NULL;
752 /* Notify status has changed */
753 g_signal_emit (self, signals[STATUS_CHANGED_SIGNAL], 0, info->msg_id, info->status);
761 _on_queue_start (TnySendQueue *self,
764 ModestTnySendQueuePrivate *priv;
765 ModestMailOperation *mail_op;
767 mail_op = modest_mail_operation_new (NULL);
768 modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (),
770 modest_mail_operation_run_queue (mail_op, MODEST_TNY_SEND_QUEUE (self));
771 g_object_unref (mail_op);
773 priv = MODEST_TNY_SEND_QUEUE_GET_PRIVATE (self);
774 priv->sending = TRUE;
778 on_queue_stop_get_headers_async_cb (TnyFolder *folder,
784 ModestTnySendQueue *self = (ModestTnySendQueue *) user_data;
787 if (cancelled || err)
790 /* Update the info about headers */
791 iter = tny_list_create_iterator (headers);
792 while (!tny_iterator_is_done (iter)) {
795 header = (TnyHeader *) tny_iterator_get_current (iter);
797 gchar *msg_id = NULL;
800 /* Get message uid */
801 msg_id = modest_tny_send_queue_get_msg_id (header);
803 item = modest_tny_send_queue_lookup_info (MODEST_TNY_SEND_QUEUE (self), msg_id);
805 g_warning ("%s: could not get msg-id for header", __FUNCTION__);
809 /* Set current status item */
811 if (tny_header_get_flags (header) & TNY_HEADER_FLAG_SUSPENDED) {
812 info->status = MODEST_TNY_SEND_QUEUE_SUSPENDED;
813 g_signal_emit (self, signals[STATUS_CHANGED_SIGNAL], 0,
814 info->msg_id, info->status);
817 g_warning ("%s: could not find item with id '%s'", __FUNCTION__, msg_id);
819 g_object_unref (header);
821 tny_iterator_next (iter);
823 g_object_unref (iter);
827 g_object_unref (headers);
828 g_object_unref (self);
832 _on_queue_stop (TnySendQueue *self,
835 ModestTnySendQueuePrivate *priv;
837 priv = MODEST_TNY_SEND_QUEUE_GET_PRIVATE (self);
838 priv->sending = FALSE;
842 priv->suspend = FALSE;
844 /* Update the state of messages in the queue */
845 headers = tny_simple_list_new ();
846 tny_folder_get_headers_async (priv->outbox, headers, TRUE,
847 on_queue_stop_get_headers_async_cb,
848 NULL, g_object_ref (self));
853 fill_list_of_caches (gpointer key, gpointer value, gpointer userdata)
855 GSList **send_queues = (GSList **) userdata;
856 *send_queues = g_slist_prepend (*send_queues, value);
859 /* This function shouldn't be here. Move it to another place. Sergio */
860 ModestTnySendQueueStatus
861 modest_tny_all_send_queues_get_msg_status (TnyHeader *header)
863 ModestCacheMgr *cache_mgr = NULL;
864 GHashTable *send_queue_cache = NULL;
865 ModestTnyAccountStore *accounts_store = NULL;
866 TnyList *accounts = NULL;
867 TnyIterator *iter = NULL;
868 TnyTransportAccount *account = NULL;
869 GSList *send_queues = NULL, *node;
870 /* get_msg_status returns suspended by default, so we want to detect changes */
871 ModestTnySendQueueStatus status = MODEST_TNY_SEND_QUEUE_UNKNOWN;
872 ModestTnySendQueueStatus queue_status = MODEST_TNY_SEND_QUEUE_UNKNOWN;
873 gchar *msg_uid = NULL;
874 ModestTnySendQueue *send_queue = NULL;
876 g_return_val_if_fail (TNY_IS_HEADER(header), MODEST_TNY_SEND_QUEUE_UNKNOWN);
878 msg_uid = modest_tny_send_queue_get_msg_id (header);
879 cache_mgr = modest_runtime_get_cache_mgr ();
880 send_queue_cache = modest_cache_mgr_get_cache (cache_mgr,
881 MODEST_CACHE_MGR_CACHE_TYPE_SEND_QUEUE);
883 g_hash_table_foreach (send_queue_cache, (GHFunc) fill_list_of_caches, &send_queues);
884 if (send_queues == NULL) {
885 accounts = tny_simple_list_new ();
886 accounts_store = modest_runtime_get_account_store ();
887 tny_account_store_get_accounts (TNY_ACCOUNT_STORE(accounts_store),
889 TNY_ACCOUNT_STORE_TRANSPORT_ACCOUNTS);
891 iter = tny_list_create_iterator (accounts);
892 while (!tny_iterator_is_done (iter)) {
893 account = TNY_TRANSPORT_ACCOUNT(tny_iterator_get_current (iter));
894 send_queue = modest_runtime_get_send_queue(TNY_TRANSPORT_ACCOUNT(account), TRUE);
895 g_object_unref(account);
896 if (TNY_IS_SEND_QUEUE (send_queue)) {
897 queue_status = modest_tny_send_queue_get_msg_status (send_queue, msg_uid);
898 if (queue_status != MODEST_TNY_SEND_QUEUE_UNKNOWN) {
899 status = queue_status;
903 tny_iterator_next (iter);
905 g_object_unref (iter);
906 g_object_unref (accounts);
909 for (node = send_queues; node != NULL; node = g_slist_next (node)) {
910 send_queue = MODEST_TNY_SEND_QUEUE (node->data);
912 queue_status = modest_tny_send_queue_get_msg_status (send_queue, msg_uid);
913 if (queue_status != MODEST_TNY_SEND_QUEUE_UNKNOWN) {
914 status = queue_status;
921 g_slist_free (send_queues);
925 typedef struct _WakeupHelper {
926 ModestTnySendQueue *self;
927 ModestTnySendQueueWakeupFunc callback;
932 wakeup_sync_cb (TnyFolder *self, gboolean cancelled, GError *err, gpointer userdata)
934 WakeupHelper *helper = (WakeupHelper *) userdata;
936 if (helper->callback) {
937 helper->callback (helper->self, cancelled, err, helper->userdata);
939 g_object_unref (helper->self);
940 g_slice_free (WakeupHelper, helper);
944 wakeup_get_headers_async_cb (TnyFolder *folder,
950 ModestTnySendQueue *self;
951 ModestTnySendQueuePrivate *priv;
953 WakeupHelper *helper = (WakeupHelper *) user_data;
955 self = MODEST_TNY_SEND_QUEUE (helper->self);
956 priv = MODEST_TNY_SEND_QUEUE_GET_PRIVATE (self);
958 if (cancelled || err) {
959 g_debug ("Failed to wake up the headers of the send queue");
960 g_object_unref (self);
961 if (helper->callback) {
962 helper->callback (helper->self, cancelled, err, helper->userdata);
964 g_object_unref (helper->self);
965 g_slice_free (WakeupHelper, helper);
969 /* Wake up every single suspended header */
970 iter = tny_list_create_iterator (headers);
971 while (!tny_iterator_is_done (iter)) {
972 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
974 if (tny_header_get_flags (header) & TNY_HEADER_FLAG_SUSPENDED) {
979 /* Unset the suspended flag */
980 tny_header_unset_flag (header, TNY_HEADER_FLAG_SUSPENDED);
983 msg_id = modest_tny_send_queue_get_msg_id (header);
984 item = modest_tny_send_queue_lookup_info (MODEST_TNY_SEND_QUEUE (self), msg_id);
986 info = g_slice_new (SendInfo);
987 info->msg_id = msg_id;
988 g_queue_push_tail (priv->queue, info);
990 info = (SendInfo *) item->data;
993 info->status = MODEST_TNY_SEND_QUEUE_WAITING;
994 g_signal_emit (self, signals[STATUS_CHANGED_SIGNAL], 0, info->msg_id, info->status);
998 g_object_unref (header);
999 tny_iterator_next (iter);
1002 /* Make changes persistent on disk */
1003 tny_folder_sync_async (priv->outbox, FALSE, wakeup_sync_cb, NULL, helper);
1006 g_object_unref (iter);
1007 g_object_unref (headers);
1011 modest_tny_send_queue_wakeup (ModestTnySendQueue *self,
1012 ModestTnySendQueueWakeupFunc callback,
1015 ModestTnySendQueuePrivate *priv;
1017 WakeupHelper *helper;
1019 g_return_if_fail (MODEST_IS_TNY_SEND_QUEUE (self));
1020 priv = MODEST_TNY_SEND_QUEUE_GET_PRIVATE (self);
1022 helper = g_slice_new (WakeupHelper);
1023 helper->self = g_object_ref (self);
1024 helper->callback = callback;
1025 helper->userdata = userdata;
1027 headers = tny_simple_list_new ();
1028 tny_folder_get_headers_async (priv->outbox, headers, TRUE,
1029 wakeup_get_headers_async_cb,
1034 modest_tny_send_queue_get_requested_send_receive (ModestTnySendQueue *self)
1036 ModestTnySendQueuePrivate *priv;
1038 g_return_val_if_fail (MODEST_IS_TNY_SEND_QUEUE (self), FALSE);
1039 priv = MODEST_TNY_SEND_QUEUE_GET_PRIVATE (self);
1041 return priv->requested_send_receive;
1045 modest_tny_send_queue_set_requested_send_receive (ModestTnySendQueue *self, gboolean requested_send_receive)
1047 ModestTnySendQueuePrivate *priv;
1049 g_return_if_fail (MODEST_IS_TNY_SEND_QUEUE (self));
1050 priv = MODEST_TNY_SEND_QUEUE_GET_PRIVATE (self);
1052 priv->requested_send_receive = requested_send_receive;