* when sending, messages with and without attachments are now handled differently...
[modest] / src / modest-tny-transport-actions.c
1 /* modest-tny-transport-actions.c */
2
3 /* insert (c)/licensing information) */
4
5 #include <tny-msg.h>
6 #include <tny-msg-iface.h>                      
7 #include <tny-msg-mime-part.h>
8 #include <tny-msg-mime-part-iface.h>            
9 #include <tny-stream-iface.h>
10 #include <tny-msg-header.h>
11 #include <tny-msg-header-iface.h>
12 #include <tny-account-iface.h>  
13 #include <tny-account-store-iface.h>
14 #include <tny-transport-account-iface.h>        
15 #include <tny-transport-account.h>
16 #include <tny-stream-camel.h>
17 #include <tny-fs-stream.h>
18 #include <string.h>
19 #include <camel/camel-folder.h>
20 #include <camel/camel.h>
21 #include <camel/camel-folder-summary.h>
22
23
24
25 #include "modest-tny-transport-actions.h"
26 /* include other impl specific header files */
27
28 /* 'private'/'protected' functions */
29 static void                              modest_tny_transport_actions_class_init   (ModestTnyTransportActionsClass *klass);
30 static void                              modest_tny_transport_actions_init         (ModestTnyTransportActions *obj);
31 static void                              modest_tny_transport_actions_finalize     (GObject *obj);
32 static gboolean                          is_ascii                                  (const gchar *s);
33 static char *                            get_content_type                          (const gchar *s);
34
35 /* list my signals */
36 enum {
37         /* MY_SIGNAL_1, */
38         /* MY_SIGNAL_2, */
39         LAST_SIGNAL
40 };
41
42 typedef struct _ModestTnyTransportActionsPrivate ModestTnyTransportActionsPrivate;
43 struct _ModestTnyTransportActionsPrivate {
44         /* my private members go here, eg. */
45         /* gboolean frobnicate_mode; */
46 };
47 #define MODEST_TNY_TRANSPORT_ACTIONS_GET_PRIVATE(o)      (G_TYPE_INSTANCE_GET_PRIVATE((o), \
48                                                           MODEST_TYPE_TNY_TRANSPORT_ACTIONS, \
49                                                           ModestTnyTransportActionsPrivate))
50 /* globals */
51 static GObjectClass *parent_class = NULL;
52
53 /* uncomment the following if you have defined any signals */
54 /* static guint signals[LAST_SIGNAL] = {0}; */
55
56 GType
57 modest_tny_transport_actions_get_type (void)
58 {
59         static GType my_type = 0;
60         if (!my_type) {
61                 static const GTypeInfo my_info = {
62                         sizeof(ModestTnyTransportActionsClass),
63                         NULL,           /* base init */
64                         NULL,           /* base finalize */
65                         (GClassInitFunc) modest_tny_transport_actions_class_init,
66                         NULL,           /* class finalize */
67                         NULL,           /* class data */
68                         sizeof(ModestTnyTransportActions),
69                         1,              /* n_preallocs */
70                         (GInstanceInitFunc) modest_tny_transport_actions_init,
71                 };
72                 my_type = g_type_register_static (G_TYPE_OBJECT,
73                                                   "ModestTnyTransportActions",
74                                                   &my_info, 0);
75         }
76         return my_type;
77 }
78
79 static void
80 modest_tny_transport_actions_class_init (ModestTnyTransportActionsClass *klass)
81 {
82         GObjectClass *gobject_class;
83         gobject_class = (GObjectClass*) klass;
84
85         parent_class            = g_type_class_peek_parent (klass);
86         gobject_class->finalize = modest_tny_transport_actions_finalize;
87
88         g_type_class_add_private (gobject_class, sizeof(ModestTnyTransportActionsPrivate));
89
90         /* signal definitions go here, e.g.: */
91 /*      signals[MY_SIGNAL_1] = */
92 /*              g_signal_new ("my_signal_1",....); */
93 /*      signals[MY_SIGNAL_2] = */
94 /*              g_signal_new ("my_signal_2",....); */
95 /*      etc. */
96 }
97
98 static void
99 modest_tny_transport_actions_init (ModestTnyTransportActions *obj)
100 {
101 /* uncomment the following if you init any of the private data */
102 /*      ModestTnyTransportActionsPrivate *priv = MODEST_TNY_TRANSPORT_ACTIONS_GET_PRIVATE(obj); */
103
104 /*      initialize this object, eg.: */
105 /*      priv->frobnicate_mode = FALSE; */
106 }
107
108 static void
109 modest_tny_transport_actions_finalize (GObject *obj)
110 {
111 /*      free/unref instance resources here */
112 }
113
114 GObject*
115 modest_tny_transport_actions_new (void)
116 {
117         return G_OBJECT(g_object_new(MODEST_TYPE_TNY_TRANSPORT_ACTIONS, NULL));
118 }
119
120 static gboolean
121 is_ascii(const gchar *s)
122 {
123         while (s[0]) {
124                 if (s[0] & 128 || s[0] < 32)
125                         return FALSE;
126                 s++;
127         }
128         return TRUE;
129 }
130
131 static char *
132 get_content_type(const gchar *s)
133 {
134         GString *type;
135         
136         type = g_string_new("text/plain");
137         if (!is_ascii(s)) {
138                 if (g_utf8_validate(s, -1, NULL)) {
139                         g_string_append(type, "; charset=\"utf-8\"");
140                 } else {
141                         /* it should be impossible to reach this, but better safe than sorry */
142                         g_warning("invalid utf8 in message");
143                         g_string_append(type, "; charset=\"latin1\"");
144                 }
145         }
146         return g_string_free(type, FALSE);
147 }
148
149 gboolean
150 modest_tny_transport_actions_send_message (ModestTnyTransportActions *self,
151                                            TnyTransportAccountIface *transport_account,
152                                            const gchar *from,
153                                            const gchar *to,
154                                            const gchar *cc,
155                                            const gchar *bcc,
156                                            const gchar *subject,
157                                            const gchar *body,
158                                            const GList *attachments_list)
159 {
160         TnyMsgIface *new_msg;
161         TnyMsgMimePartIface *attachment_part, *text_body_part;
162         TnyMsgHeaderIface *headers;
163         TnyStreamIface *text_body_stream, *attachment_stream;
164         GList *attachment;
165         gchar *content_type, *attachment_content_type;
166         gchar *filename, *attachment_filename;
167         int file;
168
169         new_msg          = TNY_MSG_IFACE(tny_msg_new ());
170         headers          = TNY_MSG_HEADER_IFACE(tny_msg_header_new ());
171         text_body_stream = TNY_STREAM_IFACE (tny_stream_camel_new
172                                              (camel_stream_mem_new_with_buffer
173                                               (body, strlen(body))));
174         
175         tny_msg_header_iface_set_from (TNY_MSG_HEADER_IFACE (headers), from);
176         tny_msg_header_iface_set_to (TNY_MSG_HEADER_IFACE (headers), to);
177         tny_msg_header_iface_set_cc (TNY_MSG_HEADER_IFACE (headers), cc);
178         tny_msg_header_iface_set_bcc (TNY_MSG_HEADER_IFACE (headers), bcc);
179         tny_msg_header_iface_set_subject (TNY_MSG_HEADER_IFACE (headers), subject);
180         tny_msg_iface_set_header (new_msg, headers);
181
182         
183         content_type = get_content_type(body);
184         
185         if (attachments_list == NULL) {
186                 tny_stream_iface_reset (text_body_stream);
187                 tny_msg_mime_part_iface_construct_from_stream (TNY_MSG_MIME_PART_IFACE(new_msg),
188                                                                text_body_stream, content_type);
189                 tny_stream_iface_reset (text_body_stream);
190         } else {
191                 text_body_part = TNY_MSG_MIME_PART_IFACE (tny_msg_mime_part_new(
192                                                           camel_mime_part_new()));
193                 tny_stream_iface_reset (text_body_stream);
194                 tny_msg_mime_part_iface_construct_from_stream (text_body_part,
195                                                                text_body_stream,
196                                                                content_type);
197                 tny_stream_iface_reset (text_body_stream);
198                 tny_msg_iface_add_part(new_msg, text_body_part);
199                 //g_object_unref (G_OBJECT(text_body_part));
200         }
201         
202         for (    attachment = (GList *)attachments_list;
203                      attachment;
204                  attachment = attachment->next    ) {
205                 filename = attachment->data;
206                 attachment_filename = g_path_get_basename(filename);
207                 file = open(filename, O_RDONLY);
208                 attachment_stream = TNY_STREAM_IFACE(tny_stream_camel_new(
209                                                     camel_stream_fs_new_with_fd(file)));
210
211                 attachment_part = TNY_MSG_MIME_PART_IFACE (tny_msg_mime_part_new (
212                                                                 camel_mime_part_new()));
213                 
214                 attachment_content_type = "image/jpeg"; /* later... */
215                 tny_msg_mime_part_iface_construct_from_stream (attachment_part,
216                                                                attachment_stream,
217                                                                attachment_content_type);
218                 tny_stream_iface_reset (attachment_stream);
219                 
220                 tny_msg_mime_part_iface_set_filename(attachment_part, attachment_filename);
221                 
222                 tny_msg_iface_add_part (new_msg, attachment_part);
223                 g_object_unref(G_OBJECT(attachment_stream));
224                 //g_object_unref(G_OBJECT(attachment_part));
225                 g_free(attachment_filename);
226                 //close(file);
227         }
228         
229         tny_transport_account_iface_send (transport_account, new_msg);
230
231         g_object_unref (G_OBJECT(text_body_stream));
232         g_object_unref (G_OBJECT(headers));
233         g_object_unref (G_OBJECT(new_msg));
234         g_free(content_type);
235
236         return TRUE;    
237 }