X-Git-Url: http://git.maemo.org/git/?p=modest;a=blobdiff_plain;f=src%2Fmodest-tny-send-queue.c;h=b1f8560eb00e31bc843a9627dd4eb0bfdf48d7a8;hp=2c238f2098f586a08f71188ff306a721c85ead2b;hb=6dff75fc6a5d9515c03abb45d2f000b9eeacfbd4;hpb=b7f38bb7c72c7ec821ce2a556c59d1e88d226f37 diff --git a/src/modest-tny-send-queue.c b/src/modest-tny-send-queue.c index 2c238f2..b1f8560 100644 --- a/src/modest-tny-send-queue.c +++ b/src/modest-tny-send-queue.c @@ -32,186 +32,291 @@ #include #include #include +#include #include +#include +#include #include +#include +#include +#include +#include +#include +#include /* strcmp */ /* 'private'/'protected' functions */ static void modest_tny_send_queue_class_init (ModestTnySendQueueClass *klass); -static void modest_tny_send_queue_init (gpointer g, gpointer iface_data); static void modest_tny_send_queue_finalize (GObject *obj); static void modest_tny_send_queue_instance_init (GTypeInstance *instance, gpointer g_class); +/* Signal handlers */ +static void _on_msg_start_sending (TnySendQueue *self, + TnyHeader *header, + TnyMsg *msg, + int done, + int total, + gpointer user_data); + +static void _on_msg_has_been_sent (TnySendQueue *self, + TnyHeader *header, + TnyMsg *msg, + int done, + int total, + gpointer user_data); + +static void _on_msg_error_happened (TnySendQueue *self, + TnyHeader *header, + TnyMsg *msg, + GError *err, + gpointer user_data); + +static void _on_queue_start (TnySendQueue *self, + gpointer user_data); + +static void modest_tny_send_queue_add_async (TnyCamelSendQueue *self, + TnyMsg *msg, + TnySendQueueAddCallback callback, + TnyStatusCallback status_callback, + gpointer user_data); + +static TnyFolder* modest_tny_send_queue_get_outbox (TnySendQueue *self); +static TnyFolder* modest_tny_send_queue_get_sentbox (TnySendQueue *self); + /* list my signals */ enum { - /* MY_SIGNAL_1, */ - /* MY_SIGNAL_2, */ + STATUS_CHANGED_SIGNAL, LAST_SIGNAL }; +typedef struct _SendInfo SendInfo; +struct _SendInfo { + gchar* msg_id; + ModestTnySendQueueStatus status; +}; + typedef struct _ModestTnySendQueuePrivate ModestTnySendQueuePrivate; struct _ModestTnySendQueuePrivate { - TnyTransportAccount *account; - GThread *flush_outbox_thread; - GMutex *flush_lock; - + /* Queued infos */ + GQueue* queue; + + /* The info that is currently being sent */ + GList* current; + + /* Special folders */ + TnyFolder *outbox; + TnyFolder *sentbox; }; + #define MODEST_TNY_SEND_QUEUE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \ MODEST_TYPE_TNY_SEND_QUEUE, \ ModestTnySendQueuePrivate)) + /* globals */ -static GObjectClass *parent_class = NULL; +static TnyCamelSendQueueClass *parent_class = NULL; /* uncomment the following if you have defined any signals */ -/* static guint signals[LAST_SIGNAL] = {0}; */ - +static guint signals[LAST_SIGNAL] = {0}; /* - * this thread actually tries to send all the mails in the outbox + * this thread actually tries to send all the mails in the outbox and keeps + * track of their state. */ -static void -flush_outbox_thread (TnySendQueue *self) + +static int +on_modest_tny_send_queue_compare_id (gconstpointer info, gconstpointer msg_id) { - TnyFolder *outbox, *sentbox; - TnyMsg *msg; - TnyHeader *header; + g_return_val_if_fail (info && ((SendInfo*)info)->msg_id && msg_id, -1); + + return strcmp( ((SendInfo*)info)->msg_id, msg_id); +} - TnyList *headers; - TnyIterator *iter; +static void +modest_tny_send_queue_info_free (SendInfo *info) +{ + g_free(info->msg_id); + g_slice_free(SendInfo, info); +} +static GList* +modest_tny_send_queue_lookup_info (ModestTnySendQueue *self, const gchar *msg_id) +{ ModestTnySendQueuePrivate *priv; - - priv = MODEST_TNY_SEND_QUEUE_GET_PRIVATE (self); - - outbox = tny_send_queue_get_outbox (self); - sentbox = tny_send_queue_get_sentbox (self); + priv = MODEST_TNY_SEND_QUEUE_GET_PRIVATE (self); - headers = tny_simple_list_new (); - - g_mutex_lock (priv->flush_lock); - tny_folder_get_headers (outbox, headers, TRUE, NULL); /* FIXME: err */ - iter = tny_list_create_iterator (headers); - - while (!tny_iterator_is_done (iter)) { - header = TNY_HEADER(tny_iterator_get_current(iter)); - msg = tny_folder_get_msg (outbox, header, NULL); - tny_transport_account_send (priv->account, - msg, NULL); /* FIXME: err */ - tny_folder_add_msg (sentbox, msg, NULL); /* FIXME: err */ - tny_folder_remove_msg (outbox, header, NULL); /* FIXME: err */ + return g_queue_find_custom (priv->queue, msg_id, on_modest_tny_send_queue_compare_id); +} - g_object_unref (G_OBJECT(header)); - g_object_unref (G_OBJECT(msg)); - tny_iterator_next (iter); - } +static void +queue_item_to_string (gpointer data, gchar **user_data) +{ + SendInfo *info = (SendInfo*)data; + const gchar *status; + gchar *tmp; + if (!(user_data && *user_data)) + return; - g_object_unref (G_OBJECT(headers)); - g_object_unref (G_OBJECT(iter)); + switch (info->status) { + case MODEST_TNY_SEND_QUEUE_UNKNOWN: status = "UNKNOWN"; break; + case MODEST_TNY_SEND_QUEUE_WAITING: status = "WAITING"; break; + case MODEST_TNY_SEND_QUEUE_SUSPENDED: status = "SUSPENDED"; break; + case MODEST_TNY_SEND_QUEUE_SENDING: status = "SENDING"; break; + case MODEST_TNY_SEND_QUEUE_FAILED: status = "FAILED"; break; + default: status= "UNEXPECTED"; break; + } - priv->flush_outbox_thread = NULL; - g_mutex_unlock (priv->flush_lock); - - g_thread_exit (NULL); + tmp = g_strdup_printf ("%s\"%s\" => [%s]\n", + *user_data, info->msg_id, status); + g_free (*user_data); + *user_data = tmp; } - -static void -modest_tny_send_queue_cancel (TnySendQueue *self, gboolean remove) +gchar* +modest_tny_send_queue_to_string (ModestTnySendQueue *self) { - MODEST_TNY_SEND_QUEUE_GET_CLASS(self)->cancel_func (self, remove); -} + gchar *str; + ModestTnySendQueuePrivate *priv; -static void -modest_tny_send_queue_add (TnySendQueue *self, TnyMsg *msg) -{ - MODEST_TNY_SEND_QUEUE_GET_CLASS(self)->add_func (self, msg); -} + g_return_val_if_fail (MODEST_IS_TNY_SEND_QUEUE(self), NULL); + priv = MODEST_TNY_SEND_QUEUE_GET_PRIVATE (self); + str = g_strdup_printf ("items in the send queue: %d\n", + g_queue_get_length (priv->queue)); + + g_queue_foreach (priv->queue, (GFunc)queue_item_to_string, &str); -static TnyFolder* -modest_tny_send_queue_get_sentbox (TnySendQueue *self) -{ - return MODEST_TNY_SEND_QUEUE_GET_CLASS(self)->get_sentbox_func (self); + return str; } - -static TnyFolder* -modest_tny_send_queue_get_outbox (TnySendQueue *self) +static void +_on_added_to_outbox (TnySendQueue *self, + gboolean cancelled, + TnyMsg *msg, + GError *err, + gpointer user_data) { - return MODEST_TNY_SEND_QUEUE_GET_CLASS(self)->get_outbox_func (self); -} + ModestTnySendQueuePrivate *priv = MODEST_TNY_SEND_QUEUE_GET_PRIVATE(self); + TnyHeader *header = NULL; + SendInfo *info = NULL; + GList* existing = NULL; + gchar* msg_id = NULL; + g_return_if_fail (TNY_IS_SEND_QUEUE(self)); + g_return_if_fail (TNY_IS_CAMEL_MSG(msg)); + header = tny_msg_get_header (msg); + msg_id = modest_tny_send_queue_get_msg_id (header); + g_return_if_fail(msg_id != NULL); + + /* Put newly added message in WAITING state */ + existing = modest_tny_send_queue_lookup_info (MODEST_TNY_SEND_QUEUE(self), msg_id); + if(existing != NULL) { + info = existing->data; + info->status = MODEST_TNY_SEND_QUEUE_WAITING; + } else { + info = g_slice_new (SendInfo); + info->msg_id = msg_id; + info->status = MODEST_TNY_SEND_QUEUE_WAITING; + g_queue_push_tail (priv->queue, info); + } + g_signal_emit (self, signals[STATUS_CHANGED_SIGNAL], 0, info->msg_id, info->status); -static void -modest_tny_send_queue_cancel_default (TnySendQueue *self, gboolean remove) -{ - /* FIXME */ + g_object_unref(G_OBJECT(header)); } - static void -modest_tny_send_queue_add_default (TnySendQueue *self, TnyMsg *msg) +_add_message (ModestTnySendQueue *self, TnyHeader *header) { - ModestTnySendQueuePrivate *priv; - TnyFolder *outbox; - - g_return_if_fail (self); - g_return_if_fail (TNY_IS_CAMEL_MSG(msg)); - + ModestWindowMgr *mgr = NULL; + ModestTnySendQueuePrivate *priv; + SendInfo *info = NULL; + GList* existing = NULL; + gchar* msg_uid = NULL; + ModestTnySendQueueStatus status = MODEST_TNY_SEND_QUEUE_UNKNOWN; + gboolean editing = FALSE; + + g_return_if_fail (TNY_IS_SEND_QUEUE(self)); + g_return_if_fail (TNY_IS_HEADER(header)); priv = MODEST_TNY_SEND_QUEUE_GET_PRIVATE (self); - outbox = tny_send_queue_get_outbox (self); - tny_folder_add_msg (outbox, msg, NULL); + /* Check whether the mail is already in the queue */ + msg_uid = modest_tny_send_queue_get_msg_id (header); + status = modest_tny_send_queue_get_msg_status (self, msg_uid); + switch (status) { + case MODEST_TNY_SEND_QUEUE_UNKNOWN: + case MODEST_TNY_SEND_QUEUE_SUSPENDED: + case MODEST_TNY_SEND_QUEUE_FAILED: + + /* Check if it already exists on queue */ + existing = modest_tny_send_queue_lookup_info (MODEST_TNY_SEND_QUEUE(self), msg_uid); + if(existing != NULL) + break; + + /* Check if its being edited */ + mgr = modest_runtime_get_window_mgr (); + editing = modest_window_mgr_find_registered_header (mgr, header, NULL); + if (editing) + break; + + /* Add new meesage info */ + info = g_slice_new (SendInfo); + info->msg_id = strdup(msg_uid); + info->status = MODEST_TNY_SEND_QUEUE_WAITING; + g_queue_push_tail (priv->queue, info); + break; + default: + break; + } - priv->flush_outbox_thread = g_thread_create ( - (GThreadFunc)flush_outbox_thread, - self, FALSE, NULL); + /* Free */ + g_free(msg_uid); } +static void +modest_tny_send_queue_add_async (TnyCamelSendQueue *self, + TnyMsg *msg, + TnySendQueueAddCallback callback, + TnyStatusCallback status_callback, + gpointer user_data) +{ + /* Call the superclass passing our own callback */ + TNY_CAMEL_SEND_QUEUE_CLASS(parent_class)->add_async_func (self, msg, _on_added_to_outbox, NULL, NULL); +} + + static TnyFolder* -modest_tny_send_queue_get_sentbox_default (TnySendQueue *self) +modest_tny_send_queue_get_sentbox (TnySendQueue *self) { - ModestTnySendQueuePrivate *priv; + ModestTnySendQueuePrivate *priv; g_return_val_if_fail (self, NULL); priv = MODEST_TNY_SEND_QUEUE_GET_PRIVATE (self); - - return modest_tny_account_get_special_folder (TNY_ACCOUNT(priv->account), - TNY_FOLDER_TYPE_SENT); + + return g_object_ref (priv->sentbox); } static TnyFolder* -modest_tny_send_queue_get_outbox_default (TnySendQueue *self) +modest_tny_send_queue_get_outbox (TnySendQueue *self) { - ModestTnySendQueuePrivate *priv; + ModestTnySendQueuePrivate *priv; g_return_val_if_fail (self, NULL); - + priv = MODEST_TNY_SEND_QUEUE_GET_PRIVATE (self); - return modest_tny_account_get_special_folder (TNY_ACCOUNT(priv->account), - TNY_FOLDER_TYPE_OUTBOX); + return g_object_ref (priv->outbox); } - GType modest_tny_send_queue_get_type (void) { static GType my_type = 0; - if (G_UNLIKELY (!camel_type_init_done)) { - if (!g_thread_supported ()) - g_thread_init (NULL); - camel_type_init (); - camel_type_init_done = TRUE; - } - - if (!my_type) { + if (my_type == 0) { static const GTypeInfo my_info = { sizeof(ModestTnySendQueueClass), NULL, /* base init */ @@ -220,43 +325,20 @@ modest_tny_send_queue_get_type (void) NULL, /* class finalize */ NULL, /* class data */ sizeof(ModestTnySendQueue), - 1, /* n_preallocs */ + 0, /* n_preallocs */ (GInstanceInitFunc) modest_tny_send_queue_instance_init, NULL }; - - static const GInterfaceInfo tny_send_queue_info = { - (GInterfaceInitFunc) modest_tny_send_queue_init, - /* interface_init */ - NULL, /* interface_finalize */ - NULL /* interface_data */ - }; - - my_type = g_type_register_static (G_TYPE_OBJECT, + + my_type = g_type_register_static (TNY_TYPE_CAMEL_SEND_QUEUE, "ModestTnySendQueue", - &my_info, 0); - g_type_add_interface_static (my_type, TNY_TYPE_SEND_QUEUE, - &tny_send_queue_info); + &my_info, 0); } - return my_type; } static void -modest_tny_send_queue_init (gpointer g, gpointer iface_data) -{ - TnySendQueueIface *klass = (TnySendQueueIface*)g; - - klass->add_func = modest_tny_send_queue_add; - klass->get_outbox_func = modest_tny_send_queue_get_outbox; - klass->get_sentbox_func = modest_tny_send_queue_get_sentbox; - klass->cancel_func = modest_tny_send_queue_cancel; -} - - - -static void modest_tny_send_queue_class_init (ModestTnySendQueueClass *klass) { GObjectClass *gobject_class; @@ -266,10 +348,19 @@ modest_tny_send_queue_class_init (ModestTnySendQueueClass *klass) parent_class = g_type_class_peek_parent (klass); gobject_class->finalize = modest_tny_send_queue_finalize; - klass->add_func = modest_tny_send_queue_add_default; - klass->get_outbox_func = modest_tny_send_queue_get_outbox_default; - klass->get_sentbox_func = modest_tny_send_queue_get_sentbox_default; - klass->cancel_func = modest_tny_send_queue_cancel_default; + TNY_CAMEL_SEND_QUEUE_CLASS(klass)->add_async_func = modest_tny_send_queue_add_async; + TNY_CAMEL_SEND_QUEUE_CLASS(klass)->get_outbox_func = modest_tny_send_queue_get_outbox; + TNY_CAMEL_SEND_QUEUE_CLASS(klass)->get_sentbox_func = modest_tny_send_queue_get_sentbox; + klass->status_changed = NULL; + + signals[STATUS_CHANGED_SIGNAL] = + g_signal_new ("status_changed", + G_TYPE_FROM_CLASS (gobject_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (ModestTnySendQueueClass, status_changed), + NULL, NULL, + modest_marshal_VOID__STRING_INT, + G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_INT); g_type_class_add_private (gobject_class, sizeof(ModestTnySendQueuePrivate)); } @@ -277,50 +368,387 @@ modest_tny_send_queue_class_init (ModestTnySendQueueClass *klass) static void modest_tny_send_queue_instance_init (GTypeInstance *instance, gpointer g_class) { - ModestTnySendQueue *self; - ModestTnySendQueuePrivate *priv; - - self = (ModestTnySendQueue*)instance; - priv = MODEST_TNY_SEND_QUEUE_GET_PRIVATE (self); + ModestTnySendQueuePrivate *priv; - priv->flush_lock = g_mutex_new (); - priv->flush_outbox_thread = NULL; - priv->account = NULL; + priv = MODEST_TNY_SEND_QUEUE_GET_PRIVATE (instance); + priv->queue = g_queue_new(); + priv->current = NULL; } static void modest_tny_send_queue_finalize (GObject *obj) { - ModestTnySendQueuePrivate *priv; + ModestTnySendQueuePrivate *priv; + priv = MODEST_TNY_SEND_QUEUE_GET_PRIVATE (obj); + + g_queue_foreach (priv->queue, (GFunc)modest_tny_send_queue_info_free, NULL); + g_queue_free (priv->queue); + + g_object_unref (priv->outbox); + g_object_unref (priv->sentbox); + + G_OBJECT_CLASS(parent_class)->finalize (obj); +} + +ModestTnySendQueue* +modest_tny_send_queue_new (TnyCamelTransportAccount *account) +{ + ModestTnySendQueue *self = NULL; + ModestTnySendQueuePrivate *priv = NULL; + TnyIterator *iter = NULL; + TnyList *headers = NULL; - if (priv->account) { - g_object_unref (priv->account); - priv->account = NULL; - } + g_return_val_if_fail (TNY_IS_CAMEL_TRANSPORT_ACCOUNT(account), NULL); + + self = MODEST_TNY_SEND_QUEUE(g_object_new(MODEST_TYPE_TNY_SEND_QUEUE, NULL)); + + /* Connect signals to control when a msg is being or has been sent */ + g_signal_connect (G_OBJECT(self), "msg-sending", + G_CALLBACK(_on_msg_start_sending), + NULL); + g_signal_connect (G_OBJECT(self), "msg-sent", + G_CALLBACK(_on_msg_has_been_sent), + NULL); + g_signal_connect (G_OBJECT(self), "error-happened", + G_CALLBACK(_on_msg_error_happened), + NULL); + g_signal_connect (G_OBJECT (self), "queue-start", + G_CALLBACK (_on_queue_start), + NULL); + + /* Set outbox and sentbox */ + priv = MODEST_TNY_SEND_QUEUE_GET_PRIVATE (self); + priv->outbox = modest_tny_account_get_special_folder (TNY_ACCOUNT(account), + TNY_FOLDER_TYPE_OUTBOX); + priv->sentbox = modest_tny_account_get_special_folder (TNY_ACCOUNT(account), + TNY_FOLDER_TYPE_SENT); + + + headers = tny_simple_list_new (); + tny_folder_get_headers (priv->outbox, headers, TRUE, NULL); + + /* Add messages to our internal queue */ + iter = tny_list_create_iterator (headers); + while (!tny_iterator_is_done (iter)) { + TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter)); + _add_message (self, header); + g_object_unref (header); - if (priv->flush_lock) { - g_mutex_free (priv->flush_lock); - priv->flush_lock = NULL; + tny_iterator_next (iter); } + + /* Reenable suspended items */ + modest_tny_send_queue_wakeup (self); + + /* Frees */ + g_object_unref (G_OBJECT (headers)); + g_object_unref (G_OBJECT (priv->outbox)); + g_object_unref (iter); + + /* Do this at the end, because it'll call tny_send_queue_flush + which will call tny_send_queue_get_outbox and + tny_send_queue_get_sentbox */ + tny_camel_send_queue_set_transport_account (TNY_CAMEL_SEND_QUEUE(self), + account); + + return self; +} + +gboolean +modest_tny_send_queue_msg_is_being_sent (ModestTnySendQueue* self, + const gchar *msg_id) +{ + ModestTnySendQueueStatus status; - G_OBJECT_CLASS(parent_class)->finalize (obj); + g_return_val_if_fail (msg_id != NULL, FALSE); + + status = modest_tny_send_queue_get_msg_status (self, msg_id); + return status == MODEST_TNY_SEND_QUEUE_SENDING; } -ModestTnySendQueue* -modest_tny_send_queue_new (TnyTransportAccount *account) +gboolean +modest_tny_send_queue_sending_in_progress (ModestTnySendQueue* self) +{ + ModestTnySendQueuePrivate *priv; + + g_return_val_if_fail (MODEST_IS_TNY_SEND_QUEUE(self), FALSE); + + priv = MODEST_TNY_SEND_QUEUE_GET_PRIVATE (self); + + return priv->current != NULL; +} + +ModestTnySendQueueStatus +modest_tny_send_queue_get_msg_status (ModestTnySendQueue *self, const gchar *msg_id) +{ + GList *item; + + g_return_val_if_fail (MODEST_IS_TNY_SEND_QUEUE(self), MODEST_TNY_SEND_QUEUE_UNKNOWN); + g_return_val_if_fail (msg_id, MODEST_TNY_SEND_QUEUE_UNKNOWN); + + item = modest_tny_send_queue_lookup_info (self, msg_id); + if (!item) + return MODEST_TNY_SEND_QUEUE_UNKNOWN; + else + return ((SendInfo*)item->data)->status; +} + +gchar * +modest_tny_send_queue_get_msg_id (TnyHeader *header) +{ + gchar* msg_uid = NULL; + const gchar *subject; + time_t date_received; + + g_return_val_if_fail (header && TNY_IS_HEADER(header), NULL); + + /* Get message uid */ + subject = tny_header_get_subject (header); + date_received = tny_header_get_date_received (header); + + msg_uid = g_strdup_printf ("%s %d", subject, (int) date_received); + + return msg_uid; +} + + +static void +_on_msg_start_sending (TnySendQueue *self, + TnyHeader *header, + TnyMsg *msg, + int done, + int total, + gpointer user_data) +{ + ModestTnySendQueuePrivate *priv = NULL; + GList *item = NULL; + SendInfo *info = NULL; + gchar *msg_id = NULL; + + priv = MODEST_TNY_SEND_QUEUE_GET_PRIVATE (self); + + /* Get message uid */ + msg_id = modest_tny_send_queue_get_msg_id (header); + + /* Get status info */ + item = modest_tny_send_queue_lookup_info (MODEST_TNY_SEND_QUEUE (self), msg_id); + + /* Set current status item */ + info = item->data; + info->status = MODEST_TNY_SEND_QUEUE_SENDING; + g_signal_emit (self, signals[STATUS_CHANGED_SIGNAL], 0, info->msg_id, info->status); + priv->current = item; + + /* free */ + g_free (msg_id); +} + +static void +_on_msg_has_been_sent (TnySendQueue *self, + TnyHeader *header, + TnyMsg *msg, + int done, + int total, + gpointer user_data) { - ModestTnySendQueue *self; ModestTnySendQueuePrivate *priv; + gchar *msg_id = NULL; + GList *item; + + priv = MODEST_TNY_SEND_QUEUE_GET_PRIVATE (self); + + /* Get message uid */ + msg_id = modest_tny_send_queue_get_msg_id (header); - g_return_val_if_fail (account, NULL); + tny_header_set_flag (header, TNY_HEADER_FLAG_SEEN); + + /* Get status info */ + item = modest_tny_send_queue_lookup_info (MODEST_TNY_SEND_QUEUE (self), msg_id); + + + /* TODO: note that item=NULL must not happen, but I found that + tinymail is issuing the message-sent signal twice, because + tny_camel_send_queue_update is called twice for each + message sent. This must be fixed in tinymail. Sergio */ + if (item) { + /* Remove status info */ + modest_tny_send_queue_info_free (item->data); + g_queue_delete_link (priv->queue, item); + priv->current = NULL; + + modest_platform_information_banner (NULL, NULL, _("mcen_ib_message_sent")); + } + + /* free */ + g_free(msg_id); +} + +static void +_on_msg_error_happened (TnySendQueue *self, + TnyHeader *header, + TnyMsg *msg, + GError *err, + gpointer user_data) +{ + ModestTnySendQueuePrivate *priv = NULL; + SendInfo *info = NULL; + GList *item = NULL; + gchar* msg_uid = NULL; - self = MODEST_TNY_SEND_QUEUE(g_object_new(MODEST_TYPE_TNY_SEND_QUEUE, NULL)); priv = MODEST_TNY_SEND_QUEUE_GET_PRIVATE (self); + + /* Get sending info (create new if it doesn not exist) */ + msg_uid = modest_tny_send_queue_get_msg_id (header); + item = modest_tny_send_queue_lookup_info (MODEST_TNY_SEND_QUEUE (self), + msg_uid); + + info = item->data; + + /* Keep in queue so that we remember that the opertion has failed */ + /* and was not just cancelled */ + if (err->code == TNY_SYSTEM_ERROR_CANCEL) + info->status = MODEST_TNY_SEND_QUEUE_SUSPENDED; + else + info->status = MODEST_TNY_SEND_QUEUE_FAILED; + priv->current = NULL; + + /* Notify status has changed */ + g_signal_emit (self, signals[STATUS_CHANGED_SIGNAL], 0, info->msg_id, info->status); + + /* free */ + g_free(msg_uid); +} + +static void +_on_queue_start (TnySendQueue *self, + gpointer data) +{ + ModestMailOperation *mail_op; - priv->account = account; - g_object_ref (G_OBJECT(priv->account)); + mail_op = modest_mail_operation_new (NULL); + modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (), + mail_op); + modest_mail_operation_run_queue (mail_op, MODEST_TNY_SEND_QUEUE (self)); + g_object_unref (mail_op); +} + +static void +fill_list_of_caches (gpointer key, gpointer value, gpointer userdata) +{ + GSList **send_queues = (GSList **) userdata; + *send_queues = g_slist_prepend (*send_queues, value); +} + +/* This function shouldn't be here. Move it to another place. Sergio */ +ModestTnySendQueueStatus +modest_tny_all_send_queues_get_msg_status (TnyHeader *header) +{ + ModestCacheMgr *cache_mgr = NULL; + GHashTable *send_queue_cache = NULL; + ModestTnyAccountStore *accounts_store = NULL; + TnyList *accounts = NULL; + TnyIterator *iter = NULL; + TnyTransportAccount *account = NULL; + GSList *send_queues = NULL, *node; + /* get_msg_status returns suspended by default, so we want to detect changes */ + ModestTnySendQueueStatus status = MODEST_TNY_SEND_QUEUE_UNKNOWN; + ModestTnySendQueueStatus queue_status = MODEST_TNY_SEND_QUEUE_UNKNOWN; + gchar *msg_uid = NULL; + ModestTnySendQueue *send_queue = NULL; - return self; + g_return_val_if_fail (TNY_IS_HEADER(header), MODEST_TNY_SEND_QUEUE_UNKNOWN); + + msg_uid = modest_tny_send_queue_get_msg_id (header); + cache_mgr = modest_runtime_get_cache_mgr (); + send_queue_cache = modest_cache_mgr_get_cache (cache_mgr, + MODEST_CACHE_MGR_CACHE_TYPE_SEND_QUEUE); + + g_hash_table_foreach (send_queue_cache, (GHFunc) fill_list_of_caches, &send_queues); + if (send_queues == NULL) { + accounts = tny_simple_list_new (); + accounts_store = modest_runtime_get_account_store (); + tny_account_store_get_accounts (TNY_ACCOUNT_STORE(accounts_store), + accounts, + TNY_ACCOUNT_STORE_TRANSPORT_ACCOUNTS); + + iter = tny_list_create_iterator (accounts); + while (!tny_iterator_is_done (iter)) { + account = TNY_TRANSPORT_ACCOUNT(tny_iterator_get_current (iter)); + send_queue = modest_runtime_get_send_queue(TNY_TRANSPORT_ACCOUNT(account)); + g_object_unref(account); + + queue_status = modest_tny_send_queue_get_msg_status (send_queue, msg_uid); + if (queue_status != MODEST_TNY_SEND_QUEUE_UNKNOWN) { + status = queue_status; + break; + } + tny_iterator_next (iter); + } + g_object_unref (iter); + g_object_unref (accounts); + } + else { + for (node = send_queues; node != NULL; node = g_slist_next (node)) { + send_queue = MODEST_TNY_SEND_QUEUE (node->data); + + queue_status = modest_tny_send_queue_get_msg_status (send_queue, msg_uid); + if (queue_status != MODEST_TNY_SEND_QUEUE_UNKNOWN) { + status = queue_status; + break; + } + } + } + + g_free(msg_uid); + g_slist_free (send_queues); + return status; } +void +modest_tny_send_queue_wakeup (ModestTnySendQueue *self) +{ + ModestTnySendQueuePrivate *priv; + TnyList *headers; + TnyIterator *iter; + + g_return_if_fail (MODEST_IS_TNY_SEND_QUEUE (self)); + + priv = MODEST_TNY_SEND_QUEUE_GET_PRIVATE (self); + + headers = tny_simple_list_new (); + tny_folder_get_headers (priv->outbox, headers, TRUE, NULL); + + /* Wake up every single suspended header */ + iter = tny_list_create_iterator (headers); + while (!tny_iterator_is_done (iter)) { + TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter)); + + if (tny_header_get_flags (header) & TNY_HEADER_FLAG_SUSPENDED) { + gchar *msg_id; + GList *item; + SendInfo *info; + + /* Unset the suspended flag */ + tny_header_unset_flag (header, TNY_HEADER_FLAG_SUSPENDED); + + /* Notify view */ + msg_id = modest_tny_send_queue_get_msg_id (header); + item = modest_tny_send_queue_lookup_info (MODEST_TNY_SEND_QUEUE (self), msg_id); + info = (SendInfo *) item->data; + info->status = MODEST_TNY_SEND_QUEUE_WAITING; + g_signal_emit (self, signals[STATUS_CHANGED_SIGNAL], 0, info->msg_id, info->status); + + /* Frees */ + g_free (msg_id); + } + + /* Frees */ + g_object_unref (header); + tny_iterator_next (iter); + } + + /* Frees */ + g_object_unref (iter); + g_object_unref (G_OBJECT (headers)); +}