X-Git-Url: http://git.maemo.org/git/?p=modest;a=blobdiff_plain;f=src%2Fmodest-tny-send-queue.c;h=bb103ab95a9794c9f5833f74bb0f05973696444d;hp=bbad20251cbc42b4a8afe561e1ad9fce23ec4355;hb=f541209a85cb6c71c79da1df81afbe10c448690a;hpb=c5503361ea2bd6c0b45c1d6a22fe3f9a383c4d84 diff --git a/src/modest-tny-send-queue.c b/src/modest-tny-send-queue.c index bbad202..bb103ab 100644 --- a/src/modest-tny-send-queue.c +++ b/src/modest-tny-send-queue.c @@ -32,9 +32,16 @@ #include #include #include +#include #include +#include +#include #include +#include +#include +#include #include +#include #include /* strcmp */ /* 'private'/'protected' functions */ @@ -43,18 +50,41 @@ 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, TnyMsg *msg, gpointer user_data); */ -static void _on_msg_has_been_sent (TnySendQueue *self, TnyMsg *msg, gpointer user_data); -static void _on_msg_error_happened (TnySendQueue *self, TnyHeader *header, TnyMsg *msg, GError *err, gpointer user_data); - -static TnyFolder*modest_tny_send_queue_get_outbox (TnySendQueue *self); -static TnyFolder*modest_tny_send_queue_get_sentbox (TnySendQueue *self); +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 (TnySendQueue *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 { - STATUS_CHANGED, - /* MY_SIGNAL_1, */ - /* MY_SIGNAL_2, */ + STATUS_CHANGED_SIGNAL, LAST_SIGNAL }; @@ -71,6 +101,13 @@ struct _ModestTnySendQueuePrivate { /* The info that is currently being sent */ GList* current; + + /* Special folders */ + TnyFolder *outbox; + TnyFolder *sentbox; + + /* last was send receive operation?*/ + gboolean requested_send_receive; }; #define MODEST_TNY_SEND_QUEUE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \ @@ -89,13 +126,15 @@ static guint signals[LAST_SIGNAL] = {0}; */ static int -on_modest_tny_send_queue_compare_id(gconstpointer info, gconstpointer msg_id) +on_modest_tny_send_queue_compare_id (gconstpointer info, gconstpointer msg_id) { + g_return_val_if_fail (info && ((SendInfo*)info)->msg_id && msg_id, -1); + return strcmp( ((SendInfo*)info)->msg_id, msg_id); } static void -modest_tny_send_queue_info_free(SendInfo *info) +modest_tny_send_queue_info_free (SendInfo *info) { g_free(info->msg_id); g_slice_free(SendInfo, info); @@ -106,144 +145,196 @@ modest_tny_send_queue_lookup_info (ModestTnySendQueue *self, const gchar *msg_id { ModestTnySendQueuePrivate *priv; priv = MODEST_TNY_SEND_QUEUE_GET_PRIVATE (self); - + return g_queue_find_custom (priv->queue, msg_id, on_modest_tny_send_queue_compare_id); } + static void -modest_tny_send_queue_cancel (TnySendQueue *self, gboolean remove, GError **err) +queue_item_to_string (gpointer data, gchar **user_data) { + SendInfo *info = (SendInfo*)data; + const gchar *status; + gchar *tmp; + + if (!(user_data && *user_data)) + return; + + 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; + } + + tmp = g_strdup_printf ("%s\"%s\" => [%s]\n", + *user_data, info->msg_id, status); + g_free (*user_data); + *user_data = tmp; +} + +gchar* +modest_tny_send_queue_to_string (ModestTnySendQueue *self) +{ + gchar *str; ModestTnySendQueuePrivate *priv; - SendInfo *info; + g_return_val_if_fail (MODEST_IS_TNY_SEND_QUEUE(self), NULL); priv = MODEST_TNY_SEND_QUEUE_GET_PRIVATE (self); - if(priv->current != NULL) - { - info = priv->current->data; - priv->current = NULL; - - /* Keep in list until retry, so that we know that this was suspended - * by the user and not by an error. */ - info->status = MODEST_TNY_SEND_QUEUE_SUSPENDED; - g_signal_emit (self, signals[STATUS_CHANGED], 0, info->msg_id, info->status); - } + 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); - /* Set flags to supend sending operaiton (if removed, this is not necessary) */ - if (!remove) { - TnyIterator *iter = NULL; - TnyFolder *outbox = NULL; - TnyList *headers = tny_simple_list_new (); - outbox = modest_tny_send_queue_get_outbox (self); - tny_folder_get_headers (outbox, headers, TRUE, err); - if (err != NULL && *err != NULL) goto frees; - iter = tny_list_create_iterator (headers); - while (!tny_iterator_is_done (iter)) { - TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter)); - tny_header_unset_flags (header, TNY_HEADER_FLAG_PRIORITY); - tny_header_set_flags (header, TNY_HEADER_FLAG_SUSPENDED_PRIORITY); - g_object_unref (header); - tny_iterator_next (iter); - } - frees: - g_object_unref (G_OBJECT (headers)); - g_object_unref (G_OBJECT (outbox)); - } - - /* Dont call super class implementaiton, becasue camel removes messages from outbox */ - TNY_CAMEL_SEND_QUEUE_CLASS(parent_class)->cancel_func (self, remove, err); /* FIXME */ + return str; } +typedef struct { + TnySendQueueAddCallback callback; + gpointer user_data; +} AddAsyncHelper; + static void -modest_tny_send_queue_add (TnySendQueue *self, TnyMsg *msg, GError **err) +_on_added_to_outbox (TnySendQueue *self, + gboolean cancelled, + TnyMsg *msg, + GError *err, + gpointer user_data) { - ModestTnySendQueuePrivate *priv; - TnyHeader *header; + ModestTnySendQueuePrivate *priv = MODEST_TNY_SEND_QUEUE_GET_PRIVATE(self); + TnyHeader *header = NULL; SendInfo *info = NULL; - GList* existing; - const gchar* msg_id; + GList* existing = NULL; + gchar* msg_id = NULL; + AddAsyncHelper *helper; g_return_if_fail (TNY_IS_SEND_QUEUE(self)); g_return_if_fail (TNY_IS_CAMEL_MSG(msg)); - priv = MODEST_TNY_SEND_QUEUE_GET_PRIVATE (self); header = tny_msg_get_header (msg); + msg_id = modest_tny_send_queue_get_msg_id (header); + if (!msg_id) { + g_warning ("%s: No msg_id returned for header", __FUNCTION__); + goto end; + } - /* FIXME: do something smart here... */ - - /* Note that this call actually sets the message id to something - * sensible. */ - TNY_CAMEL_SEND_QUEUE_CLASS(parent_class)->add_func (self, msg, err); /* FIXME */ - - /* Check whether the mail is already in the queue */ - msg_id = tny_header_get_message_id (header); + /* Put newly added message in WAITING state */ existing = modest_tny_send_queue_lookup_info (MODEST_TNY_SEND_QUEUE(self), msg_id); - if(existing != NULL) - { - //g_assert(info->status == MODEST_TNY_SEND_QUEUE_SUSPENDED || - // info->status == MODEST_TNY_SEND_QUEUE_FAILED); - + if(existing != NULL) { info = existing->data; info->status = MODEST_TNY_SEND_QUEUE_WAITING; - } - else - { - + } 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); + + end: + g_object_unref (G_OBJECT(header)); - info->msg_id = strdup(msg_id); + /* Call the user callback */ + helper = (AddAsyncHelper *) user_data; + if (helper->callback) + helper->callback (self, cancelled, msg, err, helper->user_data); + g_slice_free (AddAsyncHelper, helper); +} + +static void +_add_message (ModestTnySendQueue *self, TnyHeader *header) +{ + 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); + + /* 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_new0 (SendInfo); + info->msg_id = strdup(msg_uid); info->status = MODEST_TNY_SEND_QUEUE_WAITING; g_queue_push_tail (priv->queue, info); + break; + default: + break; } - g_signal_emit (self, signals[STATUS_CHANGED], 0, info->msg_id, info->status); + /* Free */ + g_free(msg_uid); } +static void +modest_tny_send_queue_add_async (TnySendQueue *self, + TnyMsg *msg, + TnySendQueueAddCallback callback, + TnyStatusCallback status_callback, + gpointer user_data) +{ + AddAsyncHelper *helper = g_slice_new0 (AddAsyncHelper); + helper->callback = callback; + helper->user_data = user_data; + + /* Call the superclass passing our own callback */ + TNY_CAMEL_SEND_QUEUE_CLASS(parent_class)->add_async (self, msg, + _on_added_to_outbox, + status_callback, + helper); +} + + static TnyFolder* modest_tny_send_queue_get_sentbox (TnySendQueue *self) { - TnyFolder *folder; - TnyCamelTransportAccount *account; + ModestTnySendQueuePrivate *priv; g_return_val_if_fail (self, NULL); - account = tny_camel_send_queue_get_transport_account (TNY_CAMEL_SEND_QUEUE(self)); - if (!account) { - g_printerr ("modest: no account for send queue\n"); - return NULL; - } - folder = modest_tny_account_get_special_folder (TNY_ACCOUNT(account), - TNY_FOLDER_TYPE_SENT); - g_object_unref (G_OBJECT(account)); + priv = MODEST_TNY_SEND_QUEUE_GET_PRIVATE (self); - return folder; + return g_object_ref (priv->sentbox); } static TnyFolder* modest_tny_send_queue_get_outbox (TnySendQueue *self) { - TnyFolder *folder; - TnyCamelTransportAccount *account; + ModestTnySendQueuePrivate *priv; g_return_val_if_fail (self, NULL); - account = tny_camel_send_queue_get_transport_account (TNY_CAMEL_SEND_QUEUE(self)); - if (!account) { - g_printerr ("modest: no account for send queue\n"); - return NULL; - } - folder = modest_tny_account_get_special_folder (TNY_ACCOUNT(account), - TNY_FOLDER_TYPE_OUTBOX); - - /* This vfunc's tinymail contract does not allow it to return NULL. */ - if (!folder) { - g_warning("%s: Returning NULL.\n", __FUNCTION__); - } - - g_object_unref (G_OBJECT(account)); + priv = MODEST_TNY_SEND_QUEUE_GET_PRIVATE (self); - return folder; + return g_object_ref (priv->outbox); } GType @@ -264,6 +355,7 @@ modest_tny_send_queue_get_type (void) (GInstanceInitFunc) modest_tny_send_queue_instance_init, NULL }; + my_type = g_type_register_static (TNY_TYPE_CAMEL_SEND_QUEUE, "ModestTnySendQueue", &my_info, 0); @@ -282,13 +374,12 @@ modest_tny_send_queue_class_init (ModestTnySendQueueClass *klass) parent_class = g_type_class_peek_parent (klass); gobject_class->finalize = modest_tny_send_queue_finalize; - TNY_CAMEL_SEND_QUEUE_CLASS(klass)->add_func = modest_tny_send_queue_add; - 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; - TNY_CAMEL_SEND_QUEUE_CLASS(klass)->cancel_func = modest_tny_send_queue_cancel; + TNY_CAMEL_SEND_QUEUE_CLASS(klass)->add_async = modest_tny_send_queue_add_async; + TNY_CAMEL_SEND_QUEUE_CLASS(klass)->get_outbox = modest_tny_send_queue_get_outbox; + TNY_CAMEL_SEND_QUEUE_CLASS(klass)->get_sentbox = modest_tny_send_queue_get_sentbox; klass->status_changed = NULL; - signals[STATUS_CHANGED] = + signals[STATUS_CHANGED_SIGNAL] = g_signal_new ("status_changed", G_TYPE_FROM_CLASS (gobject_class), G_SIGNAL_RUN_FIRST, @@ -320,46 +411,116 @@ modest_tny_send_queue_finalize (GObject *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); } +typedef struct { + TnyCamelTransportAccount *account; + ModestTnySendQueue *queue; +} GetHeadersInfo; + +static void +new_queue_get_headers_async_cb (TnyFolder *folder, + gboolean cancelled, + TnyList *headers, + GError *err, + gpointer user_data) +{ + ModestTnySendQueue *self; + TnyIterator *iter; + GetHeadersInfo *info; + + info = (GetHeadersInfo *) user_data; + self = MODEST_TNY_SEND_QUEUE (info->queue); + + /* In case of error set the transport account anyway */ + if (cancelled || err) + goto set_transport; + + /* 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); + tny_iterator_next (iter); + } + + /* Reenable suspended items */ + modest_tny_send_queue_wakeup (self); + + /* Frees */ + g_object_unref (iter); + g_object_unref (headers); + + set_transport: + /* 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), + info->account); + + /* Frees */ + g_object_unref (info->account); + g_object_unref (info->queue); + g_slice_free (GetHeadersInfo, info); +} + ModestTnySendQueue* modest_tny_send_queue_new (TnyCamelTransportAccount *account) { - ModestTnySendQueue *self; + ModestTnySendQueue *self = NULL; + ModestTnySendQueuePrivate *priv = NULL; + TnyList *headers = NULL; + GetHeadersInfo *info; 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)); - - tny_camel_send_queue_set_transport_account (TNY_CAMEL_SEND_QUEUE(self), - account); + + /* 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); + + /* NOTE that this could happen if there was not enough disk + space when the account was created */ + if (!priv->outbox || !priv->sentbox) { + g_object_unref (self); + return NULL; + } /* Connect signals to control when a msg is being or has been sent */ - /* TODO: this signal was implemented in tinymail camel send queue, but im - waiting for implement some unit tests nbefore commited changes */ -/* if (FALSE) { */ -/* g_signal_connect (G_OBJECT(self), "msg-sending", */ -/* G_CALLBACK(_on_msg_start_sending), */ -/* NULL); */ -/* } */ - + 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); - return self; -} + g_signal_connect (G_OBJECT (self), "queue-start", + G_CALLBACK (_on_queue_start), + NULL); + priv->requested_send_receive = FALSE; -void -modest_tny_send_queue_try_to_send (ModestTnySendQueue* self) -{ - /* Flush send queue */ - tny_camel_send_queue_flush (TNY_CAMEL_SEND_QUEUE(self)); + headers = tny_simple_list_new (); + info = g_slice_new0 (GetHeadersInfo); + info->account = g_object_ref (account); + info->queue = g_object_ref (self); + tny_folder_get_headers_async (priv->outbox, headers, TRUE, + new_queue_get_headers_async_cb, + NULL, info); + + return self; } gboolean @@ -378,6 +539,9 @@ 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; @@ -386,99 +550,356 @@ modest_tny_send_queue_sending_in_progress (ModestTnySendQueue* self) ModestTnySendQueueStatus modest_tny_send_queue_get_msg_status (ModestTnySendQueue *self, const gchar *msg_id) { - GList *item; - item = modest_tny_send_queue_lookup_info (self, msg_id); - if(item == NULL) return MODEST_TNY_SEND_QUEUE_SUSPENDED; - return ((SendInfo*)item->data)->status; + 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; } -/* static void */ -/* _on_msg_start_sending (TnySendQueue *self, */ -/* TnyMsg *msg, */ -/* gpointer user_data) */ -/* { */ -/* ModestTnySendQueuePrivate *priv; */ -/* TnyHeader *header; */ -/* GList *item; */ -/* SendInfo *info; */ +gchar * +modest_tny_send_queue_get_msg_id (TnyHeader *header) +{ + gchar* msg_uid = NULL; + gchar *subject; + time_t date_received; + + g_return_val_if_fail (header && TNY_IS_HEADER(header), NULL); -/* priv = MODEST_TNY_SEND_QUEUE_GET_PRIVATE (self); */ + /* Get message uid */ + subject = tny_header_dup_subject (header); + date_received = tny_header_get_date_received (header); -/* header = tny_msg_get_header(msg); */ -/* item = modest_tny_send_queue_lookup_info (MODEST_TNY_SEND_QUEUE (self), tny_header_get_message_id (header)); */ + msg_uid = g_strdup_printf ("%s %d", subject, (int) date_received); + g_free (subject); -/* if (item != NULL) */ -/* { */ -/* info = item->data; */ -/* info->status = MODEST_TNY_SEND_QUEUE_SENDING; */ + return msg_uid; +} -/* g_signal_emit (self, signals[STATUS_CHANGED], 0, info->msg_id, info->status); */ -/* } */ -/* priv->current = item; */ -/* } */ +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); + if (msg_id) + item = modest_tny_send_queue_lookup_info (MODEST_TNY_SEND_QUEUE (self), msg_id); + else + g_warning ("%s: could not get msg-id for header", __FUNCTION__); + + if (item) { + /* 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; + } else + g_warning ("%s: could not find item with id '%s'", __FUNCTION__, msg_id); + + /* 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) { ModestTnySendQueuePrivate *priv; - TnyHeader *header; + gchar *msg_id = NULL; GList *item; priv = MODEST_TNY_SEND_QUEUE_GET_PRIVATE (self); - header = tny_msg_get_header (msg); + /* Get message uid */ + msg_id = modest_tny_send_queue_get_msg_id (header); - /* TODO: Use this version as soon as the msg-sending - * notification works */ -#if 0 - item = priv->current; - g_assert(item != NULL); -#else - item = modest_tny_send_queue_lookup_info (MODEST_TNY_SEND_QUEUE (self), tny_header_get_message_id(header)); - g_assert(item != NULL); -#endif - - modest_tny_send_queue_info_free (item->data); - g_queue_delete_link (priv->queue, item); - priv->current = NULL; + tny_header_set_flag (header, TNY_HEADER_FLAG_SEEN); + + tny_folder_sync_async (priv->sentbox, FALSE, NULL, NULL, NULL); + + /* 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) +static void +_on_msg_error_happened (TnySendQueue *self, + TnyHeader *header, + TnyMsg *msg, + GError *err, + gpointer user_data) +{ + ModestTnySendQueuePrivate *priv = NULL; + + priv = MODEST_TNY_SEND_QUEUE_GET_PRIVATE (self); + + /* Note that header could be NULL. Tinymail notifies about + generic send queue errors with this signal as well, and + those notifications are not bound to any particular header + or message */ + if (header && TNY_IS_HEADER (header)) { + SendInfo *info = NULL; + GList *item = NULL; + gchar* msg_uid = NULL; + + /* 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); + + /* TODO: this should not happen (but it does), so the + problem should be located in the way we generate + the message uids */ + if (!item) { + g_warning ("%s: could not find item with id '%s'", __FUNCTION__, msg_uid); + g_free(msg_uid); + return; + } + + 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 { + if (err->code == TNY_SERVICE_ERROR_CONNECT) { + TnyCamelTransportAccount* transport; + + transport = tny_camel_send_queue_get_transport_account (TNY_CAMEL_SEND_QUEUE (self)); + if (transport) { + gchar *message; + message = g_strdup_printf (_("emev_ib_ui_smtp_server_invalid"), + tny_account_get_hostname (TNY_ACCOUNT (transport))); + modest_platform_run_alert_dialog (message, FALSE); + g_free (message); + g_object_unref (transport); + } + } + 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; + + 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) { -/* ModestTnySendQueuePrivate *priv; */ -/* SendInfo *info; */ -/* GList *item; */ -/* TnyHeader *msg_header; */ - -/* priv = MODEST_TNY_SEND_QUEUE_GET_PRIVATE (self); */ - - /* TODO: Use this version as soon as the msg-sending - * notification works */ -/* #if 0 */ -/* item = priv->current; */ -/* g_assert(item != NULL); */ -/* info = priv->current->data; */ -/* #else */ -/* /\* TODO: Why do we get the msg and its header separately? The docs */ -/* * don't really tell. *\/ */ -/* g_assert(header == tny_msg_get_header (msg)); // ???? */ -/* msg_header = tny_msg_get_header (msg); */ -/* item = modest_tny_send_queue_lookup_info (MODEST_TNY_SEND_QUEUE (self), */ -/* tny_header_get_message_id (msg_header)); */ -/* g_object_unref (msg_header); */ -/* g_assert(item != NULL); */ -/* info = item->data; */ -/* #endif */ - - /* Keep in queue so that we remember that the opertion has failed - * and was not just cancelled */ -/* info->status = MODEST_TNY_SEND_QUEUE_FAILED; */ -/* g_signal_emit (self, signals[STATUS_CHANGED], 0, info->msg_id, info->status); */ + 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; + + 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), TRUE); + g_object_unref(account); + if (TNY_IS_SEND_QUEUE (send_queue)) { + 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; +} + +static void +wakeup_get_headers_async_cb (TnyFolder *folder, + gboolean cancelled, + TnyList *headers, + GError *err, + gpointer user_data) +{ + ModestTnySendQueue *self; + ModestTnySendQueuePrivate *priv; + TnyIterator *iter; + + self = MODEST_TNY_SEND_QUEUE (user_data); + priv = MODEST_TNY_SEND_QUEUE_GET_PRIVATE (self); + + if (cancelled || err) { + g_debug ("Failed to wake up the headers of the send queue"); + g_object_unref (self); + return; + } + + /* 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); + } + + /* Make changes persistent on disk */ + tny_folder_sync_async (priv->outbox, FALSE, NULL, NULL, NULL); + + /* Frees */ + g_object_unref (iter); + g_object_unref (headers); + g_object_unref (self); +} + + +void +modest_tny_send_queue_wakeup (ModestTnySendQueue *self) +{ + ModestTnySendQueuePrivate *priv; + TnyList *headers; + + 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_async (priv->outbox, headers, TRUE, + wakeup_get_headers_async_cb, + NULL, g_object_ref (self)); +} + +gboolean +modest_tny_send_queue_get_requested_send_receive (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->requested_send_receive; +} + +void +modest_tny_send_queue_set_requested_send_receive (ModestTnySendQueue *self, gboolean requested_send_receive) +{ + ModestTnySendQueuePrivate *priv; + + g_return_if_fail (MODEST_IS_TNY_SEND_QUEUE (self)); + priv = MODEST_TNY_SEND_QUEUE_GET_PRIVATE (self); + + priv->requested_send_receive = requested_send_receive; }