[evolution-mapi] Bug #599311 - Doesn't show email attachments
- From: Milan Crha <mcrha src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [evolution-mapi] Bug #599311 - Doesn't show email attachments
- Date: Wed, 12 May 2010 15:39:48 +0000 (UTC)
commit f0376d03f32308a0d403f20ed7e53879a222ebd4
Author: Milan Crha <mcrha redhat com>
Date: Wed May 12 17:38:35 2010 +0200
Bug #599311 - Doesn't show email attachments
src/camel/camel-mapi-folder.c | 711 +-----------------------
src/camel/camel-mapi-folder.h | 55 --
src/camel/camel-mapi-transport.c | 7 +-
src/camel/camel-mapi-utils.c | 37 +-
src/camel/camel-mapi-utils.h | 6 +-
src/libexchangemapi/Makefile.am | 13 +-
src/libexchangemapi/exchange-mapi-cal-utils.c | 10 +-
src/libexchangemapi/exchange-mapi-cal-utils.h | 2 +-
src/libexchangemapi/exchange-mapi-connection.c | 216 ++++++--
src/libexchangemapi/exchange-mapi-connection.h | 7 +
src/libexchangemapi/exchange-mapi-mail-utils.c | 720 ++++++++++++++++++++++++
src/libexchangemapi/exchange-mapi-mail-utils.h | 90 +++
src/libexchangemapi/exchange-mapi-utils.h | 1 -
13 files changed, 1045 insertions(+), 830 deletions(-)
---
diff --git a/src/camel/camel-mapi-folder.c b/src/camel/camel-mapi-folder.c
index cc23dc8..1c45a9c 100644
--- a/src/camel/camel-mapi-folder.c
+++ b/src/camel/camel-mapi-folder.c
@@ -35,6 +35,7 @@
#include <exchange-mapi-utils.h>
#include <exchange-mapi-folder.h>
#include <exchange-mapi-cal-utils.h>
+#include "exchange-mapi-mail-utils.h"
#include "camel-mapi-store.h"
#include "camel-mapi-store-summary.h"
@@ -68,7 +69,6 @@ typedef struct {
/*For collecting summary info from server*/
-static CamelMimeMessage *mapi_folder_item_to_msg( CamelFolder *folder, MapiItem *item, CamelException *ex );
static void mapi_update_cache (CamelFolder *folder, GSList *list, CamelFolderChangeInfo **changeinfo,
CamelException *ex, gboolean uid_flag);
@@ -150,111 +150,6 @@ mapi_refresh_info(CamelFolder *folder, CamelException *ex)
return !camel_exception_is_set (ex);
}
-void
-mapi_item_free (MapiItem *item)
-{
- g_free (item->header.subject);
- g_free (item->header.from);
-
- g_free (item->header.to);
- g_free (item->header.cc);
- g_free (item->header.bcc);
-
- g_free (item->header.references);
- g_free (item->header.message_id);
- g_free (item->header.in_reply_to);
-
- exchange_mapi_util_free_attachment_list (&item->attachments);
- exchange_mapi_util_free_stream_list (&item->generic_streams);
- exchange_mapi_util_free_recipient_list (&item->recipients);
-
- g_free (item);
-}
-
-static gboolean
-read_item_common (MapiItem *item, uint32_t ulPropTag, gconstpointer prop_data)
-{
- gboolean found = TRUE;
-
- #define sv(_x,_y) G_STMT_START { g_free (_x); _x = _y; } G_STMT_END
-
- switch (ulPropTag) {
- case PR_INTERNET_CPID: {
- const uint32_t *ui32 = (const uint32_t *) prop_data;
- if (ui32)
- item->header.cpid = *ui32;
- } break;
- /* FIXME : Instead of duping. Use talloc_steal to reuse the memory */
- case PR_SUBJECT:
- sv (item->header.subject, utf8tolinux (prop_data));
- break;
- case PR_SUBJECT_UNICODE :
- sv (item->header.subject, g_strdup (prop_data));
- break;
- case PR_DISPLAY_TO :
- sv (item->header.to, utf8tolinux (prop_data));
- break;
- case PR_DISPLAY_TO_UNICODE :
- sv (item->header.to, g_strdup (prop_data));
- break;
- case PR_DISPLAY_CC:
- sv (item->header.cc, utf8tolinux (prop_data));
- break;
- case PR_DISPLAY_CC_UNICODE:
- sv (item->header.cc, g_strdup (prop_data));
- break;
- case PR_DISPLAY_BCC:
- sv (item->header.bcc, utf8tolinux (prop_data));
- break;
- case PR_DISPLAY_BCC_UNICODE:
- sv (item->header.bcc, g_strdup (prop_data));
- break;
- case PR_SENT_REPRESENTING_NAME:
- sv (item->header.from, utf8tolinux (prop_data));
- break;
- case PR_SENT_REPRESENTING_NAME_UNICODE:
- sv (item->header.from, g_strdup (prop_data));
- break;
- case PR_SENT_REPRESENTING_EMAIL_ADDRESS:
- sv (item->header.from_email, utf8tolinux (prop_data));
- break;
- case PR_SENT_REPRESENTING_EMAIL_ADDRESS_UNICODE:
- sv (item->header.from_email, g_strdup (prop_data));
- break;
- case PR_SENT_REPRESENTING_ADDRTYPE:
- sv (item->header.from_type, utf8tolinux (prop_data));
- break;
- case PR_SENT_REPRESENTING_ADDRTYPE_UNICODE:
- sv (item->header.from_type, g_strdup (prop_data));
- break;
- case PR_MESSAGE_SIZE:
- item->header.size = *(glong *)prop_data;
- break;
- case PR_INTERNET_MESSAGE_ID:
- item->header.message_id = g_strdup (prop_data);
- break;
- case PR_INTERNET_REFERENCES:
- item->header.references = g_strdup (prop_data);
- break;
- case PR_IN_REPLY_TO_ID:
- item->header.in_reply_to = g_strdup (prop_data);
- break;
- case PR_TRANSPORT_MESSAGE_HEADERS:
- sv (item->header.transport_headers, utf8tolinux (prop_data));
- break;
- case PR_TRANSPORT_MESSAGE_HEADERS_UNICODE:
- sv (item->header.transport_headers, g_strdup (prop_data));
- break;
- default:
- found = FALSE;
- break;
- }
-
- #undef sv
-
- return found;
-}
-
static gboolean
fetch_items_summary_cb (FetchItemsCallbackData *item_data, gpointer data)
{
@@ -270,7 +165,7 @@ fetch_items_summary_cb (FetchItemsCallbackData *item_data, gpointer data)
guint32 j = 0;
NTTIME ntdate;
- MapiItem *item = g_new0(MapiItem , 1);
+ MailItem *item = g_new0(MailItem , 1);
if (camel_debug_start("mapi:folder")) {
exchange_mapi_debug_property_dump (item_data->properties);
@@ -286,7 +181,7 @@ fetch_items_summary_cb (FetchItemsCallbackData *item_data, gpointer data)
for (j = 0; j < item_data->properties->cValues; j++) {
gconstpointer prop_data = get_mapi_SPropValue_data(&item_data->properties->lpProps[j]);
- if (read_item_common (item, item_data->properties->lpProps[j].ulPropTag, prop_data))
+ if (fetch_read_item_common_data (item, item_data->properties->lpProps[j].ulPropTag, prop_data))
continue;
switch (item_data->properties->lpProps[j].ulPropTag) {
@@ -339,7 +234,7 @@ fetch_items_summary_cb (FetchItemsCallbackData *item_data, gpointer data)
if ((item_data->index % SUMMARY_FETCH_BATCH_COUNT == 0) ||
item_data->index == item_data->total-1) {
mapi_update_cache (fi_data->folder, *slist, &fi_data->changes, NULL, false);
- g_slist_foreach (*slist, (GFunc)mapi_item_free, NULL);
+ g_slist_foreach (*slist, (GFunc)mail_item_free, NULL);
g_slist_free (*slist);
*slist = NULL;
}
@@ -464,8 +359,8 @@ mapi_update_cache (CamelFolder *folder, GSList *list, CamelFolderChangeInfo **ch
camel_folder_get_name (folder));
for (; item_list != NULL; item_list = g_slist_next (item_list) ) {
- MapiItem *temp_item;
- MapiItem *item;
+ MailItem *temp_item;
+ MailItem *item;
gchar *msg_uid;
guint64 id;
@@ -473,7 +368,7 @@ mapi_update_cache (CamelFolder *folder, GSList *list, CamelFolderChangeInfo **ch
status_flags = 0;
if (uid_flag == FALSE) {
- temp_item = (MapiItem *)item_list->data;
+ temp_item = (MailItem *)item_list->data;
id = temp_item->mid;
item = temp_item;
}
@@ -1181,589 +1076,11 @@ end1:
if (is_locked)
camel_service_unlock (CAMEL_SERVICE (mapi_store), CAMEL_SERVICE_REC_CONNECT_LOCK);
- g_slist_foreach (fetch_data->items_list, (GFunc) mapi_item_free, NULL);
+ g_slist_foreach (fetch_data->items_list, (GFunc) mail_item_free, NULL);
g_slist_free (fetch_data->items_list);
g_free (fetch_data);
}
-static gboolean
-mapi_camel_get_item_prop_list (ExchangeMapiConnection *conn, mapi_id_t fid, TALLOC_CTX *mem_ctx, struct SPropTagArray *props, gpointer data)
-{
- static const uint32_t item_props[] = {
- PR_FID,
- PR_MID,
- PR_INTERNET_CPID,
-
- PR_TRANSPORT_MESSAGE_HEADERS_UNICODE,
- PR_MESSAGE_CLASS,
- PR_MESSAGE_SIZE,
- PR_MESSAGE_FLAGS,
- PR_MESSAGE_DELIVERY_TIME,
- PR_MSG_EDITOR_FORMAT,
-
- PR_SUBJECT_UNICODE,
- PR_CONVERSATION_TOPIC_UNICODE,
-
- /*Properties used for message threading.*/
- PR_INTERNET_MESSAGE_ID,
- PR_INTERNET_REFERENCES,
- PR_IN_REPLY_TO_ID,
-
- PR_BODY,
- PR_BODY_UNICODE,
- PR_HTML,
- /*Fixme : If this property is fetched, it garbles everything else. */
- /*PR_BODY_HTML, */
- /*PR_BODY_HTML_UNICODE, */
-
- PR_DISPLAY_TO_UNICODE,
- PR_DISPLAY_CC_UNICODE,
- PR_DISPLAY_BCC_UNICODE,
-
- PR_CREATION_TIME,
- PR_LAST_MODIFICATION_TIME,
- PR_PRIORITY,
- PR_SENSITIVITY,
- PR_START_DATE,
- PR_END_DATE,
- PR_RESPONSE_REQUESTED,
- PR_OWNER_APPT_ID,
- PR_PROCESSED,
-
- PR_SENT_REPRESENTING_NAME_UNICODE,
- PR_SENT_REPRESENTING_ADDRTYPE_UNICODE,
- PR_SENT_REPRESENTING_EMAIL_ADDRESS_UNICODE,
-
- PR_SENDER_NAME_UNICODE,
- PR_SENDER_ADDRTYPE_UNICODE,
- PR_SENDER_EMAIL_ADDRESS_UNICODE,
-
- PR_RCVD_REPRESENTING_NAME_UNICODE,
- PR_RCVD_REPRESENTING_ADDRTYPE_UNICODE,
- PR_RCVD_REPRESENTING_EMAIL_ADDRESS_UNICODE
- };
-
- g_return_val_if_fail (props != NULL, FALSE);
-
- return exchange_mapi_utils_add_props_to_props_array (mem_ctx, props, item_props, G_N_ELEMENTS (item_props));
-}
-
-static gboolean
-fetch_item_cb (FetchItemsCallbackData *item_data, gpointer data)
-{
- long *flags;
- struct FILETIME *delivery_date;
- const gchar *msg_class;
- NTTIME ntdate;
- ExchangeMAPIStream *body;
-
- MapiItem *item = g_new0(MapiItem , 1);
- MapiItem **i = (MapiItem **)data;
- guint32 j = 0;
-
- if (camel_debug_start("mapi:folder")) {
- exchange_mapi_debug_property_dump (item_data->properties);
- camel_debug_end();
- }
-
- item->fid = item_data->fid;
- item->mid = item_data->mid;
-
- /*Hold a reference to Recipient List*/
- item->recipients = item_data->recipients;
-
- for (j = 0; j < item_data->properties->cValues; j++) {
-
- gconstpointer prop_data = get_mapi_SPropValue_data(&item_data->properties->lpProps[j]);
-
- if (read_item_common (item, item_data->properties->lpProps[j].ulPropTag, prop_data))
- continue;
-
- switch (item_data->properties->lpProps[j].ulPropTag) {
- case PR_MESSAGE_CLASS:
- case PR_MESSAGE_CLASS_UNICODE:
- msg_class = (const gchar *) prop_data;
- break;
- case PR_MESSAGE_DELIVERY_TIME:
- delivery_date = (struct FILETIME *) prop_data;
- break;
- case PR_MESSAGE_FLAGS:
- flags = (long *) prop_data;
- break;
- default:
- break;
- }
- }
-
- item->is_cal = FALSE;
- if (g_str_has_prefix (msg_class, IPM_SCHEDULE_MEETING_PREFIX)) {
- guint8 *appointment_body_str = (guint8 *) exchange_mapi_cal_util_camel_helper (item_data->conn, item_data->fid, item_data->mid, msg_class,
- item_data->streams, item_data->recipients, item_data->attachments);
-
- if (appointment_body_str && *appointment_body_str) {
- body = g_new0(ExchangeMAPIStream, 1);
- body->proptag = PR_BODY_UNICODE;
- body->value = g_byte_array_new ();
- body->value = g_byte_array_append (body->value, appointment_body_str, strlen ((const gchar *)appointment_body_str));
-
- item->msg.body_parts = g_slist_append (item->msg.body_parts, body);
- item->is_cal = TRUE;
- }
-
- g_free (appointment_body_str);
- }
-
- if (!item->is_cal) {
- /* always prefer unicode version, as that can be properly read */
- if (!(body = exchange_mapi_util_find_stream (item_data->streams, PR_BODY_UNICODE)))
- body = exchange_mapi_util_find_stream (item_data->streams, PR_BODY);
-
- if (body)
- item->msg.body_parts = g_slist_append (item->msg.body_parts, body);
-
- body = exchange_mapi_util_find_stream (item_data->streams, PR_HTML);
- if (body)
- item->msg.body_parts = g_slist_append (item->msg.body_parts, body);
- }
-
- if (delivery_date) {
- ntdate = delivery_date->dwHighDateTime;
- ntdate = ntdate << 32;
- ntdate |= delivery_date->dwLowDateTime;
- item->header.recieved_time = nt_time_to_unix(ntdate);
- }
-
- if ((*flags & MSGFLAG_READ) != 0)
- item->header.flags |= CAMEL_MESSAGE_SEEN;
- if ((*flags & MSGFLAG_HASATTACH) != 0)
- item->header.flags |= CAMEL_MESSAGE_ATTACHMENTS;
-
- item->attachments = item_data->attachments;
-
- *i = item;
-
- return TRUE;
-}
-
-static void
-mapi_mime_set_recipient_list (CamelMimeMessage *msg, MapiItem *item)
-{
- GSList *l = NULL;
- CamelInternetAddress *to_addr, *cc_addr, *bcc_addr;
-
- g_return_if_fail (item->recipients != NULL);
-
- to_addr = camel_internet_address_new ();
- cc_addr = camel_internet_address_new ();
- bcc_addr = camel_internet_address_new ();
-
- for (l = item->recipients; l; l=l->next) {
- gchar *display_name;
- const gchar *name = NULL;
- uint32_t rcpt_type = MAPI_TO;
- uint32_t *type = NULL;
- struct SRow *aRow;
- ExchangeMAPIRecipient *recip = (ExchangeMAPIRecipient *)(l->data);
-
- /*Can't continue when there is no email-id*/
- if (!recip->email_id)
- continue;
-
- /* Build a SRow structure */
- aRow = &recip->out_SRow;
-
- /*Name is probably available in one of these props.*/
- name = (const gchar *) exchange_mapi_util_find_row_propval (aRow, PR_DISPLAY_NAME_UNICODE);
- name = name ? name : (const gchar *) exchange_mapi_util_find_row_propval (aRow, PR_RECIPIENT_DISPLAY_NAME_UNICODE);
- name = name ? name : (const gchar *) exchange_mapi_util_find_row_propval (aRow, PR_7BIT_DISPLAY_NAME_UNICODE);
-
- type = (uint32_t *) exchange_mapi_util_find_row_propval (aRow, PR_RECIPIENT_TYPE);
-
- /*Fallbacks. Not good*/
- display_name = name ? g_strdup (name) : g_strdup (recip->email_id);
- rcpt_type = (type ? *type : MAPI_TO);
-
- switch (rcpt_type) {
- case MAPI_TO:
- camel_internet_address_add (to_addr, display_name, recip->email_id);
- break;
- case MAPI_CC:
- camel_internet_address_add (cc_addr, display_name, recip->email_id);
- break;
- case MAPI_BCC:
- camel_internet_address_add (bcc_addr, display_name, recip->email_id);
- break;
- }
-
- g_free (display_name);
- }
-
- /*Add to message*/
- /*Note : To field is added from PR_TRANSPORT_MESSAGE_HEADERS
- But, in sent_items folder we don't get TRANSPORT_MESSAGE_HEADERS */
- if (!item->header.transport_headers) {
- camel_mime_message_set_recipients(msg, "To", to_addr);
- camel_mime_message_set_recipients(msg, "Cc", cc_addr);
- camel_mime_message_set_recipients(msg, "Bcc", bcc_addr);
- }
-
- /*TODO : Unref *_addr ? */
-}
-
-static void
-mapi_mime_set_msg_headers (CamelFolder *folder, CamelMimeMessage *msg, MapiItem *item)
-{
- gchar *temp_str = NULL;
- const gchar *from_email;
- time_t recieved_time;
- CamelInternetAddress *addr = NULL;
- CamelMapiStore *mapi_store;
- CamelStore *parent_store;
- gint offset = 0;
- time_t actual_time;
-
- parent_store = camel_folder_get_parent_store (folder);
- mapi_store = CAMEL_MAPI_STORE (parent_store);
-
- /* Setting headers from PR_TRANSPORT_MESSAGE_HEADERS */
- if (item->header.transport_headers) {
- CamelMimePart *part = camel_mime_part_new ();
- CamelStream *stream;
- CamelMimeParser *parser;
-
- stream = camel_stream_mem_new_with_buffer (item->header.transport_headers, strlen (item->header.transport_headers));
- parser = camel_mime_parser_new ();
- camel_mime_parser_init_with_stream (parser, stream);
- camel_mime_parser_scan_from (parser, FALSE);
- g_object_unref (stream);
-
- if (camel_mime_part_construct_from_parser (part, parser) != -1) {
- struct _camel_header_raw *h;
-
- for (h = part->headers; h; h = h->next) {
- const gchar *value = h->value;
-
- /* skip all headers describing content of a message,
- because it's overwritten on message decomposition */
- if (g_ascii_strncasecmp (h->name, "Content", 7) == 0)
- continue;
-
- while (value && camel_mime_is_lwsp (*value))
- value++;
-
- camel_medium_add_header (CAMEL_MEDIUM (msg), h->name, value);
- }
- }
-
- g_object_unref (parser);
- g_object_unref (part);
- }
-
- /* Overwrite headers if we have specific properties available*/
- temp_str = item->header.subject;
- if (temp_str)
- camel_mime_message_set_subject (msg, temp_str);
-
- recieved_time = item->header.recieved_time;
-
- actual_time = camel_header_decode_date (ctime(&recieved_time), &offset);
- /* camel_mime_message_set_date (msg, actual_time, offset); */
-
- if (item->header.from) {
- if ((item->header.from_type != NULL) && !g_utf8_collate (item->header.from_type, "EX")) {
- camel_service_lock (CAMEL_SERVICE (mapi_store), CAMEL_SERVICE_REC_CONNECT_LOCK);
- from_email = exchange_mapi_connection_ex_to_smtp (camel_mapi_store_get_exchange_connection (mapi_store), item->header.from_email);
- camel_service_unlock (CAMEL_SERVICE (mapi_store), CAMEL_SERVICE_REC_CONNECT_LOCK);
- g_free (item->header.from_email);
- item->header.from_email = g_strdup (from_email);
- }
-
- item->header.from_email = item->header.from_email ?
- item->header.from_email : item->header.from;
-
- /* add reply to */
- addr = camel_internet_address_new();
- camel_internet_address_add(addr, item->header.from, item->header.from_email);
- camel_mime_message_set_reply_to(msg, addr);
-
- /* add from */
- addr = camel_internet_address_new();
- camel_internet_address_add(addr, item->header.from, item->header.from_email);
- camel_mime_message_set_from(msg, addr);
- }
-
- /* Threading */
- if (item->header.message_id)
- camel_medium_add_header (CAMEL_MEDIUM (msg), "Message-ID", item->header.message_id);
-
- if (item->header.references)
- camel_medium_add_header (CAMEL_MEDIUM (msg), "References", item->header.references);
-
- if (item->header.in_reply_to)
- camel_medium_add_header (CAMEL_MEDIUM (msg), "In-Reply-To", item->header.in_reply_to);
-
-}
-
-static CamelMimePart *
-mapi_mime_msg_body (MapiItem *item, const ExchangeMAPIStream *body)
-{
- CamelMimePart *part = camel_mime_part_new ();
- camel_mime_part_set_encoding (part, CAMEL_TRANSFER_ENCODING_8BIT);
-
- if (body && body->value && body->value->len > 0) {
- const gchar * type = NULL;
- gchar *buff = NULL;
-
- if (item->is_cal)
- type = "text/calendar";
- else
- type = (body->proptag == PR_BODY || body->proptag == PR_BODY_UNICODE) ?
- "text/plain" : "text/html";
-
- if (item->header.cpid) {
- if (item->header.cpid >= 28591 && item->header.cpid <= 28599)
- buff = g_strdup_printf ("%s; charset=\"ISO-8859-%d\"", type, item->header.cpid % 10);
- else if (item->header.cpid == 28603)
- buff = g_strdup_printf ("%s; charset=\"ISO-8859-13\"", type);
- else if (item->header.cpid == 28605)
- buff = g_strdup_printf ("%s; charset=\"ISO-8859-15\"", type);
- else if (item->header.cpid == 65000)
- buff = g_strdup_printf ("%s; charset=\"UTF-7\"", type);
- else if (item->header.cpid == 65001)
- buff = g_strdup_printf ("%s; charset=\"UTF-8\"", type);
- else
- buff = g_strdup_printf ("%s; charset=\"CP%d\"", type, item->header.cpid);
- type = buff;
- }
-
- camel_mime_part_set_content (part, (const gchar *) body->value->data, body->value->len, type);
-
- g_free (buff);
- } else
- camel_mime_part_set_content (part, " ", strlen (" "), "text/plain");
-
- return part;
-}
-
-#if 0
-
-/* GCompareFunc. Used for ordering body types in a GSList.*/
-static gint
-sort_bodies_cb (gconstpointer a, gconstpointer b)
-{
- static const gint desired_order[] = { PR_BODY, PR_BODY_UNICODE, PR_HTML };
- const ExchangeMAPIStream *stream_a = a, *stream_b = b;
- gint aidx, bidx;
-
- if (a == b)
- return 0;
- if (!a)
- return -1;
- if (!b)
- return 1;
-
- for (aidx = 0; aidx < G_N_ELEMENTS (desired_order); aidx++) {
- if (desired_order[aidx] == stream_a->proptag)
- break;
- }
-
- for (bidx = 0; bidx < G_N_ELEMENTS (desired_order); bidx++) {
- if (desired_order[bidx] == stream_b->proptag)
- break;
- }
-
- return aidx - bidx;
-}
-
-#endif
-
-/* Adds parts to multipart. Convenience function. */
-static void
-mapi_mime_multipart_add_attachments (CamelMultipart *multipart, GSList *attachs)
-{
- CamelMimePart *part;
- while (attachs) {
- part = attachs->data;
- camel_multipart_add_part (multipart, part);
- g_object_unref (part);
- attachs = attachs->next;
- }
-}
-
-/* Process body stream and related objects into a MIME mulitpart */
-static CamelMultipart *
-mapi_mime_build_multipart_related (MapiItem *item, const ExchangeMAPIStream *stream,
- GSList *inline_attachs)
-{
- CamelMimePart *part;
- CamelMultipart *m_related = camel_multipart_new ();
- camel_data_wrapper_set_mime_type (CAMEL_DATA_WRAPPER (m_related), "multipart/related");
- camel_multipart_set_boundary (m_related, NULL);
-
- part = mapi_mime_msg_body (item, stream);
- camel_multipart_add_part (m_related, part);
- g_object_unref (part);
-
- mapi_mime_multipart_add_attachments (m_related, inline_attachs);
-
- return m_related;
-}
-
-/* Process multiple body types and pack them in a MIME mulitpart */
-static CamelMultipart *
-mapi_mime_build_multipart_alternative (MapiItem *item, GSList *body_parts, GSList *inline_attachs)
-{
- CamelMimePart *part;
- CamelMultipart *m_alternative = camel_multipart_new ();
- camel_data_wrapper_set_mime_type (CAMEL_DATA_WRAPPER (m_alternative),
- "multipart/alternative");
- camel_multipart_set_boundary (m_alternative, NULL);
-
- while (body_parts) {
- const ExchangeMAPIStream *stream = (ExchangeMAPIStream *) body_parts->data;
- part = camel_mime_part_new ();
- if ((stream->proptag == PR_HTML || stream->proptag == PR_BODY_HTML_UNICODE)
- && inline_attachs) {
- CamelMultipart *m_related;
- m_related = mapi_mime_build_multipart_related (item, stream,
- inline_attachs);
- camel_medium_set_content (CAMEL_MEDIUM (part),
- CAMEL_DATA_WRAPPER (m_related));
- g_object_unref (m_related);
- } else
- part = mapi_mime_msg_body (item, stream);
-
- camel_multipart_add_part (m_alternative, part);
- g_object_unref (part);
- }
-
- return m_alternative;
-}
-
-static CamelMultipart *
-mapi_mime_build_multipart_mixed (CamelMultipart *content, GSList *attachs)
-{
- CamelMimePart *part = camel_mime_part_new ();
- CamelMultipart *m_mixed = camel_multipart_new ();
- camel_data_wrapper_set_mime_type (CAMEL_DATA_WRAPPER (m_mixed),
- "multipart/mixed");
- camel_multipart_set_boundary (m_mixed, NULL);
-
- camel_medium_set_content (CAMEL_MEDIUM (part), CAMEL_DATA_WRAPPER (content));
- camel_multipart_add_part (m_mixed, part);
-
- if (attachs)
- mapi_mime_multipart_add_attachments (m_mixed, attachs);
-
- return m_mixed;
-}
-
-/*Takes raw attachment streams and converts to MIME Parts. Parts are added to
- either inline / non-inline lists.*/
-static void
-mapi_mime_classify_attachments (GSList *attachments, GSList **inline_attachs, GSList **noninline)
-{
- for (;attachments != NULL; attachments = attachments->next) {
- ExchangeMAPIAttachment *attach = (ExchangeMAPIAttachment *)attachments->data;
- ExchangeMAPIStream *stream = NULL;
- const gchar *filename, *mime_type, *content_id = NULL;
- CamelContentType *content_type;
- CamelMimePart *part;
-
- stream = exchange_mapi_util_find_stream (attach->streams, PR_ATTACH_DATA_BIN);
-
- if (!stream || stream->value->len <= 0) {
- continue;
- }
-
- part = camel_mime_part_new ();
-
- filename = (const gchar *) exchange_mapi_util_find_SPropVal_array_propval(attach->lpProps,
- PR_ATTACH_LONG_FILENAME_UNICODE);
-
- if (!(filename && *filename))
- filename = (const gchar *) exchange_mapi_util_find_SPropVal_array_propval(attach->lpProps,
- PR_ATTACH_FILENAME_UNICODE);
- camel_mime_part_set_filename(part, g_strdup(filename));
- camel_content_type_set_param (((CamelDataWrapper *) part)->mime_type, "name", filename);
-
- /*Content-Type*/
- mime_type = (const gchar *) exchange_mapi_util_find_SPropVal_array_propval (attach->lpProps, PR_ATTACH_MIME_TAG);
- if (!mime_type)
- mime_type = "application/octet-stream";
-
- camel_mime_part_set_content (part, (const gchar *) stream->value->data, stream->value->len, mime_type);
-
- content_type = camel_mime_part_get_content_type (part);
- if (content_type && camel_content_type_is (content_type, "text", "*"))
- camel_mime_part_set_encoding (part, CAMEL_TRANSFER_ENCODING_QUOTEDPRINTABLE);
- else
- camel_mime_part_set_encoding (part, CAMEL_TRANSFER_ENCODING_BASE64);
-
- /*Content-ID*/
- content_id = (const gchar *) exchange_mapi_util_find_SPropVal_array_propval(attach->lpProps,
- PR_ATTACH_CONTENT_ID);
- /* TODO : Add disposition */
- if (content_id) {
- camel_mime_part_set_content_id (part, content_id);
- *inline_attachs = g_slist_append (*inline_attachs, part);
- } else
- *noninline = g_slist_append (*noninline, part);
- }
-}
-
-static CamelMimeMessage *
-mapi_folder_item_to_msg( CamelFolder *folder, MapiItem *item, CamelException *ex )
-{
- CamelMimeMessage *msg = NULL;
- CamelMultipart *multipart_body = NULL;
-
- GSList *attach_list = NULL;
- GSList *inline_attachs = NULL; /*Used for mulitpart/related*/
- GSList *noninline_attachs = NULL;
-
- gboolean build_alternative = FALSE;
- gboolean build_related = FALSE;
-
- attach_list = item->attachments;
- msg = camel_mime_message_new ();
-
- mapi_mime_set_recipient_list (msg, item);
- mapi_mime_set_msg_headers (folder, msg, item);
- mapi_mime_classify_attachments (attach_list, &inline_attachs, &noninline_attachs);
-
- build_alternative = (g_slist_length (item->msg.body_parts) > 1) && inline_attachs;
- build_related = !build_alternative && inline_attachs;
-
- if (build_alternative) {
- multipart_body = mapi_mime_build_multipart_alternative (item, item->msg.body_parts,
- inline_attachs);
- } else if (build_related) {
- multipart_body = mapi_mime_build_multipart_related (item,
- item->msg.body_parts->data,
- inline_attachs);
- } else { /* Simple multipart/mixed */
- CamelMimePart *part;
- multipart_body = camel_multipart_new ();
- camel_data_wrapper_set_mime_type (CAMEL_DATA_WRAPPER (multipart_body),
- "multipart/mixed");
- camel_multipart_set_boundary (multipart_body, NULL);
- part = mapi_mime_msg_body (item, item->msg.body_parts ? item->msg.body_parts->data : NULL);
- camel_multipart_add_part (multipart_body, part);
- g_object_unref (part);
- }
-
- if (noninline_attachs) { /* multipart/mixed */
- multipart_body = mapi_mime_build_multipart_mixed (multipart_body,
- noninline_attachs);
- }
-
- camel_medium_set_content (CAMEL_MEDIUM (msg), CAMEL_DATA_WRAPPER(multipart_body));
- g_object_unref (multipart_body);
-
- return msg;
-}
-
static CamelMimeMessage *
mapi_folder_get_message( CamelFolder *folder, const gchar *uid, CamelException *ex )
{
@@ -1775,7 +1092,7 @@ mapi_folder_get_message( CamelFolder *folder, const gchar *uid, CamelException *
CamelStore *parent_store;
mapi_id_t id_folder;
mapi_id_t id_message;
- MapiItem *item = NULL;
+ MailItem *item = NULL;
guint32 options = 0;
parent_store = camel_folder_get_parent_store (folder);
@@ -1852,8 +1169,8 @@ mapi_folder_get_message( CamelFolder *folder, const gchar *uid, CamelException *
camel_service_lock (CAMEL_SERVICE (mapi_store), CAMEL_SERVICE_REC_CONNECT_LOCK);
exchange_mapi_connection_fetch_item (camel_mapi_store_get_exchange_connection (mapi_store), id_folder, id_message,
- mapi_camel_get_item_prop_list, NULL,
- fetch_item_cb, &item,
+ mapi_mail_get_item_prop_list, NULL,
+ fetch_props_to_mail_item_cb, &item,
options);
camel_service_unlock (CAMEL_SERVICE (mapi_store), CAMEL_SERVICE_REC_CONNECT_LOCK);
@@ -1863,8 +1180,8 @@ mapi_folder_get_message( CamelFolder *folder, const gchar *uid, CamelException *
return NULL;
}
- msg = mapi_folder_item_to_msg (folder, item, ex);
- mapi_item_free (item);
+ msg = mapi_mail_item_to_mime_message (camel_mapi_store_get_exchange_connection (mapi_store), item);
+ mail_item_free (item);
if (!msg) {
camel_exception_set (ex, CAMEL_EXCEPTION_SERVICE_INVALID, _("Could not get message"));
@@ -2148,7 +1465,7 @@ mapi_append_message (CamelFolder *folder, CamelMimeMessage *message,
CamelAddress *from = NULL;
CamelStoreInfo *si;
CamelStore *parent_store;
- MapiItem *item = NULL;
+ MailItem *item = NULL;
mapi_id_t fid = 0, mid = 0;
const gchar *folder_id;
const gchar *full_name;
diff --git a/src/camel/camel-mapi-folder.h b/src/camel/camel-mapi-folder.h
index 09d49d5..94773be 100644
--- a/src/camel/camel-mapi-folder.h
+++ b/src/camel/camel-mapi-folder.h
@@ -55,61 +55,6 @@
G_BEGIN_DECLS
-typedef enum {
- MAPI_ITEM_TYPE_MAIL=1,
- MAPI_ITEM_TYPE_APPOINTMENT,
- MAPI_ITEM_TYPE_CONTACT,
- MAPI_ITEM_TYPE_JOURNAL,
- MAPI_ITEM_TYPE_TASK
-} MapiItemType;
-
-typedef enum {
- PART_TYPE_PLAIN_TEXT=1,
- PART_TYPE_TEXT_HTML
-} MapiItemPartType;
-
-typedef struct {
- gchar *subject;
- gchar *from;
- gchar *from_email;
- gchar *from_type;
-
- gchar *references;
- gchar *message_id;
- gchar *in_reply_to;
- /*TODO : Obsolete this. Moved to recipient list*/
- gchar *to;
- gchar *cc;
- gchar *bcc;
-
- gint flags;
- glong size;
- time_t recieved_time;
- time_t send_time;
- guint cpid; /* codepage id */
- gchar *transport_headers;
-} MapiItemHeader;
-
-typedef struct {
- GSList *body_parts;
-} MapiItemMessage;
-
-typedef struct {
- mapi_id_t fid;
- mapi_id_t mid;
-
- MapiItemHeader header;
- MapiItemMessage msg;
-
- gboolean is_cal;
-
- GSList *recipients;
- GSList *attachments;
- GSList *generic_streams;
-}MapiItem;
-
-void mapi_item_free (MapiItem *item);
-
typedef struct _CamelMapiFolder CamelMapiFolder;
typedef struct _CamelMapiFolderClass CamelMapiFolderClass;
typedef struct _CamelMapiFolderPrivate CamelMapiFolderPrivate;
diff --git a/src/camel/camel-mapi-transport.c b/src/camel/camel-mapi-transport.c
index 827a833..bf8c1e6 100644
--- a/src/camel/camel-mapi-transport.c
+++ b/src/camel/camel-mapi-transport.c
@@ -46,6 +46,7 @@
#define d(x) x
#include <exchange-mapi-defs.h>
+#include "exchange-mapi-mail-utils.h"
#define STREAM_SIZE 4000
@@ -57,7 +58,7 @@ G_DEFINE_TYPE (CamelMapiTransport, camel_mapi_transport, CAMEL_TYPE_TRANSPORT)
/*CreateItem would return the MID of the new message or '0' if we fail.*/
static mapi_id_t
-mapi_message_item_send (ExchangeMapiConnection *conn, MapiItem *item)
+mapi_message_item_send (ExchangeMapiConnection *conn, MailItem *item)
{
guint64 fid = 0;
mapi_id_t mid = 0;
@@ -74,7 +75,7 @@ mapi_send_to (CamelTransport *transport, CamelMimeMessage *message,
CamelAddress *from, CamelAddress *recipients, CamelException *ex)
{
ExchangeMapiConnection *conn;
- MapiItem *item = NULL;
+ MailItem *item = NULL;
const gchar *namep;
const gchar *addressp;
mapi_id_t st = 0;
@@ -95,7 +96,7 @@ mapi_send_to (CamelTransport *transport, CamelMimeMessage *message,
return FALSE;
}
- /* Convert MIME to MAPIItem, attacment lists and recipient list.*/
+ /* Convert MIME to MailItem, attacment lists and recipient list.*/
item = camel_mapi_utils_mime_to_item (message, from, ex);
/* send */
diff --git a/src/camel/camel-mapi-utils.c b/src/camel/camel-mapi-utils.c
index 660063c..89af5d0 100644
--- a/src/camel/camel-mapi-utils.c
+++ b/src/camel/camel-mapi-utils.c
@@ -38,6 +38,7 @@
#include <exchange-mapi-defs.h>
#include "exchange-mapi-utils.h"
+#include "exchange-mapi-mail-utils.h"
#include "camel-mapi-store.h"
#include "camel-mapi-folder.h"
@@ -49,7 +50,7 @@
#define STREAM_SIZE 4000
static void
-mapi_item_add_recipient (const gchar *recipients, OlMailRecipientType type, GSList **recipient_list)
+mail_item_add_recipient (const gchar *recipients, OlMailRecipientType type, GSList **recipient_list)
{
ExchangeMAPIRecipient *recipient;
uint32_t val = 0;
@@ -97,7 +98,7 @@ mapi_item_add_recipient (const gchar *recipients, OlMailRecipientType type, GSLi
}
static void
-mapi_item_set_from(MapiItem *item, const gchar *from)
+mail_item_set_from(MailItem *item, const gchar *from)
{
if (item->header.from)
g_free (item->header.from);
@@ -106,7 +107,7 @@ mapi_item_set_from(MapiItem *item, const gchar *from)
}
static void
-mapi_item_set_subject(MapiItem *item, const gchar *subject)
+mail_item_set_subject(MailItem *item, const gchar *subject)
{
if (item->header.subject)
g_free (item->header.subject);
@@ -117,7 +118,7 @@ mapi_item_set_subject(MapiItem *item, const gchar *subject)
#define MAX_READ_SIZE 0x1000
static void
-mapi_item_set_body_stream (MapiItem *item, CamelStream *body, MapiItemPartType part_type)
+mail_item_set_body_stream (MailItem *item, CamelStream *body, MailItemPartType part_type)
{
guint8 *buf = g_new0 (guint8 , STREAM_SIZE);
guint32 read_size = 0, i;
@@ -179,7 +180,7 @@ mapi_item_set_body_stream (MapiItem *item, CamelStream *body, MapiItemPartType p
}
static gboolean
-mapi_item_add_attach (MapiItem *item, CamelMimePart *part, CamelStream *content_stream)
+mail_item_add_attach (MailItem *item, CamelMimePart *part, CamelStream *content_stream)
{
guint8 *buf = g_new0 (guint8 , STREAM_SIZE);
const gchar *content_id = NULL;
@@ -252,7 +253,7 @@ mapi_item_add_attach (MapiItem *item, CamelMimePart *part, CamelStream *content_
}
static gboolean
-mapi_do_multipart (CamelMultipart *mp, MapiItem *item, gboolean *is_first)
+mapi_do_multipart (CamelMultipart *mp, MailItem *item, gboolean *is_first)
{
CamelDataWrapper *dw;
CamelStream *content_stream;
@@ -291,19 +292,19 @@ mapi_do_multipart (CamelMultipart *mp, MapiItem *item, gboolean *is_first)
type = camel_mime_part_get_content_type(part);
if (i_part == 0 && (*is_first) && camel_content_type_is (type, "text", "plain")) {
- mapi_item_set_body_stream (item, content_stream, PART_TYPE_PLAIN_TEXT);
+ mail_item_set_body_stream (item, content_stream, PART_TYPE_PLAIN_TEXT);
*is_first = FALSE;
} else if (camel_content_type_is (type, "text", "html")) {
- mapi_item_set_body_stream (item, content_stream, PART_TYPE_TEXT_HTML);
+ mail_item_set_body_stream (item, content_stream, PART_TYPE_TEXT_HTML);
} else {
- mapi_item_add_attach (item, part, content_stream);
+ mail_item_add_attach (item, part, content_stream);
}
}
return TRUE;
}
-MapiItem *
+MailItem *
camel_mapi_utils_mime_to_item (CamelMimeMessage *message, CamelAddress *from, CamelException *ex)
{
CamelDataWrapper *dw = NULL;
@@ -311,7 +312,7 @@ camel_mapi_utils_mime_to_item (CamelMimeMessage *message, CamelAddress *from, Ca
CamelStream *content_stream;
CamelMultipart *multipart;
CamelInternetAddress *to, *cc, *bcc;
- MapiItem *item = g_new0 (MapiItem, 1);
+ MailItem *item = g_new0 (MailItem, 1);
const gchar *namep;
const gchar *addressp;
const gchar *content_type;
@@ -333,25 +334,25 @@ camel_mapi_utils_mime_to_item (CamelMimeMessage *message, CamelAddress *from, Ca
namep = NULL;
}
- mapi_item_set_from (item, namep);
+ mail_item_set_from (item, namep);
to = camel_mime_message_get_recipients(message, CAMEL_RECIPIENT_TYPE_TO);
for (i = 0; to && camel_internet_address_get (to, i, &namep, &addressp); i++) {
- mapi_item_add_recipient (addressp, olTo, &recipient_list);
+ mail_item_add_recipient (addressp, olTo, &recipient_list);
}
cc = camel_mime_message_get_recipients(message, CAMEL_RECIPIENT_TYPE_CC);
for (i = 0; cc && camel_internet_address_get (cc, i, &namep, &addressp); i++) {
- mapi_item_add_recipient (addressp, olCC, &recipient_list);
+ mail_item_add_recipient (addressp, olCC, &recipient_list);
}
bcc = camel_mime_message_get_recipients(message, CAMEL_RECIPIENT_TYPE_BCC);
for (i = 0; bcc && camel_internet_address_get (bcc, i, &namep, &addressp); i++) {
- mapi_item_add_recipient (addressp, olBCC, &recipient_list);
+ mail_item_add_recipient (addressp, olBCC, &recipient_list);
}
if (camel_mime_message_get_subject(message)) {
- mapi_item_set_subject(item, camel_mime_message_get_subject(message));
+ mail_item_set_subject(item, camel_mime_message_get_subject(message));
}
/*Add message threading properties */
@@ -375,7 +376,7 @@ camel_mapi_utils_mime_to_item (CamelMimeMessage *message, CamelAddress *from, Ca
content_stream = (CamelStream *)camel_stream_mem_new();
content_size = camel_data_wrapper_decode_to_stream(dw, (CamelStream *)content_stream);
- mapi_item_set_body_stream (item, content_stream, PART_TYPE_PLAIN_TEXT);
+ mail_item_set_body_stream (item, content_stream, PART_TYPE_PLAIN_TEXT);
}
}
@@ -388,7 +389,7 @@ gboolean
camel_mapi_utils_create_item_build_props (ExchangeMapiConnection *conn, mapi_id_t fid, TALLOC_CTX *mem_ctx, struct SPropValue **values, uint32_t *n_values, gpointer data)
{
- MapiItem *item = (MapiItem *) data;
+ MailItem *item = (MailItem *) data;
GSList *l;
bool send_rich_info;
uint32_t msgflag;
diff --git a/src/camel/camel-mapi-utils.h b/src/camel/camel-mapi-utils.h
index d28cfae..26ec846 100644
--- a/src/camel/camel-mapi-utils.h
+++ b/src/camel/camel-mapi-utils.h
@@ -26,7 +26,11 @@
G_BEGIN_DECLS
-MapiItem *
+#include <exchange-mapi-connection.h>
+#include <exchange-mapi-mail-utils.h>
+#include <camel/camel.h>
+
+MailItem *
camel_mapi_utils_mime_to_item (CamelMimeMessage *message, CamelAddress *from, CamelException *ex);
gboolean
diff --git a/src/libexchangemapi/Makefile.am b/src/libexchangemapi/Makefile.am
index 5466880..f4d5213 100644
--- a/src/libexchangemapi/Makefile.am
+++ b/src/libexchangemapi/Makefile.am
@@ -6,7 +6,8 @@ AM_CPPFLAGS = \
$(EVOLUTION_DATA_SERVER_CFLAGS) \
$(LIBEDATASERVER_CFLAGS) \
$(LIBECAL_CFLAGS) \
- $(LIBMAPI_CFLAGS)
+ $(LIBMAPI_CFLAGS) \
+ $(CAMEL_CFLAGS)
lib_LTLIBRARIES = libexchangemapi-1.0.la
@@ -28,14 +29,17 @@ libexchangemapi_1_0_la_SOURCES = \
exchange-mapi-cal-tz-utils.c \
exchange-mapi-cal-tz-utils.h \
exchange-mapi-cal-recur-utils.c \
- exchange-mapi-cal-recur-utils.h
+ exchange-mapi-cal-recur-utils.h \
+ exchange-mapi-mail-utils.c \
+ exchange-mapi-mail-utils.h
libexchangemapi_1_0_la_LIBADD = \
$(EVOLUTION_DATA_SERVER_LIBS) \
$(LIBEDATASERVER_LIBS) \
$(LIBECAL_LIBS) \
- $(LIBMAPI_LIBS)
+ $(LIBMAPI_LIBS) \
+ $(CAMEL_LIBS)
libexchangemapi_1_0_la_LDFLAGS = $(NO_UNDEFINED)
@@ -48,7 +52,8 @@ libexchangemapiinclude_HEADERS = \
exchange-mapi-utils.h \
exchange-mapi-cal-utils.h \
exchange-mapi-cal-tz-utils.h \
- exchange-mapi-cal-recur-utils.h
+ exchange-mapi-cal-recur-utils.h \
+ exchange-mapi-mail-utils.h
pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = libexchangemapi-$(EVO_MAPI_API_VERSION).pc
diff --git a/src/libexchangemapi/exchange-mapi-cal-utils.c b/src/libexchangemapi/exchange-mapi-cal-utils.c
index f930053..f329b88 100644
--- a/src/libexchangemapi/exchange-mapi-cal-utils.c
+++ b/src/libexchangemapi/exchange-mapi-cal-utils.c
@@ -1344,7 +1344,7 @@ fetch_camel_cal_comp_cb (FetchItemsCallbackData *item_data, gpointer data)
}
gchar *
-exchange_mapi_cal_util_camel_helper (ExchangeMapiConnection *conn, mapi_id_t orig_fid, mapi_id_t orig_mid, const gchar *msg_class,
+exchange_mapi_cal_util_camel_helper (ExchangeMapiConnection *conn, mapi_id_t orig_fid, mapi_id_t orig_mid, mapi_object_t *obj_message, const gchar *msg_class,
GSList *streams, GSList *recipients, GSList *attachments)
{
struct fetch_camel_cal_data fccd = { 0 };
@@ -1367,7 +1367,13 @@ exchange_mapi_cal_util_camel_helper (ExchangeMapiConnection *conn, mapi_id_t ori
} else
return NULL;
- exchange_mapi_connection_fetch_item (conn, orig_fid, orig_mid,
+ if (obj_message)
+ exchange_mapi_connection_fetch_object_props (conn, NULL, orig_fid, obj_message,
+ exchange_mapi_cal_utils_get_props_cb, GINT_TO_POINTER (fccd.kind),
+ fetch_camel_cal_comp_cb, &fccd,
+ MAPI_OPTIONS_FETCH_ALL);
+ else
+ exchange_mapi_connection_fetch_item (conn, orig_fid, orig_mid,
exchange_mapi_cal_utils_get_props_cb, GINT_TO_POINTER (fccd.kind),
fetch_camel_cal_comp_cb, &fccd,
MAPI_OPTIONS_FETCH_ALL);
diff --git a/src/libexchangemapi/exchange-mapi-cal-utils.h b/src/libexchangemapi/exchange-mapi-cal-utils.h
index 2d110e9..196abd8 100644
--- a/src/libexchangemapi/exchange-mapi-cal-utils.h
+++ b/src/libexchangemapi/exchange-mapi-cal-utils.h
@@ -91,7 +91,7 @@ void
exchange_mapi_cal_util_generate_globalobjectid (gboolean is_clean, const gchar *uid, struct Binary_r *sb);
gchar *
-exchange_mapi_cal_util_camel_helper (ExchangeMapiConnection *conn, mapi_id_t fid, mapi_id_t mid, const gchar *msg_class,
+exchange_mapi_cal_util_camel_helper (ExchangeMapiConnection *conn, mapi_id_t fid, mapi_id_t mid, mapi_object_t *obj_message, const gchar *msg_class,
GSList *streams, GSList *recipients, GSList *attachments);
uint32_t
diff --git a/src/libexchangemapi/exchange-mapi-connection.c b/src/libexchangemapi/exchange-mapi-connection.c
index e503bc9..e6dba42 100644
--- a/src/libexchangemapi/exchange-mapi-connection.c
+++ b/src/libexchangemapi/exchange-mapi-connection.c
@@ -26,9 +26,12 @@
#include <config.h>
#endif
+#include <camel/camel.h>
+
#include "exchange-mapi-connection.h"
#include "exchange-mapi-folder.h"
#include "exchange-mapi-utils.h"
+#include "exchange-mapi-mail-utils.h"
#include <param.h>
#define DEFAULT_PROF_PATH ".evolution/mapi-profiles.ldb"
@@ -802,9 +805,48 @@ exchange_mapi_util_set_attachments (mapi_object_t *obj_message, GSList *attach_l
return status;
}
+static GByteArray *
+obj_message_to_camel_mime (ExchangeMapiConnection *conn, mapi_id_t fid, mapi_object_t *obj_msg)
+{
+ GByteArray *res = NULL;
+ MailItem *item = NULL;
+ CamelMimeMessage *msg;
+
+ g_return_val_if_fail (conn != NULL, NULL);
+ g_return_val_if_fail (obj_msg != NULL, NULL);
+
+ if (!exchange_mapi_connection_fetch_object_props (conn, NULL, fid, obj_msg, mapi_mail_get_item_prop_list, NULL,
+ fetch_props_to_mail_item_cb, &item,
+ MAPI_OPTIONS_FETCH_ALL | MAPI_OPTIONS_GETBESTBODY)
+ || item == NULL) {
+ if (item)
+ mail_item_free (item);
+
+ return NULL;
+ }
+
+ msg = mapi_mail_item_to_mime_message (conn, item);
+ mail_item_free (item);
+
+ if (msg) {
+ CamelStream *mem = camel_stream_mem_new ();
+
+ res = g_byte_array_new ();
+
+ mem = camel_stream_mem_new ();
+ camel_stream_mem_set_byte_array (CAMEL_STREAM_MEM (mem), res);
+ camel_data_wrapper_write_to_stream (CAMEL_DATA_WRAPPER (msg), mem);
+
+ g_object_unref (mem);
+ g_object_unref (msg);
+ }
+
+ return res;
+}
+
/* Returns TRUE if all attachments were read succcesfully, else returns FALSE */
static gboolean
-exchange_mapi_util_get_attachments (mapi_object_t *obj_message, GSList **attach_list)
+exchange_mapi_util_get_attachments (ExchangeMapiConnection *conn, mapi_id_t fid, mapi_object_t *obj_message, GSList **attach_list)
{
enum MAPISTATUS retval;
TALLOC_CTX *mem_ctx;
@@ -880,19 +922,64 @@ exchange_mapi_util_get_attachments (mapi_object_t *obj_message, GSList **attach_
attachment = g_new0 (ExchangeMAPIAttachment, 1);
attachment->cValues = properties.cValues;
attachment->lpProps = g_new0 (struct SPropValue, attachment->cValues + 1);
- for (z=0; z < properties.cValues; z++)
+ for (z=0; z < properties.cValues; z++) {
cast_SPropValue (&properties.lpProps[z], &(attachment->lpProps[z]));
+ if ((attachment->lpProps[z].ulPropTag & 0xFFFF) == PT_STRING8) {
+ struct SPropValue *lpProps;
+ struct SPropTagArray *tags;
+ uint32_t prop_count = 0;
+
+ /* prefer unicode strings, if available */
+ tags = set_SPropTagArray (mem_ctx, 0x1, (attachment->lpProps[z].ulPropTag & 0xFFFF0000) | PT_UNICODE);
+ if (MAPI_E_SUCCESS == GetProps (&obj_attach, tags, &lpProps, &prop_count) && prop_count == 1 && lpProps) {
+ if ((lpProps->ulPropTag & 0xFFFF) == PT_UNICODE)
+ attachment->lpProps[z] = *lpProps;
+ }
+ MAPIFreeBuffer (tags);
+ }
+ }
+
/* just to get all the other streams */
for (z=0; z < properties.cValues; z++) {
if ((properties.lpProps[z].ulPropTag & 0xFFFF) == PT_BINARY)
exchange_mapi_util_read_generic_stream (&obj_attach, properties.lpProps[z].ulPropTag, &(attachment->streams));
}
- /* HACK */
ui32 = (const uint32_t *) get_SPropValue_SRow_data(&rows_attach.aRow[i_row_attach], PR_ATTACH_METHOD);
- if (ui32 && *ui32 == ATTACH_BY_VALUE)
+ if (ui32 && *ui32 == ATTACH_BY_VALUE) {
exchange_mapi_util_read_generic_stream (&obj_attach, PR_ATTACH_DATA_BIN, &(attachment->streams));
+ } else if (ui32 && *ui32 == ATTACH_EMBEDDED_MSG) {
+ mapi_object_t obj_emb_msg;
+
+ mapi_object_init (&obj_emb_msg);
+
+ if (OpenEmbeddedMessage (&obj_attach, &obj_emb_msg, MAPI_READONLY) == MAPI_E_SUCCESS) {
+ /* very the same is in camel-mapi-folder.c, how I hate diplicating the code */
+ GByteArray *bytes;
+
+ bytes = obj_message_to_camel_mime (conn, fid, &obj_emb_msg);
+ if (bytes) {
+ ExchangeMAPIStream *stream = g_new0 (ExchangeMAPIStream, 1);
+ struct mapi_SPropValue_array properties_array;
+
+ stream->value = bytes;
+
+ /* Build a mapi_SPropValue_array structure */
+ properties_array.cValues = 1;
+ properties_array.lpProps = talloc_zero_array (mem_ctx, struct mapi_SPropValue, properties_array.cValues + 1);
+ properties_array.lpProps[0].ulPropTag = PR_ATTACH_DATA_BIN;
+ /* This call is needed in case the read stream was a named prop. */
+ mapi_SPropValue_array_named (obj_message, &properties_array);
+
+ stream->proptag = properties_array.lpProps[0].ulPropTag;
+
+ attachment->streams = g_slist_append (attachment->streams, stream);
+ }
+ }
+
+ mapi_object_release (&obj_emb_msg);
+ }
*attach_list = g_slist_append (*attach_list, attachment);
@@ -1390,7 +1477,7 @@ exchange_mapi_connection_fetch_items (ExchangeMapiConnection *conn, mapi_id_t
}
if (has_attach && *has_attach && (MAPI_OPTIONS_FETCH_ATTACHMENTS & options)) {
- exchange_mapi_util_get_attachments (&obj_message, &attach_list);
+ exchange_mapi_util_get_attachments (conn, fid, &obj_message, &attach_list);
}
if (options & MAPI_OPTIONS_FETCH_RECIPIENTS)
@@ -1499,45 +1586,30 @@ exchange_mapi_connection_fetch_items (ExchangeMapiConnection *conn, mapi_id_t
return result;
}
+/* obj_folder and obj_message are released only when obj_folder is not NULL and when returned TRUE */
gboolean
-exchange_mapi_connection_fetch_item (ExchangeMapiConnection *conn, mapi_id_t fid, mapi_id_t mid,
+exchange_mapi_connection_fetch_object_props (ExchangeMapiConnection *conn, mapi_object_t *obj_folder, mapi_id_t fid, mapi_object_t *obj_message,
BuildReadPropsCB build_props, gpointer brp_data,
FetchCallback cb, gpointer data,
guint32 options)
{
enum MAPISTATUS retval;
TALLOC_CTX *mem_ctx;
- mapi_object_t obj_folder;
- mapi_object_t obj_message;
struct mapi_SPropValue_array properties_array;
- struct SPropTagArray *propsTagArray;
+ struct SPropTagArray *propsTagArray = NULL;
GSList *attach_list = NULL;
GSList *recip_list = NULL;
GSList *stream_list = NULL;
gboolean result = FALSE;
+ mapi_id_t mid;
CHECK_CORRECT_CONN_AND_GET_PRIV (conn, FALSE);
g_return_val_if_fail (priv->session != NULL, FALSE);
- g_debug("%s: Entering %s: folder-id %016" G_GINT64_MODIFIER "X message-id %016" G_GINT64_MODIFIER "X",
- G_STRLOC, G_STRFUNC, fid, mid);
+ g_debug("%s: Entering %s: folder %p message %p", G_STRLOC, G_STRFUNC, obj_folder, obj_message);
LOCK ();
- mem_ctx = talloc_init("ExchangeMAPI_FetchItem");
- mapi_object_init(&obj_folder);
- mapi_object_init(&obj_message);
-
- if ((options & MAPI_OPTIONS_USE_PFSTORE) != 0) {
- if (!ensure_public_store (priv))
- goto cleanup;
- }
-
- /* Attempt to open the folder */
- retval = OpenFolder (((options & MAPI_OPTIONS_USE_PFSTORE) != 0 ? &priv->public_store : &priv->msg_store), fid, &obj_folder);
- if (retval != MAPI_E_SUCCESS) {
- mapi_errstr("OpenFolder", GetLastError());
- goto cleanup;
- }
+ mem_ctx = talloc_init("ExchangeMAPI_FetchObjectProps");
if (build_props) {
propsTagArray = set_SPropTagArray (mem_ctx, 0x1, PR_MESSAGE_CLASS);
@@ -1547,24 +1619,17 @@ exchange_mapi_connection_fetch_item (ExchangeMapiConnection *conn, mapi_id_t fid
}
}
- /* Open the item */
- retval = OpenMessage(&obj_folder, fid, mid, &obj_message, 0x0);
- if (retval != MAPI_E_SUCCESS) {
- mapi_errstr("OpenMessage", GetLastError());
- goto cleanup;
- }
-
/* Fetch attachments */
if (options & MAPI_OPTIONS_FETCH_ATTACHMENTS)
- exchange_mapi_util_get_attachments (&obj_message, &attach_list);
+ exchange_mapi_util_get_attachments (conn, fid, obj_message, &attach_list);
/* Fetch recipients */
if (options & MAPI_OPTIONS_FETCH_RECIPIENTS)
- exchange_mapi_util_get_recipients (&obj_message, &recip_list);
+ exchange_mapi_util_get_recipients (obj_message, &recip_list);
/* get the main body stream no matter what */
if (options & MAPI_OPTIONS_FETCH_BODY_STREAM)
- exchange_mapi_util_read_body_stream (&obj_message, &stream_list,
+ exchange_mapi_util_read_body_stream (obj_message, &stream_list,
options & MAPI_OPTIONS_GETBESTBODY);
if (propsTagArray && propsTagArray->cValues) {
@@ -1572,7 +1637,7 @@ exchange_mapi_connection_fetch_item (ExchangeMapiConnection *conn, mapi_id_t fid
uint32_t prop_count = 0, k;
lpProps = talloc_zero(mem_ctx, struct SPropValue);
- retval = GetProps (&obj_message, propsTagArray, &lpProps, &prop_count);
+ retval = GetProps (obj_message, propsTagArray, &lpProps, &prop_count);
/* Conversion from SPropValue to mapi_SPropValue. (no padding here) */
properties_array.cValues = prop_count;
@@ -1581,7 +1646,7 @@ exchange_mapi_connection_fetch_item (ExchangeMapiConnection *conn, mapi_id_t fid
cast_mapi_SPropValue(&properties_array.lpProps[k], &lpProps[k]);
} else
- retval = GetPropsAll (&obj_message, &properties_array);
+ retval = GetPropsAll (obj_message, &properties_array);
if (retval == MAPI_E_SUCCESS) {
uint32_t z;
@@ -1589,14 +1654,19 @@ exchange_mapi_connection_fetch_item (ExchangeMapiConnection *conn, mapi_id_t fid
/* just to get all the other streams */
for (z=0; z < properties_array.cValues; z++)
if ((properties_array.lpProps[z].ulPropTag & 0xFFFF) == PT_BINARY && (options & MAPI_OPTIONS_FETCH_GENERIC_STREAMS))
- exchange_mapi_util_read_generic_stream (&obj_message, properties_array.lpProps[z].ulPropTag, &stream_list);
+ exchange_mapi_util_read_generic_stream (obj_message, properties_array.lpProps[z].ulPropTag, &stream_list);
- mapi_SPropValue_array_named(&obj_message, &properties_array);
+ mapi_SPropValue_array_named (obj_message, &properties_array);
}
+ mid = mapi_object_get_id (obj_message);
+
/* Release the objects so that the callback may use the store. */
- mapi_object_release(&obj_message);
- mapi_object_release(&obj_folder);
+ if (obj_folder) {
+ /* obj_folder is not NULL, thus can do this */
+ mapi_object_release (obj_message);
+ mapi_object_release (obj_folder);
+ }
if (retval == MAPI_E_SUCCESS) {
FetchItemsCallbackData *item_data = g_new0 (FetchItemsCallbackData, 1);
@@ -1618,20 +1688,70 @@ exchange_mapi_connection_fetch_item (ExchangeMapiConnection *conn, mapi_id_t fid
exchange_mapi_util_free_attachment_list (&attach_list);
}
-// if (propsTagArray->cValues)
-// talloc_free (properties_array.lpProps);
-
result = TRUE;
cleanup:
+ talloc_free (mem_ctx);
+ UNLOCK ();
+
+ g_debug("%s: Leaving %s ", G_STRLOC, G_STRFUNC);
+
+ return result;
+}
+
+gboolean
+exchange_mapi_connection_fetch_item (ExchangeMapiConnection *conn, mapi_id_t fid, mapi_id_t mid,
+ BuildReadPropsCB build_props, gpointer brp_data,
+ FetchCallback cb, gpointer data,
+ guint32 options)
+{
+ enum MAPISTATUS retval;
+ TALLOC_CTX *mem_ctx;
+ mapi_object_t obj_folder;
+ mapi_object_t obj_message;
+ gboolean result = FALSE;
+
+ CHECK_CORRECT_CONN_AND_GET_PRIV (conn, FALSE);
+ g_return_val_if_fail (priv->session != NULL, FALSE);
+
+ g_debug("%s: Entering %s: folder-id %016" G_GINT64_MODIFIER "X message-id %016" G_GINT64_MODIFIER "X",
+ G_STRLOC, G_STRFUNC, fid, mid);
+
+ LOCK ();
+ mem_ctx = talloc_init("ExchangeMAPI_FetchItem");
+ mapi_object_init(&obj_folder);
+ mapi_object_init(&obj_message);
+
+ if ((options & MAPI_OPTIONS_USE_PFSTORE) != 0) {
+ if (!ensure_public_store (priv))
+ goto cleanup;
+ }
+
+ /* Attempt to open the folder */
+ retval = OpenFolder (((options & MAPI_OPTIONS_USE_PFSTORE) != 0 ? &priv->public_store : &priv->msg_store), fid, &obj_folder);
+ if (retval != MAPI_E_SUCCESS) {
+ mapi_errstr("OpenFolder", GetLastError());
+ goto cleanup;
+ }
+
+ /* Open the item */
+ retval = OpenMessage(&obj_folder, fid, mid, &obj_message, 0x0);
+ if (retval != MAPI_E_SUCCESS) {
+ mapi_errstr("OpenMessage", GetLastError());
+ goto cleanup;
+ }
+
+ result = exchange_mapi_connection_fetch_object_props (conn, &obj_folder, fid, &obj_message, build_props, brp_data, cb, data, options);
+
+cleanup:
if (!result) {
- mapi_object_release(&obj_message);
- mapi_object_release(&obj_folder);
+ mapi_object_release (&obj_message);
+ mapi_object_release (&obj_folder);
}
talloc_free (mem_ctx);
UNLOCK ();
- g_debug("%s: Leaving %s ", G_STRLOC, G_STRFUNC);
+ g_debug ("%s: Leaving %s ", G_STRLOC, G_STRFUNC);
return result;
}
diff --git a/src/libexchangemapi/exchange-mapi-connection.h b/src/libexchangemapi/exchange-mapi-connection.h
index b75e1f8..42e3c0e 100644
--- a/src/libexchangemapi/exchange-mapi-connection.h
+++ b/src/libexchangemapi/exchange-mapi-connection.h
@@ -153,6 +153,13 @@ ExchangeMapiConnection *exchange_mapi_connection_find (const gchar *profile);
gboolean exchange_mapi_connection_reconnect (ExchangeMapiConnection *conn, const gchar *password);
gboolean exchange_mapi_connection_close (ExchangeMapiConnection *conn);
gboolean exchange_mapi_connection_connected (ExchangeMapiConnection *conn);
+
+gboolean exchange_mapi_connection_fetch_object_props (
+ ExchangeMapiConnection *conn, mapi_object_t *obj_folder, mapi_id_t fid, mapi_object_t *obj_message,
+ BuildReadPropsCB build_props, gpointer brp_data,
+ FetchCallback cb, gpointer data,
+ guint32 options);
+
gboolean exchange_mapi_connection_fetch_item (ExchangeMapiConnection *conn, mapi_id_t fid, mapi_id_t mid,
BuildReadPropsCB build_props, gpointer brp_data,
FetchCallback cb, gpointer data,
diff --git a/src/libexchangemapi/exchange-mapi-mail-utils.c b/src/libexchangemapi/exchange-mapi-mail-utils.c
new file mode 100644
index 0000000..9d671fc
--- /dev/null
+++ b/src/libexchangemapi/exchange-mapi-mail-utils.c
@@ -0,0 +1,720 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <camel/camel.h>
+
+#include "exchange-mapi-defs.h"
+#include "exchange-mapi-utils.h"
+#include "exchange-mapi-cal-utils.h"
+#include "exchange-mapi-mail-utils.h"
+
+void
+mail_item_free (MailItem *item)
+{
+ g_free (item->header.subject);
+ g_free (item->header.from);
+
+ g_free (item->header.to);
+ g_free (item->header.cc);
+ g_free (item->header.bcc);
+
+ g_free (item->header.references);
+ g_free (item->header.message_id);
+ g_free (item->header.in_reply_to);
+
+ exchange_mapi_util_free_attachment_list (&item->attachments);
+ exchange_mapi_util_free_stream_list (&item->generic_streams);
+ exchange_mapi_util_free_recipient_list (&item->recipients);
+
+ g_free (item);
+}
+
+gboolean
+fetch_props_to_mail_item_cb (FetchItemsCallbackData *item_data, gpointer data)
+{
+ long *flags;
+ struct FILETIME *delivery_date;
+ const gchar *msg_class;
+ NTTIME ntdate;
+ ExchangeMAPIStream *body;
+
+ MailItem *item;
+ MailItem **i = (MailItem **)data;
+ guint32 j = 0;
+
+ g_return_val_if_fail (item_data != NULL, FALSE);
+ g_return_val_if_fail (data != NULL, FALSE);
+
+ if (camel_debug_start("mapi:folder")) {
+ exchange_mapi_debug_property_dump (item_data->properties);
+ camel_debug_end();
+ }
+
+ item = g_new0 (MailItem , 1);
+ item->fid = item_data->fid;
+ item->mid = item_data->mid;
+
+ /*Hold a reference to Recipient List*/
+ item->recipients = item_data->recipients;
+
+ for (j = 0; j < item_data->properties->cValues; j++) {
+
+ gconstpointer prop_data = get_mapi_SPropValue_data(&item_data->properties->lpProps[j]);
+
+ if (fetch_read_item_common_data (item, item_data->properties->lpProps[j].ulPropTag, prop_data))
+ continue;
+
+ switch (item_data->properties->lpProps[j].ulPropTag) {
+ case PR_MESSAGE_CLASS:
+ case PR_MESSAGE_CLASS_UNICODE:
+ msg_class = (const gchar *) prop_data;
+ break;
+ case PR_MESSAGE_DELIVERY_TIME:
+ delivery_date = (struct FILETIME *) prop_data;
+ break;
+ case PR_MESSAGE_FLAGS:
+ flags = (long *) prop_data;
+ break;
+ default:
+ break;
+ }
+ }
+
+ item->is_cal = FALSE;
+ if (g_str_has_prefix (msg_class, IPM_SCHEDULE_MEETING_PREFIX)) {
+ guint8 *appointment_body_str = (guint8 *) exchange_mapi_cal_util_camel_helper (item_data->conn, item_data->fid, item_data->mid, NULL, msg_class,
+ item_data->streams, item_data->recipients, item_data->attachments);
+
+ if (appointment_body_str && *appointment_body_str) {
+ body = g_new0(ExchangeMAPIStream, 1);
+ body->proptag = PR_BODY_UNICODE;
+ body->value = g_byte_array_new ();
+ body->value = g_byte_array_append (body->value, appointment_body_str, strlen ((const gchar *)appointment_body_str));
+
+ item->msg.body_parts = g_slist_append (item->msg.body_parts, body);
+ item->is_cal = TRUE;
+ }
+
+ g_free (appointment_body_str);
+ }
+
+ if (!item->is_cal) {
+ /* always prefer unicode version, as that can be properly read */
+ if (!(body = exchange_mapi_util_find_stream (item_data->streams, PR_BODY_UNICODE)))
+ body = exchange_mapi_util_find_stream (item_data->streams, PR_BODY);
+
+ if (body)
+ item->msg.body_parts = g_slist_append (item->msg.body_parts, body);
+
+ body = exchange_mapi_util_find_stream (item_data->streams, PR_HTML);
+ if (body)
+ item->msg.body_parts = g_slist_append (item->msg.body_parts, body);
+ }
+
+ if (delivery_date) {
+ ntdate = delivery_date->dwHighDateTime;
+ ntdate = ntdate << 32;
+ ntdate |= delivery_date->dwLowDateTime;
+ item->header.recieved_time = nt_time_to_unix(ntdate);
+ }
+
+ if ((*flags & MSGFLAG_READ) != 0)
+ item->header.flags |= CAMEL_MESSAGE_SEEN;
+ if ((*flags & MSGFLAG_HASATTACH) != 0)
+ item->header.flags |= CAMEL_MESSAGE_ATTACHMENTS;
+
+ item->attachments = item_data->attachments;
+
+ *i = item;
+
+ return TRUE;
+}
+
+gboolean
+fetch_read_item_common_data (MailItem *item, uint32_t propTag, gconstpointer prop_data)
+{
+ gboolean found = TRUE;
+
+ #define sv(_x,_y) G_STMT_START { g_free (_x); _x = _y; } G_STMT_END
+
+ switch (propTag) {
+ case PR_INTERNET_CPID: {
+ const uint32_t *ui32 = (const uint32_t *) prop_data;
+ if (ui32)
+ item->header.cpid = *ui32;
+ } break;
+ /* FIXME : Instead of duping. Use talloc_steal to reuse the memory */
+ case PR_SUBJECT:
+ sv (item->header.subject, utf8tolinux (prop_data));
+ break;
+ case PR_SUBJECT_UNICODE :
+ sv (item->header.subject, g_strdup (prop_data));
+ break;
+ case PR_DISPLAY_TO :
+ sv (item->header.to, utf8tolinux (prop_data));
+ break;
+ case PR_DISPLAY_TO_UNICODE :
+ sv (item->header.to, g_strdup (prop_data));
+ break;
+ case PR_DISPLAY_CC:
+ sv (item->header.cc, utf8tolinux (prop_data));
+ break;
+ case PR_DISPLAY_CC_UNICODE:
+ sv (item->header.cc, g_strdup (prop_data));
+ break;
+ case PR_DISPLAY_BCC:
+ sv (item->header.bcc, utf8tolinux (prop_data));
+ break;
+ case PR_DISPLAY_BCC_UNICODE:
+ sv (item->header.bcc, g_strdup (prop_data));
+ break;
+ case PR_SENT_REPRESENTING_NAME:
+ sv (item->header.from, utf8tolinux (prop_data));
+ break;
+ case PR_SENT_REPRESENTING_NAME_UNICODE:
+ sv (item->header.from, g_strdup (prop_data));
+ break;
+ case PR_SENT_REPRESENTING_EMAIL_ADDRESS:
+ sv (item->header.from_email, utf8tolinux (prop_data));
+ break;
+ case PR_SENT_REPRESENTING_EMAIL_ADDRESS_UNICODE:
+ sv (item->header.from_email, g_strdup (prop_data));
+ break;
+ case PR_SENT_REPRESENTING_ADDRTYPE:
+ sv (item->header.from_type, utf8tolinux (prop_data));
+ break;
+ case PR_SENT_REPRESENTING_ADDRTYPE_UNICODE:
+ sv (item->header.from_type, g_strdup (prop_data));
+ break;
+ case PR_MESSAGE_SIZE:
+ item->header.size = *(glong *)prop_data;
+ break;
+ case PR_INTERNET_MESSAGE_ID:
+ item->header.message_id = g_strdup (prop_data);
+ break;
+ case PR_INTERNET_REFERENCES:
+ item->header.references = g_strdup (prop_data);
+ break;
+ case PR_IN_REPLY_TO_ID:
+ item->header.in_reply_to = g_strdup (prop_data);
+ break;
+ case PR_TRANSPORT_MESSAGE_HEADERS:
+ sv (item->header.transport_headers, utf8tolinux (prop_data));
+ break;
+ case PR_TRANSPORT_MESSAGE_HEADERS_UNICODE:
+ sv (item->header.transport_headers, g_strdup (prop_data));
+ break;
+ default:
+ found = FALSE;
+ break;
+ }
+
+ #undef sv
+
+ return found;
+}
+
+gboolean
+mapi_mail_get_item_prop_list (ExchangeMapiConnection *conn, mapi_id_t fid, TALLOC_CTX *mem_ctx, struct SPropTagArray *props, gpointer data)
+{
+ static const uint32_t item_props[] = {
+ PR_FID,
+ PR_MID,
+ PR_INTERNET_CPID,
+
+ PR_TRANSPORT_MESSAGE_HEADERS_UNICODE,
+ PR_MESSAGE_CLASS,
+ PR_MESSAGE_SIZE,
+ PR_MESSAGE_FLAGS,
+ PR_MESSAGE_DELIVERY_TIME,
+ PR_MSG_EDITOR_FORMAT,
+
+ PR_SUBJECT_UNICODE,
+ PR_CONVERSATION_TOPIC_UNICODE,
+
+ /*Properties used for message threading.*/
+ PR_INTERNET_MESSAGE_ID,
+ PR_INTERNET_REFERENCES,
+ PR_IN_REPLY_TO_ID,
+
+ PR_BODY,
+ PR_BODY_UNICODE,
+ PR_HTML,
+ /*Fixme : If this property is fetched, it garbles everything else. */
+ /*PR_BODY_HTML, */
+ /*PR_BODY_HTML_UNICODE, */
+
+ PR_DISPLAY_TO_UNICODE,
+ PR_DISPLAY_CC_UNICODE,
+ PR_DISPLAY_BCC_UNICODE,
+
+ PR_CREATION_TIME,
+ PR_LAST_MODIFICATION_TIME,
+ PR_PRIORITY,
+ PR_SENSITIVITY,
+ PR_START_DATE,
+ PR_END_DATE,
+ PR_RESPONSE_REQUESTED,
+ PR_OWNER_APPT_ID,
+ PR_PROCESSED,
+
+ PR_SENT_REPRESENTING_NAME_UNICODE,
+ PR_SENT_REPRESENTING_ADDRTYPE_UNICODE,
+ PR_SENT_REPRESENTING_EMAIL_ADDRESS_UNICODE,
+
+ PR_SENDER_NAME_UNICODE,
+ PR_SENDER_ADDRTYPE_UNICODE,
+ PR_SENDER_EMAIL_ADDRESS_UNICODE,
+
+ PR_RCVD_REPRESENTING_NAME_UNICODE,
+ PR_RCVD_REPRESENTING_ADDRTYPE_UNICODE,
+ PR_RCVD_REPRESENTING_EMAIL_ADDRESS_UNICODE
+ };
+
+ g_return_val_if_fail (props != NULL, FALSE);
+
+ return exchange_mapi_utils_add_props_to_props_array (mem_ctx, props, item_props, G_N_ELEMENTS (item_props));
+}
+
+
+static void
+mapi_mime_set_recipient_list (CamelMimeMessage *msg, MailItem *item)
+{
+ GSList *l = NULL;
+ CamelInternetAddress *to_addr, *cc_addr, *bcc_addr;
+
+ g_return_if_fail (item->recipients != NULL);
+
+ to_addr = camel_internet_address_new ();
+ cc_addr = camel_internet_address_new ();
+ bcc_addr = camel_internet_address_new ();
+
+ for (l = item->recipients; l; l=l->next) {
+ gchar *display_name;
+ const gchar *name = NULL;
+ uint32_t rcpt_type = MAPI_TO;
+ uint32_t *type = NULL;
+ struct SRow *aRow;
+ ExchangeMAPIRecipient *recip = (ExchangeMAPIRecipient *)(l->data);
+
+ /*Can't continue when there is no email-id*/
+ if (!recip->email_id)
+ continue;
+
+ /* Build a SRow structure */
+ aRow = &recip->out_SRow;
+
+ /*Name is probably available in one of these props.*/
+ name = (const gchar *) exchange_mapi_util_find_row_propval (aRow, PR_DISPLAY_NAME_UNICODE);
+ name = name ? name : (const gchar *) exchange_mapi_util_find_row_propval (aRow, PR_RECIPIENT_DISPLAY_NAME_UNICODE);
+ name = name ? name : (const gchar *) exchange_mapi_util_find_row_propval (aRow, PR_7BIT_DISPLAY_NAME_UNICODE);
+
+ type = (uint32_t *) exchange_mapi_util_find_row_propval (aRow, PR_RECIPIENT_TYPE);
+
+ /*Fallbacks. Not good*/
+ display_name = name ? g_strdup (name) : g_strdup (recip->email_id);
+ rcpt_type = (type ? *type : MAPI_TO);
+
+ switch (rcpt_type) {
+ case MAPI_TO:
+ camel_internet_address_add (to_addr, display_name, recip->email_id);
+ break;
+ case MAPI_CC:
+ camel_internet_address_add (cc_addr, display_name, recip->email_id);
+ break;
+ case MAPI_BCC:
+ camel_internet_address_add (bcc_addr, display_name, recip->email_id);
+ break;
+ }
+
+ g_free (display_name);
+ }
+
+ /*Add to message*/
+ /*Note : To field is added from PR_TRANSPORT_MESSAGE_HEADERS
+ But, in sent_items folder we don't get TRANSPORT_MESSAGE_HEADERS */
+ if (!item->header.transport_headers) {
+ camel_mime_message_set_recipients(msg, "To", to_addr);
+ camel_mime_message_set_recipients(msg, "Cc", cc_addr);
+ camel_mime_message_set_recipients(msg, "Bcc", bcc_addr);
+ }
+
+ /*TODO : Unref *_addr ? */
+}
+
+static void
+mapi_mime_set_msg_headers (ExchangeMapiConnection *conn, CamelMimeMessage *msg, MailItem *item)
+{
+ gchar *temp_str = NULL;
+ const gchar *from_email;
+ time_t recieved_time;
+ CamelInternetAddress *addr = NULL;
+ gint offset = 0;
+ time_t actual_time;
+
+ /* Setting headers from PR_TRANSPORT_MESSAGE_HEADERS */
+ if (item->header.transport_headers) {
+ CamelMimePart *part = camel_mime_part_new ();
+ CamelStream *stream;
+ CamelMimeParser *parser;
+
+ stream = camel_stream_mem_new_with_buffer (item->header.transport_headers, strlen (item->header.transport_headers));
+ parser = camel_mime_parser_new ();
+ camel_mime_parser_init_with_stream (parser, stream);
+ camel_mime_parser_scan_from (parser, FALSE);
+ g_object_unref (stream);
+
+ if (camel_mime_part_construct_from_parser (part, parser) != -1) {
+ struct _camel_header_raw *h;
+
+ for (h = part->headers; h; h = h->next) {
+ const gchar *value = h->value;
+
+ /* skip all headers describing content of a message,
+ because it's overwritten on message decomposition */
+ if (g_ascii_strncasecmp (h->name, "Content", 7) == 0)
+ continue;
+
+ while (value && camel_mime_is_lwsp (*value))
+ value++;
+
+ camel_medium_add_header (CAMEL_MEDIUM (msg), h->name, value);
+ }
+ }
+
+ g_object_unref (parser);
+ g_object_unref (part);
+ }
+
+ /* Overwrite headers if we have specific properties available*/
+ temp_str = item->header.subject;
+ if (temp_str)
+ camel_mime_message_set_subject (msg, temp_str);
+
+ recieved_time = item->header.recieved_time;
+
+ actual_time = camel_header_decode_date (ctime(&recieved_time), &offset);
+ /* camel_mime_message_set_date (msg, actual_time, offset); */
+
+ if (item->header.from) {
+ if ((item->header.from_type != NULL) && !g_utf8_collate (item->header.from_type, "EX")) {
+ from_email = exchange_mapi_connection_ex_to_smtp (conn, item->header.from_email);
+ g_free (item->header.from_email);
+ item->header.from_email = g_strdup (from_email);
+ }
+
+ item->header.from_email = item->header.from_email ?
+ item->header.from_email : item->header.from;
+
+ /* add reply to */
+ addr = camel_internet_address_new();
+ camel_internet_address_add(addr, item->header.from, item->header.from_email);
+ camel_mime_message_set_reply_to(msg, addr);
+
+ /* add from */
+ addr = camel_internet_address_new();
+ camel_internet_address_add(addr, item->header.from, item->header.from_email);
+ camel_mime_message_set_from(msg, addr);
+ }
+
+ /* Threading */
+ if (item->header.message_id)
+ camel_medium_add_header (CAMEL_MEDIUM (msg), "Message-ID", item->header.message_id);
+
+ if (item->header.references)
+ camel_medium_add_header (CAMEL_MEDIUM (msg), "References", item->header.references);
+
+ if (item->header.in_reply_to)
+ camel_medium_add_header (CAMEL_MEDIUM (msg), "In-Reply-To", item->header.in_reply_to);
+
+}
+
+static CamelMimePart *
+mapi_mime_msg_body (MailItem *item, const ExchangeMAPIStream *body)
+{
+ CamelMimePart *part = camel_mime_part_new ();
+ camel_mime_part_set_encoding (part, CAMEL_TRANSFER_ENCODING_8BIT);
+
+ if (body && body->value && body->value->len > 0) {
+ const gchar * type = NULL;
+ gchar *buff = NULL;
+
+ if (item->is_cal)
+ type = "text/calendar";
+ else
+ type = (body->proptag == PR_BODY || body->proptag == PR_BODY_UNICODE) ?
+ "text/plain" : "text/html";
+
+ if (item->header.cpid) {
+ if (item->header.cpid == 20127)
+ buff = g_strdup_printf ("%s; charset=\"us-ascii\"", type);
+ else if (item->header.cpid >= 28591 && item->header.cpid <= 28599)
+ buff = g_strdup_printf ("%s; charset=\"ISO-8859-%d\"", type, item->header.cpid % 10);
+ else if (item->header.cpid == 28603)
+ buff = g_strdup_printf ("%s; charset=\"ISO-8859-13\"", type);
+ else if (item->header.cpid == 28605)
+ buff = g_strdup_printf ("%s; charset=\"ISO-8859-15\"", type);
+ else if (item->header.cpid == 65000)
+ buff = g_strdup_printf ("%s; charset=\"UTF-7\"", type);
+ else if (item->header.cpid == 65001)
+ buff = g_strdup_printf ("%s; charset=\"UTF-8\"", type);
+ else
+ buff = g_strdup_printf ("%s; charset=\"CP%d\"", type, item->header.cpid);
+ type = buff;
+ }
+
+ camel_mime_part_set_content (part, (const gchar *) body->value->data, body->value->len, type);
+
+ g_free (buff);
+ } else
+ camel_mime_part_set_content (part, " ", strlen (" "), "text/plain");
+
+ return part;
+}
+
+#if 0
+
+/* GCompareFunc. Used for ordering body types in a GSList.*/
+static gint
+sort_bodies_cb (gconstpointer a, gconstpointer b)
+{
+ static const gint desired_order[] = { PR_BODY, PR_BODY_UNICODE, PR_HTML };
+ const ExchangeMAPIStream *stream_a = a, *stream_b = b;
+ gint aidx, bidx;
+
+ if (a == b)
+ return 0;
+ if (!a)
+ return -1;
+ if (!b)
+ return 1;
+
+ for (aidx = 0; aidx < G_N_ELEMENTS (desired_order); aidx++) {
+ if (desired_order[aidx] == stream_a->proptag)
+ break;
+ }
+
+ for (bidx = 0; bidx < G_N_ELEMENTS (desired_order); bidx++) {
+ if (desired_order[bidx] == stream_b->proptag)
+ break;
+ }
+
+ return aidx - bidx;
+}
+
+#endif
+
+/* Adds parts to multipart. Convenience function. */
+static void
+mapi_mime_multipart_add_attachments (CamelMultipart *multipart, GSList *attachs)
+{
+ CamelMimePart *part;
+ while (attachs) {
+ part = attachs->data;
+ camel_multipart_add_part (multipart, part);
+ g_object_unref (part);
+ attachs = attachs->next;
+ }
+}
+
+/* Process body stream and related objects into a MIME mulitpart */
+static CamelMultipart *
+mapi_mime_build_multipart_related (MailItem *item, const ExchangeMAPIStream *stream,
+ GSList *inline_attachs)
+{
+ CamelMimePart *part;
+ CamelMultipart *m_related = camel_multipart_new ();
+ camel_data_wrapper_set_mime_type (CAMEL_DATA_WRAPPER (m_related), "multipart/related");
+ camel_multipart_set_boundary (m_related, NULL);
+
+ part = mapi_mime_msg_body (item, stream);
+ camel_multipart_add_part (m_related, part);
+ g_object_unref (part);
+
+ mapi_mime_multipart_add_attachments (m_related, inline_attachs);
+
+ return m_related;
+}
+
+/* Process multiple body types and pack them in a MIME mulitpart */
+static CamelMultipart *
+mapi_mime_build_multipart_alternative (MailItem *item, GSList *body_parts, GSList *inline_attachs)
+{
+ CamelMimePart *part;
+ CamelMultipart *m_alternative = camel_multipart_new ();
+ camel_data_wrapper_set_mime_type (CAMEL_DATA_WRAPPER (m_alternative),
+ "multipart/alternative");
+ camel_multipart_set_boundary (m_alternative, NULL);
+
+ while (body_parts) {
+ const ExchangeMAPIStream *stream = (ExchangeMAPIStream *) body_parts->data;
+ part = camel_mime_part_new ();
+ if ((stream->proptag == PR_HTML || stream->proptag == PR_BODY_HTML_UNICODE)
+ && inline_attachs) {
+ CamelMultipart *m_related;
+ m_related = mapi_mime_build_multipart_related (item, stream,
+ inline_attachs);
+ camel_medium_set_content (CAMEL_MEDIUM (part),
+ CAMEL_DATA_WRAPPER (m_related));
+ g_object_unref (m_related);
+ } else
+ part = mapi_mime_msg_body (item, stream);
+
+ camel_multipart_add_part (m_alternative, part);
+ g_object_unref (part);
+ }
+
+ return m_alternative;
+}
+
+static CamelMultipart *
+mapi_mime_build_multipart_mixed (CamelMultipart *content, GSList *attachs)
+{
+ CamelMimePart *part = camel_mime_part_new ();
+ CamelMultipart *m_mixed = camel_multipart_new ();
+ camel_data_wrapper_set_mime_type (CAMEL_DATA_WRAPPER (m_mixed),
+ "multipart/mixed");
+ camel_multipart_set_boundary (m_mixed, NULL);
+
+ camel_medium_set_content (CAMEL_MEDIUM (part), CAMEL_DATA_WRAPPER (content));
+ camel_multipart_add_part (m_mixed, part);
+
+ if (attachs)
+ mapi_mime_multipart_add_attachments (m_mixed, attachs);
+
+ return m_mixed;
+}
+
+/*Takes raw attachment streams and converts to MIME Parts. Parts are added to
+ either inline / non-inline lists.*/
+static void
+mapi_mime_classify_attachments (GSList *attachments, GSList **inline_attachs, GSList **noninline)
+{
+ for (;attachments != NULL; attachments = attachments->next) {
+ ExchangeMAPIAttachment *attach = (ExchangeMAPIAttachment *)attachments->data;
+ ExchangeMAPIStream *stream = NULL;
+ const gchar *filename, *mime_type, *content_id = NULL;
+ CamelContentType *content_type;
+ CamelMimePart *part;
+
+ stream = exchange_mapi_util_find_stream (attach->streams, PR_ATTACH_DATA_BIN);
+
+ if (!stream || stream->value->len <= 0) {
+ continue;
+ }
+
+ part = camel_mime_part_new ();
+
+ filename = (const gchar *) exchange_mapi_util_find_SPropVal_array_propval(attach->lpProps,
+ PR_ATTACH_LONG_FILENAME_UNICODE);
+
+ if (!(filename && *filename))
+ filename = (const gchar *) exchange_mapi_util_find_SPropVal_array_propval(attach->lpProps,
+ PR_ATTACH_FILENAME_UNICODE);
+ camel_mime_part_set_filename(part, g_strdup(filename));
+ camel_content_type_set_param (((CamelDataWrapper *) part)->mime_type, "name", filename);
+
+ /*Content-Type*/
+ mime_type = (const gchar *) exchange_mapi_util_find_SPropVal_array_propval (attach->lpProps, PR_ATTACH_MIME_TAG);
+ if (!mime_type) {
+ const uint32_t *ui32 = (const uint32_t *) exchange_mapi_util_find_SPropVal_array_propval (attach->lpProps, PR_ATTACH_METHOD);
+ if (ui32 && *ui32 == ATTACH_EMBEDDED_MSG)
+ mime_type = "message/rfc822";
+ }
+ if (!mime_type)
+ mime_type = "application/octet-stream";
+
+ camel_mime_part_set_content (part, (const gchar *) stream->value->data, stream->value->len, mime_type);
+
+ content_type = camel_mime_part_get_content_type (part);
+ if (content_type && camel_content_type_is (content_type, "text", "*"))
+ camel_mime_part_set_encoding (part, CAMEL_TRANSFER_ENCODING_QUOTEDPRINTABLE);
+ else
+ camel_mime_part_set_encoding (part, CAMEL_TRANSFER_ENCODING_BASE64);
+
+ /*Content-ID*/
+ content_id = (const gchar *) exchange_mapi_util_find_SPropVal_array_propval(attach->lpProps,
+ PR_ATTACH_CONTENT_ID);
+ /* TODO : Add disposition */
+ if (content_id) {
+ camel_mime_part_set_content_id (part, content_id);
+ *inline_attachs = g_slist_append (*inline_attachs, part);
+ } else
+ *noninline = g_slist_append (*noninline, part);
+ }
+}
+
+CamelMimeMessage *
+mapi_mail_item_to_mime_message (ExchangeMapiConnection *conn, MailItem *item)
+{
+ CamelMimeMessage *msg = NULL;
+ CamelMultipart *multipart_body = NULL;
+
+ GSList *attach_list = NULL;
+ GSList *inline_attachs = NULL; /*Used for mulitpart/related*/
+ GSList *noninline_attachs = NULL;
+
+ gboolean build_alternative = FALSE;
+ gboolean build_related = FALSE;
+
+ g_return_val_if_fail (conn != NULL, NULL);
+ g_return_val_if_fail (item != NULL, NULL);
+
+ attach_list = item->attachments;
+ msg = camel_mime_message_new ();
+
+ mapi_mime_set_recipient_list (msg, item);
+ mapi_mime_set_msg_headers (conn, msg, item);
+ mapi_mime_classify_attachments (attach_list, &inline_attachs, &noninline_attachs);
+
+ build_alternative = (g_slist_length (item->msg.body_parts) > 1) && inline_attachs;
+ build_related = !build_alternative && inline_attachs;
+
+ if (build_alternative) {
+ multipart_body = mapi_mime_build_multipart_alternative (item, item->msg.body_parts,
+ inline_attachs);
+ } else if (build_related) {
+ multipart_body = mapi_mime_build_multipart_related (item,
+ item->msg.body_parts->data,
+ inline_attachs);
+ } else { /* Simple multipart/mixed */
+ CamelMimePart *part;
+ multipart_body = camel_multipart_new ();
+ camel_data_wrapper_set_mime_type (CAMEL_DATA_WRAPPER (multipart_body),
+ "multipart/mixed");
+ camel_multipart_set_boundary (multipart_body, NULL);
+ part = mapi_mime_msg_body (item, item->msg.body_parts ? item->msg.body_parts->data : NULL);
+ camel_multipart_add_part (multipart_body, part);
+ g_object_unref (part);
+ }
+
+ if (noninline_attachs) { /* multipart/mixed */
+ multipart_body = mapi_mime_build_multipart_mixed (multipart_body,
+ noninline_attachs);
+ }
+
+ camel_medium_set_content (CAMEL_MEDIUM (msg), CAMEL_DATA_WRAPPER(multipart_body));
+ g_object_unref (multipart_body);
+
+ return msg;
+}
diff --git a/src/libexchangemapi/exchange-mapi-mail-utils.h b/src/libexchangemapi/exchange-mapi-mail-utils.h
new file mode 100644
index 0000000..295e926
--- /dev/null
+++ b/src/libexchangemapi/exchange-mapi-mail-utils.h
@@ -0,0 +1,90 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef EXCHANGE_MAPI_MAIL_UTILS_H
+#define EXCHANGE_MAPI_MAIL_UTILS_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <glib.h>
+#include <libmapi/libmapi.h>
+
+#include <exchange-mapi-connection.h>
+
+typedef enum {
+ PART_TYPE_PLAIN_TEXT=1,
+ PART_TYPE_TEXT_HTML
+} MailItemPartType;
+
+typedef struct {
+ gchar *subject;
+ gchar *from;
+ gchar *from_email;
+ gchar *from_type;
+
+ gchar *references;
+ gchar *message_id;
+ gchar *in_reply_to;
+ /*TODO : Obsolete this. Moved to recipient list*/
+ gchar *to;
+ gchar *cc;
+ gchar *bcc;
+
+ gint flags;
+ glong size;
+ time_t recieved_time;
+ time_t send_time;
+ guint cpid; /* codepage id */
+ gchar *transport_headers;
+} MailItemHeader;
+
+typedef struct {
+ GSList *body_parts;
+} MailItemMessage;
+
+typedef struct {
+ mapi_id_t fid;
+ mapi_id_t mid;
+
+ MailItemHeader header;
+ MailItemMessage msg;
+
+ gboolean is_cal;
+
+ GSList *recipients;
+ GSList *attachments;
+ GSList *generic_streams;
+}MailItem;
+
+void mail_item_free (MailItem *item);
+
+/* fetch callback, the 'data' is pointer to a MailItem pointer, where new MailItem will be placed */
+gboolean fetch_props_to_mail_item_cb (FetchItemsCallbackData *item_data, gpointer data);
+
+/* returns TRUE when filled an entry in the MailItem based on the propTag and its value */
+gboolean fetch_read_item_common_data (MailItem *item, uint32_t propTag, gconstpointer prop_data);
+
+gboolean mapi_mail_get_item_prop_list (ExchangeMapiConnection *conn, mapi_id_t fid, TALLOC_CTX *mem_ctx, struct SPropTagArray *props, gpointer data);
+
+struct _CamelMimeMessage;
+struct _CamelMimeMessage *mapi_mail_item_to_mime_message (ExchangeMapiConnection *conn, MailItem *item);
+
+#endif /* EXCHANGE_MAPI_MAIL_UTILS */
diff --git a/src/libexchangemapi/exchange-mapi-utils.h b/src/libexchangemapi/exchange-mapi-utils.h
index 7c78145..57a37b0 100644
--- a/src/libexchangemapi/exchange-mapi-utils.h
+++ b/src/libexchangemapi/exchange-mapi-utils.h
@@ -80,4 +80,3 @@ gboolean exchange_mapi_utils_add_spropvalue_named_id (ExchangeMapiConnection *co
uint32_t exchange_mapi_utils_push_crc32 (uint32_t crc32, uint8_t *bytes, uint32_t n_bytes);
#endif
-
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]