Message

Message driver

#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);
};
        

Message

#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;
};
        

mailmessage_new

#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.

mailmessage_init

#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.

mailmessage_flush

#include <libetpan/libetpan.h>

int mailmessage_flush(mailmessage * info);
        

This function will release the memory used by the MIME structure of the message.

mailmessage_check

#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.

mailmessage_fetch_result_free

#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.

mailmessage_fetch

#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).

mailmessage_fetch_header

#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.

mailmessage_fetch_body

#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).

mailmessage_fetch_size

#include <libetpan/libetpan.h>

int mailmessage_fetch_size(mailmessage * msg_info,
			   size_t * result);
        

This function returns the size of the message content.

mailmessage_get_bodystructure

#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).

mailmessage_fetch_section

#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.

mailmessage_fetch_section_header

#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.

mailmessage_fetch_section_mime

#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.

mailmessage_fetch_section_body

#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.

mailmessage_fetch_envelope

#include <libetpan/libetpan.h>

int mailmessage_fetch_envelope(mailmessage * msg_info,
			       struct mailimf_fields ** result);
        

mailmessage_get_flags

#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().

mailmessage_resolve_single_fields

#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.

Message list

#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.

Message tree

#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.

mailmessage_tree_new() will initialize a message node.

mailmessage_tree_free() will release memory used by the node. This will NOT free the message.

Message flags

#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.

Example

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);
}