aboutsummaryrefslogtreecommitdiffstats
path: root/src/message.c
diff options
context:
space:
mode:
authorVsevolod Stakhov <vsevolod@rambler-co.ru>2009-03-24 13:13:57 +0300
committerVsevolod Stakhov <vsevolod@rambler-co.ru>2009-03-24 13:13:57 +0300
commita0320ce847fb75f83e3c060ece2751f3d6684f05 (patch)
tree23c5e625f62f193a472fdf7aaa66c09ac339e6ca /src/message.c
parente894cd18cf4ce43dc63c71fecb69efd7e25e68f9 (diff)
downloadrspamd-a0320ce847fb75f83e3c060ece2751f3d6684f05.tar.gz
rspamd-a0320ce847fb75f83e3c060ece2751f3d6684f05.zip
* Add smart handling of message headers
Diffstat (limited to 'src/message.c')
-rw-r--r--src/message.c266
1 files changed, 266 insertions, 0 deletions
diff --git a/src/message.c b/src/message.c
index 807463a82..be470bb65 100644
--- a/src/message.c
+++ b/src/message.c
@@ -552,3 +552,269 @@ get_next_text_part (memory_pool_t *pool, GList *parts, GList **cur)
return NULL;
}
+
+struct raw_header {
+ struct raw_header *next;
+ char *name;
+ char *value;
+};
+
+typedef struct _GMimeHeader {
+ GHashTable *hash;
+ GHashTable *writers;
+ struct raw_header *headers;
+} local_GMimeHeader;
+
+
+/* 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)
+{
+ GList * gret = NULL;
+#ifndef GMIME24
+ struct raw_header *h;
+
+ 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));
+ }
+ h = h->next;
+ }
+ return gret;
+#else
+ GMimeHeaderList *ls;
+ GMimeHeaderIter *iter;
+ const char *name;
+
+ ls = GMIME_OBJECT(message)->headers;
+
+ if (g_mime_header_list_get_iter (ls, iter)) {
+ while (g_mime_header_iter_is_valid (iter)) {
+ name = g_mime_header_iter_get_name (iter);
+ if (!g_strncasecmp (field, name, strlen (name))) {
+ gret = g_list_prepend (gret, g_strdup (g_mime_header_iter_get_value (iter)));
+ }
+ if (!g_mime_header_iter_next (iter)) {
+ break;
+ }
+ }
+ }
+
+ return gret;
+#endif
+}
+
+/**
+* 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.
+**/
+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);
+}
+
+#ifdef GMIME24
+
+#define ADD_RECIPIENT_TEMPLATE(type,def) \
+static void \
+local_message_add_recipients_from_string_##type (GMimeMessage *message, const gchar *string, const gchar *value) \
+{ \
+ InternetAddressList *il, *new; \
+ \
+ il = g_mime_message_get_recipients (message, (def)); \
+ new = internet_address_list_parse_string (string); \
+ internet_address_list_append (il, new); \
+} \
+
+ADD_RECIPIENT_TEMPLATE(to, GMIME_RECIPIENT_TYPE_TO)
+ADD_RECIPIENT_TEMPLATE(cc, GMIME_RECIPIENT_TYPE_CC)
+ADD_RECIPIENT_TEMPLATE(bcc, GMIME_RECIPIENT_TYPE_BCC)
+
+#define GET_RECIPIENT_TEMPLATE(type,def) \
+static InternetAddressList* \
+local_message_get_recipients_##type (GMimeMessage *message, const char *unused) \
+{ \
+ return g_mime_message_get_recipients (message, (def)); \
+}
+
+GET_RECIPIENT_TEMPLATE(to, GMIME_RECIPIENT_TYPE_TO)
+GET_RECIPIENT_TEMPLATE(cc, GMIME_RECIPIENT_TYPE_CC)
+GET_RECIPIENT_TEMPLATE(bcc, GMIME_RECIPIENT_TYPE_BCC)
+
+#endif
+
+
+/* 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 },
+#ifndef GMIME24
+ { "To", NULL, (GetRcptFunc)g_mime_message_get_recipients, NULL, NULL, (SetListFunc)g_mime_message_add_recipients_from_string, FUNC_IA },
+ { "Cc", NULL, (GetRcptFunc)g_mime_message_get_recipients, NULL, NULL, (SetListFunc)g_mime_message_add_recipients_from_string, FUNC_IA },
+ { "Bcc",NULL, (GetRcptFunc)g_mime_message_get_recipients, NULL, NULL, (SetListFunc)g_mime_message_add_recipients_from_string, FUNC_IA },
+ { "Date", (GetFunc)g_mime_message_get_date_string, NULL, NULL, local_mime_message_set_date_from_string, NULL, FUNC_CHARFREEPTR },
+#else
+ { "To", NULL, local_message_get_recipients_to, NULL, NULL, local_message_add_recipients_from_string_to, FUNC_IA },
+ { "Cc", NULL, local_message_get_recipients_cc, NULL, NULL, local_message_add_recipients_from_string_cc, FUNC_IA },
+ { "Bcc", NULL, local_message_get_recipients_bcc, NULL, NULL, local_message_add_recipients_from_string_bcc, FUNC_IA },
+ { "Date", g_mime_message_get_date_as_string, NULL, NULL, local_mime_message_set_date_from_string, NULL, FUNC_CHARFREEPTR },
+#endif
+ { "Subject", g_mime_message_get_subject, NULL, NULL, g_mime_message_set_subject, NULL, FUNC_CHARPTR },
+ { "Message-Id", g_mime_message_get_message_id, NULL, NULL, g_mime_message_set_message_id, NULL, FUNC_CHARPTR },
+#ifndef GMIME24
+ { NULL, NULL, NULL, local_message_get_header, NULL, g_mime_message_add_header, FUNC_LIST }
+#else
+ { NULL, NULL, NULL, local_message_get_header, NULL, g_mime_object_append_header, FUNC_LIST }
+#endif
+};
+/**
+* message_set_header: set header of any type excluding special (Content- and MIME-Version:)
+**/
+void
+message_set_header (GMimeMessage *message, const char *field, const char *value)
+{
+ gint i;
+
+ if (!g_strcasecmp (field, "MIME-Version:") || !g_strncasecmp (field, "Content-", 8)) {
+ 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;
+ }
+ 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.
+**/
+GList *
+message_get_header (GMimeMessage *message, const char *field)
+{
+ gint i;
+ char * ret = NULL, *ia_string;
+ GList * gret = NULL;
+ InternetAddressList *ia_list = NULL, *ia;
+
+ 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_CHARFREEPTR:
+ ret = (char *)(*(fieldfunc[i].func))(message);
+ break;
+ case FUNC_CHARPTR:
+ ret = (char *)(*(fieldfunc[i].func))(message);
+ break;
+ case FUNC_IA:
+ ia_list = (*(fieldfunc[i].rcptfunc))(message, field);
+ gret = g_list_alloc();
+ ia = ia_list;
+#ifndef GMIME24
+ while (ia && ia->address) {
+
+ ia_string = internet_address_to_string ((InternetAddress *)ia->address, FALSE);
+ gret = g_list_append (gret, ia_string);
+ ia = ia->next;
+ }
+#else
+ i = internet_address_list_length (ia);
+ while (i > 0) {
+ ia_string = internet_address_to_string (internet_address_list_get_address (ia, i), FALSE);
+ gret = g_list_append (gret, ia_string);
+ -- i;
+ }
+#endif
+ break;
+ case FUNC_LIST:
+ gret = (*(fieldfunc[i].getlistfunc))(message, field);
+ break;
+ }
+ break;
+ }
+ }
+ 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;
+}