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 <glib/gi18n.h>
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);
45 #define MODEST_ERROR modest_error_quark ()
47 typedef enum _ModestMailOperationErrorCode ModestMailOperationErrorCode;
48 enum _ModestMailOperationErrorCode {
49 MODEST_MAIL_OPERATION_ERROR_BAD_ACCOUNT,
50 MODEST_MAIL_OPERATION_ERROR_MISSING_PARAMETER,
52 MODEST_MAIL_OPERATION_NUM_ERROR_CODES
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,
70 typedef struct _ModestMailOperationPrivate ModestMailOperationPrivate;
71 struct _ModestMailOperationPrivate {
73 ModestMailOperationStatus status;
76 #define MODEST_MAIL_OPERATION_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
77 MODEST_TYPE_MAIL_OPERATION, \
78 ModestMailOperationPrivate))
80 /* some utility functions */
81 static char * get_content_type(const gchar *s);
82 static gboolean is_ascii(const gchar *s);
85 static GObjectClass *parent_class = NULL;
87 /* uncomment the following if you have defined any signals */
88 /* static guint signals[LAST_SIGNAL] = {0}; */
91 modest_mail_operation_get_type (void)
93 static GType my_type = 0;
95 static const GTypeInfo my_info = {
96 sizeof(ModestMailOperationClass),
98 NULL, /* base finalize */
99 (GClassInitFunc) modest_mail_operation_class_init,
100 NULL, /* class finalize */
101 NULL, /* class data */
102 sizeof(ModestMailOperation),
104 (GInstanceInitFunc) modest_mail_operation_init,
107 my_type = g_type_register_static (G_TYPE_OBJECT,
108 "ModestMailOperation",
115 modest_mail_operation_class_init (ModestMailOperationClass *klass)
117 GObjectClass *gobject_class;
118 gobject_class = (GObjectClass*) klass;
120 parent_class = g_type_class_peek_parent (klass);
121 gobject_class->finalize = modest_mail_operation_finalize;
123 g_type_class_add_private (gobject_class, sizeof(ModestMailOperationPrivate));
125 /* signal definitions go here, e.g.: */
126 /* signals[MY_SIGNAL_1] = */
127 /* g_signal_new ("my_signal_1",....); */
128 /* signals[MY_SIGNAL_2] = */
129 /* g_signal_new ("my_signal_2",....); */
134 modest_mail_operation_init (ModestMailOperation *obj)
136 ModestMailOperationPrivate *priv;
138 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
140 priv->account = NULL;
141 priv->status = MODEST_MAIL_OPERATION_STATUS_INVALID;
146 modest_mail_operation_finalize (GObject *obj)
148 ModestMailOperationPrivate *priv;
150 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(obj);
153 g_object_unref (priv->account);
154 priv->account = NULL;
157 g_object_unref (priv->error);
161 G_OBJECT_CLASS(parent_class)->finalize (obj);
165 modest_mail_operation_new (TnyAccount *account)
167 ModestMailOperation *mail_operation;
168 ModestMailOperationPrivate *priv;
171 MODEST_MAIL_OPERATION(g_object_new(MODEST_TYPE_MAIL_OPERATION, NULL));
172 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(mail_operation);
174 priv->account = g_object_ref (account);
176 return mail_operation;
181 modest_mail_operation_send_mail (ModestMailOperation *mail_operation,
184 ModestMailOperationPrivate *priv;
185 TnyTransportAccount *transport_account;
187 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(mail_operation);
189 if (!TNY_IS_TRANSPORT_ACCOUNT (priv->account)) {
190 set_error (mail_operation,
191 MODEST_MAIL_OPERATION_ERROR_BAD_ACCOUNT,
192 _("Error trying to send a mail. Use a transport account"));
195 transport_account = TNY_TRANSPORT_ACCOUNT (priv->account);
197 mail_operation = modest_mail_operation_new (NULL);
198 tny_transport_account_send (transport_account, msg);
202 modest_mail_operation_send_new_mail (ModestMailOperation *mail_operation,
207 const gchar *subject,
209 const GList *attachments_list)
213 TnyStream *text_body_stream, *attachment_stream;
214 TnyTransportAccount *transport_account;
215 ModestMailOperationPrivate *priv;
216 ModestTnyAttachment *attachment;
219 const gchar *attachment_content_type;
220 const gchar *attachment_filename;
222 g_return_if_fail (mail_operation);
225 set_error (mail_operation,
226 MODEST_MAIL_OPERATION_ERROR_MISSING_PARAMETER,
227 _("Error trying to send a mail. You need to set almost one a recipient"));
231 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(mail_operation);
233 if (!TNY_IS_TRANSPORT_ACCOUNT (priv->account)) {
234 set_error (mail_operation,
235 MODEST_MAIL_OPERATION_ERROR_BAD_ACCOUNT,
236 _("Error trying to send a mail. Use a transport account"));
240 transport_account = TNY_TRANSPORT_ACCOUNT (priv->account);
242 new_msg = TNY_MSG (tny_camel_msg_new ());
243 headers = TNY_HEADER (tny_camel_header_new ());
244 text_body_stream = TNY_STREAM (tny_camel_stream_new
245 (camel_stream_mem_new_with_buffer
246 (body, strlen(body))));
248 /* IMPORTANT: set the header before assign values to it */
249 tny_msg_set_header (new_msg, headers);
250 tny_header_set_from (TNY_HEADER (headers), from);
251 tny_header_set_to (TNY_HEADER (headers), to);
252 tny_header_set_cc (TNY_HEADER (headers), cc);
253 tny_header_set_bcc (TNY_HEADER (headers), bcc);
254 tny_header_set_subject (TNY_HEADER (headers), subject);
256 content_type = get_content_type(body);
258 if (attachments_list == NULL) {
259 tny_stream_reset (text_body_stream);
260 tny_mime_part_construct_from_stream (TNY_MIME_PART(new_msg),
261 text_body_stream, content_type);
262 tny_stream_reset (text_body_stream);
264 TnyMimePart *text_body_part;
267 TNY_MIME_PART (tny_camel_mime_part_new (camel_mime_part_new()));
268 tny_stream_reset (text_body_stream);
269 tny_mime_part_construct_from_stream (text_body_part,
272 tny_stream_reset (text_body_stream);
273 tny_msg_add_part (new_msg, text_body_part);
274 g_object_unref (G_OBJECT(text_body_part));
277 for (pos = (GList *)attachments_list;
280 TnyMimePart *attachment_part;
282 attachment = pos->data;
283 attachment_filename = modest_tny_attachment_get_name (attachment);
284 attachment_stream = modest_tny_attachment_get_stream (attachment);
285 attachment_part = TNY_MIME_PART (tny_camel_mime_part_new (camel_mime_part_new()));
287 attachment_content_type = modest_tny_attachment_get_mime_type (attachment);
289 tny_mime_part_construct_from_stream (attachment_part,
291 attachment_content_type);
292 tny_stream_reset (attachment_stream);
294 tny_mime_part_set_filename (attachment_part, attachment_filename);
296 tny_msg_add_part (new_msg, attachment_part);
297 g_object_unref(G_OBJECT(attachment_part));
300 tny_transport_account_send (transport_account, new_msg);
303 g_object_unref (G_OBJECT(text_body_stream));
304 g_object_unref (G_OBJECT(headers));
305 g_object_unref (G_OBJECT(new_msg));
306 g_free(content_type);
310 * modest_mail_operation_create_forward_mail:
311 * @msg: a valid #TnyMsg instance
312 * @forward_type: the type of forwarded message
314 * creates a forwarded message from an existing one
316 * Returns: a new #TnyMsg, or NULL in case of error
319 modest_mail_operation_create_forward_mail (TnyMsg *msg,
320 ModestMailOperationForwardType forward_type)
323 TnyHeader *new_header, *header;
324 TnyStream *attachment_stream;
325 gchar *new_subject, *new_body, *content_type, *quoted;
327 TnyMimePart *text_body_part = NULL;
328 TnyStream *text_body_stream = NULL;
330 /* Create new objects */
331 new_msg = TNY_MSG (tny_camel_msg_new ());
332 new_header = TNY_HEADER (tny_camel_header_new ());
334 header = tny_msg_get_header (msg);
336 /* Fill the header */
337 tny_msg_set_header (new_msg, new_header);
338 /* FIXME: set it from default account, current account ... */
339 tny_header_set_from (new_header, "<me@home.org>");
341 /* Change the subject */
342 new_subject = (gchar *) modest_text_utils_create_forward_subject (tny_header_get_subject(header));
343 tny_header_set_subject (new_header, (const gchar *) new_subject);
344 g_free (new_subject);
346 /* Get body from original msg */
347 new_body = (gchar *) modest_tny_msg_actions_find_body (msg, FALSE);
349 g_object_unref (new_msg);
352 content_type = get_content_type(new_body);
354 switch (forward_type) {
355 TnyMimePart *attachment_part;
358 case MODEST_MAIL_OPERATION_FORWARD_TYPE_INLINE:
359 /* Prepend "Original message" text */
360 inlined_text = (gchar *)
361 modest_text_utils_create_inlined_text (tny_header_get_from (header),
362 tny_header_get_date_sent (header),
363 tny_header_get_to (header),
364 tny_header_get_subject (header),
365 (const gchar*) new_body);
367 new_body = inlined_text;
369 /* Create the body */
370 text_body_stream = TNY_STREAM (tny_camel_stream_new
371 (camel_stream_mem_new_with_buffer
372 (new_body, strlen(new_body))));
375 TNY_MIME_PART (tny_camel_mime_part_new (camel_mime_part_new()));
376 tny_stream_reset (text_body_stream);
377 tny_mime_part_construct_from_stream (text_body_part,
380 tny_stream_reset (text_body_stream);
382 /* Add body part to msg */
383 tny_msg_add_part (new_msg, text_body_part);
385 case MODEST_MAIL_OPERATION_FORWARD_TYPE_ATTACHMENT:
386 attachment_part = TNY_MIME_PART (tny_camel_mime_part_new (camel_mime_part_new()));
388 text_body_stream = TNY_STREAM (tny_camel_stream_new
389 (camel_stream_mem_new_with_buffer
390 (new_body, strlen(new_body))));
392 tny_mime_part_construct_from_stream (attachment_part,
395 tny_stream_reset (attachment_stream);
397 /* Set the subject as the name of the attachment */
398 tny_mime_part_set_filename (attachment_part, tny_header_get_subject (header));
400 tny_msg_add_part (new_msg, attachment_part);
401 g_object_unref (G_OBJECT (attachment_part));
404 /* TODO: attachments? */
407 if (text_body_part) g_object_unref (G_OBJECT(text_body_part));
408 if (text_body_stream) g_object_unref (G_OBJECT(text_body_stream));
409 g_free (content_type);
416 * modest_mail_operation_create_reply_mail:
417 * @msg: a valid #TnyMsg instance
418 * @reply_type: the format of the new message
419 * @reply_mode: the mode of reply, to the sender only, to a mail list or to all
421 * creates a new message to reply to an existing one
423 * Returns: Returns: a new #TnyMsg, or NULL in case of error
426 modest_mail_operation_create_reply_mail (TnyMsg *msg,
427 ModestMailOperationReplyType reply_type,
428 ModestMailOperationReplyMode reply_mode)
431 TnyHeader *new_header, *header;
432 TnyStream *attachment_stream;
433 gchar *new_subject, *new_body, *content_type, *quoted;
435 TnyMimePart *text_body_part;
436 TnyStream *text_body_stream;
437 gchar *my_email = NULL;
439 /* Create new objects */
440 new_msg = TNY_MSG (tny_camel_msg_new ());
441 new_header = TNY_HEADER (tny_camel_header_new ());
443 header = tny_msg_get_header (msg);
445 /* Fill the header */
446 tny_msg_set_header (new_msg, new_header);
447 tny_header_set_to (new_header, tny_header_get_from (header));
448 /* TODO: set "From:" from my current account */
449 /* current_account = modest_account_mgr_get_current_account (account_mgr); */
450 /* my_email = modest_account_mgr_get_string (account_mgr, */
451 /* current_account, */
452 /* MODEST_ACCOUNT_EMAIL, */
455 /* tny_header_set_from (new_header, email); */
456 my_email = g_strdup ("svillarsenin@terra.es");
458 switch (reply_mode) {
459 gchar *new_cc = NULL;
460 const gchar *cc = NULL, *bcc = NULL;
463 case MODEST_MAIL_OPERATION_REPLY_MODE_SENDER:
464 /* Do not fill neither cc nor bcc */
466 case MODEST_MAIL_OPERATION_REPLY_MODE_LIST:
469 case MODEST_MAIL_OPERATION_REPLY_MODE_ALL:
470 /* Concatenate to, cc and bcc */
471 cc = tny_header_get_cc (header);
472 bcc = tny_header_get_bcc (header);
474 tmp = g_string_new (tny_header_get_to (header));
475 if (cc) g_string_append_printf (tmp, ",%s",cc);
476 if (bcc) g_string_append_printf (tmp, ",%s",bcc);
478 /* Remove my own address from the cc list */
479 new_cc = modest_text_utils_remove_mail_from_mail_list ((const gchar *) tmp->str,
480 (const gchar *) my_email);
481 /* FIXME: remove also the mails from the new To: */
482 tny_header_set_cc (new_header, new_cc);
485 g_string_free (tmp, TRUE);
491 /* Change the subject */
492 new_subject = (gchar*) modest_text_utils_create_reply_subject (tny_header_get_subject(header));
493 tny_header_set_subject (new_header, (const gchar *) new_subject);
494 g_free (new_subject);
496 /* Get body from original msg */
497 new_body = (gchar*) modest_tny_msg_actions_find_body (msg, FALSE);
499 g_object_unref (new_msg);
502 content_type = get_content_type(new_body);
504 switch (reply_type) {
507 case MODEST_MAIL_OPERATION_REPLY_TYPE_CITE:
508 /* Prepend "Original message" text */
509 cited_text = (gchar *) modest_text_utils_create_cited_text (tny_header_get_from (header),
510 tny_header_get_date_sent (header),
511 (const gchar*) new_body);
513 new_body = cited_text;
515 case MODEST_MAIL_OPERATION_REPLY_TYPE_QUOTE:
516 /* FIXME: replace 80 with a value from ModestConf */
517 quoted = (gchar*) modest_text_utils_quote (new_body,
518 tny_header_get_from (header),
519 tny_header_get_date_sent (header),
525 /* Create the MIME part for the body */
526 text_body_stream = TNY_STREAM (tny_camel_stream_new
527 (camel_stream_mem_new_with_buffer
528 (new_body, strlen(new_body))));
531 TNY_MIME_PART (tny_camel_mime_part_new (camel_mime_part_new()));
532 tny_stream_reset (text_body_stream);
533 tny_mime_part_construct_from_stream (text_body_part,
536 tny_stream_reset (text_body_stream);
538 /* Add body part to msg */
539 tny_msg_add_part (new_msg, text_body_part);
541 /* TODO: attachments? */
544 g_object_unref (G_OBJECT(text_body_part));
545 g_object_unref (G_OBJECT(text_body_stream));
546 g_free (content_type);
553 modest_mail_operation_update_account (ModestMailOperation *mail_operation)
555 TnyStoreAccount *storage_account;
556 ModestMailOperationPrivate *priv;
558 TnyIterator *ifolders;
559 TnyFolder *cur_folder;
560 TnyFolderStoreQuery *query;
562 g_return_if_fail (mail_operation);
563 g_return_if_fail (MODEST_IS_MAIL_OPERATION (mail_operation));
565 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(mail_operation);
567 /* Check that it is a store account */
568 if (!TNY_IS_STORE_ACCOUNT (priv->account)) {
569 set_error (mail_operation,
570 MODEST_MAIL_OPERATION_ERROR_BAD_ACCOUNT,
571 _("Error trying to update an account. Use a store account"));
574 storage_account = TNY_STORE_ACCOUNT (priv->account);
576 /* Get subscribed folders */
577 folders = TNY_LIST (tny_simple_list_new ());
578 query = tny_folder_store_query_new ();
579 tny_folder_store_query_add_item (query, NULL, TNY_FOLDER_STORE_QUERY_OPTION_SUBSCRIBED);
580 tny_folder_store_get_folders (TNY_FOLDER_STORE (storage_account),
582 g_object_unref (query);
584 ifolders = tny_list_create_iterator (folders);
586 for (tny_iterator_first (ifolders);
587 !tny_iterator_is_done (ifolders);
588 tny_iterator_next (ifolders)) {
590 cur_folder = TNY_FOLDER (tny_iterator_get_current (ifolders));
591 tny_folder_refresh_async (cur_folder, folder_refresh_cb,
592 status_update_cb, mail_operation);
595 g_object_unref (ifolders);
598 ModestMailOperationStatus
599 modest_mail_operation_get_status (ModestMailOperation *mail_operation)
601 ModestMailOperationPrivate *priv;
603 /* g_return_val_if_fail (mail_operation, MODEST_MAIL_OPERATION_STATUS_INVALID); */
604 /* g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (mail_operation), */
605 /* MODEST_MAIL_OPERATION_STATUS_INVALID); */
607 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (mail_operation);
612 modest_mail_operation_get_error (ModestMailOperation *mail_operation)
614 ModestMailOperationPrivate *priv;
616 /* g_return_val_if_fail (mail_operation, NULL); */
617 /* g_return_val_if_fail (MODEST_IS_MAIL_OPERATION (mail_operation), NULL); */
619 priv = MODEST_MAIL_OPERATION_GET_PRIVATE (mail_operation);
624 modest_mail_operation_cancel (ModestMailOperation *mail_operation)
630 is_ascii(const gchar *s)
633 if (s[0] & 128 || s[0] < 32)
641 get_content_type(const gchar *s)
645 type = g_string_new("text/plain");
647 if (g_utf8_validate(s, -1, NULL)) {
648 g_string_append(type, "; charset=\"utf-8\"");
650 /* it should be impossible to reach this, but better safe than sorry */
651 g_warning("invalid utf8 in message");
652 g_string_append(type, "; charset=\"latin1\"");
655 return g_string_free(type, FALSE);
659 modest_error_quark (void)
661 static GQuark err_q = 0;
664 err_q = g_quark_from_static_string ("modest-error-quark");
671 set_error (ModestMailOperation *mail_operation,
672 ModestMailOperationErrorCode error_code,
673 const gchar *fmt, ...)
675 ModestMailOperationPrivate *priv;
680 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(mail_operation);
682 va_start (args, fmt);
684 orig = g_strdup_vprintf(fmt, args);
685 error = g_error_new (MODEST_ERROR, error_code, orig);
690 g_object_unref (priv->error);
693 priv->status = MODEST_MAIL_OPERATION_STATUS_FAILED;
697 status_update_cb (TnyFolder *folder, const gchar *what, gint status, gpointer user_data)
699 /* TODO: update main window progress bar */
703 folder_refresh_cb (TnyFolder *folder, gboolean cancelled, gpointer user_data)
706 ModestMailOperation *mail_operation;
707 ModestMailOperationPrivate *priv;
709 mail_operation = MODEST_MAIL_OPERATION (user_data);
710 priv = MODEST_MAIL_OPERATION_GET_PRIVATE(mail_operation);
712 priv->status = MODEST_MAIL_OPERATION_STATUS_CANCELLED;