The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

/* known header field types */
enum {
        HEADER_FROM = 0,
        HEADER_REPLY_TO,
        HEADER_TO,
        HEADER_CC,
        HEADER_BCC,
        HEADER_SUBJECT,
        HEADER_DATE,
        HEADER_MESSAGE_ID,
        HEADER_UNKNOWN
};

static GList *
local_message_get_header(GMimeMessage *message, const char *field)
{
    struct raw_header *h;
    GList *	gret = NULL;

    if (field == NULL)
	return NULL;
    h = GMIME_OBJECT(message)->headers->headers;
    while (h) {
	if (h->value && !g_strncasecmp(field, h->name, strlen(field))) {
	    gret = g_list_prepend(gret, g_strdup(h->value));
	    if (gmime_debug)
	    warn("Looking for %s => %s\n", field, h->value);
	}
        h = h->next;
    }
    return gret;
}

/**
* g_mime_message_set_date_from_string: Set the message sent-date
* @message: MIME Message
* @string: A string of date
* 
* Set the sent-date on a MIME Message.
**/       
static void
local_mime_message_set_date_from_string (GMimeMessage *message, const gchar *string) {
  time_t date;
  int offset = 0;

  date = g_mime_utils_header_decode_date (string, &offset);
  g_mime_message_set_date (message, date, offset); 
}



/* different declarations for different types of set and get functions */
typedef const char *(*GetFunc) (GMimeMessage *message);
typedef InternetAddressList *(*GetRcptFunc) (GMimeMessage *message, const char *type );
typedef GList *(*GetListFunc) (GMimeMessage *message, const char *type );
typedef void   (*SetFunc) (GMimeMessage *message, const char *value);
typedef void   (*SetListFunc) (GMimeMessage *message, const char *field, const char *value);

/** different types of functions
*
* FUNC_CHARPTR
*  - function with no arguments
*  - get returns char*
*
* FUNC_IA (from Internet Address)
*  - function with additional "field" argument from the fieldfunc table,
*  - get returns Glist*
*
* FUNC_LIST
*  - function with additional "field" argument (given arbitrary header field name)
*  - get returns Glist*
**/
enum {
	FUNC_CHARPTR = 0,
	FUNC_CHARFREEPTR,
	FUNC_IA,
	FUNC_LIST
};

/**
* fieldfunc struct: structure of MIME fields and corresponding get and set
* functions.
**/
static struct {
  char *	name;
  GetFunc	func;
  GetRcptFunc	rcptfunc;
  GetListFunc	getlistfunc;
  SetFunc	setfunc;
  SetListFunc	setlfunc;
  gint		functype;
} fieldfunc[] = {
  { "From",	g_mime_message_get_sender,	NULL, NULL,				g_mime_message_set_sender,	NULL, FUNC_CHARPTR },
  { "Reply-To",	g_mime_message_get_reply_to,	NULL, NULL,				g_mime_message_set_reply_to,	NULL, FUNC_CHARPTR },
  { "To",	NULL,				g_mime_message_get_recipients,	NULL, NULL, g_mime_message_add_recipients_from_string, FUNC_IA },
  { "Cc",	NULL,				g_mime_message_get_recipients,	NULL, NULL, g_mime_message_add_recipients_from_string, FUNC_IA },
  { "Bcc",	NULL,				g_mime_message_get_recipients,	NULL, NULL, g_mime_message_add_recipients_from_string, FUNC_IA },
  { "Subject",	g_mime_message_get_subject,	NULL, NULL,				g_mime_message_set_subject,	NULL, FUNC_CHARPTR },
  { "Date",	g_mime_message_get_date_string, NULL, NULL,				local_mime_message_set_date_from_string,	NULL, FUNC_CHARFREEPTR },
  { "Message-Id",g_mime_message_get_message_id,	NULL, NULL,				g_mime_message_set_message_id,	NULL, FUNC_CHARPTR },
  { NULL,	NULL,		NULL,	local_message_get_header,	NULL, g_mime_message_add_header, FUNC_LIST }
};

/**
* message_set_header: set header of any type excluding special (Content- and MIME-Version:)
**/
static void
message_set_header(GMimeMessage *message, const char *field, const char *value) {
  gint		i;

  if (gmime_debug)
    warn("message_set_header(msg=0x%x, '%s' => '%s')\n", message, field, value);

  if (!g_strcasecmp (field, "MIME-Version:") || !g_strncasecmp (field, "Content-", 8)) {
    warn ("Could not set special header: \"%s\"", field);
    return;
  }
  for (i=0; i<=HEADER_UNKNOWN; ++i) {
    if (!fieldfunc[i].name || !g_strncasecmp(field, fieldfunc[i].name, strlen(fieldfunc[i].name))) { 
      switch (fieldfunc[i].functype) {
	case FUNC_CHARPTR:
	  (*(fieldfunc[i].setfunc))(message, value);
	  break;
	case FUNC_IA:
          (*(fieldfunc[i].setlfunc))(message, fieldfunc[i].name, value);
	  break;
	case FUNC_LIST:
          (*(fieldfunc[i].setlfunc))(message, field, value);
	  break;
        default:
	  break;
      }
      break;
    }     
  }
}


/**
* message_get_header: returns the list of 'any header' values
* (except of unsupported yet Content- and MIME-Version special headers)
*
* You should free the GList list by yourself.
**/
static
GList *
message_get_header(GMimeMessage *message, const char *field) {
  gint		i;
  char *	ret = NULL;
  GList *	gret = NULL;

  for (i=0; i<=HEADER_UNKNOWN; ++i) {
    if (!fieldfunc[i].name || !g_strncasecmp(field, fieldfunc[i].name, strlen(fieldfunc[i].name))) { 
      if (gmime_debug)
        warn("message_get_header(%s) = %d",
	      field, fieldfunc[i].functype);
      switch (fieldfunc[i].functype) {
	case FUNC_CHARFREEPTR:
	  ret = (char *)(*(fieldfunc[i].func))(message);
	  break;
	case FUNC_CHARPTR:
	  ret = (char *)(*(fieldfunc[i].func))(message);
	  break;
	case FUNC_IA: {
	    InternetAddressList *ia_list = NULL, *ia;
	    
            ia_list = (*(fieldfunc[i].rcptfunc))(message, field);
	    gret = g_list_alloc();
	    ia = ia_list;
	    while (ia && ia->address) {
	      char *ia_string;

	      ia_string = internet_address_to_string((InternetAddress *)ia->address, FALSE);
	      gret = g_list_append(gret, ia_string);
	      ia = ia->next;
	    }
	  }
	  break;
	case FUNC_LIST:
          gret = (*(fieldfunc[i].getlistfunc))(message, field);
	  break;
        default:
	  break;
      }
      break;
    }     
  }
  if (gmime_debug)
    warn("message_get_header(%s) = 0x%x/%s ret=%s",
	    field, gret, gret ? (char *)(gret->data) : "", ret);
  if (gret == NULL && ret != NULL)
    gret = g_list_prepend(gret, g_strdup(ret));
  if (fieldfunc[i].functype == FUNC_CHARFREEPTR && ret)
    g_free(ret);
  return gret;
}