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.
30 #include "modest-mail-operation.h"
31 /* include other impl specific header files */
34 #include <tny-mime-part.h>
35 #include <tny-store-account.h>
36 #include <tny-folder-store.h>
37 #include <tny-folder-store-query.h>
38 #include <tny-camel-stream.h>
39 #include <tny-simple-list.h>
40 #include <tny-send-queue.h>
41 #include <tny-status.h>
42 #include <camel/camel-stream-mem.h>
43 #include <glib/gi18n.h>
44 #include <modest-tny-account.h>
45 #include <modest-tny-send-queue.h>
46 #include <modest-runtime.h>
47 #include "modest-text-utils.h"
48 #include "modest-tny-msg.h"
49 #include "modest-tny-folder.h"
50 #include "modest-tny-platform-factory.h"
51 #include "modest-marshal.h"
52 #include "modest-error.h"
54 /* 'private'/'protected' functions */
55 static void modest_mail_operation_class_init (ModestMailOperationClass *klass);
56 static void modest_mail_operation_init (ModestMailOperation *obj);
57 static void modest_mail_operation_finalize (GObject *obj);
59 /* static void update_process_msg_status_cb (GObject *obj, */
60 /* TnyStatus *status, */
61 /* gpointer user_data); */
62 static void get_msg_cb (TnyFolder *folder,
68 static void get_msg_status_cb (GObject *obj,
73 enum _ModestMailOperationSignals
75 PROGRESS_CHANGED_SIGNAL,
80 typedef struct _ModestMailOperationPrivate ModestMailOperationPrivate;
81 struct _ModestMailOperationPrivate {
84 ModestMailOperationStatus status;
85 ModestMailOperationId id;
90 #define MODEST_MAIL_OPERATION_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
91 MODEST_TYPE_MAIL_OPERATION, \
92 ModestMailOperationPrivate))
94 #define CHECK_EXCEPTION(priv, new_status) if (priv->error) {\
95 priv->status = new_status;\
98 typedef struct _GetMsgAsyncHelper {
99 ModestMailOperation *mail_op;
100 GetMsgAsynUserCallback user_callback;
105 typedef struct _XFerMsgAsyncHelper
107 ModestMailOperation *mail_op;
109 TnyFolder *dest_folder;
110 XferMsgsAsynUserCallback user_callback;
112 } XFerMsgAsyncHelper;
114 typedef struct _XFerFolderAsyncHelper
116 ModestMailOperation *mail_op;
118 } XFerFolderAsyncHelper;
121 static GObjectClass *parent_class = NULL;
123 static guint signals[NUM_SIGNALS] = {0};
126 modest_mail_operation_get_type (void)
128 static GType my_type = 0;
130 static const GTypeInfo my_info = {
131 sizeof(ModestMailOperationClass),
132 NULL, /* base init */
133 NULL, /* base finalize */
134 (GClassInitFunc) modest_mail_operation_class_init,
135 NULL, /* class finalize */
136 NULL, /* class data */
137 sizeof(ModestMailOperation),
139 (GInstanceInitFunc) modest_mail_operation_init,
142 my_type = g_type_register_static (G_TYPE_OBJECT,
143 "ModestMailOperation",
150 modest_mail_operation_class_init (ModestMailOperationClass *klass)
152 GObjectClass *gobject_class;
153 gobject_class = (GObjectClass*) klass;
155 parent_class = g_type_class_peek_parent (klass);
156 gobject_class->finalize = modest_mail_operation_finalize;
158 g_type_class_add_private (gobject_class, sizeof(ModestMailOperationPrivate));
161 * ModestMailOperation::progress-changed
162 * @self: the #MailOperation that emits the signal
163 * @user_data: user data set when the signal handler was connected
165 * Emitted when the progress of a mail operation changes
167 signals[PROGRESS_CHANGED_SIGNAL] =
168 g_signal_new ("progress-changed",
169 G_TYPE_FROM_CLASS (gobject_class),
171 G_STRUCT_OFFSET (ModestMailOperationClass, progress_changed),
173 g_cclosure_marshal_VOID__VOID,
178 modest_mail_operation_init (ModestMailOperation *obj)
180 ModestMailOperationPrivate *priv;
182 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
184 priv->status = MODEST_MAIL_OPERATION_STATUS_INVALID;
185 priv->id = MODEST_MAIL_OPERATION_ID_UNKNOWN;
193 modest_mail_operation_finalize (GObject *obj)
195 ModestMailOperationPrivate *priv;
197 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
200 g_error_free (priv->error);
204 g_object_unref (priv->source);
208 G_OBJECT_CLASS(parent_class)->finalize (obj);
212 modest_mail_operation_new (ModestMailOperationId id,
215 ModestMailOperation *obj;
216 ModestMailOperationPrivate *priv;
218 obj = MODEST_MAIL_OPERATION(g_object_new(MODEST_TYPE_MAIL_OPERATION, NULL));
219 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
223 priv->source = g_object_ref(source);
229 ModestMailOperationId
230 modest_mail_operation_get_id (ModestMailOperation *self)
232 ModestMailOperationPrivate *priv;
234 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
240 modest_mail_operation_is_mine (ModestMailOperation *self,
243 ModestMailOperationPrivate *priv;
245 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
246 if (priv->source == NULL) return FALSE;
248 return priv->source == me;
253 modest_mail_operation_send_mail (ModestMailOperation *self,
254 TnyTransportAccount *transport_account,
257 TnySendQueue *send_queue;
259 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
260 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
261 g_return_if_fail (TNY_IS_MSG (msg));
263 send_queue = TNY_SEND_QUEUE (modest_runtime_get_send_queue (transport_account));
264 if (!TNY_IS_SEND_QUEUE(send_queue))
265 g_printerr ("modest: could not find send queue for account\n");
268 tny_send_queue_add (send_queue, msg, &err);
270 g_printerr ("modest: error adding msg to send queue: %s\n",
274 /* g_message ("modest: message added to send queue"); */
278 /* Notify the queue */
279 modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (), self);
283 modest_mail_operation_send_new_mail (ModestMailOperation *self,
284 TnyTransportAccount *transport_account,
285 const gchar *from, const gchar *to,
286 const gchar *cc, const gchar *bcc,
287 const gchar *subject, const gchar *plain_body,
288 const gchar *html_body,
289 const GList *attachments_list,
290 TnyHeaderFlags priority_flags)
293 ModestMailOperationPrivate *priv = NULL;
294 /* GList *node = NULL; */
296 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
297 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
299 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
301 /* Check parametters */
303 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
304 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
305 _("Error trying to send a mail. You need to set at least one recipient"));
309 if (html_body == NULL) {
310 new_msg = modest_tny_msg_new (to, from, cc, bcc, subject, plain_body, (GSList *) attachments_list); /* FIXME: attachments */
312 new_msg = modest_tny_msg_new_html_plain (to, from, cc, bcc, subject, html_body, plain_body, (GSList *) attachments_list);
315 g_printerr ("modest: failed to create a new msg\n");
319 /* TODO: add priority handling. It's received in the priority_flags operator, and
320 it should have effect in the sending operation */
322 /* Call mail operation */
323 modest_mail_operation_send_mail (self, transport_account, new_msg);
326 g_object_unref (G_OBJECT (new_msg));
330 modest_mail_operation_save_to_drafts (ModestMailOperation *self,
331 TnyTransportAccount *transport_account,
332 const gchar *from, const gchar *to,
333 const gchar *cc, const gchar *bcc,
334 const gchar *subject, const gchar *plain_body,
335 const gchar *html_body,
336 const GList *attachments_list,
337 TnyHeaderFlags priority_flags)
340 TnyFolder *folder = NULL;
341 ModestMailOperationPrivate *priv = NULL;
344 /* GList *node = NULL; */
346 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
347 g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account));
349 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
351 if (html_body == NULL) {
352 msg = modest_tny_msg_new (to, from, cc, bcc, subject, plain_body, (GSList *) attachments_list); /* FIXME: attachments */
354 msg = modest_tny_msg_new_html_plain (to, from, cc, bcc, subject, html_body, plain_body, (GSList *) attachments_list);
357 g_printerr ("modest: failed to create a new msg\n");
361 folder = modest_tny_account_get_special_folder (TNY_ACCOUNT (transport_account), TNY_FOLDER_TYPE_DRAFTS);
363 g_printerr ("modest: failed to find Drafts folder\n");
367 tny_folder_add_msg (folder, msg, &err);
369 g_printerr ("modest: error adding msg to Drafts folder: %s",
375 modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (), self);
380 g_object_unref (G_OBJECT(msg));
382 g_object_unref (G_OBJECT(folder));
387 ModestMailOperation *mail_op;
388 TnyStoreAccount *account;
389 TnyTransportAccount *transport_account;
393 recurse_folders (TnyFolderStore *store, TnyFolderStoreQuery *query, TnyList *all_folders)
396 TnyList *folders = tny_simple_list_new ();
398 tny_folder_store_get_folders (store, folders, query, NULL);
399 iter = tny_list_create_iterator (folders);
401 while (!tny_iterator_is_done (iter)) {
403 TnyFolderStore *folder = (TnyFolderStore*) tny_iterator_get_current (iter);
405 tny_list_prepend (all_folders, G_OBJECT (folder));
406 recurse_folders (folder, query, all_folders);
407 g_object_unref (G_OBJECT (folder));
409 tny_iterator_next (iter);
411 g_object_unref (G_OBJECT (iter));
412 g_object_unref (G_OBJECT (folders));
416 * Used by update_account_thread to emit the "progress-changed" signal
417 * from the main loop. We call it inside an idle call to achieve that
420 notify_update_account_observers (gpointer data)
422 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
424 g_signal_emit (G_OBJECT (mail_op), signals[PROGRESS_CHANGED_SIGNAL], 0, NULL);
430 * Used by update_account_thread to notify the queue from the main
431 * loop. We call it inside an idle call to achieve that
434 notify_update_account_queue (gpointer data)
436 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
438 modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (),
440 g_object_unref (mail_op);
446 update_account_thread (gpointer thr_user_data)
448 UpdateAccountInfo *info;
449 TnyList *all_folders = NULL;
450 TnyIterator *iter = NULL;
451 TnyFolderStoreQuery *query = NULL;
452 ModestMailOperationPrivate *priv;
453 ModestTnySendQueue *send_queue;
456 info = (UpdateAccountInfo *) thr_user_data;
457 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(info->mail_op);
459 /* Get all the folders We can do it synchronously because
460 we're already running in a different thread than the UI */
461 all_folders = tny_simple_list_new ();
462 query = tny_folder_store_query_new ();
463 tny_folder_store_query_add_item (query, NULL, TNY_FOLDER_STORE_QUERY_OPTION_SUBSCRIBED);
464 tny_folder_store_get_folders (TNY_FOLDER_STORE (info->account),
469 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
473 iter = tny_list_create_iterator (all_folders);
474 while (!tny_iterator_is_done (iter)) {
475 TnyFolderStore *folder = TNY_FOLDER_STORE (tny_iterator_get_current (iter));
477 recurse_folders (folder, query, all_folders);
478 tny_iterator_next (iter);
480 g_object_unref (G_OBJECT (iter));
482 /* Update status and notify. We need to call the notification
483 with a source functopm in order to call it from the main
484 loop. We need that in order not to get into trouble with
485 Gtk+. We use a timeout in order to provide more status
486 information, because the sync tinymail call does not
487 provide it for the moment */
488 timeout = g_timeout_add (250, notify_update_account_observers, info->mail_op);
490 /* Refresh folders */
491 iter = tny_list_create_iterator (all_folders);
492 while (!tny_iterator_is_done (iter) && !priv->error) {
494 TnyFolderStore *folder = TNY_FOLDER_STORE (tny_iterator_get_current (iter));
496 /* Refresh the folder */
497 tny_folder_refresh (TNY_FOLDER (folder), &(priv->error));
500 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
503 g_object_unref (G_OBJECT (folder));
504 tny_iterator_next (iter);
506 g_object_unref (G_OBJECT (iter));
507 g_source_remove (timeout);
510 priv->id = MODEST_MAIL_OPERATION_ID_SEND;
512 send_queue = modest_tny_send_queue_new (TNY_CAMEL_TRANSPORT_ACCOUNT(info->transport_account));
514 timeout = g_timeout_add (250, notify_update_account_observers, info->mail_op);
515 modest_tny_send_queue_flush (send_queue);
516 g_source_remove (timeout);
518 g_object_unref (G_OBJECT(send_queue));
520 /* Check if the operation was a success */
522 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
524 /* Update the last updated key */
525 modest_account_mgr_set_int (modest_runtime_get_account_mgr (),
526 tny_account_get_id (TNY_ACCOUNT (info->account)),
527 MODEST_ACCOUNT_LAST_UPDATED,
533 /* Notify the queue. Note that the info could be freed before
534 this idle happens, but the mail operation will be still
536 g_idle_add (notify_update_account_queue, info->mail_op);
539 g_object_unref (query);
540 g_object_unref (all_folders);
541 g_object_unref (info->account);
542 g_object_unref (info->transport_account);
543 g_slice_free (UpdateAccountInfo, info);
549 modest_mail_operation_update_account (ModestMailOperation *self,
550 const gchar *account_name)
553 UpdateAccountInfo *info;
554 ModestMailOperationPrivate *priv;
555 TnyStoreAccount *modest_account;
556 TnyTransportAccount *transport_account;
558 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), FALSE);
559 g_return_val_if_fail (account_name, FALSE);
561 /* Init mail operation. Set total and done to 0, and do not
562 update them, this way the progress objects will know that
563 we have no clue about the number of the objects */
564 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
567 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
569 /* Get the Modest account */
570 modest_account = (TnyStoreAccount *)
571 modest_tny_account_store_get_tny_account_by_account (modest_runtime_get_account_store (),
573 TNY_ACCOUNT_TYPE_STORE);
575 if (!modest_account) {
576 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
577 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
578 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
579 "cannot get tny store account for %s\n", account_name);
580 modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (),
585 /* Get the transport account, we can not do it in the thread
586 due to some problems with dbus */
587 transport_account = (TnyTransportAccount *)
588 modest_tny_account_store_get_transport_account_for_open_connection (modest_runtime_get_account_store(),
590 if (!transport_account) {
591 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
592 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
593 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
594 "cannot get tny transport account for %s\n", account_name);
595 modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (),
600 /* Create the helper object */
601 info = g_slice_new (UpdateAccountInfo);
602 info->mail_op = self;
603 info->account = modest_account;
604 info->transport_account = transport_account;
606 thread = g_thread_create (update_account_thread, info, FALSE, NULL);
611 ModestMailOperationStatus
612 modest_mail_operation_get_status (ModestMailOperation *self)
614 ModestMailOperationPrivate *priv;
616 g_return_val_if_fail (self, MODEST_MAIL_OPERATION_STATUS_INVALID);
617 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self),
618 MODEST_MAIL_OPERATION_STATUS_INVALID);
620 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
625 modest_mail_operation_get_error (ModestMailOperation *self)
627 ModestMailOperationPrivate *priv;
629 g_return_val_if_fail (self, NULL);
630 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), NULL);
632 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
637 modest_mail_operation_cancel (ModestMailOperation *self)
639 ModestMailOperationPrivate *priv;
641 if (!MODEST_IS_MAIL_OPERATION (self)) {
642 g_warning ("%s: invalid parametter", G_GNUC_FUNCTION);
646 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
648 /* TODO: Tinymail does not support cancel operation */
651 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
653 /* Notify the queue */
654 modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (), self);
660 modest_mail_operation_get_task_done (ModestMailOperation *self)
662 ModestMailOperationPrivate *priv;
664 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), 0);
666 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
671 modest_mail_operation_get_task_total (ModestMailOperation *self)
673 ModestMailOperationPrivate *priv;
675 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), 0);
677 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
682 modest_mail_operation_is_finished (ModestMailOperation *self)
684 ModestMailOperationPrivate *priv;
685 gboolean retval = FALSE;
687 if (!MODEST_IS_MAIL_OPERATION (self)) {
688 g_warning ("%s: invalid parametter", G_GNUC_FUNCTION);
692 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
694 if (priv->status == MODEST_MAIL_OPERATION_STATUS_SUCCESS ||
695 priv->status == MODEST_MAIL_OPERATION_STATUS_FAILED ||
696 priv->status == MODEST_MAIL_OPERATION_STATUS_CANCELED ||
697 priv->status == MODEST_MAIL_OPERATION_STATUS_FINISHED_WITH_ERRORS) {
706 /* ******************************************************************* */
707 /* ************************** STORE ACTIONS ************************* */
708 /* ******************************************************************* */
712 modest_mail_operation_create_folder (ModestMailOperation *self,
713 TnyFolderStore *parent,
716 ModestTnyFolderRules rules;
717 ModestMailOperationPrivate *priv;
718 TnyFolder *new_folder = NULL;
719 gboolean can_create = FALSE;
721 g_return_val_if_fail (TNY_IS_FOLDER_STORE (parent), NULL);
722 g_return_val_if_fail (name, NULL);
724 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
727 if (!TNY_IS_FOLDER (parent)) {
728 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
729 MODEST_MAIL_OPERATION_ERROR_BAD_PARAMETER,
730 _("mail_in_ui_folder_create_error"));
732 /* Check folder rules */
733 rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
734 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE)
735 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
736 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
737 _("mail_in_ui_folder_create_error"));
743 /* Create the folder */
744 new_folder = tny_folder_store_create_folder (parent, name, &(priv->error));
745 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
748 /* Notify the queue */
749 modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (), self);
755 modest_mail_operation_remove_folder (ModestMailOperation *self,
757 gboolean remove_to_trash)
760 ModestMailOperationPrivate *priv;
761 ModestTnyFolderRules rules;
763 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
764 g_return_if_fail (TNY_IS_FOLDER (folder));
766 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
768 /* Check folder rules */
769 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
770 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_DELETABLE) {
771 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
772 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
773 _("mail_in_ui_folder_delete_error"));
777 /* Get the account */
778 account = tny_folder_get_account (folder);
780 /* Delete folder or move to trash */
781 if (remove_to_trash) {
782 TnyFolder *trash_folder = NULL;
783 /* TnyFolder *trash_folder, *new_folder; */
784 trash_folder = modest_tny_account_get_special_folder (account,
785 TNY_FOLDER_TYPE_TRASH);
786 /* TODO: error_handling */
787 modest_mail_operation_xfer_folder (self, folder,
788 TNY_FOLDER_STORE (trash_folder), TRUE);
789 /* new_folder = modest_mail_operation_xfer_folder (self, folder, */
790 /* TNY_FOLDER_STORE (trash_folder), TRUE); */
791 /* g_object_unref (G_OBJECT (new_folder)); */
793 TnyFolderStore *parent = tny_folder_get_folder_store (folder);
795 tny_folder_store_remove_folder (parent, folder, &(priv->error));
796 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
799 g_object_unref (G_OBJECT (parent));
801 g_object_unref (G_OBJECT (account));
804 /* Notify the queue */
805 modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (), self);
809 modest_mail_operation_rename_folder (ModestMailOperation *self,
813 ModestMailOperationPrivate *priv;
814 ModestTnyFolderRules rules;
816 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
817 g_return_if_fail (TNY_IS_FOLDER_STORE (folder));
818 g_return_if_fail (name);
820 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
822 /* Check folder rules */
823 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
824 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_RENAMEABLE) {
825 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
826 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
827 _("FIXME: unable to rename"));
829 /* Rename. Camel handles folder subscription/unsubscription */
831 TnyFolderStore *into;
834 into = tny_folder_get_folder_store (folder);
835 nfol = tny_folder_copy (folder, into, name, TRUE, &(priv->error));
837 g_object_unref (into);
839 g_object_unref (nfol);
841 CHECK_EXCEPTION (priv, MODEST_MAIL_OPERATION_STATUS_FAILED);
844 /* Notify the queue */
845 modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (), self);
849 transfer_folder_status_cb (GObject *obj,
853 XFerMsgAsyncHelper *helper = NULL;
854 ModestMailOperation *self;
855 ModestMailOperationPrivate *priv;
857 g_return_if_fail (status != NULL);
858 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_COPY_FOLDER);
860 helper = (XFerMsgAsyncHelper *) user_data;
861 g_return_if_fail (helper != NULL);
863 /* Temporary FIX: useful when tinymail send us status
864 information *after* calling the function callback */
865 if (!MODEST_IS_MAIL_OPERATION (helper->mail_op))
868 self = helper->mail_op;
869 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
871 if ((status->position == 1) && (status->of_total == 100))
874 priv->done = status->position;
875 priv->total = status->of_total;
878 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, NULL);
883 transfer_folder_cb (TnyFolder *folder, TnyFolderStore *into, gboolean cancelled, TnyFolder *new_folder, GError **err, gpointer user_data)
885 XFerFolderAsyncHelper *helper = NULL;
886 ModestMailOperation *self = NULL;
887 ModestMailOperationPrivate *priv = NULL;
889 helper = (XFerFolderAsyncHelper *) user_data;
890 self = helper->mail_op;
892 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
895 priv->error = g_error_copy (*err);
897 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
898 } else if (cancelled) {
899 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
900 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
901 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
902 _("Error trying to refresh the contents of %s"),
903 tny_folder_get_name (folder));
906 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
910 g_slice_free (XFerFolderAsyncHelper, helper);
911 g_object_unref (folder);
912 g_object_unref (into);
913 g_object_unref (new_folder);
915 /* Notify the queue */
916 modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (), self);
920 modest_mail_operation_xfer_folder (ModestMailOperation *self,
922 TnyFolderStore *parent,
923 gboolean delete_original)
925 ModestMailOperationPrivate *priv;
926 TnyFolder *new_folder = NULL;
927 ModestTnyFolderRules rules;
929 g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (self), NULL);
930 g_return_val_if_fail (TNY_IS_FOLDER_STORE (parent), NULL);
931 g_return_val_if_fail (TNY_IS_FOLDER (folder), NULL);
933 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
935 /* The moveable restriction is applied also to copy operation */
936 rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
937 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_MOVEABLE) {
938 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
939 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
940 _("FIXME: unable to rename"));
942 /* Move/Copy folder */
943 new_folder = tny_folder_copy (folder,
945 tny_folder_get_name (folder),
950 /* Notify the queue */
951 modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (), self);
957 modest_mail_operation_xfer_folder_async (ModestMailOperation *self,
959 TnyFolderStore *parent,
960 gboolean delete_original)
962 XFerFolderAsyncHelper *helper = NULL;
963 ModestMailOperationPrivate *priv = NULL;
964 ModestTnyFolderRules rules;
966 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
967 g_return_if_fail (TNY_IS_FOLDER_STORE (parent));
968 g_return_if_fail (TNY_IS_FOLDER (folder));
970 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
972 /* Pick references for async calls */
973 g_object_ref (folder);
974 g_object_ref (parent);
976 /* The moveable restriction is applied also to copy operation */
977 rules = modest_tny_folder_get_rules (TNY_FOLDER (parent));
978 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_MOVEABLE) {
979 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
980 MODEST_MAIL_OPERATION_ERROR_FOLDER_RULES,
981 _("FIXME: unable to rename"));
983 helper = g_slice_new0 (XFerFolderAsyncHelper);
984 helper->mail_op = self;
986 /* Move/Copy folder */
987 tny_folder_copy_async (folder,
989 tny_folder_get_name (folder),
992 transfer_folder_status_cb,
998 /* ******************************************************************* */
999 /* ************************** MSG ACTIONS ************************* */
1000 /* ******************************************************************* */
1002 void modest_mail_operation_get_msg (ModestMailOperation *self,
1004 GetMsgAsynUserCallback user_callback,
1007 GetMsgAsyncHelper *helper = NULL;
1009 ModestMailOperationPrivate *priv;
1011 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1012 g_return_if_fail (TNY_IS_HEADER (header));
1014 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1015 folder = tny_header_get_folder (header);
1017 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1019 /* Get message from folder */
1021 helper = g_slice_new0 (GetMsgAsyncHelper);
1022 helper->mail_op = self;
1023 helper->user_callback = user_callback;
1024 helper->pending_ops = 1;
1025 helper->user_data = user_data;
1027 tny_folder_get_msg_async (folder, header, get_msg_cb, get_msg_status_cb, helper);
1029 g_object_unref (G_OBJECT (folder));
1031 /* Set status failed and set an error */
1032 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1033 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1034 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1035 _("Error trying to get a message. No folder found for header"));
1040 get_msg_cb (TnyFolder *folder,
1046 GetMsgAsyncHelper *helper = NULL;
1047 ModestMailOperation *self = NULL;
1048 ModestMailOperationPrivate *priv = NULL;
1050 helper = (GetMsgAsyncHelper *) user_data;
1051 g_return_if_fail (helper != NULL);
1052 self = helper->mail_op;
1053 g_return_if_fail (MODEST_IS_MAIL_OPERATION(self));
1054 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1056 helper->pending_ops--;
1058 /* Check errors and cancel */
1060 priv->error = g_error_copy (*error);
1061 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1065 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1066 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1067 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1068 _("Error trying to refresh the contents of %s"),
1069 tny_folder_get_name (folder));
1073 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1075 /* If user defined callback function was defined, call it */
1076 if (helper->user_callback) {
1077 helper->user_callback (priv->source, msg, helper->user_data);
1082 if (helper->pending_ops == 0) {
1083 g_slice_free (GetMsgAsyncHelper, helper);
1085 /* Notify the queue */
1086 modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (), self);
1091 get_msg_status_cb (GObject *obj,
1095 GetMsgAsyncHelper *helper = NULL;
1096 ModestMailOperation *self;
1097 ModestMailOperationPrivate *priv;
1099 g_return_if_fail (status != NULL);
1100 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_GET_MSG);
1102 helper = (GetMsgAsyncHelper *) user_data;
1103 g_return_if_fail (helper != NULL);
1105 /* Temporary FIX: useful when tinymail send us status
1106 information *after* calling the function callback */
1107 if (!MODEST_IS_MAIL_OPERATION (helper->mail_op))
1110 self = helper->mail_op;
1111 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1113 if ((status->position == 1) && (status->of_total == 100))
1119 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, NULL);
1122 /****************************************************/
1124 ModestMailOperation *mail_op;
1126 GetMsgAsynUserCallback user_callback;
1128 GDestroyNotify notify;
1132 * Used by get_msgs_full_thread to emit the "progress-changed" signal
1133 * from the main loop. We call it inside an idle call to achieve that
1136 notify_get_msgs_full_observers (gpointer data)
1138 ModestMailOperation *mail_op = MODEST_MAIL_OPERATION (data);
1140 g_signal_emit (G_OBJECT (mail_op), signals[PROGRESS_CHANGED_SIGNAL], 0, NULL);
1142 g_object_unref (mail_op);
1148 GetMsgAsynUserCallback user_callback;
1152 } NotifyGetMsgsInfo;
1155 notify_get_msgs_full (gpointer data)
1157 NotifyGetMsgsInfo *info;
1159 info = (NotifyGetMsgsInfo *) data;
1161 /* Call the user callback */
1162 info->user_callback (info->source, info->msg, info->user_data);
1164 g_slice_free (NotifyGetMsgsInfo, info);
1170 get_msgs_full_destroyer (gpointer data)
1172 GetFullMsgsInfo *info;
1174 info = (GetFullMsgsInfo *) data;
1177 info->notify (info->user_data);
1180 g_object_unref (info->headers);
1181 g_slice_free (GetFullMsgsInfo, info);
1187 get_msgs_full_thread (gpointer thr_user_data)
1189 GetFullMsgsInfo *info;
1190 ModestMailOperationPrivate *priv = NULL;
1191 TnyIterator *iter = NULL;
1193 info = (GetFullMsgsInfo *) thr_user_data;
1194 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (info->mail_op);
1196 iter = tny_list_create_iterator (info->headers);
1197 while (!tny_iterator_is_done (iter) && !priv->error) {
1201 header = TNY_HEADER (tny_iterator_get_current (iter));
1202 folder = tny_header_get_folder (header);
1204 /* Get message from folder */
1207 /* The callback will call it per each header */
1208 msg = tny_folder_get_msg (folder, header, &(priv->error));
1213 /* notify progress */
1214 g_idle_add_full (G_PRIORITY_HIGH_IDLE,
1215 notify_get_msgs_full_observers,
1216 g_object_ref (info->mail_op), NULL);
1218 /* The callback is the responsible for
1219 freeing the message */
1220 if (info->user_callback) {
1221 NotifyGetMsgsInfo *info_notify;
1222 info_notify = g_slice_new0 (NotifyGetMsgsInfo);
1223 info_notify->user_callback = info->user_callback;
1224 info_notify->source = priv->source;
1225 info_notify->msg = msg;
1226 info_notify->user_data = info->user_data;
1227 g_idle_add_full (G_PRIORITY_HIGH_IDLE,
1228 notify_get_msgs_full,
1231 g_object_unref (msg);
1235 /* Set status failed and set an error */
1236 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1237 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1238 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1239 "Error trying to get a message. No folder found for header");
1242 g_object_unref (header);
1243 tny_iterator_next (iter);
1246 /* Notify the queue */
1247 g_idle_add (notify_update_account_queue, info->mail_op);
1249 /* Free thread resources. Will be called after all previous idles */
1250 g_idle_add_full (G_PRIORITY_DEFAULT_IDLE + 1, get_msgs_full_destroyer, info, NULL);
1256 modest_mail_operation_get_msgs_full (ModestMailOperation *self,
1257 TnyList *header_list,
1258 GetMsgAsynUserCallback user_callback,
1260 GDestroyNotify notify)
1263 ModestMailOperationPrivate *priv = NULL;
1264 GetFullMsgsInfo *info = NULL;
1266 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1268 /* Init mail operation */
1269 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1270 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1272 priv->total = tny_list_get_length(header_list);
1274 /* Create the info */
1275 info = g_slice_new0 (GetFullMsgsInfo);
1276 info->mail_op = self;
1277 info->user_callback = user_callback;
1278 info->user_data = user_data;
1279 info->headers = g_object_ref (header_list);
1280 info->notify = notify;
1282 /* Call the thread */
1283 thread = g_thread_create (get_msgs_full_thread, info, FALSE, NULL);
1288 modest_mail_operation_remove_msg (ModestMailOperation *self,
1290 gboolean remove_to_trash)
1293 ModestMailOperationPrivate *priv;
1295 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1296 g_return_if_fail (TNY_IS_HEADER (header));
1298 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1299 folder = tny_header_get_folder (header);
1301 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1303 /* Delete or move to trash */
1304 if (remove_to_trash) {
1305 TnyFolder *trash_folder;
1306 TnyStoreAccount *store_account;
1308 store_account = TNY_STORE_ACCOUNT (tny_folder_get_account (folder));
1309 trash_folder = modest_tny_account_get_special_folder (TNY_ACCOUNT(store_account),
1310 TNY_FOLDER_TYPE_TRASH);
1315 headers = tny_simple_list_new ();
1316 tny_list_append (headers, G_OBJECT (header));
1317 g_object_unref (header);
1320 modest_mail_operation_xfer_msgs (self, headers, trash_folder, TRUE, NULL, NULL);
1321 g_object_unref (headers);
1322 /* g_object_unref (trash_folder); */
1324 ModestMailOperationPrivate *priv;
1326 /* Set status failed and set an error */
1327 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1328 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1329 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1330 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1331 _("Error trying to delete a message. Trash folder not found"));
1334 g_object_unref (G_OBJECT (store_account));
1336 tny_folder_remove_msg (folder, header, &(priv->error));
1338 tny_folder_sync(folder, TRUE, &(priv->error));
1343 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1345 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1348 g_object_unref (G_OBJECT (folder));
1350 /* Notify the queue */
1351 modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (), self);
1355 transfer_msgs_status_cb (GObject *obj,
1359 XFerMsgAsyncHelper *helper = NULL;
1360 ModestMailOperation *self;
1361 ModestMailOperationPrivate *priv;
1363 g_return_if_fail (status != NULL);
1364 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_XFER_MSGS);
1366 helper = (XFerMsgAsyncHelper *) user_data;
1367 g_return_if_fail (helper != NULL);
1369 /* Temporary FIX: useful when tinymail send us status
1370 information *after* calling the function callback */
1371 if (!MODEST_IS_MAIL_OPERATION (helper->mail_op))
1374 self = helper->mail_op;
1375 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1377 if ((status->position == 1) && (status->of_total == 100))
1380 priv->done = status->position;
1381 priv->total = status->of_total;
1383 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, NULL);
1388 transfer_msgs_cb (TnyFolder *folder, gboolean cancelled, GError **err, gpointer user_data)
1390 XFerMsgAsyncHelper *helper;
1391 ModestMailOperation *self;
1392 ModestMailOperationPrivate *priv;
1394 helper = (XFerMsgAsyncHelper *) user_data;
1395 self = helper->mail_op;
1397 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self);
1400 priv->error = g_error_copy (*err);
1402 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1403 } else if (cancelled) {
1404 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1405 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1406 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1407 _("Error trying to refresh the contents of %s"),
1408 tny_folder_get_name (folder));
1411 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1414 /* If user defined callback function was defined, call it */
1415 if (helper->user_callback) {
1416 helper->user_callback (priv->source, helper->user_data);
1420 g_object_unref (helper->headers);
1421 g_object_unref (helper->dest_folder);
1422 g_object_unref (helper->mail_op);
1423 g_slice_free (XFerMsgAsyncHelper, helper);
1424 g_object_unref (folder);
1426 /* Notify the queue */
1427 modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (), self);
1431 modest_mail_operation_xfer_msgs (ModestMailOperation *self,
1434 gboolean delete_original,
1435 XferMsgsAsynUserCallback user_callback,
1438 ModestMailOperationPrivate *priv;
1440 TnyFolder *src_folder;
1441 XFerMsgAsyncHelper *helper;
1444 g_return_if_fail (MODEST_IS_MAIL_OPERATION (self));
1445 g_return_if_fail (TNY_IS_LIST (headers));
1446 g_return_if_fail (TNY_IS_FOLDER (folder));
1448 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1451 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1453 /* Create the helper */
1454 helper = g_slice_new0 (XFerMsgAsyncHelper);
1455 helper->mail_op = g_object_ref(self);
1456 helper->dest_folder = g_object_ref(folder);
1457 helper->headers = g_object_ref(headers);
1458 helper->user_callback = user_callback;
1459 helper->user_data = user_data;
1461 /* Get source folder */
1462 iter = tny_list_create_iterator (headers);
1463 header = TNY_HEADER (tny_iterator_get_current (iter));
1464 src_folder = tny_header_get_folder (header);
1465 g_object_unref (header);
1466 g_object_unref (iter);
1468 /* Transfer messages */
1469 tny_folder_transfer_msgs_async (src_folder,
1474 transfer_msgs_status_cb,
1480 on_refresh_folder (TnyFolder *folder,
1485 ModestMailOperation *self;
1486 ModestMailOperationPrivate *priv;
1488 self = MODEST_MAIL_OPERATION (user_data);
1489 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1492 priv->error = g_error_copy (*error);
1493 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
1498 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELED;
1499 g_set_error (&(priv->error), MODEST_MAIL_OPERATION_ERROR,
1500 MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1501 _("Error trying to refresh the contents of %s"),
1502 tny_folder_get_name (folder));
1506 priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS;
1510 g_object_unref (folder);
1512 /* Notify the queue */
1513 modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (), self);
1517 on_refresh_folder_status_update (GObject *obj,
1521 ModestMailOperation *self;
1522 ModestMailOperationPrivate *priv;
1524 g_return_if_fail (status != NULL);
1525 g_return_if_fail (status->code == TNY_FOLDER_STATUS_CODE_REFRESH);
1527 /* Temporary FIX: useful when tinymail send us status
1528 information *after* calling the function callback */
1529 if (!MODEST_IS_MAIL_OPERATION (user_data))
1532 self = MODEST_MAIL_OPERATION (user_data);
1533 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1535 priv->done = status->position;
1536 priv->total = status->of_total;
1538 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, NULL);
1542 modest_mail_operation_refresh_folder (ModestMailOperation *self,
1545 ModestMailOperationPrivate *priv;
1547 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(self);
1549 /* Pick a reference */
1550 g_object_ref (folder);
1552 priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
1554 /* Refresh the folder. TODO: tinymail could issue a status
1555 updates before the callback call then this could happen. We
1556 must review the design */
1557 tny_folder_refresh_async (folder,
1559 on_refresh_folder_status_update,
1564 _modest_mail_operation_notify_end (ModestMailOperation *self)
1566 g_signal_emit (G_OBJECT (self), signals[PROGRESS_CHANGED_SIGNAL], 0, NULL);