* modest-mail-operation.c: refactored some common code.
[modest] / src / modest-mail-operation.c
1 /* Copyright (c) 2006, Nokia Corporation
2  * All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met:
7  *
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.
16  *
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.
28  */
29
30 #include "modest-mail-operation.h"
31 /* include other impl specific header files */
32 #include <string.h>
33 #include <stdarg.h>
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 <glib/gi18n.h>
39
40 /* 'private'/'protected' functions */
41 static void modest_mail_operation_class_init (ModestMailOperationClass *klass);
42 static void modest_mail_operation_init       (ModestMailOperation *obj);
43 static void modest_mail_operation_finalize   (GObject *obj);
44
45 #define MODEST_ERROR modest_error_quark ()
46
47 typedef enum _ModestMailOperationErrorCode ModestMailOperationErrorCode;
48 enum _ModestMailOperationErrorCode {
49         MODEST_MAIL_OPERATION_ERROR_BAD_ACCOUNT,
50         MODEST_MAIL_OPERATION_ERROR_MISSING_PARAMETER,
51
52         MODEST_MAIL_OPERATION_NUM_ERROR_CODES
53 };
54
55 static void set_error (ModestMailOperation *mail_operation, 
56                        ModestMailOperationErrorCode error_code,
57                        const gchar *fmt, ...);
58 static void status_update_cb (TnyFolder *folder, const gchar *what, 
59                               gint status, gpointer user_data);
60 static void folder_refresh_cb (TnyFolder *folder, gboolean cancelled, 
61                                gpointer user_data);
62 static void add_attachments (TnyMsg *msg, const GList *attachments_list);
63 static TnyMimePart * add_body_part (TnyMsg *msg, const gchar *body,
64                                     const gchar *content_type, gboolean has_attachments);
65
66 /* list my signals  */
67 enum {
68         /* MY_SIGNAL_1, */
69         /* MY_SIGNAL_2, */
70         LAST_SIGNAL
71 };
72
73 typedef struct _ModestMailOperationPrivate ModestMailOperationPrivate;
74 struct _ModestMailOperationPrivate {
75         TnyAccount                *account;
76         ModestMailOperationStatus  status;
77         GError                    *error;
78 };
79 #define MODEST_MAIL_OPERATION_GET_PRIVATE(o)      (G_TYPE_INSTANCE_GET_PRIVATE((o), \
80                                                    MODEST_TYPE_MAIL_OPERATION, \
81                                                    ModestMailOperationPrivate))
82
83 /* some utility functions */
84 static char * get_content_type(const gchar *s);
85 static gboolean is_ascii(const gchar *s);
86
87 /* globals */
88 static GObjectClass *parent_class = NULL;
89
90 /* uncomment the following if you have defined any signals */
91 /* static guint signals[LAST_SIGNAL] = {0}; */
92
93 GType
94 modest_mail_operation_get_type (void)
95 {
96         static GType my_type = 0;
97         if (!my_type) {
98                 static const GTypeInfo my_info = {
99                         sizeof(ModestMailOperationClass),
100                         NULL,           /* base init */
101                         NULL,           /* base finalize */
102                         (GClassInitFunc) modest_mail_operation_class_init,
103                         NULL,           /* class finalize */
104                         NULL,           /* class data */
105                         sizeof(ModestMailOperation),
106                         1,              /* n_preallocs */
107                         (GInstanceInitFunc) modest_mail_operation_init,
108                         NULL
109                 };
110                 my_type = g_type_register_static (G_TYPE_OBJECT,
111                                                   "ModestMailOperation",
112                                                   &my_info, 0);
113         }
114         return my_type;
115 }
116
117 static void
118 modest_mail_operation_class_init (ModestMailOperationClass *klass)
119 {
120         GObjectClass *gobject_class;
121         gobject_class = (GObjectClass*) klass;
122
123         parent_class            = g_type_class_peek_parent (klass);
124         gobject_class->finalize = modest_mail_operation_finalize;
125
126         g_type_class_add_private (gobject_class, sizeof(ModestMailOperationPrivate));
127
128         /* signal definitions go here, e.g.: */
129 /*      signals[MY_SIGNAL_1] = */
130 /*              g_signal_new ("my_signal_1",....); */
131 /*      signals[MY_SIGNAL_2] = */
132 /*              g_signal_new ("my_signal_2",....); */
133 /*      etc. */
134 }
135
136 static void
137 modest_mail_operation_init (ModestMailOperation *obj)
138 {
139         ModestMailOperationPrivate *priv;
140
141         priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
142
143         priv->account = NULL;
144         priv->status = MODEST_MAIL_OPERATION_STATUS_INVALID;
145         priv->error = NULL;
146 }
147
148 static void
149 modest_mail_operation_finalize (GObject *obj)
150 {
151         ModestMailOperationPrivate *priv;
152
153         priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
154
155         if (priv->account) {
156                 g_object_unref (priv->account);
157                 priv->account = NULL;
158         }
159         if (priv->error) {
160                 g_object_unref (priv->error);
161                 priv->error = NULL;
162         }
163
164         G_OBJECT_CLASS(parent_class)->finalize (obj);
165 }
166
167 ModestMailOperation*
168 modest_mail_operation_new (TnyAccount *account)
169 {
170         ModestMailOperation *mail_operation;
171         ModestMailOperationPrivate *priv;
172
173         mail_operation = 
174                 MODEST_MAIL_OPERATION(g_object_new(MODEST_TYPE_MAIL_OPERATION, NULL));
175         priv = MODEST_MAIL_OPERATION_GET_PRIVATE(mail_operation);
176
177         priv->account = g_object_ref (account);
178
179         return mail_operation;
180 }
181
182
183 void
184 modest_mail_operation_send_mail (ModestMailOperation *mail_operation,
185                                  TnyMsg* msg)
186 {
187         ModestMailOperationPrivate *priv;
188         TnyTransportAccount *transport_account;
189
190         priv = MODEST_MAIL_OPERATION_GET_PRIVATE(mail_operation);
191
192         if (!TNY_IS_TRANSPORT_ACCOUNT (priv->account)) {
193                 set_error (mail_operation,
194                            MODEST_MAIL_OPERATION_ERROR_BAD_ACCOUNT,
195                            _("Error trying to send a mail. Use a transport account"));
196         }
197
198         transport_account = TNY_TRANSPORT_ACCOUNT (priv->account);
199
200         mail_operation = modest_mail_operation_new (NULL);
201         tny_transport_account_send (transport_account, msg);
202 }
203
204 void
205 modest_mail_operation_send_new_mail (ModestMailOperation *mail_operation,
206                                      const gchar *from,
207                                      const gchar *to,
208                                      const gchar *cc,
209                                      const gchar *bcc,
210                                      const gchar *subject,
211                                      const gchar *body,
212                                      const GList *attachments_list)
213 {
214         TnyMsg *new_msg;
215         TnyHeader *header;
216         TnyTransportAccount *transport_account;
217         ModestMailOperationPrivate *priv;
218         gchar *content_type;
219
220         g_return_if_fail (mail_operation);
221
222         /* Check parametters */
223         if (to == NULL) {
224                 set_error (mail_operation,
225                            MODEST_MAIL_OPERATION_ERROR_MISSING_PARAMETER,
226                            _("Error trying to send a mail. You need to set almost one a recipient"));
227                 return;
228         }
229
230         priv = MODEST_MAIL_OPERATION_GET_PRIVATE(mail_operation);
231
232         if (!TNY_IS_TRANSPORT_ACCOUNT (priv->account)) {
233                 set_error (mail_operation,
234                            MODEST_MAIL_OPERATION_ERROR_BAD_ACCOUNT,
235                            _("Error trying to send a mail. Use a transport account"));
236                 return;
237         }
238
239         /* Create new msg */
240         transport_account = TNY_TRANSPORT_ACCOUNT (priv->account);
241
242         new_msg          = TNY_MSG (tny_camel_msg_new ());
243         header           = TNY_HEADER (tny_camel_header_new ());
244
245         /* IMPORTANT: set the header before assign values to it */
246         tny_msg_set_header (new_msg, header);
247         tny_header_set_from (TNY_HEADER (header), from);
248         tny_header_set_to (TNY_HEADER (header), to);
249         tny_header_set_cc (TNY_HEADER (header), cc);
250         tny_header_set_bcc (TNY_HEADER (header), bcc);
251         tny_header_set_subject (TNY_HEADER (header), subject);
252
253         content_type = get_content_type(body);
254
255         /* Add the body of the new mail */      
256         add_body_part (new_msg, body, (const gchar *) content_type,
257                        (attachments_list == NULL) ? FALSE : TRUE);
258
259         /* Add attachments */
260         add_attachments (new_msg, attachments_list);
261
262         /* Send mail */ 
263         tny_transport_account_send (transport_account, new_msg);
264
265         /* Clean */
266         g_object_unref (header);
267         g_object_unref (new_msg);
268         g_free(content_type);
269 }
270
271 /**
272  * modest_mail_operation_create_forward_mail:
273  * @msg: a valid #TnyMsg instance
274  * @forward_type: the type of forwarded message
275  * 
276  * creates a forwarded message from an existing one
277  * 
278  * Returns: a new #TnyMsg, or NULL in case of error
279  **/
280 TnyMsg* 
281 modest_mail_operation_create_forward_mail (TnyMsg *msg, 
282                                            ModestMailOperationForwardType forward_type)
283 {
284         TnyMsg *new_msg;
285         TnyHeader *new_header, *header;
286         TnyStream *attachment_stream;
287         gchar *new_subject, *new_body, *content_type, *quoted;
288         TnyMimePart *text_body_part = NULL;
289         GList *attachments_list;
290         TnyList *parts;
291         TnyIterator *iter;
292
293
294         /* Create new objects */
295         new_msg          = TNY_MSG (tny_camel_msg_new ());
296         new_header       = TNY_HEADER (tny_camel_header_new ());
297
298         header = tny_msg_get_header (msg);
299
300         /* Fill the header */
301         tny_msg_set_header (new_msg, new_header);
302         /* FIXME: set it from default account, current account ... */
303         tny_header_set_from (new_header, "<svsdrozo@terra.es>");
304
305         /* Change the subject */
306         new_subject = (gchar *) modest_text_utils_create_forward_subject (tny_header_get_subject(header));
307         tny_header_set_subject (new_header, (const gchar *) new_subject);
308         g_free (new_subject);
309
310         /* Get body from original msg */
311         new_body = (gchar *) modest_tny_msg_actions_find_body (msg, FALSE);
312         if (!new_body) {
313                 g_object_unref (new_msg);
314                 return NULL;
315         }
316         content_type = get_content_type(new_body);
317
318         /* Create the list of attachments */
319         parts = TNY_LIST (tny_simple_list_new());
320         tny_msg_get_parts (msg, parts);
321         iter = tny_list_create_iterator (parts);
322         attachments_list = NULL;
323
324         while (!tny_iterator_is_done(iter)) {
325                 TnyMimePart *part;
326
327                 part = TNY_MIME_PART (tny_iterator_get_current (iter));
328                 if (tny_mime_part_is_attachment (part))
329                         attachments_list = g_list_prepend (attachments_list, part);
330
331                 tny_iterator_next (iter);
332         }
333
334         /* Add attachments */
335         add_attachments (new_msg, attachments_list);
336
337         switch (forward_type) {
338                 TnyMimePart *attachment_part;
339                 gchar *inlined_text;
340
341         case MODEST_MAIL_OPERATION_FORWARD_TYPE_INLINE:
342                 /* Prepend "Original message" text */
343                 inlined_text = (gchar *) 
344                         modest_text_utils_create_inlined_text (tny_header_get_from (header),
345                                                                tny_header_get_date_sent (header),
346                                                                tny_header_get_to (header),
347                                                                tny_header_get_subject (header),
348                                                                (const gchar*) new_body);
349                 g_free (new_body);
350                 new_body = inlined_text;
351
352                 /* Add body part */
353                 add_body_part (new_msg, new_body, 
354                                (const gchar *) content_type, 
355                                (tny_list_get_length (parts) > 0) ? TRUE : FALSE);
356
357                 break;
358         case MODEST_MAIL_OPERATION_FORWARD_TYPE_ATTACHMENT:
359                 attachment_part = add_body_part (new_msg, new_body, 
360                                                  (const gchar *) content_type, TRUE);
361
362                 /* Set the subject as the name of the attachment */
363                 tny_mime_part_set_filename (attachment_part, tny_header_get_subject (header));
364                 
365                 break;
366         }
367
368         /* Clean */
369         g_object_unref (parts);
370         if (attachments_list) g_list_free (attachments_list);
371         if (text_body_part) g_object_unref (text_body_part);
372         g_free (content_type);
373         g_free (new_body);
374
375         return new_msg;
376 }
377
378 /**
379  * modest_mail_operation_create_reply_mail:
380  * @msg: a valid #TnyMsg instance
381  * @reply_type: the format of the new message
382  * @reply_mode: the mode of reply, to the sender only, to a mail list or to all
383  * 
384  * creates a new message to reply to an existing one
385  * 
386  * Returns: Returns: a new #TnyMsg, or NULL in case of error
387  **/
388 TnyMsg* 
389 modest_mail_operation_create_reply_mail (TnyMsg *msg, 
390                                          ModestMailOperationReplyType reply_type,
391                                          ModestMailOperationReplyMode reply_mode)
392 {
393         TnyMsg *new_msg;
394         TnyHeader *new_header, *header;
395         TnyStream *attachment_stream;
396         gchar *new_subject, *new_body, *content_type, *quoted;
397         TnyList *parts;
398         TnyMimePart *text_body_part;
399         gchar *my_email = NULL;
400
401         /* Create new objects */
402         new_msg          = TNY_MSG (tny_camel_msg_new ());
403         new_header       = TNY_HEADER (tny_camel_header_new ());
404
405         header = tny_msg_get_header (msg);
406
407         /* Fill the header */
408         tny_msg_set_header (new_msg, new_header);
409         tny_header_set_to (new_header, tny_header_get_from (header));
410         /* TODO: set "From:" from my current account */
411 /*      current_account = modest_account_mgr_get_current_account (account_mgr); */
412 /*              my_email = modest_account_mgr_get_string (account_mgr, */
413 /*                                                     current_account, */
414 /*                                                     MODEST_ACCOUNT_EMAIL, */
415 /*                                                     FALSE, */
416 /*                                                     NULL); */
417 /*      tny_header_set_from (new_header, email); */
418         my_email = g_strdup ("svsdrozo@terra.es");
419
420         switch (reply_mode) {
421                 gchar *new_cc = NULL;
422                 const gchar *cc = NULL, *bcc = NULL;
423                 GString *tmp = NULL;
424
425         case MODEST_MAIL_OPERATION_REPLY_MODE_SENDER:
426                 /* Do not fill neither cc nor bcc */
427                 break;
428         case MODEST_MAIL_OPERATION_REPLY_MODE_LIST:
429                 /* TODO */
430                 break;
431         case MODEST_MAIL_OPERATION_REPLY_MODE_ALL:
432                 /* Concatenate to, cc and bcc */
433                 cc = tny_header_get_cc (header);
434                 bcc = tny_header_get_bcc (header);
435
436                 tmp = g_string_new (tny_header_get_to (header));
437                 if (cc)  g_string_append_printf (tmp, ",%s",cc);
438                 if (bcc) g_string_append_printf (tmp, ",%s",bcc);
439
440                 /* Remove my own address from the cc list */
441                 new_cc = (gchar *) 
442                         modest_text_utils_remove_mail_from_mail_list ((const gchar *) tmp->str, 
443                                                                       (const gchar *) my_email);
444                 /* FIXME: remove also the mails from the new To: */
445                 tny_header_set_cc (new_header, new_cc);
446
447                 /* Clean */
448                 g_string_free (tmp, TRUE);
449                 g_free (new_cc);
450                 break;
451         }
452         g_free (my_email);
453
454         /* Change the subject */
455         new_subject = (gchar*) modest_text_utils_create_reply_subject (tny_header_get_subject(header));
456         tny_header_set_subject (new_header, (const gchar *) new_subject);
457         g_free (new_subject);
458
459         /* Get body from original msg */
460         new_body = (gchar*) modest_tny_msg_actions_find_body (msg, FALSE);
461         if (!new_body) {
462                 g_object_unref (new_msg);
463                 return NULL;
464         }
465         content_type = get_content_type(new_body);
466
467         switch (reply_type) {
468                 gchar *cited_text;
469
470         case MODEST_MAIL_OPERATION_REPLY_TYPE_CITE:
471                 /* Prepend "Original message" text */
472                 cited_text = (gchar *) modest_text_utils_create_cited_text (tny_header_get_from (header),
473                                                                             tny_header_get_date_sent (header),
474                                                                             (const gchar*) new_body);
475                 g_free (new_body);
476                 new_body = cited_text;
477                 break;
478         case MODEST_MAIL_OPERATION_REPLY_TYPE_QUOTE:
479                 /* FIXME: replace 80 with a value from ModestConf */
480                 quoted = (gchar*) modest_text_utils_quote (new_body, 
481                                                            tny_header_get_from (header),
482                                                            tny_header_get_date_sent (header),
483                                                            80);
484                 g_free (new_body);
485                 new_body = quoted;
486                 break;
487         }
488         /* Add body part */
489         text_body_part = add_body_part (new_msg, new_body, 
490                                         (const gchar *) content_type, TRUE);
491
492         /* Clean */
493         g_object_unref (G_OBJECT(text_body_part));
494         g_free (content_type);
495         g_free (new_body);
496
497         return new_msg;
498 }
499
500 void
501 modest_mail_operation_update_account (ModestMailOperation *mail_operation)
502 {
503         TnyStoreAccount *storage_account;
504         ModestMailOperationPrivate *priv;
505         TnyList *folders;
506         TnyIterator *ifolders;
507         TnyFolder *cur_folder;
508         TnyFolderStoreQuery *query;
509
510         g_return_if_fail (mail_operation);
511         g_return_if_fail (MODEST_IS_MAIL_OPERATION (mail_operation));
512
513         priv = MODEST_MAIL_OPERATION_GET_PRIVATE(mail_operation);
514
515         /* Check that it is a store account */
516         if (!TNY_IS_STORE_ACCOUNT (priv->account)) {
517                 set_error (mail_operation,
518                            MODEST_MAIL_OPERATION_ERROR_BAD_ACCOUNT,
519                            _("Error trying to update an account. Use a store account"));
520                 return;
521         }
522         storage_account = TNY_STORE_ACCOUNT (priv->account);
523
524         /* Get subscribed folders */
525         folders = TNY_LIST (tny_simple_list_new ());
526         query = tny_folder_store_query_new ();
527         tny_folder_store_query_add_item (query, NULL, TNY_FOLDER_STORE_QUERY_OPTION_SUBSCRIBED);
528         tny_folder_store_get_folders (TNY_FOLDER_STORE (storage_account),
529                                       folders, NULL);
530         g_object_unref (query);
531         
532         ifolders = tny_list_create_iterator (folders);
533
534         /* Async refresh folders */     
535         for (tny_iterator_first (ifolders); 
536              !tny_iterator_is_done (ifolders); 
537              tny_iterator_next (ifolders)) {
538                 
539                 cur_folder = TNY_FOLDER (tny_iterator_get_current (ifolders));
540                 tny_folder_refresh_async (cur_folder, folder_refresh_cb,
541                                           status_update_cb, mail_operation);
542         }
543         
544         g_object_unref (ifolders);
545 }
546
547 ModestMailOperationStatus
548 modest_mail_operation_get_status (ModestMailOperation *mail_operation)
549 {
550         ModestMailOperationPrivate *priv;
551
552 /*      g_return_val_if_fail (mail_operation, MODEST_MAIL_OPERATION_STATUS_INVALID); */
553 /*      g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (mail_operation),  */
554 /*                            MODEST_MAIL_OPERATION_STATUS_INVALID); */
555
556         priv = MODEST_MAIL_OPERATION_GET_PRIVATE (mail_operation);
557         return priv->status;
558 }
559
560 const GError *
561 modest_mail_operation_get_error (ModestMailOperation *mail_operation)
562 {
563         ModestMailOperationPrivate *priv;
564
565 /*      g_return_val_if_fail (mail_operation, NULL); */
566 /*      g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (mail_operation), NULL); */
567
568         priv = MODEST_MAIL_OPERATION_GET_PRIVATE (mail_operation);
569         return priv->error;
570 }
571
572 void 
573 modest_mail_operation_cancel (ModestMailOperation *mail_operation)
574 {
575         /* TODO */
576 }
577
578 static gboolean
579 is_ascii(const gchar *s)
580 {
581         while (s[0]) {
582                 if (s[0] & 128 || s[0] < 32)
583                         return FALSE;
584                 s++;
585         }
586         return TRUE;
587 }
588
589 static char *
590 get_content_type(const gchar *s)
591 {
592         GString *type;
593         
594         type = g_string_new("text/plain");
595         if (!is_ascii(s)) {
596                 if (g_utf8_validate(s, -1, NULL)) {
597                         g_string_append(type, "; charset=\"utf-8\"");
598                 } else {
599                         /* it should be impossible to reach this, but better safe than sorry */
600                         g_warning("invalid utf8 in message");
601                         g_string_append(type, "; charset=\"latin1\"");
602                 }
603         }
604         return g_string_free(type, FALSE);
605 }
606
607 static GQuark 
608 modest_error_quark (void)
609 {
610   static GQuark err_q = 0;
611
612   if (err_q == 0)
613     err_q = g_quark_from_static_string ("modest-error-quark");
614
615   return err_q;
616 }
617
618
619 static void 
620 set_error (ModestMailOperation *mail_operation, 
621            ModestMailOperationErrorCode error_code,
622            const gchar *fmt, ...)
623 {
624         ModestMailOperationPrivate *priv;
625         GError* error;
626         va_list args;
627         gchar* orig;
628
629         priv = MODEST_MAIL_OPERATION_GET_PRIVATE(mail_operation);
630
631         va_start (args, fmt);
632
633         orig = g_strdup_vprintf(fmt, args);
634         error = g_error_new (MODEST_ERROR, error_code, orig);
635
636         va_end (args);
637
638         if (priv->error)
639                 g_object_unref (priv->error);
640
641         priv->error = error;
642         priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
643 }
644
645 static void
646 status_update_cb (TnyFolder *folder, const gchar *what, gint status, gpointer user_data) 
647 {
648         /* TODO: update main window progress bar */
649 }
650
651 static void
652 folder_refresh_cb (TnyFolder *folder, gboolean cancelled, gpointer user_data) 
653 {
654         if (cancelled) {
655                 ModestMailOperation *mail_operation;
656                 ModestMailOperationPrivate *priv;
657
658                 mail_operation = MODEST_MAIL_OPERATION (user_data);
659                 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(mail_operation);
660
661                 priv->status =  MODEST_MAIL_OPERATION_STATUS_CANCELLED;
662         }
663 }
664
665 static void
666 add_attachments (TnyMsg *msg, const GList *attachments_list)
667 {
668         GList *pos;
669         TnyMimePart *attachment_part, *old_attachment;
670         const gchar *attachment_content_type;
671         const gchar *attachment_filename;
672         TnyStream *attachment_stream;
673
674         for (pos = (GList *)attachments_list; pos; pos = pos->next) {
675
676                 old_attachment = pos->data;
677                 attachment_filename = tny_mime_part_get_filename (old_attachment);
678                 attachment_stream = tny_mime_part_get_stream (old_attachment);
679                 attachment_part = TNY_MIME_PART (tny_camel_mime_part_new (camel_mime_part_new()));
680                 
681                 attachment_content_type = tny_mime_part_get_content_type (old_attachment);
682                                  
683                 tny_mime_part_construct_from_stream (attachment_part,
684                                                      attachment_stream,
685                                                      attachment_content_type);
686                 tny_stream_reset (attachment_stream);
687                 
688                 tny_mime_part_set_filename (attachment_part, attachment_filename);
689                 
690                 tny_msg_add_part (msg, attachment_part);
691                 g_object_unref(G_OBJECT(attachment_part));
692         }
693 }
694
695 static TnyMimePart *
696 add_body_part (TnyMsg *msg, 
697                const gchar *body,
698                const gchar *content_type,
699                gboolean has_attachments)
700 {
701         TnyMimePart *text_body_part = NULL;
702         TnyStream *text_body_stream;
703
704         /* Create the stream */
705         text_body_stream = TNY_STREAM (tny_camel_stream_new
706                                        (camel_stream_mem_new_with_buffer
707                                         (body, strlen(body))));
708
709         /* Create body part if needed */
710         if (has_attachments)
711                 text_body_part = 
712                         TNY_MIME_PART (tny_camel_mime_part_new (camel_mime_part_new()));
713         else
714                 text_body_part = TNY_MIME_PART(msg);
715
716         /* Construct MIME part */
717         tny_stream_reset (text_body_stream);
718         tny_mime_part_construct_from_stream (text_body_part,
719                                              text_body_stream,
720                                              content_type);
721         tny_stream_reset (text_body_stream);
722
723         /* Add part if needed */
724         if (has_attachments) {
725                 tny_msg_add_part (msg, text_body_part);
726                 g_object_unref (G_OBJECT(text_body_part));
727         }
728
729         /* Clean */
730         g_object_unref (text_body_stream);
731
732         return text_body_part;
733 }