* when sending mail, check the charset and set it to "utf-8" in the header, if approp...
[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 {
158         TnyMsgIface *new_msg;
159         TnyMsgMimePartIface *body_part;
160         TnyMsgHeaderIface *headers;
161         TnyStreamIface *body_stream;
162         gchar *content_type;
163
164         new_msg     = TNY_MSG_IFACE(tny_msg_new ());
165         headers     = TNY_MSG_HEADER_IFACE(tny_msg_header_new ());
166         body_stream = TNY_STREAM_IFACE (tny_stream_camel_new
167                                         (camel_stream_mem_new_with_buffer
168                                          (body, strlen(body))));
169         body_part = TNY_MSG_MIME_PART_IFACE (tny_msg_mime_part_new
170                                              (camel_mime_part_new()));
171
172         tny_msg_header_iface_set_from (TNY_MSG_HEADER_IFACE (headers), from);
173         tny_msg_header_iface_set_to (TNY_MSG_HEADER_IFACE (headers), to);
174         tny_msg_header_iface_set_cc (TNY_MSG_HEADER_IFACE (headers), cc);
175         tny_msg_header_iface_set_bcc (TNY_MSG_HEADER_IFACE (headers), bcc);
176         tny_msg_header_iface_set_subject (TNY_MSG_HEADER_IFACE (headers), subject);
177
178         content_type = get_content_type(body);
179                 
180         tny_msg_iface_set_header (new_msg, headers);
181         tny_msg_mime_part_iface_construct_from_stream (body_part, body_stream,
182                                                        content_type);
183         tny_msg_mime_part_iface_set_content_type  (body_part, content_type);    
184         
185         tny_msg_mime_part_iface_set_content_type (
186                 TNY_MSG_MIME_PART_IFACE(new_msg), content_type);
187         tny_stream_iface_reset (body_stream);
188         
189         tny_msg_mime_part_iface_construct_from_stream (TNY_MSG_MIME_PART_IFACE(new_msg),
190                                                        body_stream, content_type);
191         
192         tny_transport_account_iface_send (transport_account, new_msg);
193
194         g_object_unref (G_OBJECT(body_stream));
195         g_object_unref (G_OBJECT(body_part));
196         g_object_unref (G_OBJECT(headers));
197         g_object_unref (G_OBJECT(new_msg));
198         g_free(content_type);
199
200         return TRUE;    
201 }