#include <libetpan/libetpan.h> struct mailmessage_driver { char * msg_name; int (* msg_initialize)(mailmessage * msg_info); void (* msg_uninitialize)(mailmessage * msg_info); void (* msg_flush)(mailmessage * msg_info); void (* msg_check)(mailmessage * msg_info); void (* msg_fetch_result_free)(mailmessage * msg_info, char * msg); int (* msg_fetch)(mailmessage * msg_info, char ** result, size_t * result_len); int (* msg_fetch_header)(mailmessage * msg_info, char ** result, size_t * result_len); int (* msg_fetch_body)(mailmessage * msg_info, char ** result, size_t * result_len); int (* msg_fetch_size)(mailmessage * msg_info, size_t * result); int (* msg_get_bodystructure)(mailmessage * msg_info, struct mailmime ** result); int (* msg_fetch_section)(mailmessage * msg_info, struct mailmime * mime, char ** result, size_t * result_len); int (* msg_fetch_section_header)(mailmessage * msg_info, struct mailmime * mime, char ** result, size_t * result_len); int (* msg_fetch_section_mime)(mailmessage * msg_info, struct mailmime * mime, char ** result, size_t * result_len); int (* msg_fetch_section_body)(mailmessage * msg_info, struct mailmime * mime, char ** result, size_t * result_len); int (* msg_fetch_envelope)(mailmessage * msg_info, struct mailimf_fields ** result); int (* msg_get_flags)(mailmessage * msg_info, struct mail_flags ** result); };
msg_name is the name of the driver.
msg_initialize() will initialize the internal message state (field msg_data of mailmessage structure (see the Section called Message).
msg_uninitialize() will free the internal message state.
msg_flush() will release memory used by the MIME structure of the message.
msg_check() will store the flags of the message into the session, so that the message can be released without the flags are lost.
msg_fetch_result_free() will free a string returned by any fetch_XXX() function.
msg_fetch() will fetch a message.
msg_fetch_header() will fetch the header fields of a message.
msg_fetch_body() will fetch a message without its main header.
msg_fetch_size() will return the size of a message.
msg_get_bodystructure will retrieve the MIME structure of the message. The returned structure must NOT be freed.
msg_fetch_section() will fetch the content of the section of the message.
msg_fetch_section_header() will fetch the header of a section of the message if the content of the section is a message.
msg_fetch_section_mime() will fetch the MIME header of a section of the message.
msg_fetch_section_body() will fetch the body of a section (without the headers) of the message if the content of the section is a message.
msg_fetch_envelope() will return a given number of parsed header fields.
msg_get_flags() will return the flags of the message. The returned structure must NOT be freed.
#include <libetpan/libetpan.h> struct mailmessage { mailsession * msg_session; mailmessage_driver * msg_driver; uint32_t msg_index; char * msg_uid; size_t msg_size; struct mailimf_fields * msg_fields; struct mail_flags * msg_flags; int msg_resolved; struct mailimf_single_fields msg_single_fields; struct mailmime * msg_mime; /* internal data */ int msg_cached; void * msg_data; /* msg_folder field : used to reference the mailfolder, this is a workaround due to the problem with initial conception, where folder notion did not exist. */ void * msg_folder; /* user data */ void * msg_user_data; };
msg_session is the session related to the message (see the Section called Session).
msg_driver is the driver used for the message (see the Section called Message driver).
msg_index is an index to indentify the message.
msg_uid is the unique identifier of the message, valid accross disconnections.
msg_size is the size of the message.
msg_fields is the list of parsed header fields of the message. This can be NULL (see the Section called mailimf_fields - list of header fields in Chapter 3).
msg_flags is the flags of the message. This can be NULL (see the Section called Message flags).
msg_resolved will tell if the field msg_single_fields has been initialized.
msg_single_fields will be filled using msg_fields (see the Section called mailimf_single_fields - simplified fields in Chapter 3).
msg_mime is the MIME structure of the message. It is intialized at least when get_bodystructure() is called once.
msg_cached is 1 when the message was cached. This is used internally.
msg_data is the internal state of the message. The content depends on the driver.
msg_folder is used to reference the mailfolder, this is a workaround due to the problem with initial conception, where folder notion did not exist.
msg_user_data is a field for free use. The user can store any data in that field.
#include <libetpan/libetpan.h> mailmessage * mailmessage_new(void); void mailmessage_free(mailmessage * info);
mailmessage_new() will create a new message (without driver). This is used internally by drivers.
mailmessage_free() will free the memory used by the given message.
#include <libetpan/libetpan.h> int mailmessage_init(mailmessage * msg_info, mailsession * session, mailmessage_driver * driver, uint32_t index, size_t size);
mailmessage_init() will initialize a message with a driver.
msg_info is the message to initialize (see the Section called Message).
session is the session related to the message (see the Section called Session).
driver is the driver to use for the message (see the Section called Message driver).
index is the index of the message.
size is the size of the message.
#include <libetpan/libetpan.h> int mailmessage_flush(mailmessage * info);
This function will release the memory used by the MIME structure of the message.
#include <libetpan/libetpan.h> int mailmessage_check(mailmessage * info);
After you set some flags, if you want to notify them to the session before destroying the message, you can use this function.
#include <libetpan/libetpan.h> int mailmessage_fetch_result_free(mailmessage * msg_info, char * msg);
This function will free a string returned by any mailmessage_fetch_XXX() function.
#include <libetpan/libetpan.h> int mailmessage_fetch(mailmessage * msg_info, char ** result, size_t * result_len);
This function returns the content of the message (headers and text).
#include <libetpan/libetpan.h> int mailmessage_fetch_header(mailmessage * msg_info, char ** result, size_t * result_len);
This function returns the header of the message as a string.
#include <libetpan/libetpan.h> int mailmessage_fetch_body(mailmessage * msg_info, char ** result, size_t * result_len);
This function returns the content of the message (without headers).
#include <libetpan/libetpan.h> int mailmessage_fetch_size(mailmessage * msg_info, size_t * result);
This function returns the size of the message content.
#include <libetpan/libetpan.h> int mailmessage_get_bodystructure(mailmessage * msg_info, struct mailmime ** result);
This functions returns the MIME structure of the message. The returned information MUST not be freed by hand. It is freed by mailmessage_flush() or mailmessage_free() (see the Section called mailmime - MIME part in Chapter 4).
#include <libetpan/libetpan.h> int mailmessage_fetch_section(mailmessage * msg_info, struct mailmime * mime, char ** result, size_t * result_len);
This function returns the content of a MIME part.
#include <libetpan/libetpan.h> int mailmessage_fetch_section_header(mailmessage * msg_info, struct mailmime * mime, char ** result, size_t * result_len);
This function returns the header of the message contained in the given MIME part.
#include <libetpan/libetpan.h> int mailmessage_fetch_section_mime(mailmessage * msg_info, struct mailmime * mime, char ** result, size_t * result_len);
This function returns the MIME header of the given MIME part.
#include <libetpan/libetpan.h> int mailmessage_fetch_section_body(mailmessage * msg_info, struct mailmime * mime, char ** result, size_t * result_len);
This function returns the text part of the message contained in the given MIME part.
#include <libetpan/libetpan.h> int mailmessage_fetch_envelope(mailmessage * msg_info, struct mailimf_fields ** result);
#include <libetpan/libetpan.h> int mailmessage_get_flags(mailmessage * msg_info, struct mail_flags ** result);
This function returns the flags related to the message. The returned information MUST not be freed by hand. It is freed by mailmessage_free().
#include <libetpan/libetpan.h> void mailmessage_resolve_single_fields(mailmessage * msg_info);
This function will use the fields information to fill the single_fields structure in the mailmessage structure.
#include <libetpan/libetpan.h> struct mailmessage_list { carray * msg_tab; /* elements are (mailmessage *) */ }; struct mailmessage_list * mailmessage_list_new(carray * msg_tab); void mailmessage_list_free(struct mailmessage_list * env_list);
This is a list of messages.
msg_tab is an array containing the messages (see linkend="carray").
mailmessage_list_new() will initialize a list of messages, using a given array of messages.
mailmessage_list_free() will free the memory used by the list of messages. This will also free the messages.
#include <libetpan/libetpan.h> struct mailmessage_tree { struct mailmessage_tree * node_parent; char * node_msgid; time_t node_date; mailmessage * node_msg; carray * node_children; /* array of (struct mailmessage_tree *) */ /* private, used for threading */ int node_is_reply; char * node_base_subject; }; struct mailmessage_tree * mailmessage_tree_new(char * node_msgid, time_t node_date, mailmessage * node_msg); void mailmessage_tree_free(struct mailmessage_tree * tree); void mailmessage_tree_free_recursive(struct mailmessage_tree * tree);
This is a node of a tree of messages.
node_parent is the parent of this node.
node_msgid is the content of the field Message-ID of the message.
node_date is the date in UNIX format.
node_msg is the message of the node. The message should have the msg_fields field initialized.
node_children is the list of children of this node.
node_is_reply is set to 1 if the message is a reply.
node_base_subject is the base subject of the message (base subject is defined in definition of IMAP thread draft).
mailmessage_tree_new() will initialize a message node.
mailmessage_tree_free() will release memory used by the node. This will NOT free the message.
#include <libetpan/libetpan.h> enum { MAIL_FLAG_NEW = 1 << 0, MAIL_FLAG_SEEN = 1 << 1, MAIL_FLAG_FLAGGED = 1 << 2, MAIL_FLAG_DELETED = 1 << 3, MAIL_FLAG_ANSWERED = 1 << 4, MAIL_FLAG_FORWARDED = 1 << 5, MAIL_FLAG_CANCELLED = 1 << 6, }; struct mail_flags { uint32_t fl_flags; clist * fl_extension; /* elements are (char *) */ }; struct mail_flags * mail_flags_new(uint32_t fl_flags, clist * fl_ext); void mail_flags_free(struct mail_flags * flags); int mail_flags_add_extension(struct mail_flags * flags, char * ext_flag); int mail_flags_remove_extension(struct mail_flags * flags, char * ext_flag); int mail_flags_has_extension(struct mail_flags * flags, char * ext_flag);
This is the structure containing the message flags.
fl_flags will contain the standards flags. The value will be a combinaison (with or binary operation) of MAIL_FLAG_XXX values.
fl_extension will be a list (see the Section called List in Chapter 2) of strings representing the non-standard flags.
Example 5-3. use of message
#include <libetpan/libetpan.h> #define DEST_CHARSET "iso-8859-1" enum { NO_ERROR, ERROR_FILE, ERROR_MEMORY, ERROR_INVAL, ERROR_FETCH, }; /* returns TRUE is given MIME part is a text part */ int etpan_mime_is_text(struct mailmime * build_info) { if (build_info->mm_type == MAILMIME_SINGLE) { if (build_info->mm_content_type != NULL) { if (build_info->mm_content_type->ct_type->tp_type == MAILMIME_TYPE_DISCRETE_TYPE) { if (build_info->mm_content_type->ct_type->tp_data.tp_discrete_type->dt_type == MAILMIME_DISCRETE_TYPE_TEXT) return 1; } } else return 1; } return 0; } /* display content type */ int show_part_info(FILE * f, struct mailmime_single_fields * mime_fields, struct mailmime_content * content) { char * description; char * filename; int col; int r; description = mime_fields->fld_description; filename = mime_fields->fld_disposition_filename; col = 0; r = fprintf(f, " [ Part "); if (r < 0) goto err; if (content != NULL) { r = mailmime_content_type_write(f, &col, content); if (r != MAILIMF_NO_ERROR) goto err; } if (filename != NULL) { r = fprintf(f, " (%s)", filename); if (r < 0) goto err; } if (description != NULL) { r = fprintf(f, " : %s", description); if (r < 0) goto err; } r = fprintf(f, " ]\n\n"); if (r < 0) goto err; return NO_ERROR; err: return ERROR_FILE; } /* fetch message and decode if it is base64 or quoted-printable */ int etpan_fetch_message(mailmessage * msg_info, struct mailmime * mime_part, struct mailmime_single_fields * fields, char ** result, size_t * result_len) { char * data; size_t len; int r; int encoding; char * decoded; size_t decoded_len; size_t cur_token; int res; int encoded; encoded = 0; r = mailmessage_fetch_section(msg_info, mime_part, &data, &len); if (r != MAIL_NO_ERROR) { res = ERROR_FETCH; goto err; } encoded = 1; /* decode message */ if (encoded) { if (fields->fld_encoding != NULL) encoding = fields->fld_encoding->enc_type; else encoding = MAILMIME_MECHANISM_8BIT; } else { encoding = MAILMIME_MECHANISM_8BIT; } cur_token = 0; r = mailmime_part_parse(data, len, &cur_token, encoding, &decoded, &decoded_len); if (r != MAILIMF_NO_ERROR) { res = ERROR_FETCH; goto free; } mailmessage_fetch_result_free(msg_info, data); * result = decoded; * result_len = decoded_len; return NO_ERROR; free: mailmessage_fetch_result_free(msg_info, data); err: return res; } /* fetch fields */ struct mailimf_fields * fetch_fields(mailmessage * msg_info, struct mailmime * mime) { char * data; size_t len; int r; size_t cur_token; struct mailimf_fields * fields; r = mailmessage_fetch_section_header(msg_info, mime, &data, &len); if (r != MAIL_NO_ERROR) return NULL; cur_token = 0; r = mailimf_envelopes_fields_parse(data, len, &cur_token, &fields); if (r != MAILIMF_NO_ERROR) { mailmessage_fetch_result_free(msg_info, data); return NULL; } mailmessage_fetch_result_free(msg_info, data); return fields; } /* render message */ static int etpan_render_mime(FILE * f, mailmessage * msg_info, struct mailmime * mime) { int r; clistiter * cur; int col; int text; int show; struct mailmime_single_fields fields; int res; mailmime_single_fields_init(&fields, mime->mm_mime_fields, mime->mm_content_type); text = etpan_mime_is_text(mime); r = show_part_info(f, &fields, mime->mm_content_type); if (r != NO_ERROR) { res = r; goto err; } switch(mime->mm_type) { case MAILMIME_SINGLE: show = 0; if (text) show = 1; if (show) { char * data; size_t len; char * converted; size_t converted_len; char * source_charset; size_t write_len; /* viewable part */ r = etpan_fetch_message(msg_info, mime, &fields, &data, &len); if (r != NO_ERROR) { res = r; goto err; } source_charset = fields.fld_content_charset; if (source_charset == NULL) source_charset = DEST_CHARSET; r = charconv_buffer(source_charset, DEST_CHARSET, data, len, &converted, &converted_len); if (r != MAIL_CHARCONV_NO_ERROR) { r = fprintf(f, "[ error converting charset from %s to %s ]\n", source_charset, DEST_CHARSET); if (r < 0) { res = ERROR_FILE; goto err; } write_len = fwrite(data, 1, len, f); if (write_len != len) { mailmime_decoded_part_free(data); res = r; goto err; } } else { write_len = fwrite(converted, 1, converted_len, f); if (write_len != len) { charconv_buffer_free(converted); mailmime_decoded_part_free(data); res = r; goto err; } charconv_buffer_free(converted); } write_len = fwrite("\r\n\r\n", 1, 4, f); if (write_len < 4) { mailmime_decoded_part_free(data); res = ERROR_FILE; goto err; } mailmime_decoded_part_free(data); } else { /* not viewable part */ r = fprintf(f, " (not shown)\n\n"); if (r < 0) { res = ERROR_FILE; goto err; } } break; case MAILMIME_MULTIPLE: if (strcasecmp(mime->mm_content_type->ct_subtype, "alternative") == 0) { struct mailmime * prefered_body; int prefered_score; /* case of multiple/alternative */ /* we choose the better part, alternative preference : text/plain => score 3 text/xxx => score 2 other => score 1 */ prefered_body = NULL; prefered_score = 0; for(cur = clist_begin(mime->mm_data.mm_multipart.mm_mp_list) ; cur != NULL ; cur = clist_next(cur)) { struct mailmime * submime; int score; score = 1; submime = clist_content(cur); if (etpan_mime_is_text(submime)) score = 2; if (submime->mm_content_type != NULL) { if (strcasecmp(submime->mm_content_type->ct_subtype, "plain") == 0) score = 3; } if (score > prefered_score) { prefered_score = score; prefered_body = submime; } } if (prefered_body != NULL) { r = etpan_render_mime(f, msg_info, prefered_body); if (r != NO_ERROR) { res = r; goto err; } } } else { for(cur = clist_begin(mime->mm_data.mm_multipart.mm_mp_list) ; cur != NULL ; cur = clist_next(cur)) { r = etpan_render_mime(f, msg_info, clist_content(cur)); if (r != NO_ERROR) { res = r; goto err; } } } break; case MAILMIME_MESSAGE: if (mime->mm_data.mm_message.mm_fields != NULL) { struct mailimf_fields * fields; if (msg_info != NULL) { fields = fetch_fields(msg_info, mime); if (fields == NULL) { res = ERROR_FETCH; goto err; } col = 0; r = mailimf_fields_write(f, &col, fields); if (r != NO_ERROR) { mailimf_fields_free(fields); res = r; goto err; } mailimf_fields_free(fields); } else { col = 0; r = fields_write(f, &col, mime->mm_data.mm_message.mm_fields); if (r != NO_ERROR) { res = r; goto err; } } r = fprintf(f, "\r\n"); if (r < 0) { res = ERROR_FILE; goto err; } } if (mime->mm_data.mm_message.mm_msg_mime != NULL) { r = etpan_render_mime(f, msg_info, mime->mm_data.mm_message.mm_msg_mime); if (r != NO_ERROR) { res = r; goto err; } } break; } return NO_ERROR; err: return res; } int main(void) { struct mailstorage * storage; int r; storage = mailstorage_new(NULL); imap_mailstorage_init(storage, "imap.my-servers.org", 0, NULL, CONNECTION_TYPE_TRY_STARTTLS, IMAP_AUTH_TYPE_PLAIN, "my-login", "my-password", 1, "/home/login/.libetpan/cache"); r = mailstorage_connect(storage); if (r == MAIL_NO_ERROR) { struct mailfolder * folder; folder = mailfolder_new(storage, "INBOX", NULL); r = mailfolder_connect(folder); if (r == MAIL_NO_ERROR) { struct mailmessage_list * msg_list; mailmessage * msg; mailfolder_get_messages_list(folder, &msg_list); if (carray_count(msg_list->msg_tab) > 0) { struct mailmime * mime; msg = carray_get(msg_list->msg_tab, 0); mailmessage_get_bodystructure(msg, &mime); recursive_fetch(msg, mime); /* do the things */ mailmessage_flush(msg); } mailmessage_list_free(msg_list); mailfolder_disconnect(folder); } mailstorage_disconnect(storage); } mailstorage_free(storage); }