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