1 /* -*-mode:c; c-style:k&r; c-basic-offset:4; -*- */
2 /* Balsa E-Mail Client
3  * Copyright (C) 1997-2013 Stuart Parmenter and others,
4  *                         See the file AUTHORS for a list.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2, or (at your option)
9  * any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
19  * 02111-1307, USA.
20  */
21 
22 #ifndef __LIBBALSA_MESSAGE_H__
23 #define __LIBBALSA_MESSAGE_H__
24 
25 #ifndef BALSA_VERSION
26 # error "Include config.h before this file."
27 #endif
28 
29 #include <glib.h>
30 
31 #include <stdio.h>
32 #include <time.h>
33 
34 #include <gmime/gmime.h>
35 
36 #ifdef HAVE_GPGME
37 #include "rfc3156.h"
38 #endif
39 
40 #define MESSAGE_COPY_CONTENT 1
41 #define LIBBALSA_TYPE_MESSAGE \
42     (libbalsa_message_get_type())
43 #define LIBBALSA_MESSAGE(obj) \
44     (G_TYPE_CHECK_INSTANCE_CAST(obj, LIBBALSA_TYPE_MESSAGE, LibBalsaMessage))
45 #define LIBBALSA_MESSAGE_CLASS(klass) \
46     (G_TYPE_CHECK_CLASS_CAST(klass, LIBBALSA_TYPE_MESSAGE, \
47                              LibBalsaMessageClass))
48 #define LIBBALSA_IS_MESSAGE(obj) \
49     (G_TYPE_CHECK_INSTANCE_TYPE(obj, LIBBALSA_TYPE_MESSAGE))
50 #define LIBBALSA_IS_MESSAGE_CLASS(klass) \
51     (G_TYPE_CHECK_CLASS_TYPE(klass, LIBBALSA_TYPE_MESSAGE))
52 
53 typedef struct _LibBalsaMessageClass LibBalsaMessageClass;
54 typedef enum _LibBalsaMessageFlag LibBalsaMessageFlag;
55 
56 enum _LibBalsaMessageFlag {
57     LIBBALSA_MESSAGE_FLAG_NEW     = 1 << 0,
58     LIBBALSA_MESSAGE_FLAG_DELETED = 1 << 1,
59     LIBBALSA_MESSAGE_FLAG_REPLIED = 1 << 2,
60     LIBBALSA_MESSAGE_FLAG_FLAGGED = 1 << 3,
61     LIBBALSA_MESSAGE_FLAG_RECENT  = 1 << 4,
62     LIBBALSA_MESSAGE_FLAG_SELECTED= 1 << 5	/* pseudo flag */
63 };
64 
65 #define LIBBALSA_MESSAGE_FLAGS_REAL \
66    (LIBBALSA_MESSAGE_FLAG_NEW       | \
67     LIBBALSA_MESSAGE_FLAG_DELETED   | \
68     LIBBALSA_MESSAGE_FLAG_REPLIED   | \
69     LIBBALSA_MESSAGE_FLAG_FLAGGED   | \
70     LIBBALSA_MESSAGE_FLAG_RECENT)
71 
72 typedef enum _LibBalsaMessageStatus LibBalsaMessageStatus;
73 enum _LibBalsaMessageStatus {
74     LIBBALSA_MESSAGE_STATUS_UNREAD,
75     LIBBALSA_MESSAGE_STATUS_DELETED,
76     LIBBALSA_MESSAGE_STATUS_FLAGGED,
77     LIBBALSA_MESSAGE_STATUS_REPLIED,
78     LIBBALSA_MESSAGE_STATUS_ICONS_NUM
79 };
80 
81 
82 #ifdef HAVE_GPGME
83 typedef enum _LibBalsaMsgProtectState LibBalsaMsgProtectState;
84 
85 enum _LibBalsaMsgProtectState {
86     LIBBALSA_MSG_PROTECT_NONE,
87     LIBBALSA_MSG_PROTECT_SIGN_UNKNOWN,
88     LIBBALSA_MSG_PROTECT_SIGN_GOOD,
89     LIBBALSA_MSG_PROTECT_SIGN_NOTRUST,
90     LIBBALSA_MSG_PROTECT_SIGN_BAD,
91     LIBBALSA_MSG_PROTECT_CRYPT
92 };
93 #endif
94 
95 typedef enum _LibBalsaMessageAttach LibBalsaMessageAttach;
96 enum _LibBalsaMessageAttach {
97     LIBBALSA_MESSAGE_ATTACH_ATTACH,
98 #ifdef HAVE_GPGME
99     LIBBALSA_MESSAGE_ATTACH_GOOD,
100     LIBBALSA_MESSAGE_ATTACH_NOTRUST,
101     LIBBALSA_MESSAGE_ATTACH_BAD,
102     LIBBALSA_MESSAGE_ATTACH_SIGN,
103     LIBBALSA_MESSAGE_ATTACH_ENCR,
104 #endif
105     LIBBALSA_MESSAGE_ATTACH_ICONS_NUM
106 };
107 
108 
109 /*
110  * Message info used by mailbox;
111  *
112  *   headers->from
113  *   headers->date
114  *   headers->to_list
115  *   headers->content_type
116  *   subj
117  *   length
118  *   lines_len (scrap?)
119  *
120  * loaded by driver:
121  *   flags
122  *
123  * needed for threading local mailboxes:
124  *   message_id
125  *   references
126  *   in_reply_to
127  */
128 /*
129  * LibBalsaMessageHeaders contains all headers which are used to display both
130  * a "main" message's headers as well as those from an embedded message/rfc822
131  * part.
132  */
133 struct _LibBalsaMessageHeaders {
134     /* message composition date */
135     time_t date;
136 
137     /* subject (for embedded messages only) */
138     gchar *subject;
139 
140     /* from, reply, and disposition notification addresses */
141     InternetAddressList *from;
142     InternetAddressList *reply_to;
143     InternetAddressList *dispnotify_to;
144 
145     /* primary, secondary, and blind recipent lists */
146     InternetAddressList *to_list;
147     InternetAddressList *cc_list;
148     InternetAddressList *bcc_list;
149 
150     /* Mime type */
151     GMimeContentType *content_type;
152 
153     /* File Carbon Copy Mailbox URL */
154     gchar *fcc_url;
155 
156     /* other headers */
157     GList *user_hdrs;
158 };
159 
160 /** FREE_HEADER_LIST() frees user_hdrs */
161 #define FREE_HEADER_LIST(l) do{ g_list_foreach((l),(GFunc)g_strfreev,NULL);\
162                                 g_list_free(l); } while(0)
163 
164 struct _LibBalsaMessage {
165     GObject object;
166 
167     /* the mailbox this message belongs to */
168     LibBalsaMailbox *mailbox;
169 
170     /* flags */
171     LibBalsaMessageFlag flags;
172 
173     /* headers */
174     LibBalsaMessageHeaders *headers;
175     int updated; /** whether complete headers have been fetched */
176 
177     GMimeMessage *mime_msg;
178 
179     /* sender address */
180     InternetAddressList *sender;
181 
182     /* subject line; we still need it here for sending;
183      * although _SET_SUBJECT might resolve it(?)
184      * but we can set to to NULL unless there is no mailbox, like
185      * on sending. */
186     gchar *subj;
187 #ifdef MESSAGE_COPY_CONTENT
188 #define LIBBALSA_MESSAGE_GET_SUBJECT(m) \
189     ((m)->subj ? (m)->subj : _("(No subject)"))
190 #else
191 #define LIBBALSA_MESSAGE_GET_SUBJECT(m) libbalsa_message_get_subject(m)
192 #endif
193 
194     /* replied message ID's */
195     GList *references;
196 
197     /* replied message ID; from address on date */
198     GList *in_reply_to;
199 
200     /* message ID */
201     gchar *message_id;
202 
203 #ifdef HAVE_GPGME
204     /* GPG sign and/or encrypt message (sending) */
205     guint gpg_mode;
206 
207     /* protection (i.e. sign/encrypt) status (received message) */
208     LibBalsaMsgProtectState prot_state;
209 
210     /* forced id of the senders secret key, empty to choose it from the mail address */
211     gchar * force_key_id;
212 #endif
213 
214     /* a forced multipart subtype or NULL for mixed; used only for
215      * sending */
216     gchar *subtype;
217 
218     /* additional message content type parameters; used only for sending */
219     GList *parameters;
220 
221     /* message body */
222     guint body_ref;
223     LibBalsaMessageBody *body_list;
224     /*  GList *body_list; */
225 
226     glong msgno;     /* message no; always copy for faster sorting;
227 		      * counting starts at 1. */
228 #if MESSAGE_COPY_CONTENT
229 #define LIBBALSA_MESSAGE_GET_NO(m)      ((m)->msgno)
230     glong length;   /* byte len */
231 #define LIBBALSA_MESSAGE_GET_LENGTH(m)  ((m)->length)
232 #else
233 #define LIBBALSA_MESSAGE_GET_LENGTH(m) libbalsa_message_get_length(m)
234 #define LIBBALSA_MESSAGE_GET_NO(m)  libbalsa_message_get_no(m)
235 #endif
236 
237     gchar *tempdir;     /* to hold named parts */
238 
239     unsigned has_all_headers:1;
240 };
241 
242 #define LIBBALSA_MESSAGE_HAS_FLAG(message, mask) \
243     ((LIBBALSA_MESSAGE(message)->flags & mask) != 0)
244 #define LIBBALSA_MESSAGE_IS_UNREAD(message) \
245     LIBBALSA_MESSAGE_HAS_FLAG(message, LIBBALSA_MESSAGE_FLAG_NEW)
246 #define LIBBALSA_MESSAGE_IS_DELETED(message) \
247     LIBBALSA_MESSAGE_HAS_FLAG(message, LIBBALSA_MESSAGE_FLAG_DELETED)
248 #define LIBBALSA_MESSAGE_IS_REPLIED(message) \
249     LIBBALSA_MESSAGE_HAS_FLAG(message, LIBBALSA_MESSAGE_FLAG_REPLIED)
250 #define LIBBALSA_MESSAGE_IS_FLAGGED(message) \
251     LIBBALSA_MESSAGE_HAS_FLAG(message, LIBBALSA_MESSAGE_FLAG_FLAGGED)
252 #define LIBBALSA_MESSAGE_IS_RECENT(message) \
253     LIBBALSA_MESSAGE_HAS_FLAG(message, LIBBALSA_MESSAGE_FLAG_RECENT)
254 
255 struct _LibBalsaMessageClass {
256     GObjectClass parent_class;
257 
258     /* deal with flags being set/unset */
259     /* Signal: */
260     void (*status_changed) (LibBalsaMessage * message,
261 			    LibBalsaMessageFlag flag, gboolean);
262 };
263 
264 
265 GType libbalsa_message_get_type(void);
266 
267 /*
268  * message headers
269  */
270 void libbalsa_message_headers_destroy(LibBalsaMessageHeaders * headers);
271 void libbalsa_message_headers_from_gmime(LibBalsaMessageHeaders *headers,
272 					 GMimeMessage *msg);
273 void libbalsa_message_init_from_gmime(LibBalsaMessage * message,
274 				      GMimeMessage * msg);
275 GList *libbalsa_message_user_hdrs_from_gmime(GMimeMessage *msg);
276 
277 
278 /*
279  * messages
280  */
281 LibBalsaMessage *libbalsa_message_new(void);
282 
283 gboolean libbalsa_message_save(LibBalsaMessage * message,
284 			       const gchar *filename);
285 
286 void libbalsa_message_reply(LibBalsaMessage * message);
287 
288 void libbalsa_message_append_part(LibBalsaMessage * message,
289 				  LibBalsaMessageBody * body);
290 
291 gboolean libbalsa_message_body_ref(LibBalsaMessage * message, gboolean read,
292                                    gboolean fetch_all_headers);
293 void libbalsa_message_body_unref(LibBalsaMessage * message);
294 
295 /*
296  * misc message releated functions
297  */
298 const gchar *libbalsa_message_pathname(LibBalsaMessage * message);
299 const gchar *libbalsa_message_body_charset(LibBalsaMessageBody * body);
300 gboolean libbalsa_message_is_multipart(LibBalsaMessage * message);
301 gboolean libbalsa_message_is_partial(LibBalsaMessage * message,
302 				     gchar ** id);
303 gboolean libbalsa_message_has_attachment(LibBalsaMessage * message);
304 #ifdef HAVE_GPGME
305 gboolean libbalsa_message_is_pgp_signed(LibBalsaMessage * message);
306 gboolean libbalsa_message_is_pgp_encrypted(LibBalsaMessage * message);
307 #endif
308 
309 const gchar* libbalsa_message_header_get_one(LibBalsaMessageHeaders* headers,
310                                              const gchar *find);
311 GList* libbalsa_message_header_get_all(LibBalsaMessageHeaders* headers,
312                                        const gchar *find);
313 const gchar *libbalsa_message_get_user_header(LibBalsaMessage * message,
314                                               const gchar * name);
315 void libbalsa_message_set_user_header(LibBalsaMessage * message,
316                                       const gchar * name,
317                                       const gchar * value);
318 
319 LibBalsaMessageBody *libbalsa_message_get_part_by_id(LibBalsaMessage *
320                                                      message,
321                                                      const gchar * id);
322 
323 void libbalsa_message_set_dispnotify(LibBalsaMessage *message,
324 				     InternetAddress *ia);
325 
326 void libbalsa_message_set_subject(LibBalsaMessage * message,
327                                   const gchar * subject);
328 void libbalsa_message_set_subject_from_header(LibBalsaMessage * message,
329                                               const gchar * header);
330 /* use LIBBALSA_MESSAGE_GET_SUBJECT() macro, we may optimize this
331    function out if we find a way.
332 */
333 #ifndef MESSAGE_COPY_CONTENT
334 const gchar* libbalsa_message_get_subject(LibBalsaMessage* message);
335 guint libbalsa_message_get_lines(LibBalsaMessage* msg);
336 glong libbalsa_message_get_length(LibBalsaMessage* msg);
337 #endif
338 glong libbalsa_message_get_no(LibBalsaMessage* msg);
339 LibBalsaMessageAttach libbalsa_message_get_attach_icon(LibBalsaMessage *
340 						       message);
341 #define libbalsa_message_date_to_utf8(m, f) libbalsa_date_to_utf8(&(m)->headers->date, (f))
342 #define libbalsa_message_headers_date_to_utf8(h, f) libbalsa_date_to_utf8(&(h)->date, (f))
343 
344 GList *libbalsa_message_refs_for_threading(LibBalsaMessage* msg);
345 
346 void libbalsa_message_load_envelope_from_stream(LibBalsaMessage * message,
347                                                 GMimeStream * stream);
348 void libbalsa_message_load_envelope(LibBalsaMessage *message);
349 gboolean libbalsa_message_set_headers_from_string(LibBalsaMessage *message,
350                                                   const gchar *str);
351 void libbalsa_message_set_references_from_string(LibBalsaMessage * message,
352 						 const gchar *str);
353 void libbalsa_message_set_in_reply_to_from_string(LibBalsaMessage * message,
354 						  const gchar *str);
355 GMimeStream *libbalsa_message_stream(LibBalsaMessage * message);
356 gboolean libbalsa_message_copy(LibBalsaMessage * message,
357                                LibBalsaMailbox * dest, GError ** err);
358 void libbalsa_message_change_flags(LibBalsaMessage * message,
359                                    LibBalsaMessageFlag set,
360                                    LibBalsaMessageFlag clear);
361 
362 const gchar *libbalsa_message_get_tempdir(LibBalsaMessage * message);
363 #endif				/* __LIBBALSA_MESSAGE_H__ */
364