X-Git-Url: http://git.maemo.org/git/?p=modest;a=blobdiff_plain;f=src%2Fmodest-tny-send-queue.c;h=bbad20251cbc42b4a8afe561e1ad9fce23ec4355;hp=78ef43c1b97e32d5d60a3ab1621dfe728e925b48;hb=f7a80e39c3b0725566145d3bc2357846610bdcfb;hpb=9dad1c303142af16fc5bf973e0a0418970391c7c diff --git a/src/modest-tny-send-queue.c b/src/modest-tny-send-queue.c index 78ef43c..bbad202 100644 --- a/src/modest-tny-send-queue.c +++ b/src/modest-tny-send-queue.c @@ -29,97 +29,229 @@ #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 (ModestTnySendQueue *obj); 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); + /* list my signals */ enum { + STATUS_CHANGED, /* MY_SIGNAL_1, */ /* MY_SIGNAL_2, */ LAST_SIGNAL }; +typedef struct _SendInfo SendInfo; +struct _SendInfo { + gchar* msg_id; + ModestTnySendQueueStatus status; +}; + typedef struct _ModestTnySendQueuePrivate ModestTnySendQueuePrivate; struct _ModestTnySendQueuePrivate { - /* my private members go here, eg. */ - /* gboolean frobnicate_mode; */ + /* Queued infos */ + GQueue* queue; + + /* The info that is currently being sent */ + GList* current; }; + #define MODEST_TNY_SEND_QUEUE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \ MODEST_TYPE_TNY_SEND_QUEUE, \ ModestTnySendQueuePrivate)) + /* globals */ -static TnySendQueueClass *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 and keeps + * track of their state. + */ -static void -modest_tny_send_queue_cancel (TnySendQueue *self, gboolean remove) +static int +on_modest_tny_send_queue_compare_id(gconstpointer info, gconstpointer msg_id) { - MODEST_TNY_SENT_QUEUE_GET_CLASS(self)->cancel_func (self, remove); + return strcmp( ((SendInfo*)info)->msg_id, msg_id); } static void -modest_tny_send_queue_add (TnySendQueue *self, TnyMsg *msg) +modest_tny_send_queue_info_free(SendInfo *info) { - MODEST_TNY_SENT_QUEUE_GET_CLASS(self)->add_func (self, msg); + g_free(info->msg_id); + g_slice_free(SendInfo, info); } - -static void -modest_tny_send_queue_get_sentbox (TnySendQueue *self) +static GList* +modest_tny_send_queue_lookup_info (ModestTnySendQueue *self, const gchar *msg_id) { - MODEST_TNY_SENT_QUEUE_GET_CLASS(self)->get_sentbox (self); -} + 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_get_outbox (TnySendQueue *self, TnyMsg *msg) +modest_tny_send_queue_cancel (TnySendQueue *self, gboolean remove, GError **err) { - MODEST_TNY_SENT_QUEUE_GET_CLASS(self)->get_outbox (self); -} + ModestTnySendQueuePrivate *priv; + SendInfo *info; + 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); + } -static void -modest_tny_send_queue_cancel_default (TnySendQueue *self, gboolean remove) -{ - /* FIXME */ + /* 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 */ } - static void -modest_tny_send_queue_add_default (TnySendQueue *self, TnyMsg *msg) +modest_tny_send_queue_add (TnySendQueue *self, TnyMsg *msg, GError **err) { - /* FIXME */ -} + ModestTnySendQueuePrivate *priv; + TnyHeader *header; + SendInfo *info = NULL; + GList* existing; + const gchar* msg_id; + + 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); + + /* 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); + 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); + + info = existing->data; + info->status = MODEST_TNY_SEND_QUEUE_WAITING; + } + else + { + + info = g_slice_new (SendInfo); + + info->msg_id = strdup(msg_id); + info->status = MODEST_TNY_SEND_QUEUE_WAITING; + g_queue_push_tail (priv->queue, info); + } + g_signal_emit (self, signals[STATUS_CHANGED], 0, info->msg_id, info->status); +} static TnyFolder* -modest_tny_send_queue_get_sentbox_default (TnySendQueue *self) +modest_tny_send_queue_get_sentbox (TnySendQueue *self) { - MODEST_TNY_SENT_QUEUE_GET_CLASS(self)->get_sentbox (self); + TnyFolder *folder; + TnyCamelTransportAccount *account; + + 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)); + + return folder; } static TnyFolder* -modest_tny_send_queue_get_outbox_default (TnySendQueue *self, TnyMsg *msg) +modest_tny_send_queue_get_outbox (TnySendQueue *self) { - MODEST_TNY_SENT_QUEUE_GET_CLASS(self)->get_outbox (self); -} + TnyFolder *folder; + TnyCamelTransportAccount *account; + 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)); + + return folder; +} GType modest_tny_send_queue_get_type (void) { static GType my_type = 0; - if (!my_type) { + + if (my_type == 0) { static const GTypeInfo my_info = { sizeof(ModestTnySendQueueClass), NULL, /* base init */ @@ -128,32 +260,19 @@ modest_tny_send_queue_get_type (void) NULL, /* class finalize */ NULL, /* class data */ sizeof(ModestTnySendQueue), - 1, /* n_preallocs */ - (GInstanceInitFunc) modest_tny_send_queue_init, + 0, /* n_preallocs */ + (GInstanceInitFunc) modest_tny_send_queue_instance_init, NULL }; - my_type = g_type_register_static (TNY__TYPE__SEND_QUEUE, - "ModestTnySendQueue", - &my_info, 0); + my_type = g_type_register_static (TNY_TYPE_CAMEL_SEND_QUEUE, + "ModestTnySendQueue", + &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; @@ -163,10 +282,20 @@ 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_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; + klass->status_changed = NULL; + + signals[STATUS_CHANGED] = + 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)); } @@ -174,26 +303,182 @@ modest_tny_send_queue_class_init (ModestTnySendQueueClass *klass) static void modest_tny_send_queue_instance_init (GTypeInstance *instance, gpointer g_class) { - TnyCamelSendQueue *self; - TnyCamelSendQueuePriv *priv; + ModestTnySendQueuePrivate *priv; - self = (TnyCamelSendQueue*)instance; - priv = TNY_CAMEL_SEND_QUEUE_GET_PRIVATE (self); - - priv->sentbox_cache = NULL; - priv->outbox_cache = 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) { -/* free/unref instance resources here */ + 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_CLASS(parent_class)->finalize (obj); } ModestTnySendQueue* -modest_tny_send_queue_new (void) +modest_tny_send_queue_new (TnyCamelTransportAccount *account) +{ + ModestTnySendQueue *self; + + 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); + + /* 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-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; +} + + + +void +modest_tny_send_queue_try_to_send (ModestTnySendQueue* self) +{ + /* Flush send queue */ + tny_camel_send_queue_flush (TNY_CAMEL_SEND_QUEUE(self)); +} + +gboolean +modest_tny_send_queue_msg_is_being_sent (ModestTnySendQueue* self, + const gchar *msg_id) +{ + ModestTnySendQueueStatus status; + + 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; +} + +gboolean +modest_tny_send_queue_sending_in_progress (ModestTnySendQueue* self) +{ + ModestTnySendQueuePrivate *priv; + 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) { - return MODEST_TNY_SEND_QUEUE(g_object_new(MODEST_TYPE_TNY_SEND_QUEUE, NULL)); + 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; } +/* static void */ +/* _on_msg_start_sending (TnySendQueue *self, */ +/* TnyMsg *msg, */ +/* gpointer user_data) */ +/* { */ +/* ModestTnySendQueuePrivate *priv; */ +/* TnyHeader *header; */ +/* GList *item; */ +/* SendInfo *info; */ + +/* priv = MODEST_TNY_SEND_QUEUE_GET_PRIVATE (self); */ + +/* header = tny_msg_get_header(msg); */ +/* item = modest_tny_send_queue_lookup_info (MODEST_TNY_SEND_QUEUE (self), tny_header_get_message_id (header)); */ + +/* if (item != NULL) */ +/* { */ +/* info = item->data; */ +/* info->status = MODEST_TNY_SEND_QUEUE_SENDING; */ + +/* g_signal_emit (self, signals[STATUS_CHANGED], 0, info->msg_id, info->status); */ +/* } */ + +/* priv->current = item; */ +/* } */ + +static void +_on_msg_has_been_sent (TnySendQueue *self, + TnyMsg *msg, + gpointer user_data) +{ + ModestTnySendQueuePrivate *priv; + TnyHeader *header; + GList *item; + + priv = MODEST_TNY_SEND_QUEUE_GET_PRIVATE (self); + + header = tny_msg_get_header (msg); + + /* 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; +} + +static void _on_msg_error_happened (TnySendQueue *self, + TnyHeader *header, + TnyMsg *msg, + GError *err, + gpointer user_data) +{ +/* 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); */ +}