[evolution-ews] Decode Oab address-book records
- From: Chenthill Palanisamy <pchen src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [evolution-ews] Decode Oab address-book records
- Date: Thu, 7 Jul 2011 19:04:29 +0000 (UTC)
commit 6fc8de8a79b4c7439cdec76059c564c6bbedd049
Author: Chenthill Palanisamy <pchenthill novell com>
Date: Fri Jul 8 00:32:38 2011 +0530
Decode Oab address-book records
src/addressbook/ews-oab-decoder.c | 588 ++++++++++++++++++++++++++++++++++++-
src/addressbook/ews-oab-decoder.h | 16 +-
src/addressbook/ews-oab-props.h | 5 +
3 files changed, 601 insertions(+), 8 deletions(-)
---
diff --git a/src/addressbook/ews-oab-decoder.c b/src/addressbook/ews-oab-decoder.c
index fbd6edd..55d4157 100644
--- a/src/addressbook/ews-oab-decoder.c
+++ b/src/addressbook/ews-oab-decoder.c
@@ -19,18 +19,35 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
+#include <math.h>
+#include <stdlib.h>
+#include <glib/gstdio.h>
+
#include "ews-oab-decoder.h"
#include "ews-oab-props.h"
G_DEFINE_TYPE (EwsOabDecoder, ews_oab_decoder, G_TYPE_OBJECT)
+#define d(x)
+
#define GET_PRIVATE(o) \
(G_TYPE_INSTANCE_GET_PRIVATE ((o), EWS_TYPE_OAB_DECODER, EwsOabDecoderPrivate))
+#define EOD_ERROR \
+ (ews_oab_decoder_error_quark ())
+
typedef struct _EwsOabDecoderPrivate EwsOabDecoderPrivate;
struct _EwsOabDecoderPrivate {
- gchar *filename;
+ gchar *cache_dir;
+ GFileInputStream *fis;
+ GDataInputStream *dis;
+
+ EBookBackendSqliteDB *ebsdb;
+
+ guint32 total_records;
+ GSList *hdr_props;
+ GSList *oab_props;
};
static void
@@ -38,9 +55,19 @@ ews_oab_decoder_finalize (GObject *object)
{
EwsOabDecoderPrivate *priv = GET_PRIVATE (object);
- if (priv->filename) {
- g_free (priv->filename);
- priv->filename = NULL;
+ if (priv->cache_dir) {
+ g_free (priv->cache_dir);
+ priv->cache_dir = NULL;
+ }
+
+ if (priv->ebsdb) {
+ g_object_unref (priv->ebsdb);
+ priv->ebsdb = NULL;
+ }
+
+ if (priv->dis) {
+ g_object_unref (priv->dis);
+ priv->dis = NULL;
}
G_OBJECT_CLASS (ews_oab_decoder_parent_class)->finalize (object);
@@ -61,17 +88,564 @@ ews_oab_decoder_init (EwsOabDecoder *self)
{
EwsOabDecoderPrivate *priv = GET_PRIVATE (self);
- priv->filename = NULL;
+ priv->cache_dir = NULL;
}
EwsOabDecoder*
-ews_oab_decoder_new (const gchar *oab_filename)
+ews_oab_decoder_new (const gchar *oab_filename,
+ const gchar *cache_dir,
+ EBookBackendSqliteDB *ebsdb,
+ GError **error)
{
EwsOabDecoder *eod;
EwsOabDecoderPrivate *priv;
+ GError *err = NULL;
+ GFile *gf = NULL;
eod = g_object_new (EWS_TYPE_OAB_DECODER, NULL);
priv = GET_PRIVATE (eod);
- priv->filename = g_strdup (oab_filename);
+ gf = g_file_new_for_path (oab_filename);
+ priv->fis = g_file_read (gf, NULL, &err);
+ if (err)
+ goto exit;
+
+ priv->dis = g_data_input_stream_new ((GInputStream *) priv->fis);
+ priv->ebsdb = g_object_ref (ebsdb);
+ priv->cache_dir = g_strdup (cache_dir);
+
+ g_data_input_stream_set_byte_order (priv->dis, G_DATA_STREAM_BYTE_ORDER_LITTLE_ENDIAN);
+exit:
+ if (gf)
+ g_object_unref (gf);
+ if (err) {
+ g_propagate_error (error, err);
+ g_object_unref (eod);
+ return NULL;
+ }
+
+ return eod;
+}
+
+static GQuark
+ews_oab_decoder_error_quark (void)
+{
+ static GQuark quark = 0;
+
+ if (G_UNLIKELY (quark == 0)) {
+ const gchar *string = "ews-oab-decoder";
+ quark = g_quark_from_static_string (string);
+ }
+
+ return quark;
+}
+
+typedef struct {
+ guint32 version;
+ guint32 serial;
+ guint32 total_recs;
+} EwsOabHdr;
+
+static EwsOabHdr *
+ews_read_oab_header (EwsOabDecoder *eod, GCancellable *cancellable, GError **error)
+{
+ EwsOabHdr *o_hdr;
+ EwsOabDecoderPrivate *priv = GET_PRIVATE (eod);
+
+ o_hdr = g_new0 (EwsOabHdr, 1);
+
+ o_hdr->version = g_data_input_stream_read_uint32 (priv->dis, cancellable, error);
+ if (*error)
+ goto exit;
+
+ if (o_hdr->version != 0x00000020) {
+ g_set_error_literal (error, EOD_ERROR, 1, "wrong version header");
+ goto exit;
+ }
+
+ o_hdr->serial = g_data_input_stream_read_uint32 (priv->dis, cancellable, error);
+ if (*error)
+ goto exit;
+ o_hdr->total_recs = g_data_input_stream_read_uint32 (priv->dis, cancellable, error);
+
+exit:
+ if (*error) {
+ g_free (o_hdr);
+ return NULL;
+ }
+
+ return o_hdr;
+}
+
+
+static gboolean
+ews_decode_hdr_props (EwsOabDecoder *eod, gboolean oab_hdrs, GCancellable *cancellable, GError **error)
+{
+ EwsOabDecoderPrivate *priv = GET_PRIVATE (eod);
+ guint32 num_props, i;
+ GSList **props;
+
+ /* number of properties */
+ num_props = g_data_input_stream_read_uint32 (priv->dis, cancellable, error);
+ if (*error)
+ return FALSE;
+
+ if (oab_hdrs)
+ props = &priv->oab_props;
+ else
+ props = &priv->hdr_props;
+
+ for (i = 0; i < num_props; i++) {
+ guint32 prop_id, flags;
+
+ prop_id = g_data_input_stream_read_uint32 (priv->dis, cancellable, error);
+ d(g_print ("%x \n", prop_id);)
+ *props = g_slist_prepend (*props, GUINT_TO_POINTER (prop_id));
+
+ if (*error)
+ return FALSE;
+ flags = g_data_input_stream_read_uint32 (priv->dis, cancellable, error);
+ if (*error)
+ return FALSE;
+
+ /* skip store anr_index and primary key prop list as we will not be using it for online search,
+ store if required later */
+ }
+
+ *props = g_slist_reverse (*props);
+
+ return TRUE;
+}
+
+static gboolean
+ews_decode_metadata (EwsOabDecoder *eod, GCancellable *cancellable, GError **error)
+{
+ EwsOabDecoderPrivate *priv = GET_PRIVATE (eod);
+ gboolean ret = TRUE;
+ guint32 size;
+
+ /* Size */
+ size = g_data_input_stream_read_uint32 (priv->dis, cancellable, error);
+ if (*error)
+ return FALSE;
+
+ ret = ews_decode_hdr_props (eod, FALSE, cancellable, error);
+ if (!ret)
+ return FALSE;
+
+ ret = ews_decode_hdr_props (eod, TRUE, cancellable, error);
+
+ return ret;
+}
+
+static gboolean
+ews_is_bit_set (const gchar *str, guint32 pos)
+{
+ guint32 index, bit_pos;
+
+ index = pos/8;
+ bit_pos = pos & (8-1);
+
+ if ((str[index] << bit_pos) & 0x80)
+ return TRUE;
+ else
+ return FALSE;
+}
+
+static guint32
+ews_decode_uint32 (EwsOabDecoder *eod, GCancellable *cancellable, GError **error)
+{
+ EwsOabDecoderPrivate *priv = GET_PRIVATE (eod);
+ guint8 first;
+ guint32 ret = -1, num;
+
+ first = g_data_input_stream_read_byte (priv->dis, cancellable, error);
+ if (*error)
+ goto exit;
+
+ if (first & 0x80)
+ num = first & 0x0F;
+ else
+ return (guint32) first;
+
+ if (num == 1) {
+ ret = g_data_input_stream_read_byte (priv->dis, cancellable, error);
+ goto exit;
+ }
+
+ if (num == 2)
+ ret = (guint16) g_data_input_stream_read_uint16 (priv->dis, cancellable, error);
+ if (num == 3) {
+ gchar *tmp, *str = g_malloc0 (num + 1);
+
+ g_input_stream_read (G_INPUT_STREAM (priv->dis), str, num, cancellable, error);
+ /* not sure if its the right way to do, test it */
+ tmp = g_strconcat ("0000", str, NULL);
+
+ ret = atoi (tmp);
+ ret = GUINT32_SWAP_LE_BE (ret);
+
+ g_free (str);
+ g_free (tmp);
+ } else if (num == 4)
+ ret = g_data_input_stream_read_uint32 (priv->dis, cancellable, error);
+
+exit:
+ return ret;
+}
+
+static gchar *
+ews_decode_binary (EwsOabDecoder *eod, GCancellable *cancellable, GError **error)
+{
+ EwsOabDecoderPrivate *priv = GET_PRIVATE (eod);
+ guint32 len;
+ gchar *binary, *filename = NULL;
+ gint fd;
+
+ len = ews_decode_uint32 (eod, cancellable, error);
+ if (*error)
+ return NULL;
+
+ binary = g_malloc (len);
+ g_input_stream_read (G_INPUT_STREAM (priv->dis), binary, len, cancellable, error);
+ if (*error)
+ goto exit;
+
+ filename = g_build_filename (priv->cache_dir, "XXXXXX", NULL);
+ fd = g_mkstemp (filename);
+ g_file_set_contents (filename, binary, len, error);
+
+exit:
+ if (binary)
+ g_free (binary);
+ close (fd);
+
+ return filename;
+}
+
+static gpointer
+ews_decode_oab_prop (EwsOabDecoder *eod, guint32 prop_id, GCancellable *cancellable, GError **error)
+{
+ EwsOabDecoderPrivate *priv = GET_PRIVATE (eod);
+ guint32 prop_type;
+ gpointer ret_val = NULL;
+
+ prop_type = prop_id & 0x0000FFFF;
+
+ switch (prop_type) {
+ case EWS_PTYP_INTEGER32:
+ {
+ guint32 val;
+
+ val = ews_decode_uint32 (eod, cancellable, error);
+ ret_val = GUINT_TO_POINTER (val);
+
+ d(g_print ("prop id %x prop type: int32 value %d \n", prop_id, val);)
+
+ break;
+ }
+ case EWS_PTYP_BOOLEAN:
+ {
+ guchar val;
+
+ val = g_data_input_stream_read_byte (priv->dis, cancellable, error);
+ ret_val = GUINT_TO_POINTER ((guint) val);
+ d(g_print ("prop id %x prop type: bool value %d \n", prop_id, val);)
+
+ break;
+ }
+ case EWS_PTYP_STRING8:
+ case EWS_PTYP_STRING:
+ {
+ gsize len;
+ gchar *val;
+
+ val= g_data_input_stream_read_upto (priv->dis, "\0", 1, &len, cancellable, error);
+ g_data_input_stream_read_byte (priv->dis, cancellable, error);
+ ret_val = (gpointer) val;
+
+ d(g_print ("prop id %x prop type: string value %s \n", prop_id, val);)
+ break;
+ }
+ case EWS_PTYP_BINARY:
+ {
+ ret_val = ews_decode_binary (eod, cancellable, error);
+ d(g_print ("prop id %x prop type: binary value %s \n", prop_id, (gchar *) ret_val);)
+ break;
+ }
+ case EWS_PTYP_MULTIPLEINTEGER32:
+ case EWS_PTYP_MULTIPLESTRING8:
+ case EWS_PTYP_MULTIPLESTRING:
+ case EWS_PTYP_MULTIPLEBINARY:
+ {
+ guint32 num, i;
+ GSList *list = NULL;
+
+ num = ews_decode_uint32 (eod, cancellable, error);
+ if (*error)
+ break;
+ d(g_print ("prop id %x prop type: multi-num %d \n", prop_id, num);)
+
+ for (i = 0; i < num; i++) {
+ gpointer val;
+
+ if (prop_type == EWS_PTYP_MULTIPLEINTEGER32) {
+ guint32 v = 0;
+
+ v = ews_decode_uint32 (eod, cancellable, error);
+ val = GUINT_TO_POINTER (v);
+ list = g_slist_prepend (list, val);
+
+ d(g_print ("prop id %x prop type: multi-int32 %d \n", prop_id, v);)
+ if (*error) {
+ g_slist_free (list);
+ return NULL;
+ }
+ } else {
+ gchar *val;
+
+ if (prop_type == EWS_PTYP_MULTIPLEBINARY) {
+ val = ews_decode_binary (eod, cancellable, error);
+
+ d(g_print ("prop id %x prop type: multi-string %s \n", prop_id, val);)
+ } else {
+ gsize len;
+
+ val= g_data_input_stream_read_upto (priv->dis, "\0", 1, &len, cancellable, error);
+ g_data_input_stream_read_byte (priv->dis, cancellable, error);
+
+ d(g_print ("prop id %x prop type: multi-string %s \n", prop_id, val);)
+ }
+
+ if (*error) {
+ g_slist_foreach (list, (GFunc) g_free, NULL);
+ g_slist_free (list);
+ return NULL;
+ }
+ }
+
+ }
+
+ break;
+ }
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+
+ return ret_val;
+}
+
+
+static void
+ews_destroy_oab_prop (guint32 prop_id, gpointer val, gboolean delete_files)
+{
+ guint32 prop_type;
+
+ prop_type = prop_id & 0x0000FFFF;
+
+ switch (prop_type) {
+ case EWS_PTYP_INTEGER32:
+ case EWS_PTYP_BOOLEAN:
+ break;
+ case EWS_PTYP_STRING8:
+ case EWS_PTYP_STRING:
+ case EWS_PTYP_BINARY:
+ g_free ((gchar *) val);
+ break;
+ case EWS_PTYP_MULTIPLEBINARY:
+ g_slist_foreach ((GSList *)val, (GFunc) g_unlink, NULL);
+ case EWS_PTYP_MULTIPLESTRING8:
+ case EWS_PTYP_MULTIPLESTRING:
+ g_slist_foreach ((GSList *)val, (GFunc) g_free, NULL);
+ case EWS_PTYP_MULTIPLEINTEGER32:
+ g_slist_free ((GSList *) val);
+ break;
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+}
+
+/**
+ * ews_decode_addressbook_record
+ * @eod:
+ * @contact: Pass a valid EContact for decoding the address-book record. NULL in case of header record.
+ * @props:
+ * @cancellable:
+ * @error:
+ *
+ * Decodes the header and address-book records.
+ * Returns:
+ **/
+static gboolean
+ews_decode_addressbook_record (EwsOabDecoder *eod, EContact *contact, GSList *props, GCancellable *cancellable, GError **error)
+{
+ EwsOabDecoderPrivate *priv = GET_PRIVATE (eod);
+ guint bit_array_size, i, len;
+ gchar *bit_str;
+ gboolean ret = TRUE;
+ goffset offset;
+
+ /* fetch the offset */
+ offset = g_seekable_tell ((GSeekable *) priv->fis);
+
+ len = g_slist_length (props);
+ bit_array_size = (guint) ceil (len/8.0);
+ bit_str = g_malloc0 (bit_array_size);
+ g_input_stream_read (G_INPUT_STREAM (priv->dis), bit_str, bit_array_size, cancellable, error);
+ if (*error) {
+ ret = FALSE;
+ goto exit;
+ }
+
+ for (i = 0; i < len; i++) {
+ gpointer val;
+ guint32 prop_id;
+
+ if (!ews_is_bit_set (bit_str, i))
+ continue;
+
+ val = g_slist_nth_data (props, i);
+ prop_id = GPOINTER_TO_UINT (val);
+
+ val = ews_decode_oab_prop (eod, prop_id, cancellable, error);
+
+ /* Check the contact map and store the data in EContact */
+ if (contact) {
+
+ }
+
+ /* Store the contact summary into the db along with the offset */
+
+ ews_destroy_oab_prop (prop_id, val, *error ? TRUE : FALSE);
+ if (*error)
+ goto exit;
+ }
+
+exit:
+ if (bit_str)
+ g_free (bit_str);
+
+ return ret;
+}
+
+/* Decodes the hrd and address-book records and stores the address-book records inside the db */
+static gboolean
+ews_decode_and_store_oab_records (EwsOabDecoder *eod, GCancellable *cancellable, GError **error)
+{
+ EwsOabDecoderPrivate *priv = GET_PRIVATE (eod);
+ gboolean ret = TRUE;
+ guint32 size, i;
+
+ size = g_data_input_stream_read_uint32 (priv->dis, cancellable, error);
+ ews_decode_addressbook_record (eod, NULL, priv->hdr_props, cancellable, error);
+ if (*error) {
+ ret = FALSE;
+ goto exit;
+ }
+
+ for (i = 0; i < priv->total_records; i++) {
+ EContact *contact;
+
+ contact = e_contact_new ();
+ size = g_data_input_stream_read_uint32 (priv->dis, cancellable, error);
+ ews_decode_addressbook_record (eod, contact, priv->oab_props, cancellable, error);
+ if (*error) {
+ g_object_unref (contact);
+ ret = FALSE;
+ goto exit;
+ }
+
+ /* Store the contact summary into db with its offset */
+
+ g_object_unref (contact);
+ }
+
+exit:
+ return ret;
+}
+
+/**
+ * ews_oab_decoder_decode
+ * @eod:
+ * @ebsdb:
+ * @cancellable:
+ * @error:
+ *
+ * Decodes the oab full details verions 4 file and stores
+ * the summary in the sqlite db.
+ * Returns: TRUE if successfully decoded and indexed in db
+ **/
+gboolean
+ews_oab_decoder_decode (EwsOabDecoder *eod,
+ GCancellable *cancellable,
+ GError **error)
+{
+ EwsOabDecoderPrivate *priv = GET_PRIVATE (eod);
+ GError *err = NULL;
+ EwsOabHdr *o_hdr;
+ gboolean ret = TRUE;
+
+ o_hdr = ews_read_oab_header (eod, cancellable, &err);
+ if (!o_hdr) {
+ ret = FALSE;
+ goto exit;
+ }
+
+ priv->total_records = o_hdr->total_recs;
+
+ ret = ews_decode_metadata (eod, cancellable, &err);
+ if (!ret)
+ goto exit;
+
+ ret = ews_decode_and_store_oab_records (eod, cancellable, &err);
+
+exit:
+ if (o_hdr)
+ g_free (o_hdr);
+
+ if (priv->oab_props) {
+ g_slist_free (priv->oab_props);
+ priv->oab_props = NULL;
+ }
+
+ if (priv->hdr_props) {
+ g_slist_free (priv->hdr_props);
+ priv->hdr_props = NULL;
+ }
+
+ if (err)
+ g_propagate_error (error, err);
+
+ return ret;
+}
+
+EContact *
+ews_oab_decoder_get_contact_from_offset (EwsOabDecoder *eod,
+ goffset offset,
+ GCancellable *cancellable,
+ GError **error)
+{
+ EwsOabDecoderPrivate *priv = GET_PRIVATE (eod);
+ EContact *contact = NULL;
+
+ if (!g_seekable_seek ((GSeekable *) priv->dis, offset, G_SEEK_CUR, cancellable, error))
+ return NULL;
+
+ /* priv->oab_props = fetch from sqlite db */
+
+ contact = e_contact_new ();
+ ews_decode_addressbook_record (eod, contact, priv->oab_props, cancellable, error);
+ if (*error) {
+ g_object_unref (contact);
+ contact = NULL;
+ }
+
+ if (priv->oab_props) {
+ g_slist_free (priv->oab_props);
+ priv->oab_props = NULL;
+ }
+
+ return contact;
}
diff --git a/src/addressbook/ews-oab-decoder.h b/src/addressbook/ews-oab-decoder.h
index f391f7a..9f0cb55 100644
--- a/src/addressbook/ews-oab-decoder.h
+++ b/src/addressbook/ews-oab-decoder.h
@@ -25,6 +25,9 @@
#include <glib.h>
#include <glib-object.h>
+#include <gio/gio.h>
+
+#include "e-book-backend-sqlitedb.h"
G_BEGIN_DECLS
@@ -55,7 +58,18 @@ typedef struct {
GType ews_oab_decoder_get_type (void);
-EwsOabDecoder* ews_oab_decoder_new (const gchar *oab_filename);
+EwsOabDecoder* ews_oab_decoder_new (const gchar *oab_filename,
+ const gchar *cache_dir,
+ EBookBackendSqliteDB *ebsdb,
+ GError **error);
+gboolean ews_oab_decoder_decode (EwsOabDecoder *eod,
+ GCancellable *cancellable,
+ GError **error);
+EContact * ews_oab_decoder_get_contact_from_offset
+ (EwsOabDecoder *eod,
+ goffset offset,
+ GCancellable *cancellable,
+ GError **error);
G_END_DECLS
diff --git a/src/addressbook/ews-oab-props.h b/src/addressbook/ews-oab-props.h
index f93179c..00970c5 100644
--- a/src/addressbook/ews-oab-props.h
+++ b/src/addressbook/ews-oab-props.h
@@ -19,6 +19,9 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
+#ifndef _EWS_OAB_PROPS
+#define _EWS_OAB_PROPS
+
/* Ews oab data types */
#define EWS_PTYP_INTEGER32 0x0003
#define EWS_PTYP_BOOLEAN 0x000B
@@ -73,3 +76,5 @@
#define EWS_PT_MEMBER_OF_DLS 0x8008101E
#define EWS_PT_TRUNCATED_PROPS 0x68051003
#define EWS_PT_THUMBNAIL_PHOTO 0x8C9E0102
+
+#endif /* _EWS_OAB_PROPS */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]