evolution-mapi r2 - in trunk: . po src src/account-setup-eplugin src/addressbook src/calendar src/camel src/libexchangemapi



Author: jjohnny
Date: Wed Nov 19 04:28:20 2008
New Revision: 2
URL: http://svn.gnome.org/viewvc/evolution-mapi?rev=2&view=rev

Log:
Initial checkin from evolution and evolution-data-server's EXCHANGE_MAPI_BRANCH

Added:
   trunk/AUTHORS
   trunk/COPYING
   trunk/COPYING.LGPL3
   trunk/ChangeLog
   trunk/INSTALL
   trunk/MAINTAINERS
   trunk/Makefile.am
   trunk/NEWS
   trunk/README
   trunk/autogen.sh   (contents, props changed)
   trunk/configure.in
   trunk/eplugin-rule.mk
   trunk/po/
   trunk/po/ChangeLog
   trunk/po/Makefile.in.in
   trunk/po/POTFILES.in
   trunk/src/
   trunk/src/Makefile.am
   trunk/src/account-setup-eplugin/
   trunk/src/account-setup-eplugin/ChangeLog
   trunk/src/account-setup-eplugin/Makefile.am
   trunk/src/account-setup-eplugin/exchange-mapi-account-listener.c
   trunk/src/account-setup-eplugin/exchange-mapi-account-listener.h
   trunk/src/account-setup-eplugin/exchange-mapi-account-setup.c
   trunk/src/account-setup-eplugin/exchange-mapi-account-setup.h
   trunk/src/account-setup-eplugin/org-gnome-exchange-mapi.eplug.xml
   trunk/src/addressbook/
   trunk/src/addressbook/ChangeLog
   trunk/src/addressbook/Makefile.am
   trunk/src/addressbook/e-book-backend-mapi-factory.c
   trunk/src/addressbook/e-book-backend-mapi.c
   trunk/src/addressbook/e-book-backend-mapi.h
   trunk/src/calendar/
   trunk/src/calendar/ChangeLog
   trunk/src/calendar/Makefile.am
   trunk/src/calendar/e-cal-backend-mapi-factory.c
   trunk/src/calendar/e-cal-backend-mapi-factory.h
   trunk/src/calendar/e-cal-backend-mapi.c
   trunk/src/calendar/e-cal-backend-mapi.h
   trunk/src/camel/
   trunk/src/camel/ChangeLog
   trunk/src/camel/Makefile.am
   trunk/src/camel/camel-mapi-folder.c
   trunk/src/camel/camel-mapi-folder.h
   trunk/src/camel/camel-mapi-private.h
   trunk/src/camel/camel-mapi-provider.c
   trunk/src/camel/camel-mapi-store-summary.c
   trunk/src/camel/camel-mapi-store-summary.h
   trunk/src/camel/camel-mapi-store.c
   trunk/src/camel/camel-mapi-store.h
   trunk/src/camel/camel-mapi-summary.c
   trunk/src/camel/camel-mapi-summary.h
   trunk/src/camel/camel-mapi-transport.c
   trunk/src/camel/camel-mapi-transport.h
   trunk/src/camel/camel-private.h
   trunk/src/camel/libcamelmapi.urls
   trunk/src/libexchangemapi/
   trunk/src/libexchangemapi/ChangeLog
   trunk/src/libexchangemapi/Makefile.am
   trunk/src/libexchangemapi/exchange-mapi-cal-recur-utils.c
   trunk/src/libexchangemapi/exchange-mapi-cal-recur-utils.h
   trunk/src/libexchangemapi/exchange-mapi-cal-tz-utils.c
   trunk/src/libexchangemapi/exchange-mapi-cal-tz-utils.h
   trunk/src/libexchangemapi/exchange-mapi-cal-utils.c
   trunk/src/libexchangemapi/exchange-mapi-cal-utils.h
   trunk/src/libexchangemapi/exchange-mapi-connection.c
   trunk/src/libexchangemapi/exchange-mapi-connection.h
   trunk/src/libexchangemapi/exchange-mapi-defs.h
   trunk/src/libexchangemapi/exchange-mapi-folder.c
   trunk/src/libexchangemapi/exchange-mapi-folder.h
   trunk/src/libexchangemapi/exchange-mapi-utils.c
   trunk/src/libexchangemapi/exchange-mapi-utils.h
   trunk/src/libexchangemapi/libexchangemapi.pc.in
   trunk/src/libexchangemapi/tz-ical-to-mapi
   trunk/src/libexchangemapi/tz-mapi-to-ical

Added: trunk/AUTHORS
==============================================================================
--- (empty file)
+++ trunk/AUTHORS	Wed Nov 19 04:28:20 2008
@@ -0,0 +1,5 @@
+AUTHORS
+-------
+Johnny Jacob  <jjohnny novell com>
+Srinivasa Ragavan  <sragavan novell com>
+Suman Manjunath  <msuman novell com>
\ No newline at end of file

Added: trunk/COPYING
==============================================================================
--- (empty file)
+++ trunk/COPYING	Wed Nov 19 04:28:20 2008
@@ -0,0 +1 @@
+placeholder
\ No newline at end of file

Added: trunk/COPYING.LGPL3
==============================================================================
--- (empty file)
+++ trunk/COPYING.LGPL3	Wed Nov 19 04:28:20 2008
@@ -0,0 +1,166 @@
+		   GNU LESSER GENERAL PUBLIC LICENSE
+                       Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+
+  This version of the GNU Lesser General Public License incorporates
+the terms and conditions of version 3 of the GNU General Public
+License, supplemented by the additional permissions listed below.
+
+  0. Additional Definitions. 
+
+  As used herein, "this License" refers to version 3 of the GNU Lesser
+General Public License, and the "GNU GPL" refers to version 3 of the GNU
+General Public License.
+
+  "The Library" refers to a covered work governed by this License,
+other than an Application or a Combined Work as defined below.
+
+  An "Application" is any work that makes use of an interface provided
+by the Library, but which is not otherwise based on the Library.
+Defining a subclass of a class defined by the Library is deemed a mode
+of using an interface provided by the Library.
+
+  A "Combined Work" is a work produced by combining or linking an
+Application with the Library.  The particular version of the Library
+with which the Combined Work was made is also called the "Linked
+Version".
+
+  The "Minimal Corresponding Source" for a Combined Work means the
+Corresponding Source for the Combined Work, excluding any source code
+for portions of the Combined Work that, considered in isolation, are
+based on the Application, and not on the Linked Version.
+
+  The "Corresponding Application Code" for a Combined Work means the
+object code and/or source code for the Application, including any data
+and utility programs needed for reproducing the Combined Work from the
+Application, but excluding the System Libraries of the Combined Work.
+
+  1. Exception to Section 3 of the GNU GPL.
+
+  You may convey a covered work under sections 3 and 4 of this License
+without being bound by section 3 of the GNU GPL.
+
+  2. Conveying Modified Versions.
+
+  If you modify a copy of the Library, and, in your modifications, a
+facility refers to a function or data to be supplied by an Application
+that uses the facility (other than as an argument passed when the
+facility is invoked), then you may convey a copy of the modified
+version:
+
+   a) under this License, provided that you make a good faith effort to
+   ensure that, in the event an Application does not supply the
+   function or data, the facility still operates, and performs
+   whatever part of its purpose remains meaningful, or
+
+   b) under the GNU GPL, with none of the additional permissions of
+   this License applicable to that copy.
+
+  3. Object Code Incorporating Material from Library Header Files.
+
+  The object code form of an Application may incorporate material from
+a header file that is part of the Library.  You may convey such object
+code under terms of your choice, provided that, if the incorporated
+material is not limited to numerical parameters, data structure
+layouts and accessors, or small macros, inline functions and templates
+(ten or fewer lines in length), you do both of the following:
+
+   a) Give prominent notice with each copy of the object code that the
+   Library is used in it and that the Library and its use are
+   covered by this License.
+
+   b) Accompany the object code with a copy of the GNU GPL and this license
+   document.
+
+  4. Combined Works.
+
+  You may convey a Combined Work under terms of your choice that,
+taken together, effectively do not restrict modification of the
+portions of the Library contained in the Combined Work and reverse
+engineering for debugging such modifications, if you also do each of
+the following:
+
+   a) Give prominent notice with each copy of the Combined Work that
+   the Library is used in it and that the Library and its use are
+   covered by this License.
+
+   b) Accompany the Combined Work with a copy of the GNU GPL and this license
+   document.
+
+   c) For a Combined Work that displays copyright notices during
+   execution, include the copyright notice for the Library among
+   these notices, as well as a reference directing the user to the
+   copies of the GNU GPL and this license document.
+
+   d) Do one of the following:
+
+       0) Convey the Minimal Corresponding Source under the terms of this
+       License, and the Corresponding Application Code in a form
+       suitable for, and under terms that permit, the user to
+       recombine or relink the Application with a modified version of
+       the Linked Version to produce a modified Combined Work, in the
+       manner specified by section 6 of the GNU GPL for conveying
+       Corresponding Source.
+
+       1) Use a suitable shared library mechanism for linking with the
+       Library.  A suitable mechanism is one that (a) uses at run time
+       a copy of the Library already present on the user's computer
+       system, and (b) will operate properly with a modified version
+       of the Library that is interface-compatible with the Linked
+       Version. 
+
+   e) Provide Installation Information, but only if you would otherwise
+   be required to provide such information under section 6 of the
+   GNU GPL, and only to the extent that such information is
+   necessary to install and execute a modified version of the
+   Combined Work produced by recombining or relinking the
+   Application with a modified version of the Linked Version. (If
+   you use option 4d0, the Installation Information must accompany
+   the Minimal Corresponding Source and Corresponding Application
+   Code. If you use option 4d1, you must provide the Installation
+   Information in the manner specified by section 6 of the GNU GPL
+   for conveying Corresponding Source.)
+
+  5. Combined Libraries.
+
+  You may place library facilities that are a work based on the
+Library side by side in a single library together with other library
+facilities that are not Applications and are not covered by this
+License, and convey such a combined library under terms of your
+choice, if you do both of the following:
+
+   a) Accompany the combined library with a copy of the same work based
+   on the Library, uncombined with any other library facilities,
+   conveyed under the terms of this License.
+
+   b) Give prominent notice with the combined library that part of it
+   is a work based on the Library, and explaining where to find the
+   accompanying uncombined form of the same work.
+
+  6. Revised Versions of the GNU Lesser General Public License.
+
+  The Free Software Foundation may publish revised and/or new versions
+of the GNU Lesser General Public License from time to time. Such new
+versions will be similar in spirit to the present version, but may
+differ in detail to address new problems or concerns.
+
+  Each version is given a distinguishing version number. If the
+Library as you received it specifies that a certain numbered version
+of the GNU Lesser General Public License "or any later version"
+applies to it, you have the option of following the terms and
+conditions either of that published version or of any later version
+published by the Free Software Foundation. If the Library as you
+received it does not specify a version number of the GNU Lesser
+General Public License, you may choose any version of the GNU Lesser
+General Public License ever published by the Free Software Foundation.
+
+  If the Library as you received it specifies that a proxy can decide
+whether future versions of the GNU Lesser General Public License shall
+apply, that proxy's public statement of acceptance of any version is
+permanent authorization for you to choose that version for the
+Library.
+

Added: trunk/INSTALL
==============================================================================
--- (empty file)
+++ trunk/INSTALL	Wed Nov 19 04:28:20 2008
@@ -0,0 +1 @@
+http://www.go-evolution.org/MAPIProvider

Added: trunk/MAINTAINERS
==============================================================================
--- (empty file)
+++ trunk/MAINTAINERS	Wed Nov 19 04:28:20 2008
@@ -0,0 +1,4 @@
+
+Johnny Jacob
+E-mail: jjohnny novell com
+Userid: jjohnny

Added: trunk/Makefile.am
==============================================================================
--- (empty file)
+++ trunk/Makefile.am	Wed Nov 19 04:28:20 2008
@@ -0,0 +1,18 @@
+AUTOMAKE_OPTIONS = 1.6
+
+SUBDIRS = src po
+DIST_SUBDIRS= src po
+
+changelogs =			\
+	ChangeLog
+
+EXTRA_DIST = 			\
+	$(changelog)		\
+	eplugin-rule.mk		\
+	intltool-merge.in	\
+	intltool-update.in	\
+	intltool-extract.in	
+
+CLEANFILES = 	intltool-merge	\
+		intltool-update	\
+		intltool-extract	

Added: trunk/NEWS
==============================================================================

Added: trunk/README
==============================================================================
--- (empty file)
+++ trunk/README	Wed Nov 19 04:28:20 2008
@@ -0,0 +1 @@
+http://www.go-evolution.org/MAPIProvider

Added: trunk/autogen.sh
==============================================================================
--- (empty file)
+++ trunk/autogen.sh	Wed Nov 19 04:28:20 2008
@@ -0,0 +1,23 @@
+#!/bin/sh
+# Run this to generate all the initial makefiles, etc.
+
+srcdir=`dirname $0`
+test -z "$srcdir" && srcdir=.
+
+PKG_NAME="evolution-mapi"
+REQUIRED_AUTOMAKE_VERSION=1.6
+
+(test -f $srcdir/configure.in \
+  && test -f $srcdir/ChangeLog \
+  && test -d $srcdir/src/account-setup-eplugin) || {
+    echo -n "**Error**: Directory "\`$srcdir\'" does not look like the"
+    echo " top-level $PKG_NAME directory"
+    exit 1
+}
+
+which gnome-autogen.sh || {
+    echo "You need to install gnome-common from the GNOME SVN"
+    exit 1
+}
+USE_GNOME2_MACROS=1 . gnome-autogen.sh
+

Added: trunk/configure.in
==============================================================================
--- (empty file)
+++ trunk/configure.in	Wed Nov 19 04:28:20 2008
@@ -0,0 +1,147 @@
+# Simple configuration script for openchange evolution plugin
+# Written by Julien Kerihuel <j kerihuel openchange org>
+# Modified for GNOME Evolution MAPI Provider by Johnny Jacob <jjohnny novell com>
+
+AC_PREREQ(2.57)
+AC_INIT(evolution-mapi, 0.1, http://go-evolution.org/MAPIProvider, evolution-mapi)
+AC_CONFIG_SRCDIR(README)
+
+AM_INIT_AUTOMAKE(AC_PACKAGE_NAME, AC_PACKAGE_VERSION)
+
+AC_CONFIG_HEADER([config.h])
+AC_DEFINE(_GNU_SOURCE, 1, [Use GNU extensions])
+AC_PROG_CC
+
+AC_PROG_INTLTOOL([0.35.5])
+
+dnl I18N stuff
+AM_GLIB_GNU_GETTEXT
+
+GETTEXT_PACKAGE=evolution-mapi
+AC_SUBST(GETTEXT_PACKAGE)
+AC_DEFINE_UNQUOTED(GETTEXT_PACKAGE, "$GETTEXT_PACKAGE", [Package name for gettext])
+
+localedir='$(prefix)/$(DATADIRNAME)/locale'
+AC_SUBST(localedir)
+
+dnl Initialize libtool
+AC_PROG_LIBTOOL
+
+PKG_PROG_PKG_CONFIG
+
+dnl ****************************
+dnl Check for evolution plugins 
+dnl ****************************
+
+AC_ARG_WITH(evolution, [  --evolution=[version] Use Evolution version.],
+			evolution_version="$withval", evolution_version="2.12")	
+
+AC_ARG_WITH(evolution-camelprovider, [  --evolution-camel=[version] Use Evolution Camel Provider version.],
+				   evolution_camel_version="$withval", evolution_camel_version="1.2" )
+
+PKG_CHECK_MODULES(EVOLUTION_DATA_SERVER, evolution-data-server-${evolution_camel_version})
+PKG_CHECK_MODULES(EVOLUTION_PLUGIN, evolution-plugin)
+
+PKG_CHECK_MODULES(LIBEDATASERVER, libedataserver-${evolution_camel_version})
+PKG_CHECK_MODULES(LIBEBACKEND, libebackend-${evolution_camel_version})
+
+PKG_CHECK_MODULES(LIBECAL, libecal-${evolution_camel_version})
+PKG_CHECK_MODULES(LIBEDATACAL, libedata-cal-${evolution_camel_version})
+
+PKG_CHECK_MODULES(LIBBOOK, libebook-${evolution_camel_version})
+PKG_CHECK_MODULES(LIBEDATABOOK, libedata-book-${evolution_camel_version})
+
+PKG_CHECK_MODULES(CAMEL, camel-provider-${evolution_camel_version})
+
+dnl TODO : Version check. 
+PKG_CHECK_MODULES(LIBMAPI, libmapi)
+PKG_CHECK_MODULES(GCONF2, gconf-2.0)
+
+AC_PATH_PROG(GCONFTOOL, gconftool-2, no)
+AM_GCONF_SOURCE_2
+
+API_VERSION=${evolution_camel_version}
+AC_SUBST(API_VERSION)
+
+BASE_VERSION=`pkg-config --variable=execversion evolution-shell`
+AC_SUBST(BASE_VERSION)
+
+GETTEXT_PACKAGE=evolution
+AC_SUBST(GETTEXT_PACKAGE)
+AC_DEFINE_UNQUOTED(GETTEXT_PACKAGE,"$GETTEXT_PACKAGE", [Package Name for Gettext])
+
+dnl Add evolution plugin rules here
+EVO_PLUGIN_RULE=$srcdir/eplugin-rule.mk
+AC_SUBST_FILE(EVO_PLUGIN_RULE)
+
+EVOLUTION_PLUGIN="evolution-plugin"
+AC_SUBST(EVOLUTION_PLUGIN)
+
+EVOLUTION_CAMEL="evolution-camel"
+AC_SUBST(EVOLUTION_CAMEL)
+
+EVOLUTION_CALENDAR="evolution-calendar"
+AC_SUBST(EVOLUTION_CALENDAR)
+
+EVOLUTION_EBOOK="evolution-ebook"
+AC_SUBST(EVOLUTION_EBOOK)
+
+EVOLUTION_PLUGIN_INSTALL="evolution-plugin-install"
+AC_SUBST(EVOLUTION_PLUGIN_INSTALL)
+
+EVOLUTION_CAMEL_INSTALL="evolution-camel-install"
+AC_SUBST(EVOLUTION_CAMEL_INSTALL)
+
+EVOLUTION_CALENDAR_INSTALL="evolution-calendar-install"
+AC_SUBST(EVOLUTION_CALENDAR_INSTALL)
+
+EVOLUTION_EBOOK_INSTALL="evolution-ebook-install"
+AC_SUBST(EVOLUTION_EBOOK_INSTALL)
+
+EVOLUTION_PLUGIN_UNINSTALL="evolution-plugin-uninstall"
+AC_SUBST(EVOLUTION_PLUGIN_UNINSTALL)
+
+EVOLUTION_CAMEL_UNINSTALL="evolution-camel-uninstall"
+AC_SUBST(EVOLUTION_CAMEL_UNINSTALL)
+
+EVOLUTION_CALENDAR_UNINSTALL="evolution-calendar-uninstall"
+AC_SUBST(EVOLUTION_CALENDAR_UNINSTALL)
+
+EVOLUTION_EBOOK_UNINSTALL="evolution-ebook-uninstall"
+AC_SUBST(EVOLUTION_EBOOK_UNINSTALL)
+
+plugindir=`$PKG_CONFIG --variable=plugindir evolution-plugin`
+AC_SUBST(plugindir)
+
+camel_providerdir=`$PKG_CONFIG --variable=camel_providerdir camel-provider-${evolution_camel_version}`
+AC_SUBST(camel_providerdir)
+
+extensiondir=`$PKG_CONFIG --variable=extensiondir evolution-data-server-${evolution_camel_version}`
+AC_SUBST(extensiondir)
+
+libmapi_ldif_dir=`$PKG_CONFIG --variable=libdir libmapi`/openchange/setup
+AC_SUBST(libmapi_ldif_dir)
+
+eds_privdatadir=`$PKG_CONFIG --variable=privdatadir evolution-data-server-${evolution_camel_version}`
+AC_SUBST(eds_privdatadir)
+
+edataserver_privincludedir=`$PKG_CONFIG --variable=privincludedir libedataserver-${evolution_camel_version}`
+AC_SUBST(edataserver_privincludedir)
+
+mapidatadir="$eds_privdatadir/mapi"
+AC_SUBST(mapidatadir)
+
+dnl ***********************
+dnl Makefiles 
+dnl ***********************
+
+AC_CONFIG_FILES([Makefile 
+src/Makefile
+src/libexchangemapi/Makefile
+src/calendar/Makefile
+src/addressbook/Makefile
+src/camel/Makefile
+src/account-setup-eplugin/Makefile
+po/Makefile.in
+])
+AC_OUTPUT
\ No newline at end of file

Added: trunk/eplugin-rule.mk
==============================================================================
--- (empty file)
+++ trunk/eplugin-rule.mk	Wed Nov 19 04:28:20 2008
@@ -0,0 +1,11 @@
+%.eplug: %.eplug.in
+	sed -e 's|\ PLUGINDIR\@|$(plugindir)|'		\
+	-e 's|\ SOEXT\@|$(SOEXT)|'			\
+	-e 's|\ GETTEXT_PACKAGE\@|$(GETTEXT_PACKAGE)|'	\
+	-e 's|\ LOCALEDIR\@|$(localedir)|' $< > $@
+
+%.eplug.in: %.eplug.xml
+	LC_ALL=C $(INTLTOOL_MERGE) -x -u /tmp $< $@
+
+%.error: %.error.xml
+	LC_ALL=C $(INTLTOOL_MERGE) -x -u /tmp $< $@

Added: trunk/po/Makefile.in.in
==============================================================================
--- (empty file)
+++ trunk/po/Makefile.in.in	Wed Nov 19 04:28:20 2008
@@ -0,0 +1,217 @@
+# Makefile for program source directory in GNU NLS utilities package.
+# Copyright (C) 1995, 1996, 1997 by Ulrich Drepper <drepper gnu ai mit edu>
+# Copyright (C) 2004-2008 Rodney Dawes <dobey pwns gmail com>
+#
+# This file may be copied and used freely without restrictions.  It may
+# be used in projects which are not available under a GNU Public License,
+# but which still want to provide support for the GNU gettext functionality.
+#
+# - Modified by Owen Taylor <otaylor redhat com> to use GETTEXT_PACKAGE
+#   instead of PACKAGE and to look for po2tbl in ./ not in intl/
+#
+# - Modified by jacob berkman <jacob ximian com> to install
+#   Makefile.in.in and po2tbl.sed.in for use with glib-gettextize
+#
+# - Modified by Rodney Dawes <dobey pwns gmail com> for use with intltool
+#
+# We have the following line for use by intltoolize:
+# INTLTOOL_MAKEFILE
+
+GETTEXT_PACKAGE = @GETTEXT_PACKAGE@
+PACKAGE = @PACKAGE@
+VERSION = @VERSION@
+
+SHELL = /bin/sh
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+top_builddir = @top_builddir@
+VPATH = @srcdir@
+
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+datadir = @datadir@
+datarootdir = @datarootdir@
+libdir = @libdir@
+DATADIRNAME = @DATADIRNAME@
+itlocaledir = $(prefix)/$(DATADIRNAME)/locale
+subdir = po
+install_sh = @install_sh@
+# Automake >= 1.8 provides @mkdir_p  
+# Until it can be supposed, use the safe fallback:
+mkdir_p = $(install_sh) -d
+
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+
+GMSGFMT = @GMSGFMT@
+MSGFMT = @MSGFMT@
+XGETTEXT = @XGETTEXT@
+INTLTOOL_UPDATE = @INTLTOOL_UPDATE@
+INTLTOOL_EXTRACT = @INTLTOOL_EXTRACT@
+MSGMERGE = INTLTOOL_EXTRACT=$(INTLTOOL_EXTRACT) srcdir=$(srcdir) $(INTLTOOL_UPDATE) --gettext-package $(GETTEXT_PACKAGE) --dist
+GENPOT   = INTLTOOL_EXTRACT=$(INTLTOOL_EXTRACT) srcdir=$(srcdir) $(INTLTOOL_UPDATE) --gettext-package $(GETTEXT_PACKAGE) --pot
+
+ALL_LINGUAS = @ALL_LINGUAS@
+
+PO_LINGUAS=$(shell if test -r $(srcdir)/LINGUAS; then grep -v "^\#" $(srcdir)/LINGUAS; else echo "$(ALL_LINGUAS)"; fi)
+
+USER_LINGUAS=$(shell if test -n "$(LINGUAS)"; then LLINGUAS="$(LINGUAS)"; ALINGUAS="$(ALL_LINGUAS)"; for lang in $$LLINGUAS; do if test -n "`grep ^$$lang$$ $(srcdir)/LINGUAS 2>/dev/null`" -o -n "`echo $$ALINGUAS|tr ' ' '\n'|grep ^$$lang$$`"; then printf "$$lang "; fi; done; fi)
+
+USE_LINGUAS=$(shell if test -n "$(USER_LINGUAS)" -o -n "$(LINGUAS)"; then LLINGUAS="$(USER_LINGUAS)"; else if test -n "$(PO_LINGUAS)"; then LLINGUAS="$(PO_LINGUAS)"; else LLINGUAS="$(ALL_LINGUAS)"; fi; fi; for lang in $$LLINGUAS; do printf "$$lang "; done)
+
+POFILES=$(shell LINGUAS="$(PO_LINGUAS)"; for lang in $$LINGUAS; do printf "$$lang.po "; done)
+
+DISTFILES = Makefile.in.in POTFILES.in $(POFILES)
+EXTRA_DISTFILES = ChangeLog POTFILES.skip Makevars LINGUAS
+
+POTFILES = \
+# This comment gets stripped out
+
+CATALOGS=$(shell LINGUAS="$(USE_LINGUAS)"; for lang in $$LINGUAS; do printf "$$lang.gmo "; done)
+
+.SUFFIXES:
+.SUFFIXES: .po .pox .gmo .mo .msg .cat
+
+.po.pox:
+	$(MAKE) $(GETTEXT_PACKAGE).pot
+	$(MSGMERGE) $< $(GETTEXT_PACKAGE).pot -o $*.pox
+
+.po.mo:
+	$(MSGFMT) -o $@ $<
+
+.po.gmo:
+	file=`echo $* | sed 's,.*/,,'`.gmo \
+	  && rm -f $$file && $(GMSGFMT) -o $$file $<
+
+.po.cat:
+	sed -f ../intl/po2msg.sed < $< > $*.msg \
+	  && rm -f $@ && gencat $@ $*.msg
+
+
+all: all- USE_NLS@
+
+all-yes: $(CATALOGS)
+all-no:
+
+$(GETTEXT_PACKAGE).pot: $(POTFILES)
+	$(GENPOT)
+
+install: install-data
+install-data: install-data- USE_NLS@
+install-data-no: all
+install-data-yes: all
+	linguas="$(USE_LINGUAS)"; \
+	for lang in $$linguas; do \
+	  dir=$(DESTDIR)$(itlocaledir)/$$lang/LC_MESSAGES; \
+	  $(mkdir_p) $$dir; \
+	  if test -r $$lang.gmo; then \
+	    $(INSTALL_DATA) $$lang.gmo $$dir/$(GETTEXT_PACKAGE).mo; \
+	    echo "installing $$lang.gmo as $$dir/$(GETTEXT_PACKAGE).mo"; \
+	  else \
+	    $(INSTALL_DATA) $(srcdir)/$$lang.gmo $$dir/$(GETTEXT_PACKAGE).mo; \
+	    echo "installing $(srcdir)/$$lang.gmo as" \
+		 "$$dir/$(GETTEXT_PACKAGE).mo"; \
+	  fi; \
+	  if test -r $$lang.gmo.m; then \
+	    $(INSTALL_DATA) $$lang.gmo.m $$dir/$(GETTEXT_PACKAGE).mo.m; \
+	    echo "installing $$lang.gmo.m as $$dir/$(GETTEXT_PACKAGE).mo.m"; \
+	  else \
+	    if test -r $(srcdir)/$$lang.gmo.m ; then \
+	      $(INSTALL_DATA) $(srcdir)/$$lang.gmo.m \
+		$$dir/$(GETTEXT_PACKAGE).mo.m; \
+	      echo "installing $(srcdir)/$$lang.gmo.m as" \
+		   "$$dir/$(GETTEXT_PACKAGE).mo.m"; \
+	    else \
+	      true; \
+	    fi; \
+	  fi; \
+	done
+
+# Empty stubs to satisfy archaic automake needs
+dvi info tags TAGS ID:
+
+# Define this as empty until I found a useful application.
+install-exec installcheck:
+
+uninstall:
+	linguas="$(USE_LINGUAS)"; \
+	for lang in $$linguas; do \
+	  rm -f $(DESTDIR)$(itlocaledir)/$$lang/LC_MESSAGES/$(GETTEXT_PACKAGE).mo; \
+	  rm -f $(DESTDIR)$(itlocaledir)/$$lang/LC_MESSAGES/$(GETTEXT_PACKAGE).mo.m; \
+	done
+
+check: all $(GETTEXT_PACKAGE).pot
+	rm -f missing notexist
+	srcdir=$(srcdir) $(INTLTOOL_UPDATE) -m
+	if [ -r missing -o -r notexist ]; then \
+	  exit 1; \
+	fi
+
+mostlyclean:
+	rm -f *.pox $(GETTEXT_PACKAGE).pot *.old.po cat-id-tbl.tmp
+	rm -f .intltool-merge-cache
+
+clean: mostlyclean
+
+distclean: clean
+	rm -f Makefile Makefile.in POTFILES stamp-it
+	rm -f *.mo *.msg *.cat *.cat.m *.gmo
+
+maintainer-clean: distclean
+	@echo "This command is intended for maintainers to use;"
+	@echo "it deletes files that may require special tools to rebuild."
+	rm -f Makefile.in.in
+
+distdir = ../$(PACKAGE)-$(VERSION)/$(subdir)
+dist distdir: $(DISTFILES)
+	dists="$(DISTFILES)"; \
+	extra_dists="$(EXTRA_DISTFILES)"; \
+	for file in $$extra_dists; do \
+	  test -f $(srcdir)/$$file && dists="$$dists $(srcdir)/$$file"; \
+	done; \
+	for file in $$dists; do \
+	  test -f $$file || file="$(srcdir)/$$file"; \
+	  ln $$file $(distdir) 2> /dev/null \
+	    || cp -p $$file $(distdir); \
+	done
+
+update-po: Makefile
+	$(MAKE) $(GETTEXT_PACKAGE).pot
+	tmpdir=`pwd`; \
+	linguas="$(USE_LINGUAS)"; \
+	for lang in $$linguas; do \
+	  echo "$$lang:"; \
+	  result="`$(MSGMERGE) -o $$tmpdir/$$lang.new.po $$lang`"; \
+	  if $$result; then \
+	    if cmp $(srcdir)/$$lang.po $$tmpdir/$$lang.new.po >/dev/null 2>&1; then \
+	      rm -f $$tmpdir/$$lang.new.po; \
+            else \
+	      if mv -f $$tmpdir/$$lang.new.po $$lang.po; then \
+	        :; \
+	      else \
+	        echo "msgmerge for $$lang.po failed: cannot move $$tmpdir/$$lang.new.po to $$lang.po" 1>&2; \
+	        rm -f $$tmpdir/$$lang.new.po; \
+	        exit 1; \
+	      fi; \
+	    fi; \
+	  else \
+	    echo "msgmerge for $$lang.gmo failed!"; \
+	    rm -f $$tmpdir/$$lang.new.po; \
+	  fi; \
+	done
+
+Makefile POTFILES: stamp-it
+	@if test ! -f $@; then \
+	  rm -f stamp-it; \
+	  $(MAKE) stamp-it; \
+	fi
+
+stamp-it: Makefile.in.in $(top_builddir)/config.status POTFILES.in
+	cd $(top_builddir) \
+	  && CONFIG_FILES=$(subdir)/Makefile.in CONFIG_HEADERS= CONFIG_LINKS= \
+	       $(SHELL) ./config.status
+
+# Tell versions [3.59,3.63) of GNU make not to export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:

Added: trunk/po/POTFILES.in
==============================================================================
--- (empty file)
+++ trunk/po/POTFILES.in	Wed Nov 19 04:28:20 2008
@@ -0,0 +1,7 @@
+src/account-setup-eplugin/exchange-account-listener.c
+src/account-setup-eplugin/exchange-mapi-account-setup.c
+src/backends/calendar/e-cal-backend-mapi.c
+src/camel/camel-mapi-folder.c
+src/camel/camel-mapi-provider.c
+src/camel/camel-mapi-store.c
+src/camel/camel-mapi-transport.c

Added: trunk/src/Makefile.am
==============================================================================
--- (empty file)
+++ trunk/src/Makefile.am	Wed Nov 19 04:28:20 2008
@@ -0,0 +1,2 @@
+SUBDIRS=libexchangemapi calendar addressbook camel account-setup-eplugin
+DIST_SUBDIRS=libexchangemapi calendar addressbook camel account-setup-eplugin
\ No newline at end of file

Added: trunk/src/account-setup-eplugin/Makefile.am
==============================================================================
--- (empty file)
+++ trunk/src/account-setup-eplugin/Makefile.am	Wed Nov 19 04:28:20 2008
@@ -0,0 +1,40 @@
+INCLUDES = -I .						\
+	-DEVOLUTION_GLADEDIR=\""$(gladedir)"\" 		\
+	-DCONNECTOR_GLADEDIR=\""$(gladedir)"\" 		\
+	-DLIBMAPI_LDIF_DIR=\""$(libmapi_ldif_dir)"\"	\
+	-I$(top_srcdir)/src/libexchangemapi/		\
+	$(CAMEL_CFLAGS)					\
+	$(EVOLUTION_PLUGIN_CFLAGS)			\
+	$(EVOLUTION_CALENDAR_CFLAGS) \
+	$(EVOLUTION_ADDRESSBOOK_CFLAGS) \
+	$(LIBMAPI_CFLAGS)
+
+
+ EVO_PLUGIN_RULE@
+
+plugin_DATA = org-gnome-exchange-mapi.eplug 	
+
+plugin_LTLIBRARIES = liborg-gnome-exchange-mapi.la
+
+liborg_gnome_exchange_mapi_la_SOURCES = 		\
+	exchange-mapi-account-setup.c			\
+	exchange-mapi-account-setup.h			\
+	exchange-mapi-account-listener.c		\
+	exchange-mapi-account-listener.h
+
+liborg_gnome_exchange_mapi_la_LIBADD = 			\
+	$(EVOLUTION_CALENDAR_LIBS) \
+	$(EVOLUTION_ADDRESSBOOK_LIBS) \
+	$(EVOLUTION_PLUGIN_LIBS)	\
+	$(CAMEL_LIBS) \
+	$(LIBMAPI_LIBS)
+
+liborg_gnome_exchange_mapi_la_LDFLAGS = -module -avoid-version -lmapi $(NO_UNDEFINED)
+liborg_gnome_exchange_mapi_la_CFLAGS = -I/usr/local/samba/include/
+
+EXTRA_DIST = 							\
+	org-gnome-exchange-mapi.eplug.xml
+
+BUILT_SOURCES = org-gnome-exchange-mapi.eplug	
+
+CLEANFILES = $(BUILT_SOURCES)

Added: trunk/src/account-setup-eplugin/exchange-mapi-account-listener.c
==============================================================================
--- (empty file)
+++ trunk/src/account-setup-eplugin/exchange-mapi-account-listener.c	Wed Nov 19 04:28:20 2008
@@ -0,0 +1,783 @@
+/*
+ * 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/> 
+ *
+ *
+ * Authors:
+ *		Srinivasa Ragavan <sragavan novell com>
+ *		Suman Manjunath <msuman novell com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "exchange-mapi-account-listener.h"
+#include "exchange-mapi-account-setup.h"
+#include <string.h>
+#include <camel/camel-i18n.h>
+#include <libedataserverui/e-passwords.h>
+#include "e-util/e-error.h"
+#include <libedataserver/e-account.h>
+#include <libecal/e-cal.h>
+#include <libedataserver/e-account-list.h>
+#include <libedataserver/e-source.h>
+#include <libedataserver/e-source-list.h>
+#include <camel/camel-url.h>
+
+#include <libmapi/libmapi.h>
+
+
+/* FIXME: The mapi should not be needed in the include statement.
+LIMBAPI_CFLAGS or something is going wrong */
+
+#include <mapi/exchange-mapi-folder.h>
+#include <mapi/exchange-mapi-connection.h>
+#include <mapi/exchange-mapi-utils.h>
+
+#define d(x) x
+
+struct _ExchangeMAPIAccountListenerPrivate {
+	GConfClient *gconf_client;
+	/* we get notification about mail account changes from this object */
+	EAccountList *account_list;
+};
+
+typedef struct _ExchangeMAPIAccountInfo ExchangeMAPIAccountInfo;
+
+/* stores some info about all currently existing mapi accounts */
+struct _ExchangeMAPIAccountInfo {
+	char *uid;
+	char *name;
+	char *source_url;
+	gboolean enabled; 
+};
+
+/* list of ExchangeMAPIAccountInfo structures */
+static 	GList *mapi_accounts = NULL;
+
+#define PARENT_TYPE G_TYPE_OBJECT
+
+static GObjectClass *parent_class = NULL;
+
+static void 
+dispose (GObject *object)
+{
+	ExchangeMAPIAccountListener *config_listener = EXCHANGE_MAPI_ACCOUNT_LISTENER (object);
+	
+	g_object_unref (config_listener->priv->gconf_client);
+	g_object_unref (config_listener->priv->account_list);
+
+	G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static void 
+finalize (GObject *object)
+{
+	ExchangeMAPIAccountListener *config_listener = EXCHANGE_MAPI_ACCOUNT_LISTENER (object);
+	GList *list;
+
+	if (config_listener->priv) {
+		g_free (config_listener->priv);
+	}
+
+	for (list = g_list_first (mapi_accounts); list ; list = g_list_next (list)) {
+		ExchangeMAPIAccountInfo *info = (ExchangeMAPIAccountInfo *)(list->data);
+		if (info) {
+			g_free (info->uid);
+			g_free (info->name);
+			g_free (info->source_url);
+			g_free (info);
+		}
+	}
+	
+	g_list_free (mapi_accounts);
+
+	G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void 
+exchange_mapi_account_listener_class_init (ExchangeMAPIAccountListenerClass *class)
+{
+	GObjectClass *object_class;
+	
+	parent_class = g_type_class_ref (PARENT_TYPE);
+	object_class = G_OBJECT_CLASS (class);
+	
+	/* virtual method override */
+	object_class->dispose = dispose;
+	object_class->finalize = finalize;
+}
+
+static void 
+exchange_mapi_account_listener_init (ExchangeMAPIAccountListener *config_listener, ExchangeMAPIAccountListenerClass *class)
+{
+	config_listener->priv = g_new0 (ExchangeMAPIAccountListenerPrivate, 1);
+}
+
+
+/* This is a list of folders returned by e-d-s. */
+static	GSList *folders_list = NULL;
+
+GSList *
+exchange_mapi_account_listener_peek_folder_list (void)
+{
+	if (!folders_list)
+		folders_list = exchange_mapi_peek_folder_list ();
+
+	return folders_list;
+}
+
+void
+exchange_mapi_account_listener_get_folder_list (void)
+{
+	if (folders_list)
+		return;
+
+	folders_list = exchange_mapi_peek_folder_list ();
+}
+
+void
+exchange_mapi_account_listener_free_folder_list (void)
+{
+	exchange_mapi_folder_list_free ();
+	folders_list = NULL;
+}
+
+/*determines whehter the passed in account is exchange or not by looking at source url */
+
+static gboolean
+is_mapi_account (EAccount *account)
+{
+	return (account->source->url && (g_ascii_strncasecmp (account->source->url, MAPI_URI_PREFIX, MAPI_PREFIX_LENGTH) == 0));
+}
+
+/* looks up for an existing exchange account info in the mapi_accounts list based on uid */
+
+static ExchangeMAPIAccountInfo* 
+lookup_account_info (const char *key)
+{
+	GList *list;
+
+	g_return_val_if_fail (key != NULL, NULL); 
+
+	for (list = g_list_first (mapi_accounts); list; list = g_list_next (list)) {
+		ExchangeMAPIAccountInfo *info = (ExchangeMAPIAccountInfo *)(list->data);
+		if (g_ascii_strcasecmp (info->uid, key) == 0)
+			return info; 
+	}
+
+	return NULL;
+}
+
+#define CALENDAR_SOURCES 	"/apps/evolution/calendar/sources"
+#define TASK_SOURCES 		"/apps/evolution/tasks/sources"
+#define JOURNAL_SOURCES 	"/apps/evolution/memos/sources"
+#define SELECTED_CALENDARS 	"/apps/evolution/calendar/display/selected_calendars"
+#define SELECTED_TASKS 		"/apps/evolution/calendar/tasks/selected_tasks"
+#define SELECTED_JOURNALS 	"/apps/evolution/calendar/memos/selected_memos"
+
+#define ITIP_MESSAGE_HANDLING 	"/apps/evolution/itip/delete_processed"
+
+static void
+add_cal_esource (EAccount *account, GSList *folders, ExchangeMAPIFolderType folder_type, CamelURL *url)
+{
+	ESourceList *source_list = NULL;
+	ESourceGroup *group = NULL;
+	const gchar *conf_key = NULL, *source_selection_key = NULL;
+ 	GSList *temp_list = NULL;
+	GConfClient* client;
+	GSList *ids, *temp ;
+	gchar *base_uri = NULL;
+
+	if (folder_type == MAPI_FOLDER_TYPE_APPOINTMENT) { 
+		conf_key = CALENDAR_SOURCES;
+		source_selection_key = SELECTED_CALENDARS;
+	} else if (folder_type == MAPI_FOLDER_TYPE_TASK) { 
+		conf_key = TASK_SOURCES;
+		source_selection_key = SELECTED_TASKS;
+	} else if (folder_type == MAPI_FOLDER_TYPE_MEMO) {
+		conf_key = JOURNAL_SOURCES;
+		source_selection_key = SELECTED_JOURNALS;
+	} else {
+		g_warning ("%s(%d): %s: Unknown ExchangeMAPIFolderType\n", __FILE__, __LINE__, __PRETTY_FUNCTION__);
+		return;
+	} 
+
+	client = gconf_client_get_default ();
+	gconf_client_set_bool (client, ITIP_MESSAGE_HANDLING, TRUE, NULL);
+	source_list = e_source_list_new_for_gconf (client, conf_key);
+	base_uri = g_strdup_printf ("%s%s %s/", MAPI_URI_PREFIX, url->user, url->host);
+	group = e_source_group_new (account->name, base_uri);
+	g_free (base_uri);
+	e_source_group_set_property (group, "create_source", "yes");
+	e_source_group_set_property (group, "username", url->user);
+	e_source_group_set_property (group, "host", url->host);
+	e_source_group_set_property (group, "profile", camel_url_get_param (url, "profile"));
+	e_source_group_set_property (group, "domain", camel_url_get_param (url, "domain"));
+
+	/* We set these because on new folder creation - these are required. */
+	e_source_group_set_property (group, "acl-user-name", account->id->name);
+	e_source_group_set_property (group, "acl-user-email", account->id->address);
+	e_source_group_set_property (group, "acl-owner-name", account->id->name);
+	e_source_group_set_property (group, "acl-owner-email", account->id->address);
+
+	for (temp_list = folders; temp_list != NULL; temp_list = g_slist_next (temp_list)) {
+ 		ExchangeMAPIFolder *folder = temp_list->data;
+		ESource *source = NULL;
+		gchar *relative_uri = NULL, *fid = NULL;
+
+		if (folder->container_class != folder_type)
+			continue;
+
+		fid = exchange_mapi_util_mapi_id_to_string (folder->folder_id);
+		relative_uri = g_strconcat (";", fid, NULL);
+		source = e_source_new (folder->folder_name, relative_uri);
+		e_source_set_property (source, "auth", "1");
+		e_source_set_property (source, "auth-domain", EXCHANGE_MAPI_PASSWORD_COMPONENT);
+		e_source_set_property (source, "auth-type", "plain/password");
+		e_source_set_property (source, "username", url->user);
+		e_source_set_property (source, "host", url->host);
+		e_source_set_property (source, "profile", camel_url_get_param (url, "profile"));
+		e_source_set_property (source, "domain", camel_url_get_param (url, "domain"));
+		e_source_set_property (source, "folder-id", fid);
+		e_source_set_property (source, "offline_sync", 
+					camel_url_get_param (url, "offline_sync") ? "1" : "0");
+
+		if (folder->is_default) 
+			e_source_set_property (source, "delete", "no");
+
+		if (folder->parent_folder_id) {
+			gchar *tmp = exchange_mapi_util_mapi_id_to_string (folder->parent_folder_id);
+			e_source_set_property (source, "parent-fid", tmp);
+			g_free (tmp);
+		}
+
+		e_source_set_property (source, "acl-user-name", account->id->name);
+		e_source_set_property (source, "acl-user-email", account->id->address);
+		/* FIXME: this would change after foreign folders/delegation is implemented */
+		e_source_set_property (source, "acl-owner-name", account->id->name);
+		e_source_set_property (source, "acl-owner-email", account->id->address);
+
+		e_source_group_add_source (group, source, -1);
+
+		if (source_selection_key && folder->is_default) {
+			ids = gconf_client_get_list (client, source_selection_key , GCONF_VALUE_STRING, NULL);
+			ids = g_slist_append (ids, g_strdup (e_source_peek_uid (source)));
+			gconf_client_set_list (client, source_selection_key, GCONF_VALUE_STRING, ids, NULL);
+
+			for (temp = ids; temp != NULL; temp = g_slist_next (temp))
+				g_free (temp->data);
+
+			g_slist_free (ids);
+		}
+
+		g_object_unref (source);
+		g_free (relative_uri);
+		g_free (fid);
+	}
+
+	if (!e_source_list_add_group (source_list, group, -1))
+		return;
+
+	if (!e_source_list_sync (source_list, NULL))
+		return;
+
+	g_object_unref (group);
+	g_object_unref (source_list);
+	g_object_unref (client);
+}
+
+static void 
+remove_cal_esource (EAccount *existing_account_info, ExchangeMAPIFolderType folder_type, CamelURL *url)
+{
+	ESourceList *list;
+	const gchar *conf_key = NULL, *source_selection_key = NULL;
+	GSList *groups;
+	gboolean found_group;
+	GConfClient* client;
+	GSList *ids;
+	GSList *node_tobe_deleted;
+	gchar *base_uri;
+
+	if (folder_type == MAPI_FOLDER_TYPE_APPOINTMENT) { 
+		conf_key = CALENDAR_SOURCES;
+		source_selection_key = SELECTED_CALENDARS;
+	} else if (folder_type == MAPI_FOLDER_TYPE_TASK) { 
+		conf_key = TASK_SOURCES;
+		source_selection_key = SELECTED_TASKS;
+	} else if (folder_type == MAPI_FOLDER_TYPE_MEMO) {
+		conf_key = JOURNAL_SOURCES;
+		source_selection_key = SELECTED_JOURNALS;
+	} else {
+		g_warning ("%s(%d): %s: Unknown ExchangeMAPIFolderType\n", __FILE__, __LINE__, __PRETTY_FUNCTION__);
+		return;
+	} 
+
+	client = gconf_client_get_default();
+	gconf_client_set_bool (client, ITIP_MESSAGE_HANDLING, FALSE, NULL);
+	list = e_source_list_new_for_gconf (client, conf_key);
+	groups = e_source_list_peek_groups (list); 
+
+	base_uri = g_strdup_printf ("mapi://%s %s/", url->user, url->host);
+
+	found_group = FALSE;
+
+	for ( ; groups != NULL && !found_group; groups = g_slist_next (groups)) {
+		ESourceGroup *group = E_SOURCE_GROUP (groups->data);
+
+		if (strcmp (e_source_group_peek_name (group), existing_account_info->name) == 0 && 
+		    strcmp (e_source_group_peek_base_uri (group), base_uri) == 0) {
+			GSList *sources = e_source_group_peek_sources (group);
+			
+			for( ; sources != NULL; sources = g_slist_next (sources)) {
+				ESource *source = E_SOURCE (sources->data);
+
+				if (source_selection_key) {
+					ids = gconf_client_get_list (client, source_selection_key , 
+								     GCONF_VALUE_STRING, NULL);
+					node_tobe_deleted = g_slist_find_custom (ids, e_source_peek_uid (source), (GCompareFunc) strcmp);
+					if (node_tobe_deleted) {
+						g_free (node_tobe_deleted->data);
+						ids = g_slist_delete_link (ids, node_tobe_deleted);
+					}
+					gconf_client_set_list (client, source_selection_key, 
+							       GCONF_VALUE_STRING, ids, NULL);
+				}
+			}
+			e_source_list_remove_group (list, group);
+			e_source_list_sync (list, NULL);	
+			found_group = TRUE;
+			break;
+		}
+	}
+
+	g_free (base_uri);
+	g_object_unref (list);
+	g_object_unref (client);		
+}
+
+/* add sources for calendar and tasks if the account added is exchange account
+   adds the new account info to mapi_accounts list */
+
+static void 
+add_calendar_sources (EAccount *account, GSList *folders)
+{
+	CamelURL *url;
+
+	url = camel_url_new (account->source->url, NULL);
+
+	if (url) {
+		add_cal_esource (account, folders, MAPI_FOLDER_TYPE_APPOINTMENT, url);
+		add_cal_esource (account, folders, MAPI_FOLDER_TYPE_TASK, url);
+		add_cal_esource (account, folders, MAPI_FOLDER_TYPE_MEMO, url);
+	}
+
+	camel_url_free (url);
+}
+
+/* removes calendar and tasks sources if the account removed is exchange account 
+   removes the the account info from mapi_account list */
+
+static void 
+remove_calendar_sources (EAccount *account)
+{
+	CamelURL *url;
+
+	url = camel_url_new (account->source->url, NULL);
+
+	if (url) {
+		remove_cal_esource (account, MAPI_FOLDER_TYPE_APPOINTMENT, url);
+		remove_cal_esource (account, MAPI_FOLDER_TYPE_TASK, url);
+		remove_cal_esource (account, MAPI_FOLDER_TYPE_MEMO, url);
+	}
+
+	camel_url_free (url);
+}
+
+static gboolean
+add_addressbook_sources (EAccount *account, GSList *folders)
+{
+	CamelURL *url;
+	ESourceList *list;
+	ESourceGroup *group;
+	ESource *source;
+	char *base_uri;
+	GSList *temp_list;
+	GConfClient* client;
+
+	url = camel_url_new (account->source->url, NULL);
+	if (url == NULL) {
+		return FALSE;
+	}
+
+	base_uri = g_strdup_printf ("mapi://%s %s/", url->user, url->host);
+	client = gconf_client_get_default ();
+	list = e_source_list_new_for_gconf (client, "/apps/evolution/addressbook/sources" );
+	group = e_source_group_new (account->name, base_uri);
+	e_source_group_set_property (group, "user", url->user);
+	e_source_group_set_property (group, "host", url->host);
+	e_source_group_set_property (group, "profile", camel_url_get_param (url, "profile"));
+	e_source_group_set_property (group, "domain", camel_url_get_param (url, "domain"));
+
+	for (temp_list = folders; temp_list != NULL; temp_list = g_slist_next (temp_list)) {
+ 		ExchangeMAPIFolder *folder = temp_list->data;
+		char *tmp = NULL;
+		if (folder->container_class != MAPI_FOLDER_TYPE_CONTACT)
+			continue;
+
+		source = e_source_new (folder->folder_name, g_strconcat (";",folder->folder_name, NULL));
+		e_source_set_property (source, "auth", "plain/password");
+		e_source_set_property (source, "auth-domain", EXCHANGE_MAPI_PASSWORD_COMPONENT);
+		e_source_set_property(source, "user", url->user);
+		e_source_set_property(source, "host", url->host);
+		e_source_set_property(source, "profile", camel_url_get_param (url, "profile"));
+		e_source_set_property(source, "domain", camel_url_get_param (url, "domain"));
+		tmp = exchange_mapi_util_mapi_id_to_string (folder->folder_id);
+		e_source_set_property(source, "folder-id", tmp);
+		g_free (tmp);
+		e_source_set_property (source, "offline_sync", 
+					       camel_url_get_param (url, "offline_sync") ? "1" : "0");
+		e_source_set_property (source, "completion", "true");
+		e_source_group_add_source (group, source, -1);
+		g_object_unref (source);
+	}
+
+	//Add GAL
+	{
+		char *uri;
+		uri = g_strdup_printf("galldap://%s %s/;Global Address List", url->user, url->host);
+		source = e_source_new_with_absolute_uri ("Global Address List", uri);
+//		source = e_source_new ("Global Address List", g_strconcat (";","Global Address List" , NULL));
+		e_source_set_property (source, "auth", "plain/password");
+		e_source_set_property (source, "auth-domain", "GALLDAP");
+		e_source_set_property(source, "user", url->user);
+		e_source_set_property(source, "host", camel_url_get_param (url, "ad_server"));
+		e_source_set_property(source, "view-limit", camel_url_get_param (url, "ad_limit"));		
+		e_source_set_property(source, "profile", camel_url_get_param (url, "profile"));
+		e_source_set_property(source, "domain", camel_url_get_param (url, "domain"));
+//		e_source_set_property (source, "offline_sync", 
+//					       camel_url_get_param (url, "offline_sync") ? "1" : "0");
+		e_source_set_property(source, "offline_sync", "1");
+		e_source_set_property (source, "completion", "true");
+		e_source_group_add_source (group, source, -1);
+		g_object_unref (source);		
+	}
+	e_source_list_add_group (list, group, -1);
+	e_source_list_sync (list, NULL);
+	g_object_unref (group);
+	g_object_unref (list);
+	g_object_unref (client);
+	g_free (base_uri);
+
+	return TRUE;
+}
+
+static void 
+remove_addressbook_sources (ExchangeMAPIAccountInfo *existing_account_info)
+{
+	ESourceList *list;
+	ESourceGroup *group;
+	GSList *groups;
+	gboolean found_group;
+	CamelURL *url;
+	char *base_uri;
+	GConfClient *client;
+
+	url = camel_url_new (existing_account_info->source_url, NULL);
+	if (url == NULL) {
+		return;
+	}
+
+	base_uri = g_strdup_printf ("mapi://%s %s/", url->user, url->host);
+	client = gconf_client_get_default ();
+	list = e_source_list_new_for_gconf (client, "/apps/evolution/addressbook/sources" );
+	groups = e_source_list_peek_groups (list); 
+
+	found_group = FALSE;
+
+	for ( ; groups != NULL && !found_group; groups = g_slist_next (groups)) {
+
+		group = E_SOURCE_GROUP (groups->data);
+		if ( strcmp ( e_source_group_peek_base_uri (group), base_uri) == 0 && strcmp (e_source_group_peek_name (group), existing_account_info->name) == 0) {
+
+			e_source_list_remove_group (list, group);
+			e_source_list_sync (list, NULL);
+			found_group = TRUE;
+		}
+	}
+
+	g_object_unref (list);
+	g_object_unref (client);
+	g_free (base_uri);
+	camel_url_free (url);
+}
+
+static void
+mapi_account_added (EAccountList *account_listener, EAccount *account)
+{
+	ExchangeMAPIAccountInfo *info = NULL;
+
+	if (!is_mapi_account (account))
+		return;
+
+	info = g_new0 (ExchangeMAPIAccountInfo, 1);
+	info->uid = g_strdup (account->uid);
+	info->name = g_strdup (account->name);
+	info->source_url = g_strdup (account->source->url);
+	info->enabled = account->enabled; 
+
+	mapi_accounts = g_list_append (mapi_accounts, info);
+
+	if (account->enabled) {
+		/* Fetch the folders into a global list for future use.*/
+		exchange_mapi_account_listener_get_folder_list ();
+
+		add_addressbook_sources (account, folders_list);
+		add_calendar_sources (account, folders_list);
+		/*FIXME: Maybe the folders_list above should be freed */
+	}
+}
+
+static void 
+mapi_account_removed (EAccountList *account_listener, EAccount *account)
+{
+	ExchangeMAPIAccountInfo *info = NULL;
+	CamelURL *url = NULL;
+
+	if (!is_mapi_account (account))
+		return;
+
+	/* We store a complete list of MAPI accounts - both enabled and disabled */
+	info = lookup_account_info (account->uid);
+	g_return_if_fail (info != NULL);  
+
+	/* Remove from the local MAPI accounts list */
+	mapi_accounts = g_list_remove (mapi_accounts, info);
+
+	/* If the account was disabled, then the corresponding ESource should have been removed
+	 * when the account was disabled. We should only clean up the MAPI profile database etc. 
+	 */
+	if (info->enabled) {
+		remove_addressbook_sources (info);
+		remove_calendar_sources (account);
+	}
+
+	/* Now, clean up the profile database etc */
+	url = camel_url_new (info->source_url, NULL);
+	if (url != NULL) {
+		const char *profile = camel_url_get_param (url, "profile");
+		gchar *key = camel_url_to_string (url, CAMEL_URL_HIDE_PASSWORD | CAMEL_URL_HIDE_PARAMS);
+		exchange_mapi_delete_profile (profile);
+		e_passwords_forget_password (EXCHANGE_MAPI_PASSWORD_COMPONENT, key); 
+		g_free (key); 
+		camel_url_free (url);
+	}
+
+	/* Free up the structure */
+	g_free (info->uid);
+	g_free (info->name);
+	g_free (info->source_url);
+	g_free (info);
+}
+
+static gboolean
+create_profile_entry (CamelURL *url)
+{
+	gboolean status = FALSE;
+	guint8 attempts = 0; 
+
+	while (!status && attempts <= 3) {
+		gchar *password = NULL, *key = NULL;
+
+		key = camel_url_to_string (url, CAMEL_URL_HIDE_PASSWORD | CAMEL_URL_HIDE_PARAMS);
+		password = e_passwords_get_password (EXCHANGE_MAPI_PASSWORD_COMPONENT, key);
+		if (!password) {
+			gboolean remember = FALSE;
+			gchar *title;
+
+			title = g_strdup_printf (_("Enter Password for %s %s"), url->user, url->host);
+			password = e_passwords_ask_password (title, EXCHANGE_MAPI_PASSWORD_COMPONENT, key, title,
+					E_PASSWORDS_REMEMBER_FOREVER|E_PASSWORDS_SECRET,
+					&remember, NULL);
+			g_free (title);
+		} 
+		g_free (key);
+
+		if (password)
+			status = exchange_mapi_create_profile (url->user, password, camel_url_get_param (url, "domain"), url->host);
+
+		++attempts; 
+	}
+
+	return status; 
+}
+
+static gboolean
+mapi_camel_url_equal (CamelURL *a, CamelURL *b)
+{
+	const char *params[] = { "profile", "domain", "ad_limit", "ad_server" }; 
+	guint n_params = G_N_ELEMENTS (params), i; 
+	gboolean retval = TRUE; 
+
+	retval &= camel_url_equal (a, b); 
+
+	for (i = 0; i < n_params; ++i)
+		retval &= (g_ascii_strcasecmp (camel_url_get_param (a, params[i]), camel_url_get_param (b, params[i])) == 0);
+
+	return retval; 
+}
+
+static void
+mapi_account_changed (EAccountList *account_listener, EAccount *account)
+{
+	CamelURL *new_url = NULL, *old_url = NULL;
+	gboolean isa_mapi_account = FALSE;
+	ExchangeMAPIAccountInfo *existing_account_info = NULL;
+
+	isa_mapi_account = is_mapi_account (account);
+
+	if (isa_mapi_account)
+		existing_account_info = lookup_account_info (account->uid);
+
+	if (existing_account_info)
+		old_url = camel_url_new (existing_account_info->source_url, NULL); 
+
+	new_url = camel_url_new (account->source->url, NULL); 
+
+	if (existing_account_info == NULL && isa_mapi_account) {
+		/* some account of other type is changed to MAPI */
+		if (create_profile_entry (new_url)) {
+			/* Things are successful */
+			gchar *profname = NULL, *uri = NULL; 
+			ExchangeMAPIAccountListener *config_listener = exchange_mapi_accounts_peek_config_listener();
+
+			profname = g_strdup_printf("%s %s", new_url->user, camel_url_get_param (new_url, "domain"));
+			camel_url_set_param(new_url, "profile", profname);
+			g_free (profname);
+
+			uri = camel_url_to_string(new_url, 0);
+			/* FIXME: Find a better way to append to the Account source URL. The current
+			 * method uses e_account_set_string() which initiates another signal emmission
+			 * which we have to block for now. */
+			g_signal_handlers_block_by_func (config_listener->priv->account_list, G_CALLBACK (mapi_account_changed), NULL); 
+			e_account_set_string(account, E_ACCOUNT_SOURCE_URL, uri);
+			g_signal_handlers_unblock_by_func (config_listener->priv->account_list, G_CALLBACK (mapi_account_changed), NULL); 
+			g_free (uri);
+
+			mapi_account_added (account_listener, account);
+		}
+	} else if (existing_account_info != NULL && !isa_mapi_account) {
+		/* MAPI account is changed to some other type */
+		mapi_account_removed (account_listener, account);
+	} else if (existing_account_info != NULL && isa_mapi_account) {
+		/* Just disabling the account requires no further action */
+		if (!account->enabled) {
+			remove_addressbook_sources (existing_account_info);
+			remove_calendar_sources (account);
+			existing_account_info->enabled = FALSE;
+		} else if (!mapi_camel_url_equal (old_url, new_url) || (existing_account_info->enabled != account->enabled)) {
+		/* Some or all of the account info changed OR the account has been moved from a disabled state to enabled state */
+			mapi_account_removed (account_listener, account);
+			if (create_profile_entry (new_url)) {
+				/* Things are successful */
+				gchar *profname = NULL, *uri = NULL; 
+				ExchangeMAPIAccountListener *config_listener = exchange_mapi_accounts_peek_config_listener();
+
+				profname = g_strdup_printf("%s %s", new_url->user, camel_url_get_param (new_url, "domain"));
+				camel_url_set_param(new_url, "profile", profname);
+				g_free (profname);
+
+				uri = camel_url_to_string(new_url, 0);
+				/* FIXME: Find a better way to append to the Account source URL. The current
+				 * method uses e_account_set_string() which initiates another signal emmission
+				 * which we have to block for now. */
+				g_signal_handlers_block_by_func (config_listener->priv->account_list, G_CALLBACK (mapi_account_changed), NULL); 
+				e_account_set_string(account, E_ACCOUNT_SOURCE_URL, uri);
+				g_signal_handlers_unblock_by_func (config_listener->priv->account_list, G_CALLBACK (mapi_account_changed), NULL); 
+				g_free (uri);
+
+				mapi_account_added (account_listener, account);
+			}
+		}
+	}
+
+	if (old_url)
+		camel_url_free (old_url); 
+
+	camel_url_free (new_url); 
+} 
+
+static void
+exchange_mapi_account_listener_construct (ExchangeMAPIAccountListener *config_listener)
+{
+	EIterator *iter;
+
+	config_listener->priv->account_list = e_account_list_new (config_listener->priv->gconf_client);
+
+	for (iter = e_list_get_iterator (E_LIST(config_listener->priv->account_list)); e_iterator_is_valid (iter); e_iterator_next (iter)) {
+		EAccount *account = E_ACCOUNT (e_iterator_get (iter));
+		if (is_mapi_account (account)) {
+			ExchangeMAPIAccountInfo *info = g_new0 (ExchangeMAPIAccountInfo, 1);
+			info->uid = g_strdup (account->uid);
+			info->name = g_strdup (account->name);
+			info->source_url = g_strdup (account->source->url);
+			info->enabled = account->enabled; 
+			mapi_accounts = g_list_append (mapi_accounts, info);
+		}
+	}
+
+	d(g_debug ("MAPI listener is constructed with %d listed MAPI accounts ", g_list_length (mapi_accounts)));
+
+	g_signal_connect (config_listener->priv->account_list, "account_added", G_CALLBACK (mapi_account_added), NULL);
+	g_signal_connect (config_listener->priv->account_list, "account_changed", G_CALLBACK (mapi_account_changed), NULL);
+	g_signal_connect (config_listener->priv->account_list, "account_removed", G_CALLBACK (mapi_account_removed), NULL);
+}
+
+GType
+exchange_mapi_account_listener_get_type (void)
+{
+	static GType exchange_mapi_account_listener_type = 0;
+
+	if (!exchange_mapi_account_listener_type) {
+		static GTypeInfo info = {
+			sizeof (ExchangeMAPIAccountListenerClass),
+			(GBaseInitFunc) NULL,
+			(GBaseFinalizeFunc) NULL,
+			(GClassInitFunc) exchange_mapi_account_listener_class_init,
+			NULL, NULL,
+			sizeof (ExchangeMAPIAccountListener),
+			0,
+			(GInstanceInitFunc) exchange_mapi_account_listener_init
+		};
+		exchange_mapi_account_listener_type = g_type_register_static (PARENT_TYPE, "ExchangeMAPIAccountListener", &info, 0);
+	}
+
+	return exchange_mapi_account_listener_type;
+}
+
+ExchangeMAPIAccountListener *
+exchange_mapi_account_listener_new ()
+{
+	ExchangeMAPIAccountListener *config_listener;
+
+	config_listener = g_object_new (EXCHANGE_MAPI_ACCOUNT_LISTENER_TYPE, NULL);
+	config_listener->priv->gconf_client = gconf_client_get_default();
+
+	exchange_mapi_account_listener_construct (config_listener);
+
+	return config_listener;
+}

Added: trunk/src/account-setup-eplugin/exchange-mapi-account-listener.h
==============================================================================
--- (empty file)
+++ trunk/src/account-setup-eplugin/exchange-mapi-account-listener.h	Wed Nov 19 04:28:20 2008
@@ -0,0 +1,58 @@
+/*
+ * 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/>  
+ *
+ *
+ * Authors:
+ *		Srinivasa Ragavan <sragavan novell com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef EXCHANGE_MAPI_ACCOUNT_LISTENER_H
+#define EXCHANGE_MAPI_ACCOUNT_LISTENER_H
+
+#include <glib.h>
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define EXCHANGE_MAPI_ACCOUNT_LISTENER_TYPE 		(exchange_mapi_account_listener_get_type ())
+#define EXCHANGE_MAPI_ACCOUNT_LISTENER(obj) 		(G_TYPE_CHECK_INSTANCE_CAST ((obj), EXCHANGE_MAPI_ACCOUNT_LISTENER_TYPE, ExchangeMAPIAccountListener))
+#define EXCHANGE_MAPI_ACCOUNT_LISTENER_CLASS(klass) 	(G_TYPE_CHECK_CLASS_CAST ((klass), EXCHANGE_MAPI_ACCOUNT_LISTENER_TYPE,  ExchangeMAPIAccountListenerClass))
+#define EXCHANGE_MAPI_IS_ACCOUNT_LISTENER(obj) 		(G_TYPE_CHECK_INSTANCE_TYPE ((obj), EXCHANGE_MAPI_ACCOUNT_LISTENER_TYPE))
+#define EXCHANGE_MAPI_IS_ACCOUNT_LISTENER_CLASS(klass) 	(G_TYPE_CHECK_CLASS_TYPE ((obj), EXCHANGE_MAPI_ACCOUNT_LISTENER_TYPE))
+
+typedef struct _ExchangeMAPIAccountListener 		ExchangeMAPIAccountListener;
+typedef struct _ExchangeMAPIAccountListenerClass 	ExchangeMAPIAccountListenerClass;
+typedef struct _ExchangeMAPIAccountListenerPrivate 	ExchangeMAPIAccountListenerPrivate;
+
+struct _ExchangeMAPIAccountListener {
+	GObject parent;
+	ExchangeMAPIAccountListenerPrivate *priv;
+};
+
+struct _ExchangeMAPIAccountListenerClass {
+	GObjectClass parent_class;
+};
+
+GType 				exchange_mapi_account_listener_get_type (void);
+ExchangeMAPIAccountListener *	exchange_mapi_account_listener_new (void);
+GSList *			exchange_mapi_account_listener_peek_folder_list (void); 
+void 				exchange_mapi_account_listener_get_folder_list (void);
+void 				exchange_mapi_account_listener_free_folder_list (void);
+
+G_END_DECLS
+
+#endif /* EXCHANGE_MAPI_ACCOUNT_LISTENER_H */

Added: trunk/src/account-setup-eplugin/exchange-mapi-account-setup.c
==============================================================================
--- (empty file)
+++ trunk/src/account-setup-eplugin/exchange-mapi-account-setup.c	Wed Nov 19 04:28:20 2008
@@ -0,0 +1,699 @@
+/*
+ * 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/>  
+ *
+ *
+ * Authors:
+ *		Srinivasa Ragavan <sragavan novell com>
+ *		Johnny Jacob  <jjohnny novell com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <string.h>
+#include <unistd.h>
+#include <glib/gi18n.h>
+
+#include <gtk/gtk.h>
+#include <camel/camel-provider.h>
+#include <camel/camel-url.h>
+#include <camel/camel-service.h>
+#include <camel/camel-folder.h>
+#include <libedataserver/e-xml-hash-utils.h>
+#include <libedataserverui/e-passwords.h>
+#include <libedataserver/e-account.h>
+#include <e-util/e-dialog-utils.h>
+#include <libmapi/libmapi.h>
+#include "mail/em-config.h"
+#include "exchange-mapi-account-setup.h"
+#include <addressbook/gui/widgets/eab-config.h>
+#include <calendar/gui/e-cal-config.h>
+
+#include <exchange-mapi-folder.h>
+#include <exchange-mapi-connection.h>
+#include <exchange-mapi-utils.h>
+
+#define d(x) x
+
+int e_plugin_lib_enable (EPluginLib *ep, int enable);
+
+/* Account Setup */
+GtkWidget *org_gnome_exchange_mapi_account_setup (EPlugin *epl, EConfigHookItemFactoryData *data);
+gboolean org_gnome_exchange_mapi_check_options(EPlugin *epl, EConfigHookPageCheckData *data);
+
+/* New Addressbook/CAL */
+GtkWidget *exchange_mapi_create (EPlugin *epl, EConfigHookItemFactoryData *data);
+
+/* New Addressbook */
+gboolean exchange_mapi_book_check (EPlugin *epl, EConfigHookPageCheckData *data);
+void exchange_mapi_book_commit (EPlugin *epl, EConfigTarget *target);
+
+/* New calendar/task list/memo list */
+gboolean exchange_mapi_cal_check (EPlugin *epl, EConfigHookPageCheckData *data);
+void exchange_mapi_cal_commit (EPlugin *epl, EConfigTarget *target);
+
+
+static ExchangeMAPIAccountListener *config_listener = NULL;
+
+static void 
+free_mapi_listener ( void )
+{
+	g_object_unref (config_listener);
+}
+
+int
+e_plugin_lib_enable (EPluginLib *ep, int enable)
+{
+	g_debug ("Loading Exchange MAPI Plugin \n");
+
+	if (!config_listener) {
+		config_listener = exchange_mapi_account_listener_new ();
+	 	g_atexit ( free_mapi_listener );
+	}
+
+	return 0;
+}
+
+ExchangeMAPIAccountListener *
+exchange_mapi_accounts_peek_config_listener ()
+{
+	return config_listener; 
+}
+
+gboolean
+exchange_mapi_delete_profile (const char *profile)
+{
+	enum MAPISTATUS	retval;
+	gboolean result = FALSE; 
+	gchar *profpath = NULL;
+
+	profpath = g_build_filename (g_get_home_dir(), DEFAULT_PROF_PATH, NULL);
+	if (!g_file_test (profpath, G_FILE_TEST_EXISTS)) {
+		g_warning ("No need to delete profile. DB itself is missing \n");
+		result = TRUE;
+		goto cleanup; 
+	}
+
+	retval = MAPIInitialize(profpath); 
+	if (retval == MAPI_E_SESSION_LIMIT)
+	/* do nothing, the profile store is already initialized */
+		; 
+	else if (retval != MAPI_E_SUCCESS) {
+		mapi_errstr("MAPIInitialize", GetLastError());
+		goto cleanup; 
+	}
+
+	g_debug ("Deleting profile %s ", profile); 
+	retval = DeleteProfile(profile); 
+	if (retval != MAPI_E_SUCCESS) {
+		mapi_errstr("DeleteProfile", GetLastError());
+		goto cleanup; 
+	}
+
+	exchange_mapi_connection_close ();
+	result = TRUE; 
+
+cleanup: 
+	g_free(profpath);
+
+	return result;
+}
+
+gboolean 
+exchange_mapi_create_profile(const char *username, const char *password, const char *domain, const char *server)
+{
+	enum MAPISTATUS	retval;
+	gboolean result = FALSE; 
+	const gchar *workstation = "localhost";
+	gchar *profname = NULL, *profpath = NULL;
+	struct mapi_session *session = NULL;
+
+	d(g_print ("Create profile with %s %s (****) %s %s\n", username, password, domain, server));
+
+	profpath = g_build_filename (g_get_home_dir(), DEFAULT_PROF_PATH, NULL);
+	profname = g_strdup_printf("%s %s", username, domain);
+
+	if (!g_file_test (profpath, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_REGULAR)) {
+		/* Create a ProfileStore */
+		retval = CreateProfileStore (profpath, LIBMAPI_LDIF_DIR); 
+		if (retval != MAPI_E_SUCCESS) {
+			mapi_errstr("CreateProfileStore", GetLastError());
+			goto cleanup; 
+		}
+	}
+
+	retval = MAPIInitialize(profpath); 
+	if (retval == MAPI_E_SESSION_LIMIT)
+	/* do nothing, the profile store is already initialized */
+		mapi_errstr("MAPIInitialize", GetLastError()); 
+	else if (retval != MAPI_E_SUCCESS) {
+		mapi_errstr("MAPIInitialize", GetLastError());
+		goto cleanup; 
+	}
+
+	/* Delete any existing profiles with the same profilename */
+	retval = DeleteProfile(profname); 
+	/* don't bother to check error - it would be valid if we got an error */
+
+	retval = CreateProfile(profname, username, password, 0); 
+	if (retval != MAPI_E_SUCCESS) {
+		mapi_errstr("CreateProfile", GetLastError());
+		goto cleanup; 
+	}
+
+	mapi_profile_add_string_attr(profname, "binding", server);
+	mapi_profile_add_string_attr(profname, "workstation", workstation);
+	mapi_profile_add_string_attr(profname, "domain", domain);
+	
+	/* This is only convenient here and should be replaced at some point */
+	mapi_profile_add_string_attr(profname, "codepage", "0x4e4");
+	mapi_profile_add_string_attr(profname, "language", "0x40c");
+	mapi_profile_add_string_attr(profname, "method", "0x409");
+	
+	/* Login now */
+	d(g_print("Logging into the server... "));
+	retval = MapiLogonProvider(&session, profname, NULL, PROVIDER_ID_NSPI); 
+	if (retval != MAPI_E_SUCCESS) {
+		mapi_errstr("MapiLogonProvider", GetLastError());
+		g_debug ("Deleting profile %s ", profname); 
+		retval = DeleteProfile(profname); 
+		if (retval != MAPI_E_SUCCESS)
+			mapi_errstr("DeleteProfile", GetLastError());
+		goto cleanup; 
+	}
+	d(g_print("succeeded \n"));
+
+	retval = ProcessNetworkProfile(session, username, NULL, NULL); 
+	if (retval != MAPI_E_SUCCESS) {
+		mapi_errstr("ProcessNetworkProfile", GetLastError());
+		goto cleanup; 
+	}
+
+	/* Set it as the default profile. Is this needed? */
+	retval = SetDefaultProfile(profname); 
+	if (retval != MAPI_E_SUCCESS) {
+		mapi_errstr("SetDefaultProfile", GetLastError());
+		goto cleanup; 
+	}
+
+	/* Close the connection, so that we can login with what we created */
+	exchange_mapi_connection_close ();
+
+	/* Initialize a global connection */
+	if (exchange_mapi_connection_new (profname, password)) {
+		result = TRUE;
+		exchange_mapi_account_listener_get_folder_list ();
+	}
+
+cleanup: 
+	if (!result)
+		MAPIUninitialize ();
+
+	g_free (profname);
+	g_free (profpath);
+
+	return result;
+}
+
+
+static void
+validate_credentials (GtkWidget *widget, EConfig *config)
+{
+	EMConfigTargetAccount *target_account = (EMConfigTargetAccount *)(config->target);
+	CamelURL *url = NULL;
+ 	gchar *key = NULL, *password = NULL;
+
+	url = camel_url_new (e_account_get_string (target_account->account, E_ACCOUNT_SOURCE_URL), NULL);
+	key = camel_url_to_string (url, CAMEL_URL_HIDE_PASSWORD | CAMEL_URL_HIDE_PARAMS);
+	password = e_passwords_get_password (EXCHANGE_MAPI_PASSWORD_COMPONENT, key);
+	if (!password) {
+		gboolean remember = FALSE;
+		gchar *title;
+
+		title = g_strdup_printf (_("Enter Password for %s %s"), url->user, url->host);
+		password = e_passwords_ask_password (title, EXCHANGE_MAPI_PASSWORD_COMPONENT, key, title,
+						     E_PASSWORDS_REMEMBER_FOREVER|E_PASSWORDS_SECRET,
+						     &remember, NULL);
+		g_free (title);
+	}
+
+	if (password) {
+		const gchar *domain_name = camel_url_get_param (url, "domain");
+		gboolean status = exchange_mapi_create_profile (url->user, password, domain_name, url->host);
+		if (status) {
+			/* Things are successful */
+			gchar *profname = NULL, *uri = NULL; 
+
+			profname = g_strdup_printf("%s %s", url->user, domain_name);
+			camel_url_set_param(url, "profile", profname);
+			g_free (profname);
+
+			uri = camel_url_to_string(url, 0);
+			e_account_set_string(target_account->account, E_ACCOUNT_SOURCE_URL, uri);
+			g_free (uri);
+		} else {
+			e_passwords_forget_password (EXCHANGE_MAPI_PASSWORD_COMPONENT, key);
+			/* FIXME: Run an error dialog here */
+		}
+	}
+
+	g_free (password);
+	g_free (key);
+	camel_url_free (url);
+}
+
+static void
+domain_entry_changed(GtkWidget *entry, EConfig *config)
+{
+	EMConfigTargetAccount *target = (EMConfigTargetAccount *)(config->target);
+	CamelURL *url = NULL;
+	const char *domain = NULL;
+	char *url_string = NULL;
+
+	url = camel_url_new (e_account_get_string(target->account, E_ACCOUNT_SOURCE_URL), NULL);
+	domain = gtk_entry_get_text (GTK_ENTRY(entry));
+
+	if (domain && domain[0])
+		camel_url_set_param (url, "domain", domain);
+	else
+		camel_url_set_param (url, "domain", NULL);
+
+	url_string = camel_url_to_string (url, 0);
+	e_account_set_string (target->account, E_ACCOUNT_SOURCE_URL, url_string);
+	g_free (url_string);
+
+	camel_url_free (url);
+}
+
+GtkWidget *
+org_gnome_exchange_mapi_account_setup (EPlugin *epl, EConfigHookItemFactoryData *data)
+{
+	EMConfigTargetAccount *target_account;
+	CamelURL *url;
+	GtkWidget *hbox = NULL;
+
+	target_account = (EMConfigTargetAccount *)data->config->target;
+	url = camel_url_new(e_account_get_string(target_account->account, E_ACCOUNT_SOURCE_URL), NULL);
+
+	g_return_val_if_fail (url != NULL, NULL); 
+
+	if (!g_ascii_strcasecmp (url->protocol, "mapi")) {
+		GtkWidget *label;
+		GtkWidget *domain_name;
+		GtkWidget *auth_button;
+		int row = ((GtkTable *)data->parent)->nrows;
+
+		/* Domain name & Authenticate Button */
+		hbox = gtk_hbox_new (FALSE, 6);
+		label = gtk_label_new_with_mnemonic (_("_Domain name:"));
+		gtk_widget_show (label);
+
+		domain_name = gtk_entry_new ();
+		gtk_label_set_mnemonic_widget (GTK_LABEL (label), domain_name);
+		gtk_box_pack_start (GTK_BOX (hbox), domain_name, FALSE, FALSE, 0);
+		g_signal_connect (domain_name, "changed", G_CALLBACK(domain_entry_changed), data->config);
+
+		auth_button = gtk_button_new_with_mnemonic (_("_Authenticate"));
+		gtk_box_pack_start (GTK_BOX (hbox), auth_button, FALSE, FALSE, 0);
+		g_signal_connect(GTK_OBJECT(auth_button), "clicked",  G_CALLBACK(validate_credentials), data->config);
+
+		gtk_table_attach (GTK_TABLE (data->parent), label, 0, 1, row, row+1, 0, 0, 0, 0);
+		gtk_widget_show_all (GTK_WIDGET (hbox));
+		gtk_table_attach (GTK_TABLE (data->parent), GTK_WIDGET (hbox), 1, 2, row, row+1, GTK_FILL|GTK_EXPAND, GTK_FILL, 0, 0); 
+	}
+
+	camel_url_free (url);
+	return GTK_WIDGET (hbox);
+}
+
+gboolean
+org_gnome_exchange_mapi_check_options(EPlugin *epl, EConfigHookPageCheckData *data)
+{
+	EMConfigTargetAccount *target = (EMConfigTargetAccount *)(data->config->target);
+	gboolean status = FALSE;
+
+	if (data->pageid != NULL && g_ascii_strcasecmp (data->pageid, "10.receive") == 0) {
+		CamelURL *url = camel_url_new (e_account_get_string(target->account,  E_ACCOUNT_SOURCE_URL), NULL);
+		if (url && url->protocol && g_ascii_strcasecmp (url->protocol, "mapi") == 0) {
+			const gchar *prof = NULL;
+
+			/* We assume that if the profile is set, then the setting is valid. */
+ 			prof = camel_url_get_param (url, "profile");
+
+			if (prof && *prof)
+				status = TRUE;
+		}
+		if (url)
+			camel_url_free(url);
+	}
+
+	/* FIXME: don't know why we should always return TRUE */
+	return TRUE;
+
+	return status;
+}
+
+enum {
+	CONTACTSNAME_COL,
+	CONTACTSFID_COL,
+	CONTACTSFOLDER_COL,
+	NUM_COLS
+};
+
+
+static gboolean
+check_node (GtkTreeStore *ts, ExchangeMAPIFolder *folder, GtkTreeIter *iter)
+{
+	mapi_id_t fid;
+	gboolean status = FALSE;
+	
+	gtk_tree_model_get (GTK_TREE_MODEL (ts), iter, 1, &fid, -1);
+	if (fid && folder->parent_folder_id == fid) {
+		/* Do something */
+		GtkTreeIter node;
+		gtk_tree_store_append (ts, &node, iter);		
+		gtk_tree_store_set (ts, &node, 0, folder->folder_name, 1, folder->folder_id, 2, folder,-1);		
+		return TRUE;
+	}
+
+	if (gtk_tree_model_iter_has_child (ts, iter)) {
+		GtkTreeIter child;
+		gtk_tree_model_iter_children (ts, &child, iter);
+		status = check_node (ts, folder, &child);
+	}
+
+	while (gtk_tree_model_iter_next (ts, iter) && !status) {
+		status = check_node (ts, folder, iter);
+	}
+
+	return status;
+}
+
+static void
+add_to_store (GtkTreeStore *ts, ExchangeMAPIFolder *folder)
+{
+	GtkTreeIter iter;
+	
+	gtk_tree_model_get_iter_first (ts, &iter);
+	if (!check_node (ts, folder, &iter)) {
+		GtkTreeIter node;
+		gtk_tree_store_append (ts, &node, &iter);		
+		gtk_tree_store_set (ts, &node, 0, folder->folder_name, 1, folder->folder_id, -1);
+		
+	}
+}
+
+static void
+add_folders (GSList *folders, GtkTreeStore *ts)
+{
+	GSList *tmp = folders;
+	GtkTreeIter iter;
+	char *node = _("Personal Folders");
+	
+	gtk_tree_store_append (ts, &iter, NULL);
+	gtk_tree_store_set (ts, &iter, 0, node, -1);
+	while (tmp) {
+		ExchangeMAPIFolder *folder = tmp->data;
+		g_print("%s\n", folder->folder_name);
+		add_to_store (ts, folder);
+		tmp = tmp->next;
+	}
+}
+
+static void
+exchange_mapi_cursor_change (GtkTreeView *treeview, ESource *source)
+{
+	GtkTreeSelection *selection;
+	GtkTreeModel     *model;
+	GtkTreeIter       iter;
+	mapi_id_t pfid;
+	gchar *sfid=NULL;
+	
+	selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview));
+	gtk_tree_selection_get_selected(selection, &model, &iter);
+
+	gtk_tree_model_get (model, &iter, CONTACTSFID_COL, &pfid, -1);
+	sfid = exchange_mapi_util_mapi_id_to_string (pfid);
+	e_source_set_property (source, "parent-fid", sfid); 
+	g_free (sfid);
+}
+
+GtkWidget *
+exchange_mapi_create (EPlugin *epl, EConfigHookItemFactoryData *data)
+{
+	GtkWidget *vbox, *label, *scroll, *tv;
+	EABConfigTargetSource *t = (EABConfigTargetSource *) data->target;
+	ESource *source = t->source;
+	char *uri_text;
+	GtkCellRenderer *rcell;
+	GtkTreeStore *ts;
+	GtkTreeViewColumn *tvc;
+	const char *acc;
+	GSList *folders = exchange_mapi_account_listener_peek_folder_list ();
+
+	uri_text = e_source_get_uri (source);
+	if (uri_text && g_ascii_strncasecmp (uri_text, MAPI_URI_PREFIX, MAPI_PREFIX_LENGTH)) {
+		return NULL;
+	}
+
+	acc = e_source_group_peek_name (e_source_peek_group (source));
+	ts = gtk_tree_store_new (NUM_COLS, G_TYPE_STRING, G_TYPE_INT64, G_TYPE_POINTER);
+
+	add_folders (folders, ts);
+	
+	vbox = gtk_vbox_new (FALSE, 6);
+
+	if (!strcmp (data->config->id, "org.gnome.evolution.calendar.calendarProperties")) {
+		int row = ((GtkTable*) data->parent)->nrows;
+		gtk_table_attach (GTK_TABLE (data->parent), vbox, 0, 2, row+1, row+2, GTK_FILL|GTK_EXPAND, 0, 0, 0);
+	} else if (!strcmp (data->config->id, "com.novell.evolution.addressbook.config.accountEditor")) {
+		gtk_container_add (GTK_CONTAINER (data->parent), vbox);
+	}
+
+	label = gtk_label_new_with_mnemonic (_("_Location:"));
+	gtk_widget_show (label);
+	gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
+	gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
+	
+	rcell = gtk_cell_renderer_text_new ();
+	tvc = gtk_tree_view_column_new_with_attributes (acc, rcell, "text", CONTACTSNAME_COL, NULL);
+	tv = gtk_tree_view_new_with_model (GTK_TREE_MODEL (ts));
+	gtk_tree_view_append_column (GTK_TREE_VIEW (tv), tvc);
+	g_object_set (tv,"expander-column", tvc, "headers-visible", TRUE, NULL);
+	gtk_tree_view_expand_all (GTK_TREE_VIEW (tv));
+	
+	scroll = gtk_scrolled_window_new (NULL, NULL);
+	gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scroll), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+	gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scroll), GTK_SHADOW_IN);
+	g_object_set (scroll, "height-request", 150, NULL);
+	gtk_container_add (GTK_CONTAINER (scroll), tv);
+	gtk_label_set_mnemonic_widget (GTK_LABEL (label), tv);
+	g_signal_connect (G_OBJECT (tv), "cursor-changed", G_CALLBACK (exchange_mapi_cursor_change), t->source);
+	gtk_widget_show_all (scroll);
+
+	gtk_box_pack_start (GTK_BOX (vbox), scroll, FALSE, FALSE, 0);
+
+	gtk_widget_show_all (vbox);
+	return vbox;
+}
+
+gboolean
+exchange_mapi_book_check (EPlugin *epl, EConfigHookPageCheckData *data)
+{
+	EABConfigTargetSource *t = (EABConfigTargetSource *) data->target;
+	ESource *source = t->source;
+	char *uri_text = e_source_get_uri (source);
+
+	if (!uri_text)
+		return TRUE;
+
+	/* FIXME: Offline handling */
+
+	/* not a MAPI account */
+	if (g_ascii_strncasecmp (uri_text, MAPI_URI_PREFIX, MAPI_PREFIX_LENGTH)) {
+		g_free (uri_text);
+		return TRUE;
+	}
+
+	/* does not have a parent-fid which is needed for folder creation on server */
+	if (!e_source_get_property (source, "parent-fid")) {
+		g_free (uri_text);
+		return FALSE;
+	}
+
+	g_free (uri_text);
+	return TRUE;
+}
+
+void 
+exchange_mapi_book_commit (EPlugin *epl, EConfigTarget *target)
+{
+	EABConfigTargetSource *t = (EABConfigTargetSource *) target;
+	ESource *source = t->source;
+	char *uri_text, *tmp;
+	const char *sfid; 
+	mapi_id_t fid, pfid;
+	ESourceGroup *grp;
+	
+	uri_text = e_source_get_uri (source);
+	if (uri_text && g_ascii_strncasecmp (uri_text, MAPI_URI_PREFIX, MAPI_PREFIX_LENGTH))
+		return;
+	
+	//FIXME: Offline handling
+	sfid = e_source_get_property (source, "parent-fid");
+	exchange_mapi_util_mapi_id_from_string (sfid, &pfid);
+
+	fid = exchange_mapi_create_folder (olFolderContacts, pfid, e_source_peek_name (source));
+	g_print("Created %016llX\n", fid);
+	grp = e_source_peek_group (source);
+	e_source_set_property (source, "auth", "plain/password");
+	e_source_set_property (source, "auth-domain", EXCHANGE_MAPI_PASSWORD_COMPONENT);
+	e_source_set_property(source, "user", e_source_group_get_property (grp, "user"));
+	e_source_set_property(source, "host", e_source_group_get_property (grp, "host"));
+	e_source_set_property(source, "profile", e_source_group_get_property (grp, "profile"));
+	e_source_set_property(source, "domain", e_source_group_get_property (grp, "domain"));
+	e_source_set_relative_uri (source, g_strconcat (";",e_source_peek_name (source), NULL));
+
+	tmp = exchange_mapi_util_mapi_id_to_string (fid);
+	e_source_set_property(source, "folder-id", tmp);
+	g_free (tmp);
+	e_source_set_property (source, "completion", "true");
+	// Update the folder list in the plugin and ExchangeMAPIFolder
+
+	return;
+}
+
+
+/* New calendar/task list/memo list */
+gboolean
+exchange_mapi_cal_check (EPlugin *epl, EConfigHookPageCheckData *data)
+{
+	ECalConfigTargetSource *t = (ECalConfigTargetSource *)(data->target);
+	ESource *source = t->source;
+	char *uri_text = e_source_get_uri (source);
+
+	if (!uri_text)
+		return TRUE; 
+
+	/* FIXME: Offline handling */
+
+	/* not a MAPI account */
+	if (g_ascii_strncasecmp (uri_text, MAPI_URI_PREFIX, MAPI_PREFIX_LENGTH)) {
+		g_free (uri_text); 
+		return TRUE; 
+	}
+
+	g_free (uri_text);
+
+	/* FIXME: Offline handling */
+
+	/* does not have a parent-fid which is needed for folder creation on server */
+	if (!e_source_get_property (source, "parent-fid"))
+		return FALSE;
+
+	return TRUE;
+}
+
+void 
+exchange_mapi_cal_commit (EPlugin *epl, EConfigTarget *target)
+{
+	ECalConfigTargetSource *t = (ECalConfigTargetSource *) target;
+	ESourceGroup *group;
+	ESource *source = t->source;
+	gchar *tmp, *sfid;
+	mapi_id_t fid, pfid;
+	uint32_t type;
+	char *uri_text = e_source_get_uri (source);
+
+	if (!uri_text || g_ascii_strncasecmp (uri_text, MAPI_URI_PREFIX, MAPI_PREFIX_LENGTH))
+		return;
+	g_free (uri_text);
+
+	switch (t->source_type) {
+		case E_CAL_SOURCE_TYPE_EVENT: 
+			type = olFolderCalendar; 
+			break;
+		case E_CAL_SOURCE_TYPE_TODO: 
+			type = olFolderTasks; 
+			break;
+		case E_CAL_SOURCE_TYPE_JOURNAL: 
+			type = olFolderNotes; 
+			break;
+		default: 
+			g_warning ("%s(%d): %s: Unknown ExchangeMAPIFolderType\n", __FILE__, __LINE__, __PRETTY_FUNCTION__);
+			return;
+	}
+
+	/* FIXME: Offline handling */
+
+	exchange_mapi_util_mapi_id_from_string (e_source_get_property (source, "parent-fid"), &pfid);
+
+	fid = exchange_mapi_create_folder (type, pfid, e_source_peek_name (source));
+
+	sfid = exchange_mapi_util_mapi_id_to_string (fid);
+	tmp = g_strconcat (";", sfid, NULL);
+	e_source_set_relative_uri (source, tmp);
+	g_free (tmp);
+	g_free (sfid);
+
+	e_source_set_property (source, "auth", "1");
+	e_source_set_property (source, "auth-domain", EXCHANGE_MAPI_PASSWORD_COMPONENT);
+	e_source_set_property (source, "auth-type", "plain/password");
+
+	group = e_source_peek_group (source);
+
+	tmp = e_source_group_get_property (group, "username");
+	e_source_set_property (source, "username", tmp);
+	g_free (tmp);
+	
+	tmp = e_source_group_get_property (group, "host");
+	e_source_set_property (source, "host", tmp);
+	g_free (tmp);
+
+	tmp = e_source_group_get_property (group, "profile");
+	e_source_set_property (source, "profile", tmp);
+	g_free (tmp);
+
+	tmp = e_source_group_get_property (group, "domain");
+	e_source_set_property (source, "domain", tmp);
+	g_free (tmp);
+
+	tmp = exchange_mapi_util_mapi_id_to_string (fid);
+	e_source_set_property (source, "folder-id", tmp);
+	g_free (tmp);
+
+	e_source_set_property (source, "offline_sync", "0");
+
+	/* Delegatees can never create folders for delegators. So we can copy safely. */
+	tmp = e_source_group_get_property (group, "acl-user-name");
+	e_source_set_property (source, "acl-user-name", tmp);
+	g_free (tmp);
+	tmp = e_source_group_get_property (group, "acl-user-email");
+	e_source_set_property (source, "acl-user-email", tmp);
+	g_free (tmp);
+	tmp = e_source_group_get_property (group, "acl-owner-name");
+	e_source_set_property (source, "acl-owner-name", tmp);
+	g_free (tmp);
+	tmp = e_source_group_get_property (group, "acl-owner-email");
+	e_source_set_property (source, "acl-owner-email", tmp);
+	g_free (tmp);
+
+	// Update the folder list in the plugin and ExchangeMAPIFolder
+	return;
+}
+

Added: trunk/src/account-setup-eplugin/exchange-mapi-account-setup.h
==============================================================================
--- (empty file)
+++ trunk/src/account-setup-eplugin/exchange-mapi-account-setup.h	Wed Nov 19 04:28:20 2008
@@ -0,0 +1,47 @@
+/*
+ * 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/>  
+ *
+ *
+ * Authors:
+ *		Srinivasa Ragavan <sragavan novell com>
+ *		Johnny Jacob  <jjohnny novell com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+
+#ifndef EXCHANGE_MAPI_ACCOUNT_SETUP_H
+#define EXCHANGE_MAPI_ACCOUNT_SETUP_H
+
+#include "exchange-mapi-account-listener.h"
+
+/* This definition should be in-sync with the definition in camel-mapi-store.c */
+#define EXCHANGE_MAPI_PASSWORD_COMPONENT "ExchangeMAPI"
+
+#define DEFAULT_PROF_PATH ".evolution/mapi-profiles.ldb"
+
+#define MAPI_URI_PREFIX   "mapi://" 
+#define MAPI_PREFIX_LENGTH 7
+
+ExchangeMAPIAccountListener *
+exchange_mapi_accounts_peek_config_listener (void); 
+
+gboolean 
+exchange_mapi_create_profile(const char *username, const char *password, const char *domain, const char *server);
+
+gboolean
+exchange_mapi_delete_profile (const char *profile); 
+
+#endif /* EXCHANGE_MAPI_ACCOUNT_SETUP_H */

Added: trunk/src/account-setup-eplugin/org-gnome-exchange-mapi.eplug.xml
==============================================================================
--- (empty file)
+++ trunk/src/account-setup-eplugin/org-gnome-exchange-mapi.eplug.xml	Wed Nov 19 04:28:20 2008
@@ -0,0 +1,70 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<e-plugin-list>
+	<e-plugin type="shlib" location="@PLUGINDIR@/liborg-gnome-exchange-mapi.so" load-on-startup="true" id="org.gnome.evolution.plugin.exchange-mapi" name="Exchange MAPI">
+
+		<author name="Srinivasa Ragavan" email="sragavan novell com"/>
+		<author name="Johnny Jacob" email="jjohnny novell com"/>
+		<author name="Suman Manjunath" email="msuman novell com"/>
+
+		<description>Exchange MAPI Plugin</description>
+
+		<hook class="org.gnome.evolution.mail.config:1.0">
+			<group 
+				target="account" 
+				id="org.gnome.evolution.mail.config.accountWizard" 
+				check="org_gnome_exchange_mapi_check_options">
+				<item 
+					type="item_table" 
+					path="10.receive/20.config/30.mapi" 
+					factory="org_gnome_exchange_mapi_account_setup"/>
+			</group>
+		</hook>
+		<hook class="org.gnome.evolution.mail.config:1.0">
+			<group 
+				target="account" 
+				id="org.gnome.evolution.mail.config.accountDruid" 
+				check="org_gnome_exchange_mapi_check_options">
+				<item 
+					type="item_table" 
+					path="10.receive/20.config/30.mapi" 
+					factory="org_gnome_exchange_mapi_account_setup"/>
+			</group>
+		</hook>
+		<hook class="org.gnome.evolution.mail.config:1.0">
+			<group 
+				target="account" 
+				id="org.gnome.evolution.mail.config.accountEditor" 
+				check="org_gnome_exchange_mapi_check_options">
+				<item 
+					type="item_table" 
+					path="10.receive/20.config/30.mapi" 
+					factory="org_gnome_exchange_mapi_account_setup"/>
+			</group>
+		</hook>
+		<hook class="org.gnome.evolution.addressbook.config:1.0">
+			<group 
+				target="source" 
+				id="com.novell.evolution.addressbook.config.accountEditor" 
+				check="exchange_mapi_book_check" 
+				commit="exchange_mapi_book_commit">
+				<item 
+					type="item" 
+					path="00.general/10.display/50.createcontacts" 
+					factory="exchange_mapi_create"/>
+			</group>
+		</hook>
+		<hook class="org.gnome.evolution.calendar.config:1.0">
+			<group 
+				target="source" 
+				id="org.gnome.evolution.calendar.calendarProperties" 
+				check="exchange_mapi_cal_check" 
+				commit="exchange_mapi_cal_commit">
+				<item 
+					type="item_table" 
+					path="00.general/10.source/40.pcalendar" 
+					factory="exchange_mapi_create"/>
+			</group>
+		</hook>
+
+	</e-plugin>
+</e-plugin-list>

Added: trunk/src/addressbook/Makefile.am
==============================================================================
--- (empty file)
+++ trunk/src/addressbook/Makefile.am	Wed Nov 19 04:28:20 2008
@@ -0,0 +1,38 @@
+INCLUDES =						\
+	-DG_LOG_DOMAIN=\"libebookbackend\"		\
+	-I$(top_srcdir)/src/addressbook			\
+	-I$(top_builddir)/src/addressbook		\
+	-I$(top_srcdir)/src/libexchangemapi		\
+	$(LIBMAPI_CFLAGS)				\
+	$(LIBEDATABOOK_CFLAGS)				\
+	$(LIBEDATASERVER_CFLAGS)			\
+	$(LIBEBACKEND_CFLAGS)				\
+	$(EVOLUTION_DATA_SERVER_CFLAGS)			\
+        $(EVOLUTION_ADDRESSBOOK_CFLAGS)
+
+extension_LTLIBRARIES = libebookbackendmapi.la
+
+libebookbackendmapi_la_SOURCES =			\
+	e-book-backend-mapi.c				\
+	e-book-backend-mapi.h				\
+	e-book-backend-mapi-factory.c
+
+libebookbackendmapi_la_LIBADD =						\
+	$(top_builddir)/src/libexchangemapi/libexchangemapi-1.0.la		\
+	$(LIBEDATABOOK_LIBS)				\
+	$(LIBEBACKEND_CFLAGS)			\
+	$(LIBEDATASERVER_LIBS)				\
+	$(EVOLUTION_DATA_SERVER_LIBS)			\
+	$(EVOLUTION_ADDRESSBOOK_LIBS)			\
+	$(LIBMAPI_LIBS)
+
+libebookbackendmapi_la_LDFLAGS =	\
+	-module -avoid-version $(NO_UNDEFINED)
+
+#LDAP_SCHEMA =						\
+#	evolutionperson.schema
+
+#ldapschemadir = $(privdatadir)
+#ldapschema_DATA= $(LDAP_SCHEMA)
+
+#EXTRA_DIST = $(LDAP_SCHEMA) openldap-extract.h

Added: trunk/src/addressbook/e-book-backend-mapi-factory.c
==============================================================================
--- (empty file)
+++ trunk/src/addressbook/e-book-backend-mapi-factory.c	Wed Nov 19 04:28:20 2008
@@ -0,0 +1,52 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ *  Authors: 
+ *    Srinivasa Ragavan <sragavan novell com>
+ *
+ *  Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of version 2 of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation.
+ *
+ *  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 this program; if not, write to: 
+ *  Free Software Foundation, 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <libebackend/e-data-server-module.h>
+#include <libedata-book/e-book-backend-factory.h>
+#include "e-book-backend-mapi.h"
+
+E_BOOK_BACKEND_FACTORY_SIMPLE (mapi,
+			       MAPI,
+			       e_book_backend_mapi_new)
+
+static GType mapi_type;
+
+void	eds_module_initialize (GTypeModule *module)
+{
+	mapi_type = _mapi_factory_get_type (module);
+}
+
+void	eds_module_shutdown   (void)
+{
+}
+
+void	eds_module_list_types (const GType **types, int *num_types)
+{
+	*types = &mapi_type;
+	*num_types = 1;
+}

Added: trunk/src/addressbook/e-book-backend-mapi.c
==============================================================================
--- (empty file)
+++ trunk/src/addressbook/e-book-backend-mapi.c	Wed Nov 19 04:28:20 2008
@@ -0,0 +1,1770 @@
+/* -*- 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/>  
+ *
+ *
+ * Authors:
+ *    Srinivasa Ragavan <sragavan novell com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>  
+#endif
+
+#include <stdlib.h>
+#include <fcntl.h>
+#include <string.h>
+#include <glib.h>
+
+#include <sys/time.h>
+/*
+** #include <glib/gi18n-lib.h>
+*/
+
+#include <libedataserver/e-sexp.h>
+#include "libedataserver/e-flag.h"
+#include <libebook/e-contact.h>
+
+#include <libedata-book/e-book-backend-sexp.h>
+#include <libedata-book/e-data-book.h>
+#include <libedata-book/e-data-book-view.h>
+#include <libedata-book/e-book-backend-cache.h>
+#include <libedata-book/e-book-backend-summary.h>
+#include "e-book-backend-mapi.h"
+
+
+static EBookBackendClass *e_book_backend_mapi_parent_class;
+static gboolean enable_debug = TRUE;
+
+struct _EBookBackendMAPIPrivate
+{
+	char *profile;
+	mapi_id_t fid;
+	int mode;
+	gboolean marked_for_offline;
+	gboolean is_cache_ready;
+	gboolean is_summary_ready;
+	gboolean is_writable;
+	char *uri;
+	char *book_name;
+	
+	GMutex *lock;
+	char *summary_file_name;
+	EBookBackendSummary *summary;
+	EBookBackendCache *cache;
+
+};
+
+#define LOCK() g_mutex_lock (priv->lock)
+#define UNLOCK() g_mutex_unlock (priv->lock)
+
+#define ELEMENT_TYPE_SIMPLE 0x01
+#define ELEMENT_TYPE_COMPLEX 0x02 /* fields which require explicit functions to set values into EContact and EGwItem */
+
+#define SUMMARY_FLUSH_TIMEOUT 5000
+#define ELEMENT_TYPE_SIMPLE 0x01
+#define ELEMENT_TYPE_COMPLEX 0x02
+
+static EContact * emapidump_contact(struct mapi_SPropValue_array *properties);
+
+static const struct field_element_mapping {
+		EContactField field_id;
+		int element_type;
+	        int mapi_id;
+	        int contact_type;
+//		char *element_name;
+//		void (*populate_contact_func)(EContact *contact,    gpointer data);
+//		void (*set_value_in_gw_item) (EGwItem *item, gpointer data);
+//		void (*set_changes) (EGwItem *new_item, EGwItem *old_item);
+
+	} mappings [] = { 
+
+	{ E_CONTACT_UID, PT_STRING8, 0, ELEMENT_TYPE_SIMPLE},
+	{ E_CONTACT_REV, PT_SYSTIME, PR_LAST_MODIFICATION_TIME, ELEMENT_TYPE_SIMPLE},
+		
+	{ E_CONTACT_FILE_AS, PT_STRING8, PR_EMS_AB_MANAGER_T, ELEMENT_TYPE_SIMPLE},
+	{ E_CONTACT_FULL_NAME, PT_STRING8, PR_DISPLAY_NAME, ELEMENT_TYPE_SIMPLE },
+	{ E_CONTACT_GIVEN_NAME, PT_STRING8, PR_GIVEN_NAME, ELEMENT_TYPE_SIMPLE},
+	{ E_CONTACT_FAMILY_NAME, PT_STRING8, PR_SURNAME , ELEMENT_TYPE_SIMPLE},
+	{ E_CONTACT_NICKNAME, PT_STRING8, PR_NICKNAME, ELEMENT_TYPE_SIMPLE },
+
+	{ E_CONTACT_EMAIL_1, PT_STRING8, 0x8084001e, ELEMENT_TYPE_SIMPLE},
+	{ E_CONTACT_EMAIL_2, PT_STRING8, 0x8094001e, ELEMENT_TYPE_SIMPLE},
+	{ E_CONTACT_EMAIL_3, PT_STRING8, 0x80a4001e, ELEMENT_TYPE_SIMPLE},
+	{ E_CONTACT_IM_AIM, PT_STRING8, 0x8062001e, ELEMENT_TYPE_COMPLEX},
+		
+	{ E_CONTACT_PHONE_BUSINESS, PT_STRING8, PR_OFFICE_TELEPHONE_NUMBER, ELEMENT_TYPE_SIMPLE},
+	{ E_CONTACT_PHONE_HOME, PT_STRING8, PR_HOME_TELEPHONE_NUMBER, ELEMENT_TYPE_SIMPLE},
+	{ E_CONTACT_PHONE_MOBILE, PT_STRING8, PR_MOBILE_TELEPHONE_NUMBER, ELEMENT_TYPE_SIMPLE},
+	{ E_CONTACT_PHONE_HOME_FAX, PT_STRING8, PR_HOME_FAX_NUMBER ,ELEMENT_TYPE_SIMPLE},
+	{ E_CONTACT_PHONE_BUSINESS_FAX, PT_STRING8, PR_BUSINESS_FAX_NUMBER,ELEMENT_TYPE_SIMPLE},
+	{ E_CONTACT_PHONE_PAGER, PT_STRING8, PR_PAGER_TELEPHONE_NUMBER,ELEMENT_TYPE_SIMPLE},
+	{ E_CONTACT_PHONE_ASSISTANT, PT_STRING8, PR_ASSISTANT_TELEPHONE_NUMBER ,ELEMENT_TYPE_SIMPLE},
+	{ E_CONTACT_PHONE_COMPANY, PT_STRING8, PR_COMPANY_MAIN_PHONE_NUMBER ,ELEMENT_TYPE_SIMPLE},
+
+	{ E_CONTACT_HOMEPAGE_URL, PT_STRING8, 0x802b001e, ELEMENT_TYPE_SIMPLE},
+	{ E_CONTACT_FREEBUSY_URL, PT_STRING8, 0x80d8001e, ELEMENT_TYPE_SIMPLE},
+
+	{ E_CONTACT_ROLE, PT_STRING8, PR_PROFESSION, ELEMENT_TYPE_SIMPLE},
+	{ E_CONTACT_TITLE, PT_STRING8, PR_TITLE, ELEMENT_TYPE_SIMPLE},
+	{ E_CONTACT_ORG, PT_STRING8, PR_COMPANY_NAME, ELEMENT_TYPE_SIMPLE},
+	{ E_CONTACT_ORG_UNIT, PT_STRING8, PR_DEPARTMENT_NAME,ELEMENT_TYPE_SIMPLE},
+	{ E_CONTACT_MANAGER, PT_STRING8, PR_MANAGER_NAME, ELEMENT_TYPE_SIMPLE},
+	{ E_CONTACT_ASSISTANT, PT_STRING8, PR_ASSISTANT, ELEMENT_TYPE_SIMPLE},
+		
+	{ E_CONTACT_OFFICE, PT_STRING8, PR_OFFICE_LOCATION, ELEMENT_TYPE_SIMPLE},
+	{ E_CONTACT_SPOUSE, PT_STRING8, PR_SPOUSE_NAME, ELEMENT_TYPE_SIMPLE},
+		
+	{ E_CONTACT_BIRTH_DATE,  PT_SYSTIME, PR_BIRTHDAY, ELEMENT_TYPE_COMPLEX},
+	{ E_CONTACT_ANNIVERSARY, PT_SYSTIME, PR_WEDDING_ANNIVERSARY, ELEMENT_TYPE_COMPLEX},
+		  
+	{ E_CONTACT_NOTE, PT_STRING8, PR_BODY, ELEMENT_TYPE_SIMPLE},
+		
+
+	{ E_CONTACT_ADDRESS_HOME, PT_STRING8, 0x801a001e, ELEMENT_TYPE_COMPLEX},
+	{ E_CONTACT_ADDRESS_WORK, PT_STRING8, 0x801c001e, ELEMENT_TYPE_COMPLEX},
+//		{ E_CONTACT_BOOK_URI, ELEMENT_TYPE_SIMPLE, "book_uri"}
+//		{ E_CONTACT_EMAIL, PT_STRING8, 0x8084001e},
+//		{ E_CONTACT_CATEGORIES, },		
+	};
+
+static maplen = G_N_ELEMENTS(mappings);
+
+static EDataBookView *
+find_book_view (EBookBackendMAPI *ebmapi)
+{
+	EList *views = e_book_backend_get_book_views (E_BOOK_BACKEND (ebmapi));
+	EIterator *iter;
+	EDataBookView *rv = NULL;
+
+	if (!views)
+		return NULL;
+
+	iter = e_list_get_iterator (views);
+
+	if (!iter) {
+		g_object_unref (views);
+		return NULL;
+	}
+
+	if (e_iterator_is_valid (iter)) {
+		/* just always use the first book view */
+		EDataBookView *v = (EDataBookView*)e_iterator_get(iter);
+		if (v)
+			rv = v;
+	}
+
+	g_object_unref (iter);
+	g_object_unref (views);
+	
+	return rv;
+}
+
+static gboolean
+build_restriction_emails_contains (struct mapi_SRestriction *res, 
+				   char *query)
+{
+	char *email=NULL, *tmp, *tmp1;
+	int status;
+
+	/* This currently supports "email foo bar soo" */
+	tmp = strdup (query);
+	
+	tmp = strstr (tmp, "email");
+	if (tmp ) {
+		tmp = strchr (tmp, '\"');
+		if (tmp && ++tmp) {
+			tmp = strchr (tmp, '\"');
+			if (tmp && ++tmp) {
+				tmp1 = tmp;
+				tmp1 = strchr (tmp1, '\"');
+				if (tmp1) {
+					*tmp1 = 0;
+					email = tmp;
+				}
+			}
+		}
+	}
+	
+
+	if (email==NULL || !strchr (email, '@'))
+		return FALSE;
+
+	res->rt = RES_PROPERTY;
+	res->res.resProperty.relop = RES_PROPERTY;
+	res->res.resProperty.ulPropTag = 0x801f001e; /* EMAIL */
+	res->res.resProperty.lpProp.ulPropTag = 0x801f001e; /* EMAIL*/
+	res->res.resProperty.lpProp.value.lpszA = email;
+
+	return TRUE;
+}
+
+static char *
+get_filename_from_uri (const char *uri, const char *file)
+{
+	char *mangled_uri, *filename;
+	int i;
+
+	/* mangle the URI to not contain invalid characters */
+	mangled_uri = g_strdup (uri);
+	for (i = 0; i < strlen (mangled_uri); i++) {
+		switch (mangled_uri[i]) {
+		case ':' :
+		case '/' :
+			mangled_uri[i] = '_';
+		}
+	}
+
+	/* generate the file name */
+	filename = g_build_filename (g_get_home_dir (), ".evolution/cache/addressbook",
+				     mangled_uri, file, NULL);
+
+	/* free memory */
+	g_free (mangled_uri);
+
+	return filename;
+}
+
+static GNOME_Evolution_Addressbook_CallStatus
+e_book_backend_mapi_load_source (EBookBackend           *backend,
+				       ESource                *source,
+				       gboolean                only_if_exists)
+{
+	char *tmp;
+	EBookBackendMAPIPrivate *priv = ((EBookBackendMAPI *) backend)->priv;
+	char * offline;
+	char **tokens;
+	char *uri;
+	if (enable_debug)
+		printf("MAPI load source\n");
+	offline = e_source_get_property (source, "offline_sync");
+	if (offline  && g_str_equal (offline, "1"))
+		priv->marked_for_offline = TRUE;
+
+
+
+	/* Either we are in Online mode or this is marked for offline */
+	
+	priv->uri = g_strdup (e_source_get_uri (source));
+
+	tokens = g_strsplit (priv->uri, ";", 2);
+  	if (tokens[0])
+ 		uri = g_strdup (tokens [0]);
+  	priv->book_name  = g_strdup (tokens[1]);
+  	if (priv->book_name == NULL) {
+		g_warning ("Bookname is null for %s\n", uri);
+  		return GNOME_Evolution_Addressbook_OtherError;
+	}
+  	g_strfreev (tokens);
+
+	if (priv->mode ==  GNOME_Evolution_Addressbook_MODE_LOCAL &&
+	    !priv->marked_for_offline ) {
+		return GNOME_Evolution_Addressbook_OfflineUnavailable;
+	}
+	
+	if (priv->marked_for_offline) {
+ 		priv->summary_file_name = get_filename_from_uri (priv->uri, "cache.summary"); 
+		if (g_file_test (priv->summary_file_name, G_FILE_TEST_EXISTS)) {
+			printf("Loading the summary\n");
+			priv->summary = e_book_backend_summary_new (priv->summary_file_name, 
+								    SUMMARY_FLUSH_TIMEOUT);
+			e_book_backend_summary_load (priv->summary);
+			priv->is_summary_ready = TRUE;
+		}
+
+		/* Load the cache as well.*/
+		if (e_book_backend_cache_exists (priv->uri)) {
+			printf("Loading the cache\n");
+			priv->cache = e_book_backend_cache_new (priv->uri);
+			priv->is_cache_ready = TRUE;
+		}
+		//FIXME: We may have to do a time based reload. Or deltas should upload.
+	}
+
+	g_free (uri);
+	e_book_backend_set_is_loaded (E_BOOK_BACKEND (backend), TRUE);
+	e_book_backend_set_is_writable (backend, TRUE);	
+	if (priv->mode ==  GNOME_Evolution_Addressbook_MODE_LOCAL) {
+		e_book_backend_set_is_writable (backend, FALSE);
+		e_book_backend_notify_writable (backend, FALSE);
+		e_book_backend_notify_connection_status (backend, FALSE);
+		if (!priv->cache) {
+			printf("Unfortunately the cache is not yet created\n");
+			return GNOME_Evolution_Addressbook_OfflineUnavailable;
+		}
+	} else {
+		e_book_backend_notify_connection_status (backend, TRUE);
+	}
+	
+	priv->profile = g_strdup (e_source_get_property (source, "profile"));
+	exchange_mapi_util_mapi_id_from_string (e_source_get_property (source, "folder-id"), &priv->fid);
+
+	tmp = e_source_get_property (source, "folder-id");
+	printf("Folder is %s %016llX\n", tmp, priv->fid);
+
+	/* Once aunthentication in address book works this can be removed */
+	if (priv->mode == GNOME_Evolution_Addressbook_MODE_LOCAL) {
+		return GNOME_Evolution_Addressbook_Success;
+	}
+
+	// writable property will be set in authenticate_user callback
+	e_book_backend_set_is_loaded (E_BOOK_BACKEND (backend), TRUE);
+	e_book_backend_notify_connection_status (E_BOOK_BACKEND (backend), TRUE);
+
+
+	if (enable_debug)
+		printf("For profile %s and folder %s - %016llX\n", priv->profile, tmp, priv->fid);
+
+	return GNOME_Evolution_Addressbook_Success;
+}
+
+static char *
+e_book_backend_mapi_get_static_capabilities (EBookBackend *backend)
+{
+	if(enable_debug)
+		printf("mapi get_static_capabilities\n");
+	//FIXME: Implement this.
+	
+	return g_strdup ("net,bulk-removes,do-initial-query,contact-lists");
+}
+
+gboolean
+mapi_book_build_name_id (struct mapi_nameid *nameid, gpointer data)
+{
+	EContact *contact = data;
+	
+	mapi_nameid_lid_add(nameid, 0x8005, PSETID_Address);
+	mapi_nameid_lid_add(nameid, 0x8084, PSETID_Address);
+	mapi_nameid_lid_add(nameid, 0x8083, PSETID_Address);
+
+	mapi_nameid_lid_add(nameid, 0x8093, PSETID_Address);
+	mapi_nameid_lid_add(nameid, 0x80A3, PSETID_Address);
+	
+	mapi_nameid_string_add(nameid, "urn:schemas:contacts:fileas", PS_PUBLIC_STRINGS);
+
+	mapi_nameid_lid_add(nameid, 0x802B, PSETID_Address);
+	mapi_nameid_lid_add(nameid, 0x8062, PSETID_Address);
+
+	mapi_nameid_lid_add(nameid, 0x801A, PSETID_Address);	
+	mapi_nameid_lid_add(nameid, 0x801B, PSETID_Address);
+
+	mapi_nameid_lid_add(nameid, 0x3A4F, PS_MAPI);
+
+	mapi_nameid_lid_add(nameid, 0x8094, PSETID_Address);
+	mapi_nameid_lid_add(nameid, 0x80A4, PSETID_Address);
+
+	return TRUE;
+}
+
+#define set_str_value(field_id, hex) if (e_contact_get (contact, field_id)) set_SPropValue_proptag (&props[i++], hex, e_contact_get (contact, field_id));
+
+int
+mapi_book_build_props (struct SPropValue ** value, struct SPropTagArray * SPropTagArray, gpointer data)
+{
+	EContact *contact = data;	
+	int len = -1;
+	struct SPropValue *props;
+	int i=0;
+
+	for (i=0; i<13; i++)
+		printf("hex %x\n", SPropTagArray->aulPropTag[i]);
+	i=0;
+	props = g_new (struct SPropValue, 50); //FIXME: Correct value tbd
+	set_str_value ( E_CONTACT_FILE_AS, SPropTagArray->aulPropTag[0]);
+
+	set_str_value (E_CONTACT_FULL_NAME, PR_DISPLAY_NAME);
+	set_SPropValue_proptag(&props[i++], PR_MESSAGE_CLASS, (const void *)IPM_CONTACT);
+	set_str_value (E_CONTACT_FILE_AS, PR_NORMALIZED_SUBJECT);
+	set_str_value (E_CONTACT_EMAIL_1,  SPropTagArray->aulPropTag[1]);
+//	set_str_value (E_CONTACT_EMAIL_1,  SPropTagArray->aulPropTag[2]);
+	set_str_value (E_CONTACT_FILE_AS,  SPropTagArray->aulPropTag[5]);
+
+	
+//	set_str_value ( E_CONTACT_EMAIL_1, 0x8083001e);
+	set_str_value ( E_CONTACT_EMAIL_2, SPropTagArray->aulPropTag[3]);
+//	set_str_value ( E_CONTACT_EMAIL_2, SPropTagArray->aulPropTag[11]);
+	
+	set_str_value ( E_CONTACT_EMAIL_3, SPropTagArray->aulPropTag[4]);
+//	set_str_value ( E_CONTACT_EMAIL_3, SPropTagArray->aulPropTag[12]);
+	
+	set_str_value (E_CONTACT_HOMEPAGE_URL, SPropTagArray->aulPropTag[6]);
+	set_str_value (E_CONTACT_FREEBUSY_URL, 0x812C001E);
+	
+
+	set_str_value ( E_CONTACT_PHONE_BUSINESS, PR_OFFICE_TELEPHONE_NUMBER);
+	set_str_value ( E_CONTACT_PHONE_HOME, PR_HOME_TELEPHONE_NUMBER);
+	set_str_value ( E_CONTACT_PHONE_MOBILE, PR_MOBILE_TELEPHONE_NUMBER);
+	set_str_value ( E_CONTACT_PHONE_HOME_FAX, PR_HOME_FAX_NUMBER);
+	set_str_value ( E_CONTACT_PHONE_BUSINESS_FAX, PR_BUSINESS_FAX_NUMBER);
+	set_str_value ( E_CONTACT_PHONE_PAGER, PR_PAGER_TELEPHONE_NUMBER);
+	set_str_value ( E_CONTACT_PHONE_ASSISTANT, PR_ASSISTANT_TELEPHONE_NUMBER);
+	set_str_value ( E_CONTACT_PHONE_COMPANY, PR_COMPANY_MAIN_PHONE_NUMBER);
+
+	set_str_value (E_CONTACT_MANAGER, PR_MANAGER_NAME);
+	set_str_value (E_CONTACT_ASSISTANT, PR_ASSISTANT);
+	set_str_value (E_CONTACT_ORG, PR_COMPANY_NAME);
+	set_str_value (E_CONTACT_ORG_UNIT, PR_DEPARTMENT_NAME);
+	set_str_value (E_CONTACT_ROLE, PR_PROFESSION);
+	set_str_value (E_CONTACT_TITLE, PR_TITLE);
+
+	set_str_value (E_CONTACT_OFFICE, PR_OFFICE_LOCATION);
+	set_str_value (E_CONTACT_SPOUSE, PR_SPOUSE_NAME);
+
+	set_str_value (E_CONTACT_NOTE, PR_BODY);
+
+	//BDAY AND ANNV
+	if (e_contact_get (contact, E_CONTACT_BIRTH_DATE)) {
+		EContactDate *date = e_contact_get (contact, E_CONTACT_BIRTH_DATE);
+		struct tm tmtime;
+		time_t lt;
+		NTTIME nt;
+		struct FILETIME t;
+		
+		tmtime.tm_mday = date->day - 1;
+		tmtime.tm_mon = date->month - 1;
+		tmtime.tm_year = date->year - 1900;
+
+		lt = mktime (&tmtime);
+		unix_to_nt_time (&nt, lt);
+		t.dwLowDateTime = (nt << 32) >> 32;
+		t.dwHighDateTime = (nt >> 32);
+		printf("sending bday\n");
+		set_SPropValue_proptag (&props[i++], PR_BIRTHDAY, &t);
+	}
+
+	if (e_contact_get (contact, E_CONTACT_ANNIVERSARY)) {
+		EContactDate *date = e_contact_get (contact, E_CONTACT_ANNIVERSARY);
+		struct tm tmtime;
+		time_t lt;
+		NTTIME nt;
+		struct FILETIME t;
+		
+		tmtime.tm_mday = date->day - 1;
+		tmtime.tm_mon = date->month - 1;
+		tmtime.tm_year = date->year - 1900;
+
+		lt = mktime (&tmtime);
+		unix_to_nt_time (&nt, lt);
+		t.dwLowDateTime = (nt << 32) >> 32;
+		t.dwHighDateTime = (nt >> 32);
+		printf("sending wed\n");
+		set_SPropValue_proptag (&props[i++], PR_WEDDING_ANNIVERSARY, &t);
+	}	
+	//Home and Office address
+	if (e_contact_get (contact, E_CONTACT_ADDRESS_HOME)) {
+		EContactAddress *contact_addr;
+
+		contact_addr = e_contact_get (contact, E_CONTACT_ADDRESS_HOME);
+		set_SPropValue_proptag (&props[i++], SPropTagArray->aulPropTag[8], contact_addr->street);
+		set_SPropValue_proptag (&props[i++], PR_HOME_ADDRESS_POST_OFFICE_BOX, contact_addr->ext);
+		set_SPropValue_proptag (&props[i++], PR_HOME_ADDRESS_CITY, contact_addr->locality);
+		set_SPropValue_proptag (&props[i++], PR_HOME_ADDRESS_STATE_OR_PROVINCE, contact_addr->region);
+		set_SPropValue_proptag (&props[i++], PR_HOME_ADDRESS_POSTAL_CODE, contact_addr->code);
+		set_SPropValue_proptag (&props[i++], PR_HOME_ADDRESS_COUNTRY, contact_addr->country);				
+	}
+
+	if (e_contact_get (contact, E_CONTACT_ADDRESS_WORK)) {
+		EContactAddress *contact_addr;
+
+		contact_addr = e_contact_get (contact, E_CONTACT_ADDRESS_WORK);
+		set_SPropValue_proptag (&props[i++], SPropTagArray->aulPropTag[9], contact_addr->street);
+		set_SPropValue_proptag (&props[i++], PR_POST_OFFICE_BOX, contact_addr->ext);
+		set_SPropValue_proptag (&props[i++], PR_LOCALITY, contact_addr->locality);
+		set_SPropValue_proptag (&props[i++], PR_STATE_OR_PROVINCE, contact_addr->region);
+		set_SPropValue_proptag (&props[i++], PR_POSTAL_CODE, contact_addr->code);
+		set_SPropValue_proptag (&props[i++], PR_COUNTRY, contact_addr->country);				
+	}
+
+	
+// 	set_str_value (E_CONTACT_NICKNAME, SPropTagArray->aulPropTag[10]); 
+	if (e_contact_get (contact, E_CONTACT_IM_AIM)) {
+		GList *l = e_contact_get (contact, E_CONTACT_IM_AIM);
+		set_SPropValue_proptag (&props[i++], SPropTagArray->aulPropTag[7], l->data);
+	}
+
+	if (e_contact_get (contact, E_CONTACT_NICKNAME)) {
+		char *nick  = e_contact_get (contact, E_CONTACT_NICKNAME);
+//		set_SPropValue_proptag (&props[i++], SPropTagArray->aulPropTag[10], nick);
+		printf("nickname %s %x\n", nick,  SPropTagArray->aulPropTag[10]);
+	}
+	
+	*value =props;
+	printf("Sending %d \n", i);
+	return i;
+}
+
+static void
+e_book_backend_mapi_create_contact (EBookBackend *backend,
+					  EDataBook *book,
+					  guint32 opid,
+					  const char *vcard )
+{
+	EContact *contact;
+	char *id;
+	mapi_id_t status;
+	int element_type;
+	char* value;
+	int i;
+	EBookBackendMAPIPrivate *priv = ((EBookBackendMAPI *) backend)->priv;
+
+	if(enable_debug)
+		printf("mapi create_contact \n");
+	
+	switch (priv->mode) {
+
+	case GNOME_Evolution_Addressbook_MODE_LOCAL :
+		e_data_book_respond_create(book, opid, GNOME_Evolution_Addressbook_RepositoryOffline, NULL);
+		return;
+	   
+	case  GNOME_Evolution_Addressbook_MODE_REMOTE :
+		contact = e_contact_new_from_vcard(vcard);
+		status = exchange_mapi_create_item (olFolderContacts, priv->fid, mapi_book_build_name_id, contact, mapi_book_build_props, contact, NULL, NULL, NULL, 0);
+		if (!status) {
+			e_data_book_respond_create(book, opid, GNOME_Evolution_Addressbook_OtherError, NULL);
+			return;
+		}
+		id = exchange_mapi_util_mapi_ids_to_uid (priv->fid, status); 
+	
+		/* UID of the contact is nothing but the concatenated string of hex id of folder and the message.*/
+		e_contact_set (contact, E_CONTACT_UID, id);		
+		e_contact_set (contact, E_CONTACT_BOOK_URI, priv->uri);
+		
+		//somehow get the mid.
+		//add to summary and cache.
+		if (priv->marked_for_offline && priv->is_cache_ready)
+			e_book_backend_cache_add_contact (priv->cache, contact);
+
+		if (priv->marked_for_offline && priv->is_summary_ready)
+			e_book_backend_summary_add_contact (priv->summary, contact);
+
+		e_data_book_respond_create(book, opid, GNOME_Evolution_Addressbook_Success, contact);
+		return;			
+	}
+	
+	return;
+}
+
+static void
+e_book_backend_mapi_remove_contacts (EBookBackend *backend,
+					   EDataBook    *book,
+					   guint32 opid,
+					   GList *id_list)
+{
+	GSList *list=NULL, *tmp = id_list;
+	EBookBackendMAPIPrivate *priv = ((EBookBackendMAPI *) backend)->priv;
+	mapi_id_t fid, mid;
+			
+	if(enable_debug)
+		printf("mapi: remove_contacts\n");
+
+	switch (priv->mode) {
+
+	case GNOME_Evolution_Addressbook_MODE_LOCAL :
+		e_data_book_respond_remove_contacts (book, opid, GNOME_Evolution_Addressbook_RepositoryOffline, NULL);
+		return;
+
+	case GNOME_Evolution_Addressbook_MODE_REMOTE:
+		
+		while (tmp) {
+			struct id_list *data = g_new (struct id_list, 1);
+			exchange_mapi_util_mapi_ids_from_uid (tmp->data, &fid, &mid);
+			data->id = mid;
+			list = g_slist_prepend (list, (gpointer) data);
+			tmp = tmp->next;
+		}
+
+		exchange_mapi_remove_items (olFolderContacts, priv->fid, list);
+		if (priv->marked_for_offline && priv->is_cache_ready) {
+			tmp = id_list;
+			while (tmp) {
+				e_book_backend_cache_remove_contact (priv->cache, tmp->data);
+				tmp = tmp->next;
+			}
+		}
+
+		if (priv->marked_for_offline && priv->is_summary_ready) {
+			tmp = id_list;
+			while (tmp) {
+				e_book_backend_summary_remove_contact (priv->summary, tmp->data);		
+				tmp = tmp->next;
+			}
+		}
+		
+		g_slist_free (list);
+		e_data_book_respond_remove_contacts (book, opid,
+							     GNOME_Evolution_Addressbook_Success,  id_list);
+		return;
+	default:
+		break;
+	}
+}
+
+static void
+e_book_backend_mapi_modify_contact (EBookBackend *backend,
+					  EDataBook    *book,
+					  guint32       opid,
+					  const char   *vcard)
+{
+	EBookBackendMAPIPrivate *priv = ((EBookBackendMAPI *) backend)->priv;
+	EContact *contact;
+	mapi_id_t fid, mid;
+	gboolean status;
+	char *tmp, *id;
+	GList *l = NULL;
+	
+	if(enable_debug)
+		printf("mapi: modify_contacts\n");
+
+	switch (priv->mode) {
+
+	case GNOME_Evolution_Addressbook_MODE_LOCAL :
+		e_data_book_respond_modify(book, opid, GNOME_Evolution_Addressbook_RepositoryOffline, NULL);
+		return;
+	case GNOME_Evolution_Addressbook_MODE_REMOTE :
+		contact = e_contact_new_from_vcard(vcard);
+		tmp = e_contact_get (contact, E_CONTACT_UID);
+		exchange_mapi_util_mapi_ids_from_uid (tmp, &fid, &mid);		
+		printf("modify id %s\n", tmp);
+		
+		status = exchange_mapi_modify_item (olFolderContacts, priv->fid, mid, mapi_book_build_name_id, contact, mapi_book_build_props, contact, NULL, NULL, NULL, 0);
+		printf("getting %016llX\n", status);
+		if (!status) {
+			e_data_book_respond_modify(book, opid, GNOME_Evolution_Addressbook_OtherError, NULL);
+			return;
+		}
+		
+		e_contact_set (contact, E_CONTACT_BOOK_URI, priv->uri);
+
+		//FIXME: Write it cleanly
+		if (priv->marked_for_offline && priv->is_cache_ready)
+			printf("delete cache %d\n", e_book_backend_cache_remove_contact (priv->cache, tmp));
+
+		if (priv->marked_for_offline && priv->is_summary_ready)
+				e_book_backend_summary_remove_contact (priv->summary, tmp);
+		
+		if (priv->marked_for_offline && priv->is_cache_ready)
+			e_book_backend_cache_add_contact (priv->cache, contact);
+
+		if (priv->marked_for_offline && priv->is_summary_ready)
+			e_book_backend_summary_add_contact (priv->summary, contact);
+		
+		
+		e_data_book_respond_modify (book, opid, GNOME_Evolution_Addressbook_Success, contact);
+
+
+	}
+}
+
+static gboolean
+create_contact_item (FetchItemsCallbackData *item_data, gpointer data)
+{
+	EContact *contact;
+	char *suid;
+	
+	contact = emapidump_contact (item_data->properties);
+	suid = exchange_mapi_util_mapi_ids_to_uid (item_data->fid, item_data->mid);
+	printf("got contact %s\n", suid);
+	if (contact) {
+		/* UID of the contact is nothing but the concatenated string of hex id of folder and the message.*/
+		e_contact_set (contact, E_CONTACT_UID, suid);
+		data = contact;
+	}
+
+	g_free (suid);
+
+	return TRUE;
+}
+
+static void
+e_book_backend_mapi_get_contact (EBookBackend *backend,
+				       EDataBook    *book,
+				       guint32       opid,
+				       const char   *id)
+{
+	EBookBackendMAPIPrivate *priv = ((EBookBackendMAPI *) backend)->priv;
+	EContact *contact;
+	char *vcard;
+	
+	if (enable_debug)
+		printf("mapi: get_contact %s\n", id);
+
+	switch (priv->mode) {
+	
+	case GNOME_Evolution_Addressbook_MODE_LOCAL:
+		contact = e_book_backend_cache_get_contact (priv->cache,
+							    id);
+		if (contact) {
+			vcard =  e_vcard_to_string (E_VCARD (contact), 
+						     EVC_FORMAT_VCARD_30);
+			e_data_book_respond_get_contact (book,
+							 opid,
+							 GNOME_Evolution_Addressbook_Success,
+							 vcard);
+			g_free (vcard);
+			g_object_unref (contact);
+			return;
+		}
+		else {
+			e_data_book_respond_get_contact (book, opid, GNOME_Evolution_Addressbook_ContactNotFound, "");			
+			return;
+		}
+		
+	case GNOME_Evolution_Addressbook_MODE_REMOTE:
+
+		if (priv->marked_for_offline && e_book_backend_cache_is_populated (priv->cache)) {
+			contact = e_book_backend_cache_get_contact (priv->cache,
+								    id);
+			if (contact) {
+				vcard =  e_vcard_to_string (E_VCARD (contact), 
+							     EVC_FORMAT_VCARD_30);
+				e_data_book_respond_get_contact (book,
+								 opid,
+								 GNOME_Evolution_Addressbook_Success,
+								 vcard);
+				g_free (vcard);
+				g_object_unref (contact);
+				return;
+			}
+			else {
+				e_data_book_respond_get_contact (book, opid, GNOME_Evolution_Addressbook_ContactNotFound, "");			
+				return;
+			}
+
+		} else {
+			mapi_id_t fid, mid;
+			
+			exchange_mapi_util_mapi_ids_from_uid (id, &fid, &mid);
+			exchange_mapi_connection_fetch_item (priv->fid, mid, 
+							NULL, 0, 
+							NULL, NULL, 
+							create_contact_item, contact, 
+							MAPI_OPTIONS_FETCH_ALL);
+
+			if (contact) {
+				e_contact_set (contact, E_CONTACT_BOOK_URI, priv->uri);
+				vcard =  e_vcard_to_string (E_VCARD (contact), 
+							     EVC_FORMAT_VCARD_30);
+				e_data_book_respond_get_contact (book,
+								 opid,
+								 GNOME_Evolution_Addressbook_Success,
+								 vcard);
+				g_free (vcard);
+				g_object_unref (contact);
+				return;
+			
+			} else {
+				e_data_book_respond_get_contact (book, opid, GNOME_Evolution_Addressbook_ContactNotFound, "");			
+				return;				
+			}
+		}
+
+	default:
+		break;
+	}
+
+	return;
+	
+}
+
+static gboolean
+create_contact_list_cb (struct mapi_SPropValue_array *array, const mapi_id_t fid, const mapi_id_t mid, 
+			GSList *streams, GSList *recipients, GSList *attachments, gpointer data)
+{
+	GList *list = * (GList **) data;
+	EContact *contact;
+	char *suid;
+	
+	contact = emapidump_contact (array);
+	suid = exchange_mapi_util_mapi_ids_to_uid (fid, mid);
+	
+	if (contact) {
+		/* UID of the contact is nothing but the concatenated string of hex id of folder and the message.*/
+		printf("Contact added %s\n", suid);
+		e_contact_set (contact, E_CONTACT_UID, suid);		
+//		e_contact_set (contact, E_CONTACT_BOOK_URI, priv->uri);
+		//FIXME: Should we set this? How can we get this first?
+		list = g_list_prepend (list, e_vcard_to_string (E_VCARD (contact),
+							        EVC_FORMAT_VCARD_30));
+		g_object_unref (contact);
+		if (* (GList **)data == NULL)
+			* (GList **)data = list;
+	}
+
+	g_free (suid);
+	return TRUE;
+}
+
+static const uint32_t GetPropsList[] = {
+	PR_FID,
+	PR_MID,
+	PR_INST_ID,
+	PR_INSTANCE_NUM,
+	PR_SUBJECT,
+	PR_MESSAGE_CLASS,
+	PR_HASATTACH,
+/* FIXME: is this tag fit to check if a recipient table exists or not ? */
+//	PR_DISCLOSURE_OF_RECIPIENTS,
+	PR_RULE_MSG_PROVIDER,
+	PR_RULE_MSG_NAME
+};
+static const uint16_t n_GetPropsList = G_N_ELEMENTS (GetPropsList);
+
+gboolean
+mapi_book_build_name_id_for_getprops (struct mapi_nameid *nameid, gpointer data)
+{
+	mapi_nameid_lid_add(nameid, 0x8084, PSETID_Address); /* PT_STRING8 - EmailOriginalDisplayName */
+//	mapi_nameid_lid_add(nameid, 0x8020, PSETID_Address);
+//	mapi_nameid_lid_add(nameid, 0x8021, PSETID_Address);
+
+	return TRUE;
+}
+
+static void
+e_book_backend_mapi_get_contact_list (EBookBackend *backend,
+					    EDataBook    *book,
+					    guint32       opid,
+					    const char   *query )
+{
+	EBookBackendMAPIPrivate *priv = ((EBookBackendMAPI *) backend)->priv;
+
+	printf("mapi: get contact list %s\n", query);
+	switch (priv->mode) {
+	case GNOME_Evolution_Addressbook_MODE_LOCAL:
+		if (priv->marked_for_offline && priv->cache) {
+			GList *contacts;
+			GList *vcard_strings = NULL;
+			GList *l;
+
+			contacts = e_book_backend_cache_get_contacts (priv->cache, query);
+
+			for (l = contacts; l; l = g_list_next (l)) {
+				EContact *contact = l->data;
+				vcard_strings = g_list_prepend (vcard_strings, e_vcard_to_string (E_VCARD (contact),
+								EVC_FORMAT_VCARD_30));
+				g_object_unref (contact);
+			}
+
+			g_list_free (contacts);
+			printf("get_contact_list in  %s returning %d contacts\n", priv->uri, g_list_length (vcard_strings));
+			e_data_book_respond_get_contact_list (book, opid, GNOME_Evolution_Addressbook_Success, vcard_strings);
+			return;
+		}
+		e_data_book_respond_get_contact_list (book, opid, GNOME_Evolution_Addressbook_RepositoryOffline,
+						      NULL);
+		return;
+		
+	case GNOME_Evolution_Addressbook_MODE_REMOTE:
+		printf("Mode : Remote\n");
+		if (priv->marked_for_offline && priv->cache) {
+			GList *contacts;
+			GList *vcard_strings = NULL;
+			GList *l;
+
+			contacts = e_book_backend_cache_get_contacts (priv->cache, query);
+
+			for (l = contacts; l ;l = g_list_next (l)) {
+				EContact *contact = l->data;
+				vcard_strings = g_list_prepend (vcard_strings, e_vcard_to_string (E_VCARD (contact),
+							        EVC_FORMAT_VCARD_30));
+				g_object_unref (contact);
+			}
+
+			g_list_free (contacts);
+			printf("get_contact_list in %s  returning %d contacts\n", priv->uri, g_list_length (vcard_strings));			
+			e_data_book_respond_get_contact_list (book, opid, GNOME_Evolution_Addressbook_Success, vcard_strings);
+			return ;
+		}
+		else {
+			struct mapi_SRestriction res;
+			GList *vcard_str = NULL;
+
+			printf("Not marked for cache\n");
+
+			/* Unfortunately MAPI Doesn't support searching well, we do allow only online search for emails rest all are returned as error. */
+			if (!build_restriction_emails_contains (&res, query)) {
+				e_data_book_respond_get_contact_list (book, opid, GNOME_Evolution_Addressbook_OtherError, NULL);
+				return ;				
+			}
+
+			if (!exchange_mapi_connection_fetch_items (priv->fid, &res, 
+								GetPropsList, n_GetPropsList, 
+								mapi_book_build_name_id_for_getprops, NULL, 
+								create_contact_list_cb, &vcard_str, 
+								MAPI_OPTIONS_FETCH_ALL)) {
+				e_data_book_respond_get_contact_list (book, opid, GNOME_Evolution_Addressbook_OtherError, NULL);
+				return ;
+			}
+			printf("get_contact_list in %s returning %d contacts\n", priv->uri, g_list_length (vcard_str));			
+			e_data_book_respond_get_contact_list (book, opid, GNOME_Evolution_Addressbook_Success, vcard_str);
+			return ;
+			
+		}
+	}	
+}
+
+typedef struct {
+	EBookBackendMAPI *bg;
+	GThread *thread;
+	EFlag *running;
+} BESearchClosure;
+
+static void
+closure_destroy (BESearchClosure *closure)
+{
+	e_flag_free (closure->running);
+	g_free (closure);
+}
+
+static BESearchClosure*
+init_closure (EDataBookView *book_view, EBookBackendMAPI *bg)
+{
+	BESearchClosure *closure = g_new (BESearchClosure, 1);
+
+	closure->bg = bg;
+	closure->thread = NULL;
+	closure->running = e_flag_new ();
+
+	g_object_set_data_full (G_OBJECT (book_view), "closure",
+				closure, (GDestroyNotify)closure_destroy);
+
+	return closure;
+}
+
+static BESearchClosure*
+get_closure (EDataBookView *book_view)
+{
+	return g_object_get_data (G_OBJECT (book_view), "closure");
+}
+
+static void
+mapi_dump_props (struct mapi_SPropValue_array *properties)
+{
+	int i;
+	
+	for (i = 0; i < properties->cValues; i++) {
+		struct mapi_SPropValue *lpProp = &properties->lpProps[i];
+		const char *tmp =  get_proptag_name (lpProp->ulPropTag);
+		if (tmp && *tmp)
+			printf("%s \t",tmp);
+		else
+			printf("%x \t", lpProp->ulPropTag);
+		switch(lpProp->ulPropTag & 0xFFFF) {
+		case PT_BOOLEAN:
+			printf(" (bool) - %d\n", lpProp->value.b);
+			break;
+		case PT_I2:
+			printf(" (uint16_t) - %d\n", lpProp->value.i);
+			break;
+		case PT_LONG:
+			printf(" (long) - %ld\n", lpProp->value.l);
+			break;
+		case PT_DOUBLE:
+			printf (" (double) -  %lf\n", lpProp->value.dbl);
+			break;
+		case PT_I8:
+			printf (" (int) - %d\n", lpProp->value.d);
+			break;
+		case PT_SYSTIME:
+			printf (" (struct FILETIME *) - %p\n", &lpProp->value.ft);
+			break;
+		case PT_ERROR:
+			printf (" (error) - %p\n", lpProp->value.err);
+			break;
+		case PT_STRING8:
+			printf(" (string) - %s\n", lpProp->value.lpszA ? lpProp->value.lpszA : "null" );
+			break;
+		case PT_UNICODE:
+			printf(" (unicodestring) - %s\n", lpProp->value.lpszW ? lpProp->value.lpszW : "null");
+			break;
+		case PT_BINARY:
+			printf(" (struct SBinary_short *) - %p\n", &lpProp->value.bin);
+			break;
+		case PT_MV_STRING8:
+			printf(" (struct mapi_SLPSTRArray *) - %p\n", &lpProp->value.MVszA);
+			break;
+		default:
+			printf(" - NONE NULL\n");
+		}
+		
+	}
+	
+}
+//FIXME: Be more clever in dumping contacts. Can we have a callback mechanism for each types?
+static EContact *
+emapidump_contact(struct mapi_SPropValue_array *properties)
+{
+	EContact *contact = e_contact_new ();
+	int i;
+	
+//	mapi_dump_props (properties);
+	for (i=1; i<maplen; i++) {
+		gpointer value;
+
+		value = find_mapi_SPropValue_data (properties, mappings[i].mapi_id);
+		if (mappings[i].element_type == PT_STRING8 && mappings[i].contact_type == ELEMENT_TYPE_SIMPLE) {
+			if (value)
+				e_contact_set (contact, mappings[i].field_id, value);
+		} else if (mappings[i].contact_type == ELEMENT_TYPE_SIMPLE) {
+			if (value && mappings[i].element_type == PT_SYSTIME) {
+				struct FILETIME *t = value;
+				time_t time;
+				NTTIME nt;
+				char *tmp;
+				nt = t->dwHighDateTime;
+				nt = nt << 32;
+				nt |= t->dwLowDateTime;
+				time = nt_time_to_unix (nt);
+				tmp = ctime (&time);
+				e_contact_set (contact, mappings[i].field_id, tmp);
+				//g_free (tmp);
+			} else
+				printf("Nothing is printed\n");
+		} else if (mappings[i].contact_type == ELEMENT_TYPE_COMPLEX) {
+			if (mappings[i].field_id == E_CONTACT_IM_AIM) {
+				GList *list = NULL;
+				EVCardAttribute *attr;
+				
+				attr = e_vcard_attribute_new ("", e_contact_vcard_attribute(E_CONTACT_IM_AIM));
+//				e_vcard_attribute_add_param_with_value (attr, e_vcard_attribute_param_new (EVC_TYPE), "AIM");
+				e_vcard_attribute_add_value (attr, value);
+				list = g_list_append (list, value);
+				//printf("%s -----\n", value);
+				e_contact_set (contact, mappings[i].field_id, list);
+				//FIXME: FREE them
+			} else if (mappings[i].field_id == E_CONTACT_BIRTH_DATE
+				   || mappings[i].field_id == E_CONTACT_ANNIVERSARY) {
+				struct FILETIME *t = value;
+				time_t time;
+				NTTIME nt;
+				struct tm * tmtime;
+				if (value) {
+					EContactDate *date = g_new (EContactDate, 1);
+					nt = t->dwHighDateTime;
+					nt = nt << 32;
+					nt |= t->dwLowDateTime;
+					time = nt_time_to_unix (nt);
+					tmtime = gmtime (&time);
+					//FIXME: Move to new libmapi api to get string dates.
+					date->day = tmtime->tm_mday + 1;
+					date->month = tmtime->tm_mon + 1;
+					date->year = tmtime->tm_year + 1900;
+					e_contact_set (contact, mappings[i].field_id, date);
+					
+				}
+				
+			} else if (mappings[i].field_id == E_CONTACT_ADDRESS_WORK
+				   || mappings[i].field_id == E_CONTACT_ADDRESS_HOME) {
+				EContactAddress *contact_addr;
+
+				contact_addr = g_new0(EContactAddress, 1);
+				if (mappings[i].field_id == E_CONTACT_ADDRESS_HOME) {
+						contact_addr->address_format = NULL;
+						contact_addr->po = NULL;
+						contact_addr->street = value;
+						contact_addr->ext = find_mapi_SPropValue_data (properties, PR_HOME_ADDRESS_POST_OFFICE_BOX);
+						contact_addr->locality = find_mapi_SPropValue_data (properties, PR_HOME_ADDRESS_CITY);
+						contact_addr->region = find_mapi_SPropValue_data (properties, PR_HOME_ADDRESS_STATE_OR_PROVINCE);
+						contact_addr->code = find_mapi_SPropValue_data (properties, PR_HOME_ADDRESS_POSTAL_CODE);
+						contact_addr->country = find_mapi_SPropValue_data (properties, PR_HOME_ADDRESS_COUNTRY);
+
+				} else {
+					
+						contact_addr->address_format = NULL;
+						contact_addr->po = NULL;
+						contact_addr->street = value;
+						contact_addr->ext = find_mapi_SPropValue_data (properties, PR_POST_OFFICE_BOX);
+						contact_addr->locality = find_mapi_SPropValue_data (properties, PR_LOCALITY);
+						contact_addr->region = find_mapi_SPropValue_data (properties, PR_STATE_OR_PROVINCE);
+						contact_addr->code = find_mapi_SPropValue_data (properties, PR_POSTAL_CODE);
+						contact_addr->country = find_mapi_SPropValue_data (properties, PR_COUNTRY);
+				}
+				e_contact_set (contact, mappings[i].field_id, contact_addr);
+				//FIXME: Free everything.
+				
+			}
+			
+			
+		}
+	}
+	
+	return contact;
+}
+
+static void
+get_contacts_from_cache (EBookBackendMAPI *ebmapi, 
+			 const char *query,
+			 GPtrArray *ids,
+			 EDataBookView *book_view, 
+			 BESearchClosure *closure)
+{
+	int i;
+
+	if (enable_debug)
+		printf ("\nread contacts from cache for the ids found in summary\n");
+	for (i = 0; i < ids->len; i ++) {
+		char *uid;
+		EContact *contact; 
+
+                if (!e_flag_is_set (closure->running))
+                        break;
+
+ 		uid = g_ptr_array_index (ids, i);
+		contact = e_book_backend_cache_get_contact (ebmapi->priv->cache, uid);
+		if (contact) {
+			e_data_book_view_notify_update (book_view, contact);
+			g_object_unref (contact);
+		}
+	}
+	if (e_flag_is_set (closure->running))
+		e_data_book_view_notify_complete (book_view, 
+						  GNOME_Evolution_Addressbook_Success);
+}
+
+static gboolean
+create_contact_cb (FetchItemsCallbackData *item_data, gpointer data)
+{
+	EDataBookView *book_view = data;
+	BESearchClosure *closure = get_closure (book_view);
+	EBookBackendMAPI *be = closure->bg;
+	EContact *contact;
+	EBookBackendMAPIPrivate *priv = ((EBookBackendMAPI *) be)->priv;
+	char *suid;
+	
+	if (!e_flag_is_set (closure->running)) {
+		printf("Might be that the operation is cancelled. Lets ask our parent also to do.\n");
+		return FALSE;
+	}
+	
+	contact = emapidump_contact (item_data->properties);
+	suid = exchange_mapi_util_mapi_ids_to_uid (item_data->fid, item_data->mid);
+	
+	if (contact) {
+		/* UID of the contact is nothing but the concatenated string of hex id of folder and the message.*/
+		e_contact_set (contact, E_CONTACT_UID, suid);		
+		e_contact_set (contact, E_CONTACT_BOOK_URI, priv->uri);
+		e_data_book_view_notify_update (book_view, contact);
+		g_object_unref(contact);
+	}
+
+	g_free (suid);
+	return TRUE;
+}
+
+static void
+book_view_thread (gpointer data)
+{
+	EDataBookView *book_view = data;
+	BESearchClosure *closure = get_closure (book_view);
+	EBookBackend  *backend = closure->bg;
+	EBookBackendMAPIPrivate *priv = ((EBookBackendMAPI *) backend)->priv;
+	const char *query = NULL;
+	GPtrArray *ids = NULL;
+	GList *contacts = NULL, *temp_list = NULL;
+	
+	if (enable_debug)
+		printf("mapi: book view\n");
+	
+	bonobo_object_ref (book_view);
+	e_flag_set (closure->running);
+						
+	e_data_book_view_notify_status_message (book_view, "Searching...");
+	query = e_data_book_view_get_card_query (book_view);
+						
+	switch (priv->mode) {
+
+	case GNOME_Evolution_Addressbook_MODE_LOCAL:
+		if (!priv->marked_for_offline) {
+			e_data_book_view_notify_complete (book_view, 
+					GNOME_Evolution_Addressbook_OfflineUnavailable);
+			bonobo_object_unref (book_view);
+			return;
+		}
+		if (!priv->cache) {
+			printf("The cache is not yet built\n");
+			e_data_book_view_notify_complete (book_view, 
+					GNOME_Evolution_Addressbook_Success);
+			return;
+		}
+
+		if (priv->is_summary_ready && 
+	    	    e_book_backend_summary_is_summary_query (priv->summary, query)) {
+			if (enable_debug)
+				printf ("reading the contacts from summary \n");
+			ids = e_book_backend_summary_search (priv->summary, query);
+			if (ids && ids->len > 0) {
+				get_contacts_from_cache (backend, query, ids, book_view, closure);
+				g_ptr_array_free (ids, TRUE);
+			}
+			bonobo_object_unref (book_view);
+			return;
+		}
+
+		/* fall back to cache */
+		if (enable_debug)
+			printf ("summary not found or a summary query  reading the contacts from cache %s\n", query);
+		
+		contacts = e_book_backend_cache_get_contacts (priv->cache, 
+							      query);
+		temp_list = contacts;
+		for (; contacts != NULL; contacts = g_list_next(contacts)) {
+			if (!e_flag_is_set (closure->running)) {
+				for (;contacts != NULL; contacts = g_list_next (contacts))
+					g_object_unref (contacts->data);
+				break;
+			}			
+			e_data_book_view_notify_update (book_view, 
+							E_CONTACT(contacts->data));
+			g_object_unref (contacts->data);
+		}
+		if (e_flag_is_set (closure->running))
+			e_data_book_view_notify_complete (book_view, 
+							  GNOME_Evolution_Addressbook_Success);
+		if (temp_list)
+			 g_list_free (temp_list);
+		bonobo_object_unref (book_view);
+		return;
+		
+	case GNOME_Evolution_Addressbook_MODE_REMOTE:
+
+		if (!exchange_mapi_connection_exists ()) {
+			e_book_backend_notify_auth_required (backend);
+			e_data_book_view_notify_complete (book_view,
+						GNOME_Evolution_Addressbook_AuthenticationRequired);
+			bonobo_object_unref (book_view);
+			return;
+		}
+		
+
+		if (priv->marked_for_offline && priv->cache && priv->is_cache_ready) {
+			if (priv->is_summary_ready && 
+			    e_book_backend_summary_is_summary_query (priv->summary, query)) {
+				if (enable_debug)
+					printf ("reading the contacts from summary \n");
+				ids = e_book_backend_summary_search (priv->summary, query);
+				if (ids && ids->len > 0) {
+					get_contacts_from_cache (backend, query, ids, book_view, closure);
+					g_ptr_array_free (ids, TRUE);
+				}
+				bonobo_object_unref (book_view);
+				return;
+			}
+			
+			printf("Summary seems to be not there or not a summary query, lets fetch from cache directly\n");
+			
+			/* We are already cached. Lets return from there. */
+			contacts = e_book_backend_cache_get_contacts (priv->cache, 
+								      query);
+			temp_list = contacts;
+			for (; contacts != NULL; contacts = g_list_next(contacts)) {
+				if (!e_flag_is_set (closure->running)) {
+					for (;contacts != NULL; contacts = g_list_next (contacts))
+						g_object_unref (contacts->data);
+					break;
+				}							
+				e_data_book_view_notify_update (book_view, 
+								E_CONTACT(contacts->data));
+				g_object_unref (contacts->data);
+			}
+			if (e_flag_is_set (closure->running))
+				e_data_book_view_notify_complete (book_view, 
+								  GNOME_Evolution_Addressbook_Success);
+			if (temp_list)
+				 g_list_free (temp_list);
+			bonobo_object_unref (book_view);
+			return;
+		}
+
+		//FIXME: We need to fetch only the query from the server live and not everything.
+		/* execute the query */
+		if (!exchange_mapi_connection_fetch_items (priv->fid, NULL, 
+							NULL, 0, 
+							NULL, NULL, 
+							create_contact_cb, book_view, 
+							MAPI_OPTIONS_FETCH_ALL)) {
+			if (e_flag_is_set (closure->running))
+				e_data_book_view_notify_complete (book_view, 
+								  GNOME_Evolution_Addressbook_OtherError);	
+			bonobo_object_unref (book_view);
+			return;
+		}
+
+		if (e_flag_is_set (closure->running))
+			e_data_book_view_notify_complete (book_view,
+							  GNOME_Evolution_Addressbook_Success);
+		bonobo_object_unref (book_view);
+
+		
+
+	default:
+		break;
+	}
+
+	return;
+	
+
+}
+
+static void
+e_book_backend_mapi_start_book_view (EBookBackend  *backend,
+					   EDataBookView *book_view)
+{
+	BESearchClosure *closure = init_closure (book_view, backend);
+
+	if (enable_debug)
+		printf ("mapi: start_book_view...\n");
+	closure->thread = g_thread_create (book_view_thread, book_view, FALSE, NULL);
+	e_flag_wait (closure->running);
+	
+	/* at this point we know the book view thread is actually running */	
+}
+
+static void
+e_book_backend_mapi_stop_book_view (EBookBackend  *backend,
+					  EDataBookView *book_view)
+{
+	if(enable_debug)
+		printf("mapi: stop book view\n");	
+	/* FIXME : provide implmentation */
+}
+
+static void
+e_book_backend_mapi_get_changes (EBookBackend *backend,
+				       EDataBook    *book,
+				       guint32       opid,
+				       const char *change_id  )
+{
+	if(enable_debug)
+		printf("mapi: get changes\n");	
+	/* FIXME : provide implmentation */
+}
+
+static gboolean 
+cache_contact_cb (FetchItemsCallbackData *item_data, gpointer data)
+{
+	EBookBackendMAPI *be = data;
+	EContact *contact;
+	EBookBackendMAPIPrivate *priv = ((EBookBackendMAPI *) be)->priv;
+	char *suid;
+
+	contact = emapidump_contact (item_data->properties);
+	suid = exchange_mapi_util_mapi_ids_to_uid (item_data->fid, item_data->mid);
+	
+	if (contact) {
+		/* UID of the contact is nothing but the concatenated string of hex id of folder and the message.*/
+		e_contact_set (contact, E_CONTACT_UID, suid);		
+		e_contact_set (contact, E_CONTACT_BOOK_URI, priv->uri);
+		e_book_backend_cache_add_contact (priv->cache, contact);
+		e_book_backend_summary_add_contact (priv->summary, contact);		
+		g_object_unref(contact);
+	}
+
+	g_free (suid);
+	return TRUE;	
+}
+
+static gpointer
+build_cache (EBookBackendMAPI *ebmapi)
+{
+	EBookBackendMAPIPrivate *priv = ((EBookBackendMAPI *) ebmapi)->priv;
+	char *tmp;
+	
+	//FIXME: What if book view is NULL? Can it be? Check that.
+	if (!priv->cache) {
+		printf("Caching for the first time\n");
+		priv->cache = e_book_backend_cache_new (priv->uri);
+	}
+
+	if (!priv->summary) {
+		priv->summary = e_book_backend_summary_new (priv->summary_file_name, 
+							    SUMMARY_FLUSH_TIMEOUT);
+		printf("Summary file name is %s\n", priv->summary_file_name);
+	}
+	
+	e_file_cache_freeze_changes (E_FILE_CACHE (priv->cache));
+	
+	if (!exchange_mapi_connection_fetch_items (priv->fid, NULL, 
+						NULL, 0, 
+						NULL, NULL, 
+						cache_contact_cb, ebmapi, 
+						MAPI_OPTIONS_FETCH_ALL)) {
+		printf("Error during caching addressbook\n");
+		e_file_cache_thaw_changes (E_FILE_CACHE (priv->cache));
+		return NULL;
+	}
+	tmp = g_strdup_printf("%d", (int)time (NULL));
+	e_book_backend_cache_set_time (priv->cache, tmp);
+	printf("setting time  %s\n", tmp);
+	g_free (tmp);
+	e_file_cache_thaw_changes (E_FILE_CACHE (priv->cache));
+	e_book_backend_summary_save (priv->summary);
+	priv->is_cache_ready = TRUE;
+	priv->is_summary_ready = TRUE;
+	return NULL;		
+}
+
+static gpointer
+update_cache (EBookBackendMAPI *ebmapi)
+{
+	EBookBackendMAPIPrivate *priv = ((EBookBackendMAPI *) ebmapi)->priv;
+	char *tmp = e_book_backend_cache_get_time (priv->cache);
+	//FIXME: What if book view is NULL? Can it be? Check that.
+	time_t t=0;
+	struct mapi_SRestriction res;
+	
+	if (tmp)
+		t = atoi (tmp);
+
+	
+	
+//	res.rt = RES_PROPERTY;
+//	res.res.resProperty.relop = RES_PROPERTY;
+//	res.res.resProperty.ulPropTag = PR_LAST_MODIFICATION_TIME;
+//	res.res.resProperty.lpProp.ulPropTag = PR_LAST_MODIFICATION_TIME;
+//	res.res.resProperty.lpProp.value.lpszA = email;
+
+#if 0
+	printf("time updated was %d\n", t);
+	/* Assume the cache and summary are already there */
+	
+	e_file_cache_freeze_changes (E_FILE_CACHE (priv->cache));
+	
+	if (!exchange_mapi_connection_fetch_items ( priv->fid, &res, 
+						NULL, 0, 
+						NULL, NULL, 
+						cache_contact_cb, ebmapi, 
+						MAPI_OPTIONS_FETCH_ALL)) {
+		printf("Error during caching addressbook\n");
+		e_file_cache_thaw_changes (E_FILE_CACHE (priv->cache));
+		return NULL;
+	}
+	e_file_cache_thaw_changes (E_FILE_CACHE (priv->cache));
+	e_book_backend_summary_save (priv->summary);
+	priv->is_cache_ready = TRUE;
+	priv->is_summary_ready = TRUE;
+#endif
+	
+	return NULL;
+}
+
+static void
+e_book_backend_mapi_authenticate_user (EBookBackend *backend,
+					    EDataBook    *book,
+					    guint32       opid,
+					    const char *user,
+					    const char *passwd,
+					    const char *auth_method)
+{
+	EBookBackendMAPIPrivate *priv = ((EBookBackendMAPI *) backend)->priv;
+	
+	if (enable_debug) {
+		printf ("mapi: authenticate user\n");
+	}	
+
+	
+	switch (priv->mode) {
+	case GNOME_Evolution_Addressbook_MODE_LOCAL:
+		e_book_backend_notify_writable (backend, FALSE);
+		e_book_backend_notify_connection_status (backend, FALSE); 
+		e_data_book_respond_authenticate_user (book, opid, GNOME_Evolution_Addressbook_Success); 
+		return;
+		
+	case GNOME_Evolution_Addressbook_MODE_REMOTE:
+		
+		if (!exchange_mapi_connection_new (priv->profile, NULL))
+			return e_data_book_respond_authenticate_user (book, opid,GNOME_Evolution_Addressbook_OtherError);
+
+		if (priv->cache && priv->is_cache_ready) {
+			printf("FIXME: Should check for an update in the cache\n");
+//			g_thread_create ((GThreadFunc) update_cache, 
+	//					  backend, FALSE, backend);
+		} else if (priv->marked_for_offline && !priv->is_cache_ready) {
+			/* Means we dont have a cache. Lets build that first */
+			printf("Preparing to build cache\n");
+			g_thread_create ((GThreadFunc) build_cache, backend, FALSE, backend);
+		} 
+		e_book_backend_set_is_writable (backend, TRUE);
+		e_data_book_respond_authenticate_user (book, opid, GNOME_Evolution_Addressbook_Success);
+		return;
+		
+	default :
+		break;
+	}	
+}
+
+static void
+e_book_backend_mapi_get_required_fields (EBookBackend *backend,
+					       EDataBook    *book,
+					       guint32       opid)
+{
+	GList *fields = NULL;
+
+	if (enable_debug)
+		printf ("mapi get_required_fields...\n");
+  
+	fields = g_list_append (fields, (char *)e_contact_field_name (E_CONTACT_FILE_AS));
+	e_data_book_respond_get_supported_fields (book, opid,
+						  GNOME_Evolution_Addressbook_Success,
+						  fields);
+	g_list_free (fields);	
+}
+
+static void
+e_book_backend_mapi_get_supported_fields (EBookBackend *backend,
+					       EDataBook    *book,
+					       guint32       opid)
+{
+	GList *fields = NULL;
+	int i;
+
+	if (enable_debug)
+		printf ("mapi get_supported_fields...\n");
+
+	for (i=0; i<maplen; i++)
+	{
+		fields = g_list_append (fields, (char *)e_contact_field_name (mappings[i].field_id));
+	}
+	fields = g_list_append (fields, g_strdup (e_contact_field_name (E_CONTACT_BOOK_URI)));
+
+	e_data_book_respond_get_supported_fields (book, opid,
+						  GNOME_Evolution_Addressbook_Success,
+						  fields);
+	g_list_free (fields);
+	
+}
+
+static void 
+e_book_backend_mapi_get_supported_auth_methods (EBookBackend *backend, EDataBook *book, guint32 opid)
+{
+	GList *auth_methods = NULL;
+	char *auth_method;
+	
+	if (enable_debug)
+		printf ("mapi get_supported_auth_methods...\n");
+
+	auth_method =  g_strdup_printf ("plain/password");
+	auth_methods = g_list_append (auth_methods, auth_method);
+	e_data_book_respond_get_supported_auth_methods (book,
+							opid,
+							GNOME_Evolution_Addressbook_Success,
+							auth_methods);  
+	g_free (auth_method);
+	g_list_free (auth_methods);	
+}
+
+
+static GNOME_Evolution_Addressbook_CallStatus
+e_book_backend_mapi_cancel_operation (EBookBackend *backend, EDataBook *book)
+{
+	if (enable_debug)
+		printf ("mapi cancel_operation...\n");
+	return GNOME_Evolution_Addressbook_CouldNotCancel;	
+}
+
+
+static void
+e_book_backend_mapi_remove (EBookBackend *backend,
+				  EDataBook    *book,
+				  guint32      opid)
+{
+	EBookBackendMAPIPrivate *priv = ((EBookBackendMAPI *) backend)->priv;
+	char *cache_uri = NULL;
+	gboolean status;
+
+	if(enable_debug)
+		printf("mapi: remove\n");
+	
+	switch (priv->mode) {
+	
+	case GNOME_Evolution_Addressbook_MODE_LOCAL:
+		e_data_book_respond_remove (book, opid, GNOME_Evolution_Addressbook_OfflineUnavailable);
+		return;
+		
+	case GNOME_Evolution_Addressbook_MODE_REMOTE:
+
+		status = exchange_mapi_remove_folder (olFolderContacts, priv->fid);
+		if (!status) {
+			e_data_book_respond_remove (book, opid, GNOME_Evolution_Addressbook_OtherError);
+			return;			
+		}
+		
+		if (priv->marked_for_offline && priv->is_summary_ready) {
+			g_object_unref (priv->summary);
+			priv->summary = NULL;
+		}
+
+		if (e_book_backend_cache_exists (priv->uri)) {
+
+			g_object_unref (priv->cache);
+			priv->cache= NULL;
+			
+		}
+
+		/* Remove the summary and cache independent of whether they are loaded or not. */		
+		cache_uri = get_filename_from_uri (priv->uri, "cache.summary");
+		if (g_file_test (cache_uri, G_FILE_TEST_EXISTS)) {
+			g_unlink (cache_uri);
+		}
+		g_free (cache_uri);
+		
+		cache_uri = get_filename_from_uri (priv->uri, "cache.xml");
+		if (g_file_test (cache_uri, G_FILE_TEST_EXISTS)) {
+			g_unlink (cache_uri);
+		}
+		g_free (cache_uri);
+				
+		e_data_book_respond_remove (book, opid, GNOME_Evolution_Addressbook_Success);
+		return;
+
+
+	default:
+		break;
+	}
+
+	return;
+	
+	/* FIXME : provide implmentation */
+}
+
+static void 
+e_book_backend_mapi_set_mode (EBookBackend *backend, int mode)
+{
+	EBookBackendMAPIPrivate *priv = ((EBookBackendMAPI *) backend)->priv;
+
+	if(enable_debug)
+		printf("mapi: set_mode \n");
+	
+	priv->mode = mode;
+	if (e_book_backend_is_loaded (backend)) {
+		if (mode == GNOME_Evolution_Addressbook_MODE_LOCAL) {
+			e_book_backend_notify_writable (backend, FALSE);
+			e_book_backend_notify_connection_status (backend, FALSE);
+			/* FIXME: Uninitialize mapi here. may be.*/
+		}
+		else if (mode == GNOME_Evolution_Addressbook_MODE_REMOTE) {
+			e_book_backend_notify_writable (backend, TRUE);
+			e_book_backend_notify_connection_status (backend, TRUE);
+			e_book_backend_notify_auth_required (backend); //FIXME: WTH is this required.
+		}
+	}	
+}
+
+static void
+e_book_backend_mapi_dispose (GObject *object)
+{
+	/* FIXME : provide implmentation */
+	EBookBackendMAPIPrivate *priv = ((EBookBackendMAPI *) object)->priv;
+	
+	if (priv->profile) {
+		g_free (priv->profile);
+		priv->profile = NULL;
+	}
+	if (priv->uri) {
+		g_free (priv->uri);
+		priv->uri = NULL;
+	}
+	
+}
+
+
+
+static void e_book_backend_mapi_class_init (EBookBackendMAPIClass *klass)
+{
+	GObjectClass  *object_class = G_OBJECT_CLASS (klass);
+	EBookBackendClass *parent_class;
+	
+	
+	e_book_backend_mapi_parent_class = g_type_class_peek_parent (klass);
+	
+	parent_class = E_BOOK_BACKEND_CLASS (klass);
+	
+	/* Set the virtual methods. */
+	parent_class->load_source		   = e_book_backend_mapi_load_source;
+	parent_class->get_static_capabilities    = e_book_backend_mapi_get_static_capabilities;
+	parent_class->create_contact             = e_book_backend_mapi_create_contact;
+	parent_class->remove_contacts            = e_book_backend_mapi_remove_contacts;
+	parent_class->modify_contact             = e_book_backend_mapi_modify_contact;
+	parent_class->get_contact                = e_book_backend_mapi_get_contact;
+	parent_class->get_contact_list           = e_book_backend_mapi_get_contact_list;
+	parent_class->start_book_view            = e_book_backend_mapi_start_book_view;
+	parent_class->stop_book_view             = e_book_backend_mapi_stop_book_view;
+	parent_class->get_changes                = e_book_backend_mapi_get_changes;
+	parent_class->authenticate_user          = e_book_backend_mapi_authenticate_user;
+	parent_class->get_required_fields        = e_book_backend_mapi_get_required_fields;
+	parent_class->get_supported_fields       = e_book_backend_mapi_get_supported_fields;
+	parent_class->get_supported_auth_methods = e_book_backend_mapi_get_supported_auth_methods;
+	parent_class->cancel_operation           = e_book_backend_mapi_cancel_operation;
+	parent_class->remove                     = e_book_backend_mapi_remove;
+	parent_class->set_mode                   = e_book_backend_mapi_set_mode;
+	object_class->dispose                    = e_book_backend_mapi_dispose;
+	
+}
+
+EBookBackend *e_book_backend_mapi_new (void)
+{
+	EBookBackendMAPI *backend;
+	
+	
+	backend = g_object_new (E_TYPE_BOOK_BACKEND_MAPI, NULL);
+	return E_BOOK_BACKEND (backend);
+}
+
+
+static void	e_book_backend_mapi_init (EBookBackendMAPI *backend)
+{
+	EBookBackendMAPIPrivate *priv;
+  
+	priv= g_new0 (EBookBackendMAPIPrivate, 1);
+	/* Priv Struct init */
+	backend->priv = priv;
+
+	priv->marked_for_offline = FALSE;
+	priv->uri = NULL;
+	priv->cache = NULL;
+	priv->is_summary_ready = FALSE;
+	priv->is_cache_ready = FALSE;
+	
+	if (g_getenv ("MAPI_DEBUG"))
+		enable_debug = TRUE;
+	else
+		enable_debug = FALSE;
+	
+	
+}
+
+
+GType	e_book_backend_mapi_get_type (void)
+{
+	static GType type = 0;
+	
+	if (! type) {
+		GTypeInfo info = {
+			sizeof (EBookBackendMAPIClass),
+			NULL, /* base_class_init */
+			NULL, /* base_class_finalize */
+			(GClassInitFunc)  e_book_backend_mapi_class_init,
+			NULL, /* class_finalize */
+			NULL, /* class_data */
+			sizeof (EBookBackendMAPI),
+			0,    /* n_preallocs */
+			(GInstanceInitFunc) e_book_backend_mapi_init
+		};
+		
+		type = g_type_register_static (E_TYPE_BOOK_BACKEND, "EBookBackendMAPI", &info, 0);
+	}
+	
+	return type;
+}

Added: trunk/src/addressbook/e-book-backend-mapi.h
==============================================================================
--- (empty file)
+++ trunk/src/addressbook/e-book-backend-mapi.h	Wed Nov 19 04:28:20 2008
@@ -0,0 +1,60 @@
+/* -*- 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/>  
+ *
+ *
+ * Authors:
+ *    Srinivasa Ragavan <sragavan novell com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef __E_BOOK_BACKEND_MAPI_H__
+#define __E_BOOK_BACKEND_MAPI_H__
+
+#include <libedata-book/e-book-backend.h>
+#include <libedata-book/e-book-backend-sync.h>
+#include "exchange-mapi-connection.h"
+#include "exchange-mapi-defs.h"
+#include "exchange-mapi-utils.h"
+
+/* #include "db.h" */
+
+
+#define E_TYPE_BOOK_BACKEND_MAPI         (e_book_backend_mapi_get_type ())
+#define E_BOOK_BACKEND_MAPI(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), E_TYPE_BOOK_BACKEND_MAPI, EBookBackendMAPI))
+#define E_BOOK_BACKEND_MAPI_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST((k), E_TYPE_BOOK_BACKEND_MAPI, EBookBackendMAPIClass))
+#define E_IS_BOOK_BACKEND_MAPI(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), E_TYPE_BOOK_BACKEND_MAPI))
+#define E_IS_BOOK_BACKEND_MAPI_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), E_TYPE_BOOK_BACKEND_MAPI))
+#define E_BOOK_BACKEND_MAPI_GET_CLASS(k) (G_TYPE_INSTANCE_GET_CLASS ((obj), E_TYPE_BOOK_BACKEND_MAPI, EBookBackendMAPIClass))
+
+typedef struct _EBookBackendMAPIPrivate EBookBackendMAPIPrivate;
+
+typedef struct
+{
+	EBookBackend             parent_object;
+	EBookBackendMAPIPrivate *priv;
+} EBookBackendMAPI;
+
+typedef struct
+{
+	EBookBackendClass parent_class;
+} EBookBackendMAPIClass;
+
+EBookBackend *e_book_backend_mapi_new      (void);
+GType         e_book_backend_mapi_get_type (void);
+
+#endif /* ! __E_BOOK_BACKEND_MAPI_H__ */
+

Added: trunk/src/calendar/Makefile.am
==============================================================================
--- (empty file)
+++ trunk/src/calendar/Makefile.am	Wed Nov 19 04:28:20 2008
@@ -0,0 +1,31 @@
+INCLUDES =					\
+	-DG_LOG_DOMAIN=\"libecalbackendmapi\"	\
+	-I$(top_srcdir)/src/calendar		\
+	-I$(top_builddir)/src/calendar		\
+	-I$(top_srcdir)/src/libexchangemapi		\
+	-I$(top_builddir)/src/libexchangemapi		\
+	$(LIBEBACKEND_CFLAGS)			\
+	$(EVOLUTION_CALENDAR_CFLAGS)		\
+	$(LIBECAL_CFLAGS)			\
+	$(LIBEDATACAL_CFLAGS)			\
+	$(LIBMAPI_CFLAGS)
+
+extension_LTLIBRARIES = libecalbackendmapi.la
+
+libecalbackendmapi_la_SOURCES =			\
+	e-cal-backend-mapi-factory.c		\
+	e-cal-backend-mapi-factory.h		\
+	e-cal-backend-mapi.c			\
+	e-cal-backend-mapi.h
+
+libecalbackendmapi_la_LIBADD =					\
+	$(top_builddir)/src/libexchangemapi/libexchangemapi-1.0.la		\
+	$(LIBEBACKEND_LIBS)					\
+	$(EVOLUTION_CALENDAR_LIBS)				\
+	$(LIBECAL_LIBS)						\
+	$(LIBEDATACAL_LIBS)					\
+	$(LIBMAPI_LIBS)
+
+libecalbackendmapi_la_LDFLAGS =			\
+	-module -avoid-version $(NO_UNDEFINED)
+

Added: trunk/src/calendar/e-cal-backend-mapi-factory.c
==============================================================================
--- (empty file)
+++ trunk/src/calendar/e-cal-backend-mapi-factory.c	Wed Nov 19 04:28:20 2008
@@ -0,0 +1,214 @@
+/* -*- 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/>  
+ *
+ *
+ * Authors:
+ *    Suman Manjunath <msuman novell com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#include "e-cal-backend-mapi-factory.h"
+#include "e-cal-backend-mapi.h"
+
+#define d(x) 
+
+typedef struct {
+	ECalBackendFactory            parent_object;
+} ECalBackendMAPIFactory;
+
+typedef struct {
+	ECalBackendFactoryClass parent_class;
+} ECalBackendMAPIFactoryClass;
+
+static void
+e_cal_backend_mapi_factory_instance_init (ECalBackendMAPIFactory *factory)
+{
+}
+
+static const char *
+_get_protocol (ECalBackendFactory *factory)
+{
+	return "mapi";
+}
+
+static ECalBackend*
+_todos_new_backend (ECalBackendFactory *factory, ESource *source)
+{
+	return g_object_new (e_cal_backend_mapi_get_type (),
+			     "source", source,
+			     "kind", ICAL_VTODO_COMPONENT,
+			     NULL);
+}
+
+static icalcomponent_kind
+_todos_get_kind (ECalBackendFactory *factory)
+{
+	return ICAL_VTODO_COMPONENT;
+}
+
+static void
+todos_backend_factory_class_init (ECalBackendMAPIFactoryClass *klass)
+{
+	E_CAL_BACKEND_FACTORY_CLASS (klass)->get_protocol = _get_protocol;
+	E_CAL_BACKEND_FACTORY_CLASS (klass)->get_kind     = _todos_get_kind;
+	E_CAL_BACKEND_FACTORY_CLASS (klass)->new_backend  = _todos_new_backend;
+}
+
+static GType
+todos_backend_factory_get_type (GTypeModule *module)
+{
+	GType type;
+
+	GTypeInfo info = {
+		sizeof (ECalBackendMAPIFactoryClass),
+		NULL, /* base_class_init */
+		NULL, /* base_class_finalize */
+		(GClassInitFunc)  todos_backend_factory_class_init,
+		NULL, /* class_finalize */
+		NULL, /* class_data */
+		sizeof (ECalBackend),
+		0,    /* n_preallocs */
+		(GInstanceInitFunc) e_cal_backend_mapi_factory_instance_init
+	};
+
+	type = g_type_module_register_type (module,
+					    E_TYPE_CAL_BACKEND_FACTORY,
+					    "ECalBackendMAPITodosFactory",
+					    &info, 0);
+
+	return type;
+}
+
+static ECalBackend*
+_events_new_backend (ECalBackendFactory *factory, ESource *source)
+{
+	return g_object_new (e_cal_backend_mapi_get_type (),
+			     "source", source,
+			     "kind", ICAL_VEVENT_COMPONENT,
+			     NULL);
+}
+
+static icalcomponent_kind
+_events_get_kind (ECalBackendFactory *factory)
+{
+	return ICAL_VEVENT_COMPONENT;
+}
+
+static void
+events_backend_factory_class_init (ECalBackendMAPIFactoryClass *klass)
+{
+	E_CAL_BACKEND_FACTORY_CLASS (klass)->get_protocol = _get_protocol;
+	E_CAL_BACKEND_FACTORY_CLASS (klass)->get_kind     = _events_get_kind;
+	E_CAL_BACKEND_FACTORY_CLASS (klass)->new_backend  = _events_new_backend;
+}
+
+static GType
+events_backend_factory_get_type (GTypeModule *module)
+{
+	GType type;
+
+	GTypeInfo info = {
+		sizeof (ECalBackendMAPIFactoryClass),
+		NULL, /* base_class_init */
+		NULL, /* base_class_finalize */
+		(GClassInitFunc)  events_backend_factory_class_init,
+		NULL, /* class_finalize */
+		NULL, /* class_data */
+		sizeof (ECalBackend),
+		0,    /* n_preallocs */
+		(GInstanceInitFunc) e_cal_backend_mapi_factory_instance_init
+	};
+
+	type = g_type_module_register_type (module,
+					    E_TYPE_CAL_BACKEND_FACTORY,
+					    "ECalBackendMAPIEventsFactory",
+					    &info, 0);
+
+	return type;
+}
+
+/* NOTE: Outlook "Notes" = Evolution "Memos" */
+static ECalBackend*
+_journal_new_backend (ECalBackendFactory *factory, ESource *source)
+{
+	return g_object_new (e_cal_backend_mapi_get_type (),
+			     "source", source,
+			     "kind", ICAL_VJOURNAL_COMPONENT,
+			     NULL);
+}
+
+static icalcomponent_kind
+_journal_get_kind (ECalBackendFactory *factory)
+{
+	return ICAL_VJOURNAL_COMPONENT;
+}
+
+static void
+journal_backend_factory_class_init (ECalBackendMAPIFactoryClass *klass)
+{
+	E_CAL_BACKEND_FACTORY_CLASS (klass)->get_protocol = _get_protocol;
+	E_CAL_BACKEND_FACTORY_CLASS (klass)->get_kind     = _journal_get_kind;
+	E_CAL_BACKEND_FACTORY_CLASS (klass)->new_backend  = _journal_new_backend;
+}
+
+static GType
+journal_backend_factory_get_type (GTypeModule *module)
+{
+	GType type;
+
+	GTypeInfo info = {
+		sizeof (ECalBackendMAPIFactoryClass),
+		NULL, /* base_class_init */
+		NULL, /* base_class_finalize */
+		(GClassInitFunc)  journal_backend_factory_class_init,
+		NULL, /* class_finalize */
+		NULL, /* class_data */
+		sizeof (ECalBackend),
+		0,    /* n_preallocs */
+		(GInstanceInitFunc) e_cal_backend_mapi_factory_instance_init
+	};
+
+	type = g_type_module_register_type (module,
+					    E_TYPE_CAL_BACKEND_FACTORY,
+					    "ECalBackendMAPIJournalFactory",
+					    &info, 0);
+
+	return type;
+}
+
+static GType mapi_types[3];
+
+void
+eds_module_initialize (GTypeModule *module)
+{
+	mapi_types[0] = todos_backend_factory_get_type (module);
+	mapi_types[1] = events_backend_factory_get_type (module);
+	mapi_types[2] = journal_backend_factory_get_type (module);
+}
+
+void
+eds_module_shutdown   (void)
+{
+}
+
+void
+eds_module_list_types (const GType **types, int *num_types)
+{
+	*types = mapi_types;
+	*num_types = 3;
+}
+

Added: trunk/src/calendar/e-cal-backend-mapi-factory.h
==============================================================================
--- (empty file)
+++ trunk/src/calendar/e-cal-backend-mapi-factory.h	Wed Nov 19 04:28:20 2008
@@ -0,0 +1,38 @@
+/* -*- 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/>  
+ *
+ *
+ * Authors:
+ *    Suman Manjunath <msuman novell com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef _E_CAL_BACKEND_MAPI_FACTORY_H_
+#define _E_CAL_BACKEND_MAPI_FACTORY_H_
+
+#include <libedata-cal/e-cal-backend-factory.h>
+
+G_BEGIN_DECLS
+
+void                 eds_module_initialize (GTypeModule *module);
+void                 eds_module_shutdown   (void);
+void                 eds_module_list_types (const GType **types, int *num_types);
+
+G_END_DECLS
+
+#endif /* _E_CAL_BACKEND_MAPI_FACTORY_H_ */
+

Added: trunk/src/calendar/e-cal-backend-mapi.c
==============================================================================
--- (empty file)
+++ trunk/src/calendar/e-cal-backend-mapi.c	Wed Nov 19 04:28:20 2008
@@ -0,0 +1,2421 @@
+/* -*- 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/>  
+ *
+ *
+ * Authors:
+ *    Suman Manjunath <msuman novell com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#include <glib/gi18n.h>
+#include <gio/gio.h>
+
+#include "e-cal-backend-mapi.h"
+
+#include <libedata-cal/e-cal-backend-cache.h>
+#include <libedataserver/e-xml-hash-utils.h>
+
+#include <exchange-mapi-connection.h>
+#include <exchange-mapi-cal-utils.h>
+#include <exchange-mapi-utils.h>
+
+#define d(x) x
+
+#ifdef G_OS_WIN32
+/* Undef the similar macro from pthread.h, it doesn't check if
+ * gmtime() returns NULL.
+ */
+#undef gmtime_r
+
+/* The gmtime() in Microsoft's C library is MT-safe */
+#define gmtime_r(tp,tmp) (gmtime(tp)?(*(tmp)=*gmtime(tp),(tmp)):0)
+#endif
+
+typedef struct {
+	GCond *cond;
+	GMutex *mutex;
+	gboolean exit;
+} SyncDelta;
+
+/* Private part of the CalBackendMAPI structure */
+struct _ECalBackendMAPIPrivate {
+	mapi_id_t 		fid;
+	uint32_t 		olFolder;
+	gchar 			*profile; 
+
+	/* These fields are entirely for access rights */
+	gchar 			*owner_name;
+	gchar 			*owner_email;	
+	gchar			*user_name;
+	gchar			*user_email;
+
+	/* A mutex to control access to the private structure */
+	GMutex			*mutex;
+	ECalBackendCache	*cache;
+	gboolean		read_only;
+	gchar			*uri;
+	gchar			*username;
+	gchar			*password;
+	CalMode			mode;
+	gboolean		mode_changed;
+	icaltimezone		*default_zone;
+
+	/* timeout handler for syncing sendoptions */
+	guint			sendoptions_sync_timeout;
+	
+	gchar			*local_attachments_store;
+
+	/* used exclusively for delta fetching */
+	guint 			timeout_id;
+	GThread 		*dthread;
+	SyncDelta 		*dlock;
+	GSList 			*cache_keys;
+};
+
+#define PARENT_TYPE E_TYPE_CAL_BACKEND_SYNC
+static ECalBackendClass *parent_class = NULL;
+
+#define CACHE_REFRESH_INTERVAL 600000
+
+static gboolean authenticated = FALSE;
+static GStaticMutex auth_mutex = G_STATIC_MUTEX_INIT;
+
+static ECalBackendSyncStatus
+e_cal_backend_mapi_authenticate (ECalBackend *backend)
+{
+	ECalBackendMAPI *cbmapi;
+	ECalBackendMAPIPrivate *priv;
+
+	cbmapi = E_CAL_BACKEND_MAPI (backend);
+	priv = cbmapi->priv;
+
+	if (authenticated || exchange_mapi_connection_exists () || exchange_mapi_connection_new (priv->profile, priv->password)) {
+		authenticated = TRUE;
+		return GNOME_Evolution_Calendar_Success;
+	} else { 
+		authenticated = FALSE;
+		e_cal_backend_notify_error (E_CAL_BACKEND (cbmapi), _("Authentication failed"));
+		return GNOME_Evolution_Calendar_AuthenticationFailed;
+	}
+}
+
+/***** OBJECT CLASS FUNCTIONS *****/
+static void 
+e_cal_backend_mapi_dispose (GObject *object)
+{
+	ECalBackendMAPI *cbmapi;
+	ECalBackendMAPIPrivate *priv;
+
+	cbmapi = E_CAL_BACKEND_MAPI (object);
+	priv = cbmapi->priv;
+
+	if (G_OBJECT_CLASS (parent_class)->dispose)
+		(* G_OBJECT_CLASS (parent_class)->dispose) (object);
+}
+
+static void 
+e_cal_backend_mapi_finalize (GObject *object)
+{
+	ECalBackendMAPI *cbmapi;
+	ECalBackendMAPIPrivate *priv;
+
+	g_return_if_fail (object != NULL);
+	g_return_if_fail (E_IS_CAL_BACKEND_MAPI (object));
+
+	cbmapi = E_CAL_BACKEND_MAPI (object);
+	priv = cbmapi->priv;
+
+	/* Clean up */
+	if (priv->timeout_id) {
+		g_source_remove (priv->timeout_id);
+		priv->timeout_id = 0;
+	}
+
+	if (priv->dlock) {
+		g_mutex_lock (priv->dlock->mutex);
+		priv->dlock->exit = TRUE;
+		g_mutex_unlock (priv->dlock->mutex);
+		
+		g_cond_signal (priv->dlock->cond);
+
+		if (priv->dthread)
+			g_thread_join (priv->dthread);
+		
+		g_mutex_free (priv->dlock->mutex);
+		g_cond_free (priv->dlock->cond);
+		g_free (priv->dlock);
+		priv->dthread = NULL;
+	}
+
+	if (priv->mutex) {
+		g_mutex_free (priv->mutex);
+		priv->mutex = NULL;
+	}
+
+	if (priv->cache) {
+		g_object_unref (priv->cache);
+		priv->cache = NULL;
+	}
+
+	if (priv->username) {
+		g_free (priv->username);
+		priv->username = NULL;
+	}
+
+	if (priv->password) {
+		g_free (priv->password);
+		priv->password = NULL;
+	}
+
+	if (priv->profile) {
+		g_free (priv->profile);
+		priv->profile = NULL;
+	}
+
+	if (priv->user_name) {
+		g_free (priv->user_name);
+		priv->user_name = NULL;
+	}
+
+	if (priv->user_email) {
+		g_free (priv->user_email);
+		priv->user_email = NULL;
+	}
+
+	if (priv->owner_name) {
+		g_free (priv->owner_name);
+		priv->owner_name = NULL;
+	}
+
+	if (priv->owner_email) {
+		g_free (priv->owner_email);
+		priv->owner_email = NULL;
+	}
+
+	if (priv->local_attachments_store) {
+		g_free (priv->local_attachments_store);
+		priv->local_attachments_store = NULL;
+	}
+
+	if (priv->sendoptions_sync_timeout) {
+		g_source_remove (priv->sendoptions_sync_timeout);
+		priv->sendoptions_sync_timeout = 0;
+	}
+
+	if (priv->default_zone) {
+		icaltimezone_free (priv->default_zone, 1);
+		priv->default_zone = NULL;
+	}
+
+	g_free (priv);
+	cbmapi->priv = NULL;
+
+	if (G_OBJECT_CLASS (parent_class)->finalize)
+		(* G_OBJECT_CLASS (parent_class)->finalize) (object);
+}
+
+
+/***** SYNC CLASS FUNCTIONS *****/
+static ECalBackendSyncStatus 
+e_cal_backend_mapi_is_read_only (ECalBackendSync *backend, EDataCal *cal, gboolean *read_only)
+{
+	ECalBackendMAPI *cbmapi;
+	ECalBackendMAPIPrivate *priv;
+
+	cbmapi = E_CAL_BACKEND_MAPI (backend);
+	priv = cbmapi->priv;
+
+	*read_only = priv->read_only;
+
+	return GNOME_Evolution_Calendar_Success;
+}
+
+static ECalBackendSyncStatus 
+e_cal_backend_mapi_get_cal_address (ECalBackendSync *backend, EDataCal *cal, char **address)
+{
+	ECalBackendMAPI *cbmapi;
+	ECalBackendMAPIPrivate *priv;
+
+	cbmapi = E_CAL_BACKEND_MAPI (backend);
+	priv = cbmapi->priv;
+
+	*address = g_strdup (priv->user_email);
+
+	return GNOME_Evolution_Calendar_Success;
+}
+
+static ECalBackendSyncStatus 
+e_cal_backend_mapi_get_alarm_email_address (ECalBackendSync *backend, EDataCal *cal, char **address)
+{
+	/* We don't support email alarms. This should not have been called. */
+
+	*address = NULL;
+
+	return GNOME_Evolution_Calendar_Success;
+}
+
+static ECalBackendSyncStatus 
+e_cal_backend_mapi_get_ldap_attribute (ECalBackendSync *backend, EDataCal *cal, char **attribute)
+{
+	/* This is just a hack for SunONE */
+	*attribute = NULL;
+
+	return GNOME_Evolution_Calendar_Success;
+}
+
+static ECalBackendSyncStatus 
+e_cal_backend_mapi_get_static_capabilities (ECalBackendSync *backend, EDataCal *cal, char **capabilities)
+{
+	/* FIXME: what else ? */
+
+	*capabilities = g_strdup (
+				CAL_STATIC_CAPABILITY_NO_ALARM_REPEAT ","
+				CAL_STATIC_CAPABILITY_NO_AUDIO_ALARMS ","
+//				CAL_STATIC_CAPABILITY_NO_DISPLAY_ALARMS ","
+				CAL_STATIC_CAPABILITY_NO_EMAIL_ALARMS ","
+				CAL_STATIC_CAPABILITY_NO_PROCEDURE_ALARMS ","
+				CAL_STATIC_CAPABILITY_ONE_ALARM_ONLY ","
+				CAL_STATIC_CAPABILITY_REMOVE_ALARMS ","
+
+//				CAL_STATIC_CAPABILITY_NO_SHARED_MEMOS ","
+//				CAL_STATIC_CAPABILITY_NO_TASK_ASSIGNMENT ","
+				CAL_STATIC_CAPABILITY_NO_THISANDFUTURE ","
+				CAL_STATIC_CAPABILITY_NO_THISANDPRIOR ","
+//				CAL_STATIC_CAPABILITY_NO_TRANSPARENCY ","
+//				CAL_STATIC_CAPABILITY_ORGANIZER_MUST_ATTEND ","
+//				CAL_STATIC_CAPABILITY_ORGANIZER_NOT_EMAIL_ADDRESS ","
+//				CAL_STATIC_CAPABILITY_CREATE_MESSAGES ","
+//				CAL_STATIC_CAPABILITY_SAVE_SCHEDULES ","
+				CAL_STATIC_CAPABILITY_NO_CONV_TO_ASSIGN_TASK ","
+				CAL_STATIC_CAPABILITY_NO_CONV_TO_RECUR ","
+//				CAL_STATIC_CAPABILITY_NO_GEN_OPTIONS ","
+//				CAL_STATIC_CAPABILITY_REQ_SEND_OPTIONS ","
+//				CAL_STATIC_CAPABILITY_RECURRENCES_NO_MASTER ","
+//				CAL_STATIC_CAPABILITY_ORGANIZER_MUST_ACCEPT ","
+//				CAL_STATIC_CAPABILITY_DELEGATE_SUPPORTED ","
+//				CAL_STATIC_CAPABILITY_NO_ORGANIZER ","
+//				CAL_STATIC_CAPABILITY_DELEGATE_TO_MANY ","
+				CAL_STATIC_CAPABILITY_HAS_UNACCEPTED_MEETING
+				  );
+
+	return GNOME_Evolution_Calendar_Success;
+}
+
+static ECalBackendSyncStatus 	
+e_cal_backend_mapi_remove (ECalBackendSync *backend, EDataCal *cal)
+{
+	ECalBackendMAPI *cbmapi;
+	ECalBackendMAPIPrivate *priv;
+	gboolean status = FALSE;
+
+	cbmapi = E_CAL_BACKEND_MAPI (backend);
+	priv = cbmapi->priv;
+
+	if (priv->mode == CAL_MODE_LOCAL)
+		return GNOME_Evolution_Calendar_RepositoryOffline;
+
+	/* FIXME: check for return status and respond */
+	if (!authenticated) {
+		g_static_mutex_lock (&auth_mutex); 
+		e_cal_backend_mapi_authenticate (E_CAL_BACKEND (cbmapi));
+		g_static_mutex_unlock (&auth_mutex);
+	}
+
+	if (!authenticated)
+		return GNOME_Evolution_Calendar_AuthenticationFailed;
+
+	status = exchange_mapi_remove_folder (priv->olFolder, priv->fid);
+	if (!status)
+		return GNOME_Evolution_Calendar_OtherError;
+
+	g_mutex_lock (priv->mutex);
+
+	/* remove the cache */
+	if (priv->cache)
+		e_file_cache_remove (E_FILE_CACHE (priv->cache));
+
+	g_mutex_unlock (priv->mutex);
+
+	/* anything else ? */
+
+	return GNOME_Evolution_Calendar_Success;
+}
+
+static const char *
+get_element_type (icalcomponent_kind kind)
+{
+
+	const char *type = "";
+
+	if (kind == ICAL_VEVENT_COMPONENT)
+		type = "Appointment";
+	else if (kind == ICAL_VTODO_COMPONENT)
+		type = "Task";
+	else if (kind == ICAL_VJOURNAL_COMPONENT)
+		type = "Note";
+
+	return type;
+
+}
+
+static void 
+notify_progress (ECalBackendMAPI *cbmapi, guint64 index, guint64 total)
+{
+	guint percent = ((float)index/total) * 100 ;
+	if (percent > 100)
+		percent = 99; 
+
+	gchar *progress_string = g_strdup_printf (_("Loading %s items"), get_element_type (e_cal_backend_get_kind (E_CAL_BACKEND (cbmapi)))); 
+
+	e_cal_backend_notify_view_progress (E_CAL_BACKEND (cbmapi), progress_string, percent);
+
+	g_free (progress_string); 
+}
+
+static gboolean
+mapi_cal_get_changes_cb (FetchItemsCallbackData *item_data, gpointer data)
+{
+	struct mapi_SPropValue_array *array = item_data->properties; 
+	const mapi_id_t mid = item_data->mid; 
+	GSList *streams = item_data->streams; 
+	GSList *recipients = item_data->recipients; 
+	GSList *attachments = item_data->attachments; 
+	ECalBackendMAPI *cbmapi	= data;
+	ECalBackendMAPIPrivate *priv = cbmapi->priv;
+	icalcomponent_kind kind = e_cal_backend_get_kind (E_CAL_BACKEND (cbmapi));
+	gchar *tmp = NULL;
+	ECalComponent *cache_comp = NULL;
+	const bool *recurring;
+
+//	exchange_mapi_debug_property_dump (array);
+
+	recurring = NULL;
+	/* FIXME: Evolution does not support recurring tasks */
+	recurring = (const bool *)find_mapi_SPropValue_data(array, PROP_TAG(PT_BOOLEAN, 0x8126));
+	if (recurring && *recurring) {
+		g_warning ("Encountered a recurring task.");
+		exchange_mapi_util_free_stream_list (&streams);
+		exchange_mapi_util_free_recipient_list (&recipients);
+		exchange_mapi_util_free_attachment_list (&attachments);
+		return TRUE;
+	}
+
+	tmp = exchange_mapi_util_mapi_id_to_string (mid);
+	cache_comp = e_cal_backend_cache_get_component (priv->cache, tmp, NULL);
+
+	if (cache_comp == NULL) {
+		ECalComponent *comp = exchange_mapi_cal_util_mapi_props_to_comp (kind, tmp, array, 
+									streams, recipients, attachments, 
+									priv->local_attachments_store, priv->default_zone);
+
+		if (E_IS_CAL_COMPONENT (comp)) {
+			char *comp_str;
+
+			e_cal_component_commit_sequence (comp);
+			comp_str = e_cal_component_get_as_string (comp);	
+
+			e_cal_backend_notify_object_created (E_CAL_BACKEND (cbmapi), (const char *) comp_str);
+			e_cal_backend_cache_put_component (priv->cache, comp);
+
+			g_free (comp_str);
+		}
+		g_object_unref (comp);
+	} else {
+		struct timeval t;
+
+		if (get_mapi_SPropValue_array_date_timeval (&t, array, PR_LAST_MODIFICATION_TIME) == MAPI_E_SUCCESS) {
+			struct icaltimetype itt, *cache_comp_lm = NULL;
+
+			itt = icaltime_from_timet_with_zone (t.tv_sec, 0, 0);
+			icaltime_set_timezone (&itt, icaltimezone_get_utc_timezone ());
+
+			e_cal_component_get_last_modified (cache_comp, &cache_comp_lm);
+			if (!cache_comp_lm || (icaltime_compare (itt, *cache_comp_lm) != 0)) {
+				ECalComponent *comp;
+				char *cache_comp_str = NULL, *modif_comp_str = NULL;
+
+				e_cal_component_commit_sequence (cache_comp);
+				cache_comp_str = e_cal_component_get_as_string (cache_comp);
+
+				comp = exchange_mapi_cal_util_mapi_props_to_comp (kind, tmp, array, 
+									streams, recipients, attachments, 
+									priv->local_attachments_store, priv->default_zone);
+
+				e_cal_component_commit_sequence (comp);
+				modif_comp_str = e_cal_component_get_as_string (comp);
+
+				e_cal_backend_notify_object_modified (E_CAL_BACKEND (cbmapi), cache_comp_str, modif_comp_str);
+				e_cal_backend_cache_put_component (priv->cache, comp);
+
+				g_object_unref (comp);
+				g_free (cache_comp_str); 
+				g_free (modif_comp_str);
+			}
+			g_object_unref (cache_comp);
+			g_free (cache_comp_lm);
+		}
+	}
+
+	g_free (tmp);
+	exchange_mapi_util_free_stream_list (&streams);
+	exchange_mapi_util_free_recipient_list (&recipients);
+	exchange_mapi_util_free_attachment_list (&attachments);
+
+	notify_progress (cbmapi, item_data->index, item_data->total);
+
+	return TRUE;
+}
+
+static gboolean
+handle_deleted_items_cb (FetchItemsCallbackData *item_data, gpointer data)
+{
+	const mapi_id_t mid = item_data->mid; 
+	ECalBackendMAPI *cbmapi	= data;
+	ECalBackendMAPIPrivate *priv = cbmapi->priv;
+	gchar *tmp = NULL;
+	GSList *cache_comp_uid = NULL;
+
+	tmp = exchange_mapi_util_mapi_id_to_string (mid);
+	cache_comp_uid = g_slist_find_custom (priv->cache_keys, tmp, (GCompareFunc) (g_ascii_strcasecmp));
+	if (cache_comp_uid != NULL)
+		priv->cache_keys = g_slist_remove_link (priv->cache_keys, cache_comp_uid);
+
+	g_free (tmp);
+	return TRUE;
+}
+
+/* Simple workflow for fetching deltas: 
+ * Poke cache for server_utc_time -> if exists, fetch all items modified after that time, 
+ * note current time before fetching and update cache with the same after fetching. 
+ * If server_utc_time does not exist OR is invalid, fetch all items 
+ * (we anyway process the results only if last_modified has changed).
+ */
+
+static gboolean
+get_deltas (gpointer handle)
+{
+	ECalBackendMAPI *cbmapi;
+	ECalBackendMAPIPrivate *priv;
+	icalcomponent_kind kind;
+	static GStaticMutex updating = G_STATIC_MUTEX_INIT;
+	icaltimetype itt_current, itt_cache = icaltime_null_time(); 
+	time_t current_time;
+	struct tm tm;
+	gchar *time_string = NULL;
+	gchar t_str [26]; 
+	const char *serv_time;
+	struct mapi_SRestriction res;
+	gboolean use_restriction = FALSE;
+	GSList *ls = NULL;
+
+	if (!handle)
+		return FALSE;
+
+	cbmapi = (ECalBackendMAPI *) handle;
+	priv= cbmapi->priv;
+	kind = e_cal_backend_get_kind (E_CAL_BACKEND (cbmapi));
+
+	if (priv->mode == CAL_MODE_LOCAL)
+		return FALSE;
+
+	g_static_mutex_lock (&updating);
+
+	serv_time = e_cal_backend_cache_get_server_utc_time (priv->cache);
+	if (serv_time)
+		itt_cache = icaltime_from_string (serv_time); 
+	if (!icaltime_is_null_time (itt_cache)) {
+		struct SPropValue sprop;
+		struct timeval t;
+
+		use_restriction = TRUE;
+		res.rt = RES_PROPERTY;
+		res.res.resProperty.relop = RELOP_GE;
+		res.res.resProperty.ulPropTag = PR_LAST_MODIFICATION_TIME;
+
+		t.tv_sec = icaltime_as_timet_with_zone (itt_cache, icaltimezone_get_utc_timezone ());
+		t.tv_usec = 0;
+		set_SPropValue_proptag_date_timeval (&sprop, PR_LAST_MODIFICATION_TIME, &t);
+		cast_mapi_SPropValue (&(res.res.resProperty.lpProp), &sprop);
+	} else
+		g_warning ("Cache time-stamp not found."); 
+
+	itt_current = icaltime_current_time_with_zone (icaltimezone_get_utc_timezone ());
+	current_time = icaltime_as_timet_with_zone (itt_current, icaltimezone_get_utc_timezone ());
+	gmtime_r (&current_time, &tm);
+	strftime (t_str, 26, "%Y-%m-%dT%H:%M:%SZ", &tm);
+
+	e_cal_backend_notify_view_progress_start (E_CAL_BACKEND (cbmapi));
+
+//	e_file_cache_freeze_changes (E_FILE_CACHE (priv->cache));
+	/* FIXME: GetProps does not seem to work for tasks :-( */
+	if (kind == ICAL_VTODO_COMPONENT) {
+		if (!exchange_mapi_connection_fetch_items (priv->fid, use_restriction ? &res : NULL, 
+						NULL, 0, NULL, NULL, 
+						mapi_cal_get_changes_cb, cbmapi, 
+						MAPI_OPTIONS_FETCH_ALL)) {
+			/* FIXME: better string please... */
+			e_cal_backend_notify_error (E_CAL_BACKEND (cbmapi), _("Error fetching changes from the server. Removing the cache might help."));
+//			e_file_cache_thaw_changes (E_FILE_CACHE (priv->cache));
+			g_static_mutex_unlock (&updating);
+			return FALSE;
+		}
+	} else if (!exchange_mapi_connection_fetch_items (priv->fid, use_restriction ? &res : NULL, 
+						cal_GetPropsList, G_N_ELEMENTS (cal_GetPropsList), 
+						exchange_mapi_cal_util_build_name_id, GINT_TO_POINTER(kind), 
+						mapi_cal_get_changes_cb, cbmapi, 
+						MAPI_OPTIONS_FETCH_ALL)) {
+		/* FIXME: better string please... */
+		e_cal_backend_notify_error (E_CAL_BACKEND (cbmapi), _("Error fetching changes from the server. Removing the cache might help."));
+//		e_file_cache_thaw_changes (E_FILE_CACHE (priv->cache));
+		g_static_mutex_unlock (&updating);
+		return FALSE;
+	}
+//	e_file_cache_thaw_changes (E_FILE_CACHE (priv->cache));
+
+	e_cal_backend_notify_view_done (E_CAL_BACKEND (cbmapi), GNOME_Evolution_Calendar_Success);
+
+	time_string = g_strdup (t_str);
+	e_cal_backend_cache_put_server_utc_time (priv->cache, time_string);
+	g_free (time_string);
+
+	/* handle deleted items here by going over the entire cache and
+	 * checking for deleted items.*/
+
+	/* e_cal_backend_cache_get_keys returns a list of all the keys. 
+	 * The items in the list are pointers to internal data, 
+	 * so should not be freed, only the list should. */
+	priv->cache_keys = e_cal_backend_cache_get_keys (priv->cache);
+	if (!exchange_mapi_connection_fetch_items (priv->fid, NULL, 
+						cal_IDList, G_N_ELEMENTS (cal_IDList), 
+						NULL, NULL, 
+						handle_deleted_items_cb, cbmapi, 
+						0)) {
+		/* FIXME: better string please... */
+		e_cal_backend_notify_error (E_CAL_BACKEND (cbmapi), _("Error fetching changes from the server. Removing the cache might help."));
+		priv->cache_keys = NULL;
+		g_static_mutex_unlock (&updating);
+		return FALSE;
+	}
+
+	e_file_cache_freeze_changes (E_FILE_CACHE (priv->cache));
+	for (ls = priv->cache_keys; ls ; ls = g_slist_next (ls)) {
+		ECalComponent *comp = NULL;
+		icalcomponent *icalcomp = NULL;
+
+		comp = e_cal_backend_cache_get_component (priv->cache, (const char *) ls->data, NULL);
+
+		if (!comp)
+			continue;
+
+		icalcomp = e_cal_component_get_icalcomponent (comp);
+		if (kind == icalcomponent_isa (icalcomp)) {
+			char *comp_str = NULL;
+			ECalComponentId *id = e_cal_component_get_id (comp);
+			
+			comp_str = e_cal_component_get_as_string (comp);
+			e_cal_backend_notify_object_removed (E_CAL_BACKEND (cbmapi), 
+					id, comp_str, NULL);
+			e_cal_backend_cache_remove_component (priv->cache, (const char *) id->uid, id->rid);
+
+			e_cal_component_free_id (id);
+			g_free (comp_str);
+		}
+		g_object_unref (comp);
+	}
+	e_file_cache_thaw_changes (E_FILE_CACHE (priv->cache));
+
+//	g_slist_free (priv->cache_keys); 
+	priv->cache_keys = NULL;
+
+	g_static_mutex_unlock (&updating);
+	return TRUE;        
+}
+
+static ECalBackendSyncStatus
+e_cal_backend_mapi_get_default_object (ECalBackendSync *backend, EDataCal *cal, char **object)
+{
+	ECalComponent *comp;
+
+        comp = e_cal_component_new ();
+
+	switch (e_cal_backend_get_kind (E_CAL_BACKEND (backend))) {
+	case ICAL_VEVENT_COMPONENT:
+        	e_cal_component_set_new_vtype (comp, E_CAL_COMPONENT_EVENT);
+		break;
+	case ICAL_VTODO_COMPONENT:
+		e_cal_component_set_new_vtype (comp, E_CAL_COMPONENT_TODO);
+		break;
+	case ICAL_VJOURNAL_COMPONENT:
+		e_cal_component_set_new_vtype (comp, E_CAL_COMPONENT_JOURNAL);
+		break;
+	default:
+		g_object_unref (comp);
+		return GNOME_Evolution_Calendar_ObjectNotFound;
+	}
+
+	*object = e_cal_component_get_as_string (comp);
+	g_object_unref (comp);
+
+	return GNOME_Evolution_Calendar_Success;
+}
+
+static ECalBackendSyncStatus 
+e_cal_backend_mapi_get_object (ECalBackendSync *backend, EDataCal *cal, const char *uid, const char *rid, char **object)
+{
+	ECalBackendMAPI *cbmapi;
+	ECalBackendMAPIPrivate *priv;
+	ECalComponent *comp;
+
+	cbmapi = (ECalBackendMAPI *)(backend);
+	g_return_val_if_fail (E_IS_CAL_BACKEND_MAPI (cbmapi), GNOME_Evolution_Calendar_OtherError);
+
+	priv = cbmapi->priv;
+
+	g_mutex_lock (priv->mutex);
+
+	/* search the object in the cache */
+	comp = e_cal_backend_cache_get_component (priv->cache, uid, rid);
+
+	if (comp) {
+		g_mutex_unlock (priv->mutex);
+		if (e_cal_backend_get_kind (E_CAL_BACKEND (backend)) ==
+		    icalcomponent_isa (e_cal_component_get_icalcomponent (comp)))
+			*object = e_cal_component_get_as_string (comp);
+		else
+			*object = NULL;
+
+		g_object_unref (comp);
+
+		return *object ? GNOME_Evolution_Calendar_Success : GNOME_Evolution_Calendar_ObjectNotFound;
+	}
+
+	g_mutex_unlock (priv->mutex);
+
+	/* callers will never have a uid that is in server but not in cache */
+	return GNOME_Evolution_Calendar_ObjectNotFound;
+}
+
+static ECalBackendSyncStatus 
+e_cal_backend_mapi_get_object_list (ECalBackendSync *backend, EDataCal *cal, const char *sexp, GList **objects)
+{
+	ECalBackendMAPI *cbmapi;
+	ECalBackendMAPIPrivate *priv;
+	GList *components, *l;
+	ECalBackendSExp *cbsexp;
+	gboolean search_needed = TRUE;
+
+	cbmapi = E_CAL_BACKEND_MAPI (backend);	
+	priv = cbmapi->priv;
+
+	g_mutex_lock (priv->mutex);
+
+//	d(g_message (G_STRLOC ": Getting object list (%s)", sexp));
+
+	if (!strcmp (sexp, "#t"))
+		search_needed = FALSE;
+
+	cbsexp = e_cal_backend_sexp_new (sexp);
+
+	if (!cbsexp) {
+		g_mutex_unlock (priv->mutex);
+		return GNOME_Evolution_Calendar_InvalidQuery;
+	}
+
+	*objects = NULL;
+	components = e_cal_backend_cache_get_components (priv->cache);
+
+	for (l = components; l != NULL; l = l->next) {
+		ECalComponent *comp = E_CAL_COMPONENT (l->data);
+		if (e_cal_backend_get_kind (E_CAL_BACKEND (backend)) ==
+				icalcomponent_isa (e_cal_component_get_icalcomponent (comp))) {
+			if ((!search_needed) ||
+					(e_cal_backend_sexp_match_comp (cbsexp, comp, E_CAL_BACKEND (backend)))) {
+				*objects = g_list_append (*objects, e_cal_component_get_as_string (comp));
+			} 
+		}  
+	}	
+
+	g_object_unref (cbsexp);
+	g_list_foreach (components, (GFunc) g_object_unref, NULL);
+	g_list_free (components);
+	g_mutex_unlock (priv->mutex);
+
+	return GNOME_Evolution_Calendar_Success;
+}
+
+static ECalBackendSyncStatus 
+e_cal_backend_mapi_get_attachment_list (ECalBackendSync *backend, EDataCal *cal, const char *uid, const char *rid, GSList **list)
+{
+	/* TODO implement the function */
+	return GNOME_Evolution_Calendar_Success;
+}
+
+static guint
+get_cache_refresh_interval (void)
+{
+	guint time_interval;
+	const char *time_interval_string = NULL;
+	
+	time_interval = CACHE_REFRESH_INTERVAL;
+	time_interval_string = g_getenv ("GETQM_TIME_INTERVAL");
+	if (time_interval_string) {
+		time_interval = g_ascii_strtod (time_interval_string, NULL);
+		time_interval *= (60*1000);
+	}
+		
+	return time_interval;
+}
+
+static gpointer
+delta_thread (gpointer data)
+{
+	ECalBackendMAPI *cbmapi;
+	ECalBackendMAPIPrivate *priv;
+	GTimeVal timeout;
+
+	cbmapi = (ECalBackendMAPI *)(data);
+	g_return_val_if_fail (E_IS_CAL_BACKEND_MAPI (cbmapi), GINT_TO_POINTER (GNOME_Evolution_Calendar_OtherError));
+
+	priv = cbmapi->priv;
+
+	timeout.tv_sec = 0;
+	timeout.tv_usec = 0;
+
+	while (TRUE)	{
+		gboolean succeeded = get_deltas (cbmapi);
+
+		g_mutex_lock (priv->dlock->mutex);
+
+		if (!succeeded || priv->dlock->exit) 
+			break;
+
+		g_get_current_time (&timeout);
+		g_time_val_add (&timeout, get_cache_refresh_interval () * 1000);
+		g_cond_timed_wait (priv->dlock->cond, priv->dlock->mutex, &timeout);
+		
+		if (priv->dlock->exit) 
+			break;	
+		
+		g_mutex_unlock (priv->dlock->mutex);
+	}
+
+	g_mutex_unlock (priv->dlock->mutex);
+	priv->dthread = NULL;	
+	return NULL;
+}
+
+static gboolean
+fetch_deltas (ECalBackendMAPI *cbmapi)
+{
+	ECalBackendMAPIPrivate *priv;
+	GError *error = NULL;
+
+	g_return_val_if_fail (E_IS_CAL_BACKEND_MAPI (cbmapi), GNOME_Evolution_Calendar_OtherError);
+
+	priv = cbmapi->priv;
+
+	/* If the thread is already running just return back */	
+	if (priv->dthread) 
+		return FALSE;
+	
+	if (!priv->dlock) {
+		priv->dlock = g_new0 (SyncDelta, 1);
+		priv->dlock->mutex = g_mutex_new ();
+		priv->dlock->cond = g_cond_new ();
+	}
+	
+	priv->dlock->exit = FALSE;
+	priv->dthread = g_thread_create ((GThreadFunc) delta_thread, cbmapi, TRUE, &error);
+	if (!priv->dthread) {
+		g_warning (G_STRLOC ": %s", error->message);
+		g_error_free (error);
+	}
+
+	return TRUE;
+}
+
+
+static gboolean
+start_fetch_deltas (gpointer data)
+{
+	ECalBackendMAPI *cbmapi;
+	ECalBackendMAPIPrivate *priv;
+
+	cbmapi = (ECalBackendMAPI *)(data);
+	g_return_val_if_fail (E_IS_CAL_BACKEND_MAPI (cbmapi), GNOME_Evolution_Calendar_OtherError);
+
+	priv = cbmapi->priv;
+
+	fetch_deltas (cbmapi);
+
+	priv->timeout_id = 0;
+
+	return FALSE;
+}
+
+static gboolean
+mapi_cal_cache_create_cb (FetchItemsCallbackData *item_data, gpointer data)
+{
+	struct mapi_SPropValue_array *properties = item_data->properties; 
+	const mapi_id_t mid = item_data->mid; 
+	GSList *streams = item_data->streams; 
+	GSList *recipients = item_data->recipients; 
+	GSList *attachments = item_data->attachments; 	
+	ECalBackendMAPI *cbmapi	= E_CAL_BACKEND_MAPI (data);
+	ECalBackendMAPIPrivate *priv = cbmapi->priv;
+	icalcomponent_kind kind = e_cal_backend_get_kind (E_CAL_BACKEND (cbmapi));
+        ECalComponent *comp = NULL;
+	gchar *tmp = NULL;
+	const bool *recurring = NULL;
+
+//	exchange_mapi_debug_property_dump (properties);
+
+	switch (kind) {
+		case ICAL_VTODO_COMPONENT:
+			/* FIXME: Evolution does not support recurring tasks */
+			recurring = (const bool *)find_mapi_SPropValue_data(properties, PROP_TAG(PT_BOOLEAN, 0x8126));
+			if (recurring && *recurring) {
+				g_warning ("Encountered a recurring task.");
+				exchange_mapi_util_free_stream_list (&streams);
+				exchange_mapi_util_free_recipient_list (&recipients);
+				exchange_mapi_util_free_attachment_list (&attachments);
+				return TRUE;
+			}
+			break;
+		case ICAL_VEVENT_COMPONENT  :
+		case ICAL_VJOURNAL_COMPONENT:
+			break;
+		default:
+			return FALSE; 
+	}
+	
+	tmp = exchange_mapi_util_mapi_id_to_string (mid);
+	comp = exchange_mapi_cal_util_mapi_props_to_comp (kind, tmp, properties, 
+							streams, recipients, attachments, 
+							priv->local_attachments_store, priv->default_zone);
+	g_free (tmp);
+
+	if (E_IS_CAL_COMPONENT (comp)) {
+		gchar *comp_str;
+		e_cal_component_commit_sequence (comp);
+		comp_str = e_cal_component_get_as_string (comp);	
+		e_cal_backend_notify_object_created (E_CAL_BACKEND (cbmapi), (const char *) comp_str);
+		g_free (comp_str);
+		e_cal_backend_cache_put_component (priv->cache, comp);
+		g_object_unref (comp);
+	}
+
+	exchange_mapi_util_free_stream_list (&streams);
+	exchange_mapi_util_free_recipient_list (&recipients);
+	exchange_mapi_util_free_attachment_list (&attachments);
+
+	notify_progress (cbmapi, item_data->index, item_data->total);
+
+	return TRUE;
+}
+
+static ECalBackendSyncStatus
+populate_cache (ECalBackendMAPI *cbmapi)
+{
+	ECalBackendMAPIPrivate *priv;
+	ESource *source = NULL;
+	icalcomponent_kind kind;
+	icaltimetype itt_current; 
+	time_t current_time;
+	struct tm tm;
+	gchar *time_string = NULL;
+	gchar t_str [26]; 
+
+	priv = cbmapi->priv;
+	source = e_cal_backend_get_source (E_CAL_BACKEND (cbmapi));
+	kind = e_cal_backend_get_kind (E_CAL_BACKEND (cbmapi));
+
+	g_mutex_lock (priv->mutex);
+
+	itt_current = icaltime_current_time_with_zone (icaltimezone_get_utc_timezone ());
+	current_time = icaltime_as_timet_with_zone (itt_current, icaltimezone_get_utc_timezone ());
+	gmtime_r (&current_time, &tm);
+	strftime (t_str, 26, "%Y-%m-%dT%H:%M:%SZ", &tm);
+
+	e_cal_backend_notify_view_progress_start (E_CAL_BACKEND (cbmapi));
+
+//	e_file_cache_freeze_changes (E_FILE_CACHE (priv->cache));
+	/* FIXME: GetProps does not seem to work for tasks :-( */
+	if (kind == ICAL_VTODO_COMPONENT) {
+		if (!exchange_mapi_connection_fetch_items (priv->fid, NULL, 
+						NULL, 0, NULL, NULL, 
+						mapi_cal_cache_create_cb, cbmapi, 
+						MAPI_OPTIONS_FETCH_ALL)) {
+			e_cal_backend_notify_error (E_CAL_BACKEND (cbmapi), _("Could not create cache file"));
+			e_file_cache_thaw_changes (E_FILE_CACHE (priv->cache));
+			g_mutex_unlock (priv->mutex);
+			return GNOME_Evolution_Calendar_OtherError;
+		}
+	} else if (!exchange_mapi_connection_fetch_items (priv->fid, NULL, 
+						cal_GetPropsList, G_N_ELEMENTS (cal_GetPropsList), 
+						exchange_mapi_cal_util_build_name_id, GINT_TO_POINTER(kind), 
+						mapi_cal_cache_create_cb, cbmapi, 
+						MAPI_OPTIONS_FETCH_ALL)) {
+		e_cal_backend_notify_error (E_CAL_BACKEND (cbmapi), _("Could not create cache file"));
+		e_file_cache_thaw_changes (E_FILE_CACHE (priv->cache));
+		g_mutex_unlock (priv->mutex);
+		return GNOME_Evolution_Calendar_OtherError;
+	}
+//	e_file_cache_thaw_changes (E_FILE_CACHE (priv->cache));
+
+	e_cal_backend_notify_view_done (E_CAL_BACKEND (cbmapi), GNOME_Evolution_Calendar_Success);
+
+	time_string = g_strdup (t_str);
+	e_cal_backend_cache_put_server_utc_time (priv->cache, time_string);
+	g_free (time_string);
+
+	e_cal_backend_cache_set_marker (priv->cache);
+
+	g_mutex_unlock (priv->mutex);
+
+	return GNOME_Evolution_Calendar_Success;
+}
+
+static gpointer
+cache_init (ECalBackendMAPI *cbmapi)
+{
+	ECalBackendMAPIPrivate *priv = cbmapi->priv;
+	icalcomponent_kind kind;
+	ECalBackendSyncStatus status; 
+
+	kind = e_cal_backend_get_kind (E_CAL_BACKEND (cbmapi));
+
+	priv->mode = CAL_MODE_REMOTE;
+
+	if (!e_cal_backend_cache_get_marker (priv->cache)) {
+		/* Populate the cache for the first time.*/
+		status = populate_cache (cbmapi);
+		if (status != GNOME_Evolution_Calendar_Success) {
+			g_warning (G_STRLOC ": Could not populate the cache");
+			/*FIXME  why dont we do a notify here */
+			return GINT_TO_POINTER(GNOME_Evolution_Calendar_PermissionDenied);
+		} else {
+			/*  Set delta fetch timeout */
+			priv->timeout_id = g_timeout_add (get_cache_refresh_interval (), start_fetch_deltas, (gpointer) cbmapi);
+
+			return NULL;
+		}
+	}
+
+	g_mutex_lock (priv->mutex);
+	fetch_deltas (cbmapi);
+	g_mutex_unlock (priv->mutex);
+
+	return NULL;
+}
+
+static ECalBackendSyncStatus
+e_cal_backend_mapi_connect (ECalBackendMAPI *cbmapi)
+{
+	ECalBackendMAPIPrivate *priv;
+	ESource *source;
+	ECalSourceType source_type;
+	GThread *thread;
+	GError *error = NULL;
+
+	priv = cbmapi->priv;
+
+	if (!priv->fid)
+		return GNOME_Evolution_Calendar_OtherError;
+
+	source = e_cal_backend_get_source (E_CAL_BACKEND (cbmapi));
+
+	if (!authenticated) {
+		e_cal_backend_notify_error (E_CAL_BACKEND (cbmapi), _("Authentication failed"));
+		return GNOME_Evolution_Calendar_AuthenticationFailed; 
+	}
+
+	/* We have established a connection */
+	if (priv->cache && priv->fid) {
+		priv->mode = CAL_MODE_REMOTE;
+		if (priv->mode_changed && !priv->dthread) {
+			priv->mode_changed = FALSE;
+			fetch_deltas (cbmapi);
+		}
+
+		/* FIXME: put server UTC time in cache */
+		return GNOME_Evolution_Calendar_Success;
+	}
+
+	priv->mode_changed = FALSE;
+
+	switch (e_cal_backend_get_kind (E_CAL_BACKEND (cbmapi))) {
+	case ICAL_VEVENT_COMPONENT:
+		source_type = E_CAL_SOURCE_TYPE_EVENT;
+		break;
+	case ICAL_VTODO_COMPONENT:
+		source_type = E_CAL_SOURCE_TYPE_TODO;
+		break;
+	case ICAL_VJOURNAL_COMPONENT:
+		source_type = E_CAL_SOURCE_TYPE_JOURNAL;
+		break;
+	default:
+		source_type = E_CAL_SOURCE_TYPE_EVENT;
+		break;
+	}
+
+	priv->cache = e_cal_backend_cache_new (e_cal_backend_get_uri (E_CAL_BACKEND (cbmapi)), source_type);
+	if (!priv->cache) {
+		e_cal_backend_notify_error (E_CAL_BACKEND (cbmapi), _("Could not create cache file"));
+		return GNOME_Evolution_Calendar_OtherError;
+	}
+
+	e_cal_backend_cache_put_default_timezone (priv->cache, priv->default_zone);
+
+	/* spawn a new thread for caching the calendar items */
+	thread = g_thread_create ((GThreadFunc) cache_init, cbmapi, FALSE, &error);
+	if (!thread) {
+		g_warning (G_STRLOC ": %s", error->message);
+		g_error_free (error);
+		e_cal_backend_notify_error (E_CAL_BACKEND (cbmapi), _("Could not create thread for populating cache"));
+		return GNOME_Evolution_Calendar_OtherError;
+	} 
+
+	return GNOME_Evolution_Calendar_Success;
+}
+
+static ECalBackendSyncStatus 
+e_cal_backend_mapi_open (ECalBackendSync *backend, EDataCal *cal, gboolean only_if_exists, const char *username, const char *password)
+{
+	ECalBackendMAPI *cbmapi;
+	ECalBackendMAPIPrivate *priv;
+	ECalBackendSyncStatus status;
+	ECalSourceType source_type;
+	ESource *esource;
+	const char *source = NULL, *fid = NULL;
+	char *filename;
+	char *mangled_uri;
+	int i;
+	uint32_t olFolder = 0;
+
+	cbmapi = E_CAL_BACKEND_MAPI (backend);
+	priv = cbmapi->priv;
+
+	esource = e_cal_backend_get_source (E_CAL_BACKEND (cbmapi));
+	fid = e_source_get_property (esource, "folder-id");
+	if (!(fid && *fid))
+		return GNOME_Evolution_Calendar_OtherError;
+
+	g_mutex_lock (priv->mutex);
+
+	cbmapi->priv->read_only = FALSE;
+
+	switch (e_cal_backend_get_kind (E_CAL_BACKEND (cbmapi))) {
+	case ICAL_VEVENT_COMPONENT:
+		source_type = E_CAL_SOURCE_TYPE_EVENT;
+		source = "calendar";
+		olFolder = olFolderCalendar;
+		break;
+	case ICAL_VTODO_COMPONENT:
+		source_type = E_CAL_SOURCE_TYPE_TODO;
+		source = "tasks";
+		olFolder = olFolderTasks;
+		break;
+	case ICAL_VJOURNAL_COMPONENT:
+		source_type = E_CAL_SOURCE_TYPE_JOURNAL;
+		source = "journal";
+		olFolder = olFolderNotes;
+		break;
+	default:
+		source_type = E_CAL_SOURCE_TYPE_EVENT;
+		break;
+	}
+
+	/* Not for remote */	
+	if (priv->mode == CAL_MODE_LOCAL) {
+		const gchar *display_contents = NULL;
+
+		cbmapi->priv->read_only = TRUE;				
+		display_contents = e_source_get_property (esource, "offline_sync");
+		
+		if (!display_contents || !g_str_equal (display_contents, "1")) {
+			g_mutex_unlock (priv->mutex);	
+			return GNOME_Evolution_Calendar_RepositoryOffline;
+		}
+
+		/* Cache created here for the first time */
+		if (!priv->cache) {
+			priv->cache = e_cal_backend_cache_new (e_cal_backend_get_uri (E_CAL_BACKEND (cbmapi)), source_type);
+			if (!priv->cache) {
+				g_mutex_unlock (priv->mutex);
+				e_cal_backend_notify_error (E_CAL_BACKEND (cbmapi), _("Could not create cache file"));
+				return GNOME_Evolution_Calendar_OtherError;
+			}
+		}
+		e_cal_backend_cache_put_default_timezone (priv->cache, priv->default_zone);
+		g_mutex_unlock (priv->mutex);	
+		return GNOME_Evolution_Calendar_Success;
+	}
+
+	priv->username = g_strdup (username);
+	priv->password = g_strdup (password);
+
+	priv->profile = g_strdup (e_source_get_property (esource, "profile"));
+	priv->user_name = g_strdup (e_source_get_property (esource, "acl-user-name"));
+	priv->user_email = g_strdup (e_source_get_property (esource, "acl-user-email"));
+	priv->owner_name = g_strdup (e_source_get_property (esource, "acl-owner-name"));
+	priv->owner_email = g_strdup (e_source_get_property (esource, "acl-owner-email"));
+
+	exchange_mapi_util_mapi_id_from_string (fid, &priv->fid);
+	priv->olFolder = olFolder;
+
+	/* Set the local attachment store */
+	mangled_uri = g_strdup (e_cal_backend_get_uri (E_CAL_BACKEND (cbmapi)));
+	/* mangle the URI to not contain invalid characters */
+	for (i = 0; i < strlen (mangled_uri); i++) {
+		switch (mangled_uri[i]) {
+		case ':' :
+		case '/' :
+			mangled_uri[i] = '_';
+		}
+	}
+
+	filename = g_build_filename (g_get_home_dir (),
+				     ".evolution/cache/", source,
+				     mangled_uri,
+				     G_DIR_SEPARATOR_S, 
+				     NULL);
+
+	g_free (mangled_uri);
+	priv->local_attachments_store = 
+		g_filename_to_uri (filename, NULL, NULL);
+	g_free (filename);
+
+	g_mutex_unlock (priv->mutex);
+
+	g_static_mutex_lock (&auth_mutex);
+	status = e_cal_backend_mapi_authenticate (E_CAL_BACKEND (cbmapi));
+	g_static_mutex_unlock (&auth_mutex); 
+
+	if (status == GNOME_Evolution_Calendar_Success)
+		return e_cal_backend_mapi_connect (cbmapi);
+	else
+		return status;
+}
+
+static gboolean 
+capture_req_props (FetchItemsCallbackData *item_data, gpointer data)
+{
+	struct mapi_SPropValue_array *properties = item_data->properties; 
+	struct cbdata *cbdata = (struct cbdata *) data;
+	const uint32_t *ui32;
+
+	ui32 = (const uint32_t *)find_mapi_SPropValue_data(properties, PR_OWNER_APPT_ID);
+	if (ui32)
+		cbdata->appt_id = *ui32;
+	ui32 = (const uint32_t *)find_mapi_SPropValue_data(properties, PROP_TAG(PT_LONG, 0x8201));
+	if (ui32)
+		cbdata->appt_seq = *ui32;
+	cbdata->cleanglobalid = (const struct SBinary *)find_mapi_SPropValue_data(properties, PROP_TAG(PT_BINARY, 0x0023));
+	cbdata->globalid = (const struct SBinary *)find_mapi_SPropValue_data(properties, PROP_TAG(PT_BINARY, 0x0003));
+	cbdata->username = exchange_mapi_util_find_array_propval (properties, PR_SENT_REPRESENTING_NAME);
+	cbdata->useridtype = exchange_mapi_util_find_array_propval (properties, PR_SENT_REPRESENTING_ADDRTYPE);
+	cbdata->userid = exchange_mapi_util_find_array_propval (properties, PR_SENT_REPRESENTING_EMAIL_ADDRESS);
+	cbdata->ownername = exchange_mapi_util_find_array_propval (properties, PR_SENDER_NAME);
+	cbdata->owneridtype = exchange_mapi_util_find_array_propval (properties, PR_SENDER_ADDRTYPE);
+	cbdata->ownerid = exchange_mapi_util_find_array_propval (properties, PR_SENDER_EMAIL_ADDRESS);
+
+	return TRUE;
+}
+
+static void
+get_server_data (ECalBackendMAPI *cbmapi, icalcomponent *comp, struct cbdata *cbdata)
+{
+	ECalBackendMAPIPrivate *priv = cbmapi->priv;
+	const char *uid;
+	mapi_id_t mid;
+	struct mapi_SRestriction res;
+	struct SPropValue sprop;
+	struct SBinary sb;
+	uint32_t proptag = 0x0;
+	struct SPropTagArray *array;
+
+	uid = icalcomponent_get_uid (comp);
+	exchange_mapi_util_mapi_id_from_string (uid, &mid);
+	if (exchange_mapi_connection_fetch_item (priv->fid, mid, 
+					NULL, 0, 
+					NULL, NULL, 
+					capture_req_props, cbdata, 
+					MAPI_OPTIONS_FETCH_GENERIC_STREAMS))
+
+		return;
+
+	array = exchange_mapi_util_resolve_named_prop (priv->olFolder, priv->fid, 0x0023, PSETID_Meeting);
+	proptag = array->aulPropTag[0];
+
+	res.rt = RES_PROPERTY;
+	res.res.resProperty.relop = RELOP_EQ;
+	res.res.resProperty.ulPropTag = proptag;
+
+	exchange_mapi_cal_util_generate_globalobjectid (TRUE, uid, &sb);
+
+	set_SPropValue_proptag (&sprop, proptag, (const void *) &sb);
+	cast_mapi_SPropValue (&(res.res.resProperty.lpProp), &sprop);
+
+	exchange_mapi_connection_fetch_items (priv->fid, &res, 
+					NULL, 0, 
+					NULL, NULL, 
+					capture_req_props, cbdata, 
+					MAPI_OPTIONS_FETCH_GENERIC_STREAMS);
+}
+
+static ECalBackendSyncStatus 
+e_cal_backend_mapi_create_object (ECalBackendSync *backend, EDataCal *cal, char **calobj, char **uid)
+{
+	ECalBackendMAPI *cbmapi;
+	ECalBackendMAPIPrivate *priv;
+	icalcomponent_kind kind;
+	icalcomponent *icalcomp;
+	ECalComponent *comp;
+	const char *compuid;
+	mapi_id_t mid = 0;
+	gchar *tmp = NULL;
+	GSList *recipients = NULL;
+	GSList *attachments = NULL;
+	GSList *streams = NULL;
+	struct cbdata cbdata;
+	struct SBinary globalid;
+
+	cbmapi = E_CAL_BACKEND_MAPI (backend);
+	priv = cbmapi->priv;
+	kind = e_cal_backend_get_kind (E_CAL_BACKEND (backend));
+
+	g_return_val_if_fail (E_IS_CAL_BACKEND_MAPI (cbmapi), GNOME_Evolution_Calendar_InvalidObject);
+	g_return_val_if_fail (calobj != NULL && *calobj != NULL, GNOME_Evolution_Calendar_InvalidObject);
+
+	if (priv->mode == CAL_MODE_LOCAL)
+		return GNOME_Evolution_Calendar_RepositoryOffline;
+
+	/* check the component for validity */
+	icalcomp = icalparser_parse_string (*calobj);
+	if (!icalcomp)
+		return GNOME_Evolution_Calendar_InvalidObject;
+
+	if (kind != icalcomponent_isa (icalcomp)) {
+		icalcomponent_free (icalcomp);
+		return GNOME_Evolution_Calendar_InvalidObject;
+	}
+
+	comp = e_cal_component_new ();
+	e_cal_component_set_icalcomponent (comp, icalcomp);
+
+	/* FIXME: [WIP] Add support for recurrences */
+	if (e_cal_component_has_recurrences (comp)) {
+		GByteArray *ba = exchange_mapi_cal_util_rrule_to_bin (comp, NULL); 
+		if (ba) {
+			struct SPropTagArray *tag_array; 
+			ExchangeMAPIStream *stream = g_new0 (ExchangeMAPIStream, 1); 
+			stream->value = ba; 
+			tag_array = exchange_mapi_util_resolve_named_prop (priv->olFolder, priv->fid, 0x8216, PSETID_Appointment); 
+			if (tag_array) {
+				stream->proptag = tag_array->aulPropTag[0];
+				streams = g_slist_append (streams, stream); 
+			}
+		}
+	}
+
+	/* FIXME: [WIP] Add support for meetings/assigned tasks */
+	if (e_cal_component_has_attendees (comp)) 
+		exchange_mapi_cal_util_fetch_recipients (comp, &recipients);
+
+	if (e_cal_component_has_attachments (comp))
+		exchange_mapi_cal_util_fetch_attachments (comp, &attachments, priv->local_attachments_store);
+
+	cbdata.username = e_cal_backend_mapi_get_user_name (cbmapi);
+	cbdata.useridtype = "SMTP";
+	cbdata.userid = e_cal_backend_mapi_get_user_email (cbmapi);
+	cbdata.ownername = e_cal_backend_mapi_get_owner_name (cbmapi);
+	cbdata.owneridtype = "SMTP";
+	cbdata.ownerid = e_cal_backend_mapi_get_owner_email (cbmapi);
+
+	/* Check if object exists */
+	switch (priv->mode) {
+		case CAL_MODE_ANY:
+		case CAL_MODE_REMOTE:
+			/* Create an appointment */
+			cbdata.comp = comp;
+			cbdata.is_modify = FALSE;
+			cbdata.msgflags = MSGFLAG_READ;
+			cbdata.meeting_type = (recipients != NULL) ? MEETING_OBJECT : NOT_A_MEETING;
+			cbdata.resp = (recipients != NULL) ? olResponseOrganized : olResponseNone;
+			cbdata.appt_id = exchange_mapi_cal_util_get_new_appt_id (priv->fid);
+			cbdata.appt_seq = 0;
+			e_cal_component_get_uid (comp, &compuid);
+			exchange_mapi_cal_util_generate_globalobjectid (TRUE, compuid, &globalid);
+			cbdata.globalid = &globalid;
+			cbdata.cleanglobalid = &globalid;
+
+			mid = exchange_mapi_create_item (priv->olFolder, priv->fid, 
+							exchange_mapi_cal_util_build_name_id, GINT_TO_POINTER(kind), 
+							exchange_mapi_cal_util_build_props, &cbdata, 
+							recipients, attachments, streams, MAPI_OPTIONS_DONT_SUBMIT);
+			g_free (cbdata.props);
+//			g_free (globalid.lpb);
+			if (!mid) {
+				g_object_unref (comp);
+				exchange_mapi_util_free_recipient_list (&recipients);
+				exchange_mapi_util_free_stream_list (&streams);
+				exchange_mapi_util_free_attachment_list (&attachments);
+				return GNOME_Evolution_Calendar_OtherError;
+			}
+
+			tmp = exchange_mapi_util_mapi_id_to_string (mid);
+			e_cal_component_set_uid (comp, tmp);
+			g_free (tmp);
+
+			e_cal_component_commit_sequence (comp);
+			e_cal_backend_cache_put_component (priv->cache, comp);
+			*calobj = e_cal_component_get_as_string (comp);
+			e_cal_backend_notify_object_created (E_CAL_BACKEND (cbmapi), *calobj);
+			break;
+		default:
+			exchange_mapi_util_free_recipient_list (&recipients);
+			exchange_mapi_util_free_stream_list (&streams);
+			exchange_mapi_util_free_attachment_list (&attachments);
+			return GNOME_Evolution_Calendar_CalListener_MODE_NOT_SUPPORTED;
+	}
+
+	/* blatant HACK /me blames some stupid design in e-d-s */
+	if (e_cal_component_has_attachments (comp) && !fetch_deltas(cbmapi))
+		g_cond_signal (priv->dlock->cond);
+
+	g_object_unref (comp);
+	exchange_mapi_util_free_recipient_list (&recipients);
+	exchange_mapi_util_free_stream_list (&streams);
+	exchange_mapi_util_free_attachment_list (&attachments);
+
+	return GNOME_Evolution_Calendar_Success;
+}
+
+static gboolean
+modifier_is_organizer (ECalBackendMAPI *cbmapi, ECalComponent *comp)
+{
+	ECalComponentOrganizer org; 
+	const char *ownerid, *orgid; 
+
+	if (!e_cal_component_has_organizer(comp))
+		return TRUE;
+
+	e_cal_component_get_organizer (comp, &org);
+	if (!g_ascii_strncasecmp (org.value, "mailto:";, 7))
+		orgid = (org.value) + 7;
+	else 
+		orgid = org.value;
+	ownerid = e_cal_backend_mapi_get_owner_email (cbmapi);
+
+	return (!g_ascii_strcasecmp(orgid, ownerid) ? TRUE : FALSE);
+}
+
+static OlResponseStatus 
+get_trackstatus_from_partstat (icalparameter_partstat partstat)
+{
+	switch (partstat) {
+		case ICAL_PARTSTAT_ACCEPTED 	: return olResponseAccepted;
+		case ICAL_PARTSTAT_TENTATIVE 	: return olResponseTentative;
+		case ICAL_PARTSTAT_DECLINED 	: return olResponseDeclined;
+		default 			: return olResponseTentative;
+	}
+}
+
+static OlResponseStatus
+find_my_response (ECalBackendMAPI *cbmapi, ECalComponent *comp)
+{
+	icalcomponent *icalcomp = e_cal_component_get_icalcomponent (comp);
+	icalproperty *attendee; 
+	gchar *att = NULL;
+	OlResponseStatus val = olResponseTentative; 
+
+	att = g_strdup_printf ("MAILTO:%s", e_cal_backend_mapi_get_owner_email (cbmapi));
+	attendee = icalcomponent_get_first_property (icalcomp, ICAL_ATTENDEE_PROPERTY);
+	while (attendee) {
+		const char *value = icalproperty_get_attendee (attendee);
+		if (!g_ascii_strcasecmp (value, att)) {
+			icalparameter *param = icalproperty_get_first_parameter (attendee, ICAL_PARTSTAT_PARAMETER);
+			val = get_trackstatus_from_partstat (icalparameter_get_partstat(param));
+			break;
+		}
+		attendee = icalcomponent_get_next_property (icalcomp, ICAL_ATTENDEE_PROPERTY);
+	}
+	g_free (att);
+
+	return val;
+}
+
+static ECalBackendSyncStatus 
+e_cal_backend_mapi_modify_object (ECalBackendSync *backend, EDataCal *cal, const char *calobj, 
+				  CalObjModType mod, char **old_object, char **new_object)
+{
+	ECalBackendMAPI *cbmapi;
+        ECalBackendMAPIPrivate *priv;
+	icalcomponent_kind kind;
+	icalcomponent *icalcomp;
+	ECalComponent *comp, *cache_comp = NULL;
+	gboolean status;
+	mapi_id_t mid;
+	const char *uid = NULL, *rid = NULL;
+	GSList *recipients = NULL;
+	GSList *streams = NULL;
+	GSList *attachments = NULL;
+	struct cbdata cbdata;
+	gboolean no_increment = FALSE;
+	icalproperty *prop; 
+
+	*old_object = *new_object = NULL;
+	cbmapi = E_CAL_BACKEND_MAPI (backend);
+	priv = cbmapi->priv;
+	kind = e_cal_backend_get_kind (E_CAL_BACKEND (backend));
+
+	g_return_val_if_fail (E_IS_CAL_BACKEND_MAPI (cbmapi), GNOME_Evolution_Calendar_InvalidObject);
+	g_return_val_if_fail (calobj != NULL, GNOME_Evolution_Calendar_InvalidObject);
+
+	if (priv->mode == CAL_MODE_LOCAL)
+		return GNOME_Evolution_Calendar_RepositoryOffline;
+
+	if (mod != CALOBJ_MOD_ALL) {
+		e_cal_backend_notify_error (E_CAL_BACKEND (cbmapi), _("Support for modifying single instances of a recurring appointment is not yet implemented. No change was made to the appointment on the server.")); 
+		return GNOME_Evolution_Calendar_Success;
+	}
+
+	/* check the component for validity */
+	icalcomp = icalparser_parse_string (calobj);
+	if (!icalcomp)
+		return GNOME_Evolution_Calendar_InvalidObject;
+
+	prop = icalcomponent_get_first_property (icalcomp, ICAL_X_PROPERTY);
+	while (prop) {
+		const char *name = icalproperty_get_x_name (prop);
+		if (!g_ascii_strcasecmp (name, "X-EVOLUTION-IS-REPLY")) {
+			no_increment = TRUE; 
+			icalcomponent_remove_property (icalcomp, prop);
+		}
+		prop = icalcomponent_get_next_property (icalcomp, ICAL_X_PROPERTY);
+	}
+
+	comp = e_cal_component_new ();
+	e_cal_component_set_icalcomponent (comp, icalcomp);
+
+	/* FIXME: [WIP] Add support for recurrences */
+	if (e_cal_component_has_recurrences (comp)) {
+		GByteArray *ba = exchange_mapi_cal_util_rrule_to_bin (comp, NULL); 
+		if (ba) {
+			struct SPropTagArray *tag_array; 
+			ExchangeMAPIStream *stream = g_new0 (ExchangeMAPIStream, 1); 
+			stream->value = ba; 
+			tag_array = exchange_mapi_util_resolve_named_prop (priv->olFolder, priv->fid, 0x8216, PSETID_Appointment); 
+			if (tag_array) {
+				stream->proptag = tag_array->aulPropTag[0];
+				streams = g_slist_append (streams, stream); 
+			}
+		}
+	}
+
+	if (e_cal_component_has_attendees (comp)) 
+		exchange_mapi_cal_util_fetch_recipients (comp, &recipients);
+
+	if (e_cal_component_has_attachments (comp))
+		exchange_mapi_cal_util_fetch_attachments (comp, &attachments, priv->local_attachments_store);
+
+	e_cal_component_get_uid (comp, &uid);
+//	rid = e_cal_component_get_recurid_as_string (comp);
+
+	switch (priv->mode) {
+	case CAL_MODE_ANY :
+	case CAL_MODE_REMOTE :	/* when online, send the item to the server */
+		/* check if the object exists */
+		cache_comp = e_cal_backend_cache_get_component (priv->cache, uid, rid);
+		if (!cache_comp) {
+			get_deltas (cbmapi);
+			cache_comp = e_cal_backend_cache_get_component (priv->cache, uid, rid);
+		}
+
+		if (!cache_comp) {
+			g_message ("CRITICAL : Could not find the object in cache");
+			g_object_unref (comp);
+			exchange_mapi_util_free_recipient_list (&recipients);
+			exchange_mapi_util_free_stream_list (&streams);
+			exchange_mapi_util_free_attachment_list (&attachments);
+			return GNOME_Evolution_Calendar_ObjectNotFound;
+		}
+		exchange_mapi_util_mapi_id_from_string (uid, &mid);
+
+		cbdata.comp = comp;
+		cbdata.msgflags = MSGFLAG_READ;
+		cbdata.is_modify = TRUE;
+
+		get_server_data (cbmapi, icalcomp, &cbdata);
+		if (modifier_is_organizer(cbmapi, comp)) {
+			cbdata.meeting_type = (recipients != NULL) ? MEETING_OBJECT : NOT_A_MEETING; 
+			cbdata.resp = (recipients != NULL) ? olResponseOrganized : olResponseNone;
+			if (!no_increment)
+				cbdata.appt_seq += 1;
+			cbdata.username = e_cal_backend_mapi_get_user_name (cbmapi);
+			cbdata.useridtype = "SMTP";
+			cbdata.userid = e_cal_backend_mapi_get_user_email (cbmapi);
+			cbdata.ownername = e_cal_backend_mapi_get_owner_name (cbmapi);
+			cbdata.owneridtype = "SMTP";
+			cbdata.ownerid = e_cal_backend_mapi_get_owner_email (cbmapi);
+		} else {
+			cbdata.resp = (recipients != NULL) ? find_my_response(cbmapi, comp) : olResponseNone;
+			cbdata.meeting_type = (recipients != NULL) ? MEETING_OBJECT_RCVD : NOT_A_MEETING; 
+		}
+
+		status = exchange_mapi_modify_item (priv->olFolder, priv->fid, mid, 
+						exchange_mapi_cal_util_build_name_id, GINT_TO_POINTER(kind), 
+						exchange_mapi_cal_util_build_props, &cbdata, 
+						recipients, attachments, streams, MAPI_OPTIONS_DONT_SUBMIT);
+		g_free (cbdata.props);
+		if (!status) {
+			g_object_unref (comp);
+			g_object_unref (cache_comp);
+			exchange_mapi_util_free_recipient_list (&recipients);
+			exchange_mapi_util_free_stream_list (&streams);
+			exchange_mapi_util_free_attachment_list (&attachments);
+			return GNOME_Evolution_Calendar_OtherError;
+		}
+		break;
+	default : 
+		g_object_unref (comp);
+		g_object_unref (cache_comp);
+		exchange_mapi_util_free_recipient_list (&recipients);
+		exchange_mapi_util_free_stream_list (&streams);
+		exchange_mapi_util_free_attachment_list (&attachments);
+		return GNOME_Evolution_Calendar_CalListener_MODE_NOT_SUPPORTED;
+	}
+
+	*old_object = e_cal_component_get_as_string (cache_comp);
+	*new_object = e_cal_component_get_as_string (comp);
+
+	g_object_unref (comp);
+	g_object_unref (cache_comp);
+	exchange_mapi_util_free_recipient_list (&recipients);
+	exchange_mapi_util_free_stream_list (&streams);
+	exchange_mapi_util_free_attachment_list (&attachments);
+
+	return GNOME_Evolution_Calendar_Success;
+}
+
+static ECalBackendSyncStatus 
+e_cal_backend_mapi_remove_object (ECalBackendSync *backend, EDataCal *cal,
+				  const char *uid, const char *rid, CalObjModType mod, 
+				  char **old_object, char **object)
+{
+	ECalBackendMAPI *cbmapi;
+        ECalBackendMAPIPrivate *priv;
+	icalcomponent *icalcomp;
+	ECalBackendSyncStatus status;
+	char *calobj = NULL;
+	mapi_id_t mid;
+
+	*old_object = *object = NULL;
+	cbmapi = E_CAL_BACKEND_MAPI (backend);
+	priv = cbmapi->priv;
+
+	g_return_val_if_fail (E_IS_CAL_BACKEND_MAPI (cbmapi), GNOME_Evolution_Calendar_InvalidObject);
+
+	if (priv->mode == CAL_MODE_LOCAL)
+		return GNOME_Evolution_Calendar_RepositoryOffline;
+
+	switch (priv->mode) {
+	case CAL_MODE_ANY :
+	case CAL_MODE_REMOTE : 	/* when online, modify/delete the item from the server */
+		/* check if the object exists */
+		/* FIXME: we may have detached instances which need to be removed */
+		status = e_cal_backend_mapi_get_object (backend, cal, uid, NULL, &calobj);
+		if (status != GNOME_Evolution_Calendar_Success)
+			return status;
+
+		/* check the component for validity */
+		icalcomp = icalparser_parse_string (calobj);
+		if (!icalcomp) {
+			g_free (calobj);
+			return GNOME_Evolution_Calendar_InvalidObject;
+		}
+
+		exchange_mapi_util_mapi_id_from_string (uid, &mid);
+
+		if (mod == CALOBJ_MOD_THIS && rid && *rid) {
+			char *obj = NULL, *new_object = NULL, *new_calobj = NULL;
+			struct icaltimetype time_rid;
+
+			/*remove a single instance of a recurring event and modify */
+			time_rid = icaltime_from_string (rid);
+			e_cal_util_remove_instances (icalcomp, time_rid, mod);
+			new_calobj  = (char *) icalcomponent_as_ical_string (icalcomp);
+			status = e_cal_backend_mapi_modify_object (backend, cal, new_calobj, CALOBJ_MOD_ALL, &obj, &new_object);
+			if (status == GNOME_Evolution_Calendar_Success) {
+				*old_object = obj;
+				*object = new_object;
+			}
+			g_free (new_calobj);
+		} else {
+			GSList *list=NULL, *l, *comp_list = e_cal_backend_cache_get_components_by_uid (priv->cache, uid);
+
+//			if (e_cal_component_has_attendees (E_CAL_COMPONENT (comp_list->data))) { 
+//			} else { 
+				struct id_list *data = g_new (struct id_list, 1);
+				data->id = mid;
+				list = g_slist_prepend (list, (gpointer) data);
+//			}
+
+			if (exchange_mapi_remove_items (priv->olFolder, priv->fid, list)) {
+				for (l = comp_list; l; l = l->next) {
+					ECalComponent *comp = E_CAL_COMPONENT (l->data);
+					ECalComponentId *id = e_cal_component_get_id (comp);
+
+					e_cal_backend_cache_remove_component (priv->cache, id->uid, id->rid);
+					if (!id->rid || !g_str_equal (id->rid, rid))
+						e_cal_backend_notify_object_removed (E_CAL_BACKEND (cbmapi), id, e_cal_component_get_as_string (comp), NULL);
+					e_cal_component_free_id (id);
+
+					g_object_unref (comp);
+				}
+				*old_object = g_strdup (calobj);
+				*object = NULL;
+				status = GNOME_Evolution_Calendar_Success;
+			} else
+				status = GNOME_Evolution_Calendar_OtherError;
+
+			g_slist_free (list);
+			g_slist_free (comp_list);
+		} 
+		g_free (calobj);
+		break; 
+	default :
+		status = GNOME_Evolution_Calendar_CalListener_MODE_NOT_SUPPORTED;
+		break; 
+	}
+
+	return status;
+}
+
+static ECalBackendSyncStatus 
+e_cal_backend_mapi_discard_alarm (ECalBackendSync *backend, EDataCal *cal, const char *uid, const char *auid)
+{
+
+	return GNOME_Evolution_Calendar_Success;
+	
+}
+
+static ECalBackendSyncStatus 
+e_cal_backend_mapi_send_objects (ECalBackendSync *backend, EDataCal *cal, const char *calobj, 
+				 GList **users, char **modified_calobj)
+{
+	ECalBackendSyncStatus status = GNOME_Evolution_Calendar_OtherError;
+	ECalBackendMAPI *cbmapi;
+	ECalBackendMAPIPrivate *priv;
+	icalcomponent_kind kind;
+	icalcomponent *icalcomp;
+
+	cbmapi = E_CAL_BACKEND_MAPI (backend);
+	priv = cbmapi->priv;
+	kind = e_cal_backend_get_kind (E_CAL_BACKEND (backend));
+
+	g_return_val_if_fail (E_IS_CAL_BACKEND_MAPI (cbmapi), GNOME_Evolution_Calendar_InvalidObject);
+	g_return_val_if_fail (calobj != NULL, GNOME_Evolution_Calendar_InvalidObject);
+
+	if (priv->mode == CAL_MODE_LOCAL)
+		return GNOME_Evolution_Calendar_RepositoryOffline;
+
+	/* check the component for validity */
+	icalcomp = icalparser_parse_string (calobj);
+	if (!icalcomp)
+		return GNOME_Evolution_Calendar_InvalidObject;
+
+	*modified_calobj = NULL;
+	*users = NULL;
+
+	if (icalcomponent_isa (icalcomp) == ICAL_VCALENDAR_COMPONENT) {
+		icalproperty_method method = icalcomponent_get_method (icalcomp);
+		icalcomponent *subcomp = icalcomponent_get_first_component (icalcomp, kind);
+		while (subcomp) {
+			ECalComponent *comp = e_cal_component_new ();
+			struct cbdata cbdata;
+			mapi_id_t mid = 0;
+			GSList *recipients = NULL;
+			GSList *attachments = NULL;
+
+			e_cal_component_set_icalcomponent (comp, icalcomponent_new_clone (subcomp));
+
+			/* FIXME: Add support for recurrences */
+			if (e_cal_component_has_recurrences (comp)) {
+				g_object_unref (comp);
+				return GNOME_Evolution_Calendar_OtherError;
+			}
+
+			if (e_cal_component_has_attachments (comp))
+				exchange_mapi_cal_util_fetch_attachments (comp, &attachments, priv->local_attachments_store);
+
+			cbdata.comp = comp;
+			cbdata.is_modify = TRUE;
+			cbdata.msgflags = MSGFLAG_READ | MSGFLAG_SUBMIT | MSGFLAG_UNSENT;
+
+			switch (method) {
+			case ICAL_METHOD_REQUEST : 
+				cbdata.meeting_type = MEETING_REQUEST;
+				cbdata.resp = olResponseNotResponded;
+				if (e_cal_component_has_attendees (comp))
+					exchange_mapi_cal_util_fetch_recipients (comp, &recipients);
+				break;
+			case ICAL_METHOD_CANCEL : 
+				cbdata.meeting_type = MEETING_CANCEL;
+				cbdata.resp = olResponseNotResponded;
+				if (e_cal_component_has_attendees (comp))
+					exchange_mapi_cal_util_fetch_recipients (comp, &recipients);
+				break;
+			case ICAL_METHOD_RESPONSE : 
+				cbdata.meeting_type = MEETING_RESPONSE;
+				cbdata.resp = find_my_response (cbmapi, comp);
+				if (e_cal_component_has_organizer (comp))
+					exchange_mapi_cal_util_fetch_organizer (comp, &recipients);
+				break;
+			default :
+				cbdata.meeting_type = NOT_A_MEETING;
+				cbdata.resp = olResponseNone;
+				if (e_cal_component_has_attendees (comp))
+					exchange_mapi_cal_util_fetch_recipients (comp, &recipients);
+				break;
+			}
+
+			get_server_data (cbmapi, subcomp, &cbdata);
+			cbdata.username = e_cal_backend_mapi_get_user_name (cbmapi);
+			cbdata.useridtype = "SMTP";
+			cbdata.userid = e_cal_backend_mapi_get_user_email (cbmapi);
+			cbdata.ownername = e_cal_backend_mapi_get_owner_name (cbmapi);
+			cbdata.owneridtype = "SMTP";
+			cbdata.ownerid = e_cal_backend_mapi_get_owner_email (cbmapi);
+
+			mid = exchange_mapi_create_item (olFolderOutbox, 0, 
+							exchange_mapi_cal_util_build_name_id, GINT_TO_POINTER(kind), 
+							exchange_mapi_cal_util_build_props, &cbdata, 
+							recipients, attachments, NULL, 0);
+			g_free (cbdata.props);
+			if (!mid) {
+				g_object_unref (comp);
+				exchange_mapi_util_free_recipient_list (&recipients);
+				exchange_mapi_util_free_attachment_list (&attachments);
+				return GNOME_Evolution_Calendar_OtherError;
+			} else 
+				status = GNOME_Evolution_Calendar_Success;
+
+			g_object_unref (comp);
+			exchange_mapi_util_free_recipient_list (&recipients);
+			exchange_mapi_util_free_attachment_list (&attachments);
+
+			subcomp = icalcomponent_get_next_component (icalcomp,
+								    e_cal_backend_get_kind (E_CAL_BACKEND (backend)));
+		}
+	}
+
+	if (status == GNOME_Evolution_Calendar_Success)
+		*modified_calobj = g_strdup (calobj);
+
+	icalcomponent_free (icalcomp);
+
+	return GNOME_Evolution_Calendar_Success;
+}
+
+static ECalBackendSyncStatus 
+e_cal_backend_mapi_receive_objects (ECalBackendSync *backend, EDataCal *cal, const char *calobj)
+{
+	ECalBackendSyncStatus status = GNOME_Evolution_Calendar_OtherError;
+	ECalBackendMAPI *cbmapi;
+	ECalBackendMAPIPrivate *priv;
+	icalcomponent_kind kind;
+	icalcomponent *icalcomp;
+
+	cbmapi = E_CAL_BACKEND_MAPI (backend);
+	priv = cbmapi->priv;
+	kind = e_cal_backend_get_kind (E_CAL_BACKEND (backend));
+
+	g_return_val_if_fail (E_IS_CAL_BACKEND_MAPI (cbmapi), GNOME_Evolution_Calendar_InvalidObject);
+	g_return_val_if_fail (calobj != NULL, GNOME_Evolution_Calendar_InvalidObject);
+
+	if (priv->mode == CAL_MODE_LOCAL)
+		return GNOME_Evolution_Calendar_RepositoryOffline;
+
+	/* check the component for validity */
+	icalcomp = icalparser_parse_string (calobj);
+	if (!icalcomp)
+		return GNOME_Evolution_Calendar_InvalidObject;
+
+	if (icalcomponent_isa (icalcomp) == ICAL_VCALENDAR_COMPONENT) {
+		gboolean stop = FALSE;
+		icalproperty_method method = icalcomponent_get_method (icalcomp);
+		icalcomponent *subcomp = icalcomponent_get_first_component (icalcomp, kind);
+		while (subcomp && !stop) {
+			ECalComponent *comp = e_cal_component_new ();
+			gchar *rid = NULL; 
+			const char *uid;
+			gchar *old_object = NULL, *new_object = NULL, *comp_str; 
+
+			e_cal_component_set_icalcomponent (comp, icalcomponent_new_clone (subcomp));
+
+			/* FIXME: Add support for recurrences */
+			if (e_cal_component_has_recurrences (comp)) {
+				g_object_unref (comp);
+				return GNOME_Evolution_Calendar_OtherError;
+			}
+
+			e_cal_component_get_uid (comp, &uid);
+			rid = e_cal_component_get_recurid_as_string (comp);
+
+			switch (method) {
+			case ICAL_METHOD_REQUEST :
+				comp_str = e_cal_component_get_as_string (comp);
+				status = e_cal_backend_mapi_modify_object (backend, cal, comp_str, CALOBJ_MOD_THIS, &old_object, &new_object);
+				g_free (comp_str);
+				g_free (old_object);
+				g_free (new_object);
+				if (status == GNOME_Evolution_Calendar_Success) {
+					GList *users = NULL, *l;
+					icalcomponent *resp_comp = e_cal_util_new_top_level ();
+					icalcomponent_set_method (resp_comp, ICAL_METHOD_RESPONSE);
+					icalcomponent_add_component (resp_comp, 
+						icalcomponent_new_clone(e_cal_component_get_icalcomponent(comp)));
+					comp_str = icalcomponent_as_ical_string (resp_comp);
+					status = e_cal_backend_mapi_send_objects (backend, cal, comp_str, &users, &new_object);
+					g_free (comp_str);
+					g_free (new_object);
+					for (l = users; l; l = l->next)
+						g_free (l->data);
+					g_list_free (users);
+					icalcomponent_free (resp_comp);
+				}
+
+				if (status != GNOME_Evolution_Calendar_Success)
+					stop = TRUE;
+				break;
+			case ICAL_METHOD_CANCEL :
+				status = e_cal_backend_mapi_remove_object (backend, cal, uid, rid, CALOBJ_MOD_THIS, &old_object, &new_object);
+				if (status != GNOME_Evolution_Calendar_Success)
+					stop = TRUE;
+				g_free (old_object);
+				g_free (new_object);
+				break;
+			case ICAL_METHOD_REPLY :
+				/* responses are automatically updated even as they are rendered (just like in Outlook) */
+				status = GNOME_Evolution_Calendar_Success;
+				break; 
+			default :
+				break;
+			}
+
+			g_free (rid);
+			g_object_unref (comp);
+
+			subcomp = icalcomponent_get_next_component (icalcomp,
+								    e_cal_backend_get_kind (E_CAL_BACKEND (backend)));
+		}
+	}
+
+	return status;
+}
+
+
+static ECalBackendSyncStatus 
+e_cal_backend_mapi_get_timezone (ECalBackendSync *backend, EDataCal *cal, const char *tzid, char **object)
+{
+	ECalBackendMAPI *cbmapi;
+	ECalBackendMAPIPrivate *priv;
+
+	icaltimezone *zone;
+	icalcomponent *icalcomp;
+
+	cbmapi = E_CAL_BACKEND_MAPI (backend);
+	priv = cbmapi->priv;
+
+	g_return_val_if_fail (tzid != NULL, GNOME_Evolution_Calendar_ObjectNotFound);
+
+	if (!strcmp (tzid, "UTC")) {
+		zone = icaltimezone_get_utc_timezone ();
+	} else {
+		zone = icaltimezone_get_builtin_timezone_from_tzid (tzid);
+		if (!zone)
+			return GNOME_Evolution_Calendar_ObjectNotFound;
+	}
+
+	icalcomp = icaltimezone_get_component (zone);
+	if (!icalcomp)
+		return GNOME_Evolution_Calendar_InvalidObject;
+
+	*object = icalcomponent_as_ical_string (icalcomp);
+
+	return GNOME_Evolution_Calendar_Success;
+}
+
+static ECalBackendSyncStatus 
+e_cal_backend_mapi_add_timezone (ECalBackendSync *backend, EDataCal *cal, const char *tzobj)
+{
+	ECalBackendMAPI *cbmapi;
+	ECalBackendMAPIPrivate *priv;
+	icalcomponent *tz_comp;
+
+	cbmapi = (ECalBackendMAPI *) backend;
+
+	g_return_val_if_fail (E_IS_CAL_BACKEND_MAPI (cbmapi), GNOME_Evolution_Calendar_OtherError);
+	g_return_val_if_fail (tzobj != NULL, GNOME_Evolution_Calendar_OtherError);
+
+	priv = cbmapi->priv;
+
+	tz_comp = icalparser_parse_string (tzobj);
+	if (!tz_comp)
+		return GNOME_Evolution_Calendar_InvalidObject;
+
+	if (icalcomponent_isa (tz_comp) == ICAL_VTIMEZONE_COMPONENT) {
+		icaltimezone *zone;
+		zone = icaltimezone_new ();
+		icaltimezone_set_component (zone, tz_comp);
+
+		if (e_cal_backend_cache_put_timezone (priv->cache, zone) == FALSE) {
+			icaltimezone_free (zone, 1);
+			return GNOME_Evolution_Calendar_OtherError;
+		}
+		icaltimezone_free (zone, 1);
+	}
+
+	return GNOME_Evolution_Calendar_Success;
+}
+
+static ECalBackendSyncStatus 
+e_cal_backend_mapi_set_default_zone (ECalBackendSync *backend, EDataCal *cal, const char *tzobj)
+{
+	icalcomponent *tz_comp;
+	ECalBackendMAPI *cbmapi;
+	ECalBackendMAPIPrivate *priv;
+	icaltimezone *zone;
+
+	cbmapi = (ECalBackendMAPI *) backend;
+
+	g_return_val_if_fail (E_IS_CAL_BACKEND_MAPI (cbmapi), GNOME_Evolution_Calendar_OtherError);
+	g_return_val_if_fail (tzobj != NULL, GNOME_Evolution_Calendar_OtherError);
+
+	priv = cbmapi->priv;
+
+	tz_comp = icalparser_parse_string (tzobj);
+	if (!tz_comp)
+		return GNOME_Evolution_Calendar_InvalidObject;
+
+	zone = icaltimezone_new ();
+	icaltimezone_set_component (zone, tz_comp);
+
+	if (priv->default_zone)
+		icaltimezone_free (priv->default_zone, 1);
+
+	/* Set the default timezone to it. */
+	priv->default_zone = zone;
+
+	return GNOME_Evolution_Calendar_Success;
+}
+
+static ECalBackendSyncStatus 
+e_cal_backend_mapi_get_free_busy (ECalBackendSync *backend, EDataCal *cal, 
+				  GList *users, time_t start, time_t end, GList **freebusy)
+{
+
+	return GNOME_Evolution_Calendar_Success;	
+
+}
+
+typedef struct {
+	ECalBackendMAPI *backend;
+	icalcomponent_kind kind;
+	GList *deletes;
+	EXmlHash *ehash;
+} ECalBackendMAPIComputeChangesData;
+
+static void
+e_cal_backend_mapi_compute_changes_foreach_key (const char *key, const char *value, gpointer data)
+{
+	ECalBackendMAPIComputeChangesData *be_data = data;
+
+	if (!e_cal_backend_cache_get_component (be_data->backend->priv->cache, key, NULL)) {
+		ECalComponent *comp;
+
+		comp = e_cal_component_new ();
+		if (be_data->kind == ICAL_VTODO_COMPONENT)
+			e_cal_component_set_new_vtype (comp, E_CAL_COMPONENT_TODO);
+		else
+			e_cal_component_set_new_vtype (comp, E_CAL_COMPONENT_EVENT);
+
+		e_cal_component_set_uid (comp, key);
+		be_data->deletes = g_list_prepend (be_data->deletes, e_cal_component_get_as_string (comp));
+
+		e_xmlhash_remove (be_data->ehash, key);
+		g_object_unref (comp);
+ 	}
+}
+
+static ECalBackendSyncStatus
+e_cal_backend_mapi_compute_changes (ECalBackendMAPI *cbmapi, const char *change_id,
+				    GList **adds, GList **modifies, GList **deletes)
+{
+	ECalBackendSyncStatus status;
+	ECalBackendCache *cache;
+	gchar *filename;
+	EXmlHash *ehash;
+	ECalBackendMAPIComputeChangesData be_data;
+	GList *i, *list = NULL;
+	gchar *unescaped_uri;
+
+	cache = cbmapi->priv->cache;
+
+	/* FIXME Will this always work? */
+	unescaped_uri = g_uri_unescape_string (cbmapi->priv->uri, "");
+	filename = g_strdup_printf ("%s-%s.db", unescaped_uri, change_id);
+	ehash = e_xmlhash_new (filename);
+	g_free (filename);
+	g_free (unescaped_uri);
+
+        status = e_cal_backend_mapi_get_object_list (E_CAL_BACKEND_SYNC (cbmapi), NULL, "#t", &list);
+        if (status != GNOME_Evolution_Calendar_Success)
+                return status;
+
+        /* Calculate adds and modifies */
+	for (i = list; i != NULL; i = g_list_next (i)) {
+		const char *uid;
+		char *calobj;
+		ECalComponent *comp;
+
+		comp = e_cal_component_new_from_string (i->data);
+		e_cal_component_get_uid (comp, &uid);
+		calobj = i->data;
+
+		g_assert (calobj != NULL);
+
+		/* check what type of change has occurred, if any */
+		switch (e_xmlhash_compare (ehash, uid, calobj)) {
+		case E_XMLHASH_STATUS_SAME:
+			break;
+		case E_XMLHASH_STATUS_NOT_FOUND:
+			*adds = g_list_prepend (*adds, g_strdup (calobj));
+			e_xmlhash_add (ehash, uid, calobj);
+			break;
+		case E_XMLHASH_STATUS_DIFFERENT:
+			*modifies = g_list_prepend (*modifies, g_strdup (calobj));
+			e_xmlhash_add (ehash, uid, calobj);
+			break;
+		}
+
+		g_free (calobj);
+		g_object_unref (comp);
+	}
+	g_list_free (list);
+
+	/* Calculate deletions */
+	be_data.backend = cbmapi;
+	be_data.kind = e_cal_backend_get_kind (E_CAL_BACKEND (cbmapi));
+	be_data.deletes = NULL;
+	be_data.ehash = ehash;
+   	e_xmlhash_foreach_key (ehash, (EXmlHashFunc)e_cal_backend_mapi_compute_changes_foreach_key, &be_data);
+
+	*deletes = be_data.deletes;
+
+	e_xmlhash_write (ehash);
+  	e_xmlhash_destroy (ehash);
+
+	return GNOME_Evolution_Calendar_Success;
+}
+
+static ECalBackendSyncStatus
+e_cal_backend_mapi_get_changes (ECalBackendSync *backend, EDataCal *cal, const char *change_id,
+				GList **adds, GList **modifies, GList **deletes)
+{
+	ECalBackendMAPI *cbmapi;
+
+	cbmapi = E_CAL_BACKEND_MAPI (backend);
+
+	g_return_val_if_fail (E_IS_CAL_BACKEND_MAPI (cbmapi), GNOME_Evolution_Calendar_InvalidObject);
+	g_return_val_if_fail (change_id != NULL, GNOME_Evolution_Calendar_ObjectNotFound);
+
+	return e_cal_backend_mapi_compute_changes (cbmapi, change_id, adds, modifies, deletes);
+
+}
+
+
+/***** BACKEND CLASS FUNCTIONS *****/
+static gboolean	
+e_cal_backend_mapi_is_loaded (ECalBackend *backend)
+{
+	ECalBackendMAPI *cbmapi;
+	ECalBackendMAPIPrivate *priv;
+
+	cbmapi = E_CAL_BACKEND_MAPI (backend);
+	priv = cbmapi->priv;
+
+	return priv->cache ? TRUE : FALSE;
+}
+
+static void 
+e_cal_backend_mapi_start_query (ECalBackend *backend, EDataCalView *query)
+{
+        ECalBackendSyncStatus status;
+	ECalBackendMAPI *cbmapi;
+	ECalBackendMAPIPrivate *priv;
+        GList *objects = NULL;
+
+	cbmapi = E_CAL_BACKEND_MAPI (backend);
+	priv = cbmapi->priv;
+
+        status = e_cal_backend_mapi_get_object_list (E_CAL_BACKEND_SYNC (backend), NULL,
+						     e_data_cal_view_get_text (query), &objects);
+        if (status != GNOME_Evolution_Calendar_Success) {
+		e_data_cal_view_notify_done (query, status);
+                return;
+	}
+
+       	/* notify listeners of all objects */
+	if (objects) {
+		e_data_cal_view_notify_objects_added (query, (const GList *) objects);
+		/* free memory */
+		g_list_foreach (objects, (GFunc) g_free, NULL);
+		g_list_free (objects);
+	}
+
+	e_data_cal_view_notify_done (query, GNOME_Evolution_Calendar_Success);
+}
+
+static CalMode 
+e_cal_backend_mapi_get_mode (ECalBackend *backend)
+{
+	ECalBackendMAPI *cbmapi;
+	ECalBackendMAPIPrivate *priv;
+
+	cbmapi = E_CAL_BACKEND_MAPI (backend);
+	priv = cbmapi->priv;
+
+	return priv->mode;
+}
+
+static void 
+e_cal_backend_mapi_set_mode (ECalBackend *backend, CalMode mode)
+{
+	ECalBackendMAPI *cbmapi;
+	ECalBackendMAPIPrivate *priv;
+
+	cbmapi = E_CAL_BACKEND_MAPI (backend);
+	priv = cbmapi->priv;
+
+	if (!priv->mode && priv->mode == mode) {
+		e_cal_backend_notify_mode (backend, GNOME_Evolution_Calendar_CalListener_MODE_SET,
+				  	   cal_mode_to_corba (mode));
+		return;
+	}	
+
+	g_mutex_lock (priv->mutex);
+
+	priv->mode_changed = TRUE;
+	switch (mode) {
+		case CAL_MODE_REMOTE:
+			priv->mode = CAL_MODE_REMOTE;
+			priv->read_only = FALSE;
+			e_cal_backend_notify_mode (backend, GNOME_Evolution_Calendar_CalListener_MODE_SET,
+					GNOME_Evolution_Calendar_MODE_REMOTE);
+			e_cal_backend_notify_readonly (backend, priv->read_only);
+			if (e_cal_backend_mapi_is_loaded (backend))
+		              e_cal_backend_notify_auth_required(backend);
+			break;
+		case CAL_MODE_LOCAL:
+			priv->mode = CAL_MODE_LOCAL;
+			priv->read_only = TRUE;
+			/* do we have to close the connection here ? */
+			e_cal_backend_notify_mode (backend, GNOME_Evolution_Calendar_CalListener_MODE_SET,
+					GNOME_Evolution_Calendar_MODE_REMOTE);
+			e_cal_backend_notify_readonly (backend, priv->read_only);
+			break;
+		default:
+			e_cal_backend_notify_mode (backend, GNOME_Evolution_Calendar_CalListener_MODE_NOT_SUPPORTED,
+					cal_mode_to_corba (mode));
+	}	
+
+	g_mutex_unlock (priv->mutex);
+}
+
+static icaltimezone * 
+e_cal_backend_mapi_internal_get_default_timezone (ECalBackend *backend)
+{
+	ECalBackendMAPI *cbmapi;
+	ECalBackendMAPIPrivate *priv;
+
+	cbmapi = E_CAL_BACKEND_MAPI (backend);
+	priv = cbmapi->priv;
+
+	return priv->default_zone;
+}
+
+static icaltimezone *
+e_cal_backend_mapi_internal_get_timezone (ECalBackend *backend, const char *tzid)
+{
+	icaltimezone *zone;
+
+	zone = icaltimezone_get_builtin_timezone_from_tzid (tzid);
+
+	if (!zone && E_CAL_BACKEND_CLASS (parent_class)->internal_get_timezone)
+		zone = E_CAL_BACKEND_CLASS (parent_class)->internal_get_timezone (backend, tzid);
+
+	if (!zone)
+		return icaltimezone_get_utc_timezone ();
+
+	return zone;
+}
+
+
+/* MAPI CLASS INIT */
+static void 
+e_cal_backend_mapi_class_init (ECalBackendMAPIClass *class)
+{
+	GObjectClass *object_class;
+	ECalBackendSyncClass *sync_class;
+	ECalBackendClass *backend_class;
+	
+	object_class = (GObjectClass *) class;
+	sync_class = (ECalBackendSyncClass *) class;
+	backend_class = (ECalBackendClass *) class;
+	
+	parent_class = g_type_class_peek_parent (class);
+
+	object_class->dispose = e_cal_backend_mapi_dispose;
+	object_class->finalize = e_cal_backend_mapi_finalize;
+
+	sync_class->is_read_only_sync = e_cal_backend_mapi_is_read_only;
+	sync_class->get_cal_address_sync = e_cal_backend_mapi_get_cal_address;
+	sync_class->get_alarm_email_address_sync = e_cal_backend_mapi_get_alarm_email_address;
+	sync_class->get_ldap_attribute_sync = e_cal_backend_mapi_get_ldap_attribute;
+	sync_class->get_static_capabilities_sync = e_cal_backend_mapi_get_static_capabilities;
+	sync_class->open_sync = e_cal_backend_mapi_open;
+	sync_class->remove_sync = e_cal_backend_mapi_remove;
+	sync_class->get_default_object_sync = e_cal_backend_mapi_get_default_object;
+	sync_class->get_object_sync = e_cal_backend_mapi_get_object;
+	sync_class->get_object_list_sync = e_cal_backend_mapi_get_object_list;
+	sync_class->get_attachment_list_sync = e_cal_backend_mapi_get_attachment_list;
+	sync_class->create_object_sync = e_cal_backend_mapi_create_object;
+	sync_class->modify_object_sync = e_cal_backend_mapi_modify_object;
+	sync_class->remove_object_sync = e_cal_backend_mapi_remove_object;
+	sync_class->discard_alarm_sync = e_cal_backend_mapi_discard_alarm;
+	sync_class->receive_objects_sync = e_cal_backend_mapi_receive_objects;
+	sync_class->send_objects_sync = e_cal_backend_mapi_send_objects;
+	sync_class->get_timezone_sync = e_cal_backend_mapi_get_timezone;
+	sync_class->add_timezone_sync = e_cal_backend_mapi_add_timezone;
+	sync_class->set_default_zone_sync = e_cal_backend_mapi_set_default_zone;
+	sync_class->get_freebusy_sync = e_cal_backend_mapi_get_free_busy;
+	sync_class->get_changes_sync = e_cal_backend_mapi_get_changes;
+
+	backend_class->is_loaded = e_cal_backend_mapi_is_loaded;
+	backend_class->start_query = e_cal_backend_mapi_start_query;
+	backend_class->get_mode = e_cal_backend_mapi_get_mode;
+	backend_class->set_mode = e_cal_backend_mapi_set_mode;
+	backend_class->internal_get_default_timezone = e_cal_backend_mapi_internal_get_default_timezone;
+	backend_class->internal_get_timezone = e_cal_backend_mapi_internal_get_timezone;
+}
+
+
+static void
+e_cal_backend_mapi_init (ECalBackendMAPI *cbmapi, ECalBackendMAPIClass *class)
+{
+	ECalBackendMAPIPrivate *priv;
+	
+	priv = g_new0 (ECalBackendMAPIPrivate, 1);
+
+	priv->timeout_id = 0;
+	priv->sendoptions_sync_timeout = 0;
+
+	/* create the mutex for thread safety */
+	priv->mutex = g_mutex_new ();
+
+	cbmapi->priv = priv;
+
+	e_cal_backend_sync_set_lock (E_CAL_BACKEND_SYNC (cbmapi), TRUE);
+}
+
+GType
+e_cal_backend_mapi_get_type (void)
+{
+	static GType e_cal_backend_mapi_type = 0;
+
+	if (!e_cal_backend_mapi_type) {
+		static GTypeInfo info = {
+                        sizeof (ECalBackendMAPIClass),
+                        (GBaseInitFunc) NULL,
+                        (GBaseFinalizeFunc) NULL,
+                        (GClassInitFunc) e_cal_backend_mapi_class_init,
+                        NULL, NULL,
+                        sizeof (ECalBackendMAPI),
+                        0,
+                        (GInstanceInitFunc) e_cal_backend_mapi_init
+                };
+		e_cal_backend_mapi_type = g_type_register_static (E_TYPE_CAL_BACKEND_SYNC,
+								  "ECalBackendMAPI", &info, 0);
+	}
+
+	return e_cal_backend_mapi_type;
+}
+
+
+/***** UTILITY FUNCTIONS *****/
+const char *	
+e_cal_backend_mapi_get_local_attachments_store (ECalBackendMAPI *cbmapi)
+{
+	ECalBackendMAPIPrivate *priv;
+
+	priv = cbmapi->priv;
+
+	return priv->local_attachments_store;
+}
+
+const char *	
+e_cal_backend_mapi_get_owner_name (ECalBackendMAPI *cbmapi)
+{
+	ECalBackendMAPIPrivate *priv;
+
+	priv = cbmapi->priv;
+
+	return priv->owner_name;
+}
+
+const char *	
+e_cal_backend_mapi_get_owner_email (ECalBackendMAPI *cbmapi)
+{
+	ECalBackendMAPIPrivate *priv;
+
+	priv = cbmapi->priv;
+
+	return priv->owner_email;
+}
+
+const char *	
+e_cal_backend_mapi_get_user_name (ECalBackendMAPI *cbmapi)
+{
+	ECalBackendMAPIPrivate *priv;
+
+	priv = cbmapi->priv;
+
+	return priv->user_name;
+}
+
+const char *	
+e_cal_backend_mapi_get_user_email (ECalBackendMAPI *cbmapi)
+{
+	ECalBackendMAPIPrivate *priv;
+
+	priv = cbmapi->priv;
+
+	return priv->user_email;
+}

Added: trunk/src/calendar/e-cal-backend-mapi.h
==============================================================================
--- (empty file)
+++ trunk/src/calendar/e-cal-backend-mapi.h	Wed Nov 19 04:28:20 2008
@@ -0,0 +1,72 @@
+/* -*- 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/>  
+ *
+ *
+ * Authors:
+ *    Suman Manjunath <msuman novell com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef E_CAL_BACKEND_MAPI_H
+#define E_CAL_BACKEND_MAPI_H
+
+#include <glib.h>
+
+#include <libedata-cal/e-cal-backend-sync.h>
+
+G_BEGIN_DECLS
+
+#define E_TYPE_CAL_BACKEND_MAPI            (e_cal_backend_mapi_get_type ())
+#define E_CAL_BACKEND_MAPI(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), E_TYPE_CAL_BACKEND_MAPI,	ECalBackendMAPI))
+#define E_CAL_BACKEND_MAPI_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), E_TYPE_CAL_BACKEND_MAPI,	ECalBackendMAPIClass))
+#define E_IS_CAL_BACKEND_MAPI(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), E_TYPE_CAL_BACKEND_MAPI))
+#define E_IS_CAL_BACKEND_MAPI_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), E_TYPE_CAL_BACKEND_MAPI))
+
+typedef struct _ECalBackendMAPI        ECalBackendMAPI;
+typedef struct _ECalBackendMAPIClass   ECalBackendMAPIClass;
+typedef struct _ECalBackendMAPIPrivate ECalBackendMAPIPrivate;
+
+struct _ECalBackendMAPI {
+	ECalBackendSync backend;
+
+	/* Private data */
+	ECalBackendMAPIPrivate *priv;
+};
+
+struct _ECalBackendMAPIClass {
+	ECalBackendSyncClass parent_class;
+};
+
+GType	e_cal_backend_mapi_get_type(void);
+
+const char *	
+e_cal_backend_mapi_get_local_attachments_store (ECalBackendMAPI *cbmapi);
+
+const char *	
+e_cal_backend_mapi_get_owner_name (ECalBackendMAPI *cbmapi);
+const char *	
+e_cal_backend_mapi_get_owner_email (ECalBackendMAPI *cbmapi);
+
+const char *	
+e_cal_backend_mapi_get_user_name (ECalBackendMAPI *cbmapi);
+const char *	
+e_cal_backend_mapi_get_user_email (ECalBackendMAPI *cbmapi);
+
+G_END_DECLS
+
+#endif /* E_CAL_BACKEND_MAPI_H */
+

Added: trunk/src/camel/Makefile.am
==============================================================================
--- (empty file)
+++ trunk/src/camel/Makefile.am	Wed Nov 19 04:28:20 2008
@@ -0,0 +1,35 @@
+## Process this file with automake to produce Makefile.in
+
+camel_provider_LTLIBRARIES = libcamelmapi.la
+camel_provider_DATA = libcamelmapi.urls
+
+INCLUDES = -I.. \
+	-I$(top_srcdir)/src/camel		\
+	-I$(top_srcdir)/src/libexchangemapi	\
+	$(CAMEL_CFLAGS)				\
+        $(LIBMAPI_CFLAGS)                       \
+	-DG_LOG_DOMAIN=\"camel-mapi-provider\"
+
+libcamelmapi_la_SOURCES = 			\
+	camel-mapi-provider.c			\
+	camel-mapi-folder.c                	\
+        camel-mapi-store.c	                \
+	camel-mapi-store-summary.c         	\
+	camel-mapi-summary.c	         	\
+	camel-mapi-transport.c			
+
+noinst_HEADERS =         			\
+	camel-mapi-folder.h			\
+	camel-mapi-store.h			\
+	camel-mapi-summary.h	         	\
+	camel-mapi-transport.h			\
+	camel-mapi-private.h			\
+	camel-private.h				
+
+libcamelmapi_la_LDFLAGS = -avoid-version -module $(NO_UNDEFINED)
+libcamelmapi_la_LIBADD =                         \
+	$(top_builddir)/src/libexchangemapi/libexchangemapi-1.0.la		\
+	$(CAMEL_LIBS)                            \
+        $(LIBMAPI_LIBS)
+
+EXTRA_DIST = libcamelmapi.urls

Added: trunk/src/camel/camel-mapi-folder.c
==============================================================================
--- (empty file)
+++ trunk/src/camel/camel-mapi-folder.c	Wed Nov 19 04:28:20 2008
@@ -0,0 +1,1590 @@
+/* -*- 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/>  
+ *
+ *
+ * Authors:
+ *     Johnny Jacob <jjohnny novell com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#include <pthread.h>
+#include <string.h>
+#include <time.h>
+
+#include <camel/camel-folder-search.h>
+#include <camel/camel-mime-part.h>
+#include <camel/camel-mime-utils.h>
+#include <camel/camel-string-utils.h>
+#include <camel/camel-object.h>
+#include <camel/camel-mime-message.h>
+#include <camel/camel-data-wrapper.h>
+#include <camel/camel-multipart.h>
+#include <camel/camel-private.h>
+#include <camel/camel-stream-buffer.h>
+#include <camel/camel-stream-mem.h>
+#include <camel/camel-debug.h>
+
+#include <libmapi/libmapi.h>
+#include <exchange-mapi-defs.h>
+#include <exchange-mapi-utils.h>
+#include <exchange-mapi-folder.h>
+
+#include "camel-mapi-store.h"
+#include "camel-mapi-folder.h"
+#include "camel-mapi-private.h"
+#include "camel-mapi-summary.h"
+
+#define DEBUG_FN( ) printf("----%u %s\n", (unsigned int)pthread_self(), __FUNCTION__);
+#define d(x)
+
+static CamelOfflineFolderClass *parent_class = NULL;
+
+struct _CamelMapiFolderPrivate {
+	
+//#ifdef ENABLE_THREADS
+	GStaticMutex search_lock;	/* for locking the search object */
+	GStaticRecMutex cache_lock;	/* for locking the cache object */
+//#endif
+
+};
+
+/*for syncing flags back to server*/
+typedef struct {
+	guint32 changed;
+	guint32 bits;
+} flags_diff_t;
+
+/*For collecting summary info from server*/
+typedef struct {
+	GSList *items_list;
+	const struct timeval *last_modification_time;
+}fetch_items_data;
+
+static CamelMimeMessage *mapi_folder_item_to_msg( CamelFolder *folder, MapiItem *item, CamelException *ex );
+
+static GPtrArray *
+mapi_folder_search_by_expression (CamelFolder *folder, const char *expression, CamelException *ex)
+{
+	CamelMapiFolder *mapi_folder = CAMEL_MAPI_FOLDER(folder);
+	GPtrArray *matches;
+
+	CAMEL_MAPI_FOLDER_LOCK(mapi_folder, search_lock);
+	camel_folder_search_set_folder (mapi_folder->search, folder);
+	matches = camel_folder_search_search(mapi_folder->search, expression, NULL, ex);
+	CAMEL_MAPI_FOLDER_UNLOCK(mapi_folder, search_lock);
+
+	return matches;
+}
+
+
+static int
+mapi_getv (CamelObject *object, CamelException *ex, CamelArgGetV *args)
+{
+	CamelFolder *folder = (CamelFolder *)object;
+	int i, count = 0;
+	guint32 tag;
+
+	for (i=0 ; i<args->argc ; i++) {
+		CamelArgGet *arg = &args->argv[i];
+
+		tag = arg->tag;
+
+		switch (tag & CAMEL_ARG_TAG) {
+
+			case CAMEL_OBJECT_ARG_DESCRIPTION:
+				if (folder->description == NULL) {
+					CamelURL *uri = ((CamelService *)folder->parent_store)->url;
+
+					folder->description = g_strdup_printf("%s %s:%s", uri->user, uri->host, folder->full_name);
+				}
+				*arg->ca_str = folder->description;
+				break;
+			default:
+				count++;
+				continue;
+		}
+
+		arg->tag = (tag & CAMEL_ARG_TYPE) | CAMEL_ARG_IGNORE;
+	}
+
+	if (count)
+		return ((CamelObjectClass *)parent_class)->getv(object, ex, args);
+
+	return 0;
+
+}
+
+static void
+mapi_refresh_info(CamelFolder *folder, CamelException *ex)
+{
+	CamelStoreInfo *si;
+	/*
+	 * Checking for the summary->time_string here since the first the a
+	 * user views a folder, the read cursor is in progress, and the getQM
+	 * should not interfere with the process
+	 */
+	//	if (summary->time_string && (strlen (summary->time_string) > 0))  {
+	if(1){
+		mapi_refresh_folder(folder, ex);
+		si = camel_store_summary_path ((CamelStoreSummary *)((CamelMapiStore *)folder->parent_store)->summary, folder->full_name);
+
+		if (si) {
+			guint32 unread, total;
+			camel_object_get (folder, NULL, CAMEL_FOLDER_TOTAL, &total, CAMEL_FOLDER_UNREAD, &unread, NULL);
+			if (si->total != total || si->unread != unread) {
+				si->total = total;
+				si->unread = unread;
+				camel_store_summary_touch ((CamelStoreSummary *)((CamelMapiStore *)folder->parent_store)->summary);
+			}
+			camel_store_summary_info_free ((CamelStoreSummary *)((CamelMapiStore *)folder->parent_store)->summary, si);
+		}
+		camel_folder_summary_save_to_db (folder->summary, ex);
+		camel_store_summary_save ((CamelStoreSummary *)((CamelMapiStore *)folder->parent_store)->summary);
+	} else {
+		/* We probably could not get the messages the first time. (get_folder) failed???!
+		 * so do a get_folder again. And hope that it works
+		 */
+		g_print("Reloading folder...something wrong with the summary....\n");
+	}
+	//#endif
+
+}
+
+static 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);
+
+	exchange_mapi_util_free_attachment_list (&item->attachments);
+	exchange_mapi_util_free_stream_list (&item->generic_streams);
+}
+static gboolean
+fetch_items_cb (FetchItemsCallbackData *item_data, gpointer data)
+{
+	fetch_items_data *fi_data = (fetch_items_data *)data;
+	
+	GSList **slist = &(fi_data->items_list);
+
+	long *flags;
+	struct FILETIME *delivery_date = NULL;
+	struct FILETIME *last_modification_time = NULL;
+	struct timeval *item_modification_time = NULL;
+	guint32 j = 0;
+	NTTIME ntdate;
+
+	MapiItem *item = g_new0(MapiItem , 1);
+
+	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;
+
+	for (j = 0; j < item_data->properties->cValues; j++) {
+
+		gpointer prop_data = get_mapi_SPropValue_data(&item_data->properties->lpProps[j]);
+
+		switch (item_data->properties->lpProps[j].ulPropTag) {
+		/* FIXME : Instead of duping. Use talloc_steal to reuse the memory */
+		case PR_NORMALIZED_SUBJECT:
+		case PR_NORMALIZED_SUBJECT_UNICODE :
+			item->header.subject = g_strdup (prop_data);
+			break;
+		case PR_DISPLAY_TO :
+		case PR_DISPLAY_TO_UNICODE :
+			item->header.to = g_strdup (prop_data);
+			break;
+		case PR_DISPLAY_CC:
+		case PR_DISPLAY_CC_UNICODE:
+			item->header.cc = g_strdup (prop_data);
+			break;
+		case PR_DISPLAY_BCC:
+		case PR_DISPLAY_BCC_UNICODE:
+			item->header.bcc = g_strdup (prop_data);
+			break;
+		case PR_SENT_REPRESENTING_NAME:
+		case PR_SENT_REPRESENTING_NAME_UNICODE:
+			item->header.from = g_strdup (prop_data);
+			break;
+		case PR_MESSAGE_SIZE:
+			item->header.size = *(glong *)prop_data;
+			break;
+		case PR_MESSAGE_DELIVERY_TIME:
+			delivery_date = (struct FILETIME *) prop_data;
+			break;
+		case PR_LAST_MODIFICATION_TIME:
+			last_modification_time = (struct FILETIME *) prop_data;
+			break;
+		case PR_MESSAGE_FLAGS:
+			flags = (long *) prop_data;
+			break;
+		default:
+			break;
+		}
+	}
+
+	if (delivery_date) {
+		ntdate = delivery_date->dwHighDateTime;
+		ntdate = ntdate << 32;
+		ntdate |= delivery_date->dwLowDateTime;
+		item->header.recieved_time = nt_time_to_unix(ntdate);
+	}
+
+	if (last_modification_time) {
+		ntdate = last_modification_time->dwHighDateTime;
+		ntdate = ntdate << 32;
+		ntdate |= last_modification_time->dwLowDateTime;
+		item_modification_time = g_new0 (struct timeval, 1);
+		nttime_to_timeval(item_modification_time, ntdate);
+	}
+
+	if (timeval_compare (item_modification_time, fi_data->last_modification_time) == 1) 
+			fi_data->last_modification_time = item_modification_time;
+
+	if ((*flags & MSGFLAG_READ) != 0)
+		item->header.flags |= CAMEL_MESSAGE_SEEN;
+	if ((*flags & MSGFLAG_HASATTACH) != 0)
+		item->header.flags |= CAMEL_MESSAGE_ATTACHMENTS;
+
+	*slist = g_slist_prepend (*slist, item);
+
+	if (item_data->total > 0)
+               camel_operation_progress (NULL, (item_data->index * 100)/item_data->total);
+
+	return TRUE;
+}
+
+static void
+mapi_update_cache (CamelFolder *folder, GSList *list, CamelException *ex, gboolean uid_flag) 
+{
+	CamelMapiMessageInfo *mi = NULL;
+	CamelMessageInfo *pmi = NULL;
+	CamelMapiStore *mapi_store = CAMEL_MAPI_STORE (folder->parent_store);
+
+	guint32 status_flags = 0;
+	CamelFolderChangeInfo *changes = NULL;
+	gboolean exists = FALSE;
+	GString *str = g_string_new (NULL);
+	const gchar *folder_id = NULL;
+	GSList *item_list = list;
+	int total_items = g_slist_length (item_list), i=0;
+
+	changes = camel_folder_change_info_new ();
+	folder_id = camel_mapi_store_folder_id_lookup (mapi_store, folder->full_name);
+
+	if (!folder_id) {
+		d(printf("\nERROR - Folder id not present. Cannot refresh info\n"));
+		camel_folder_change_info_free (changes);
+		return;
+	}
+
+	camel_operation_start (NULL, _("Fetching summary information for new messages in %s"), folder->name);
+
+	for ( ; item_list != NULL ; item_list = g_slist_next (item_list) ) {
+		MapiItem *temp_item ;
+		MapiItem *item;
+		guint64 id;
+
+		exists = FALSE;
+		status_flags = 0;
+
+		if (uid_flag == FALSE) {
+ 			temp_item = (MapiItem *)item_list->data;
+			id = temp_item->mid;
+			item = temp_item;
+		}
+
+		camel_operation_progress (NULL, (100*i)/total_items);
+
+		/************************ First populate summary *************************/
+		mi = NULL;
+		pmi = NULL;
+		char *msg_uid = exchange_mapi_util_mapi_ids_to_uid (item->fid, item->mid);
+		pmi = camel_folder_summary_uid (folder->summary, msg_uid);
+
+		if (pmi) {
+			exists = TRUE;
+			camel_message_info_ref (pmi);
+			mi = (CamelMapiMessageInfo *)pmi;
+		}
+
+		if (!exists) {
+			mi = (CamelMapiMessageInfo *)camel_message_info_new (folder->summary); 
+			if (mi->info.content == NULL) {
+				mi->info.content = camel_folder_summary_content_info_new (folder->summary);
+				mi->info.content->type = camel_content_type_new ("multipart", "mixed");	
+			}
+		}
+		
+		mi->info.flags = item->header.flags;
+
+		if (!exists) {
+			mi->info.uid = g_strdup (exchange_mapi_util_mapi_ids_to_uid(item->fid, item->mid));
+			mi->info.subject = camel_pstring_strdup(item->header.subject);
+			mi->info.date_sent = mi->info.date_received = item->header.recieved_time;
+			mi->info.from = camel_pstring_strdup (item->header.from);
+			mi->info.to = camel_pstring_strdup (item->header.to);
+			mi->info.size = (guint32) item->header.size;
+		}
+
+		if (exists) {
+			camel_folder_change_info_change_uid (changes, mi->info.uid);
+			camel_message_info_free (pmi);
+		} else {
+			camel_folder_summary_add (folder->summary,(CamelMessageInfo *)mi);
+			camel_folder_change_info_add_uid (changes, mi->info.uid);
+			camel_folder_change_info_recent_uid (changes, mi->info.uid);
+		}
+
+		/********************* Summary ends *************************/
+		if (!strcmp (folder->full_name, "Junk Mail"))
+			continue;
+
+		g_free (msg_uid);
+		i++;
+	}
+	camel_operation_end (NULL);
+
+	g_string_free (str, TRUE);
+	camel_object_trigger_event (folder, "folder_changed", changes);
+
+	camel_folder_change_info_free (changes);
+}
+
+static void 
+mapi_sync_summary (CamelFolder *folder, CamelException *ex)
+{
+	camel_folder_summary_save_to_db (folder->summary, ex);
+	camel_store_summary_touch ((CamelStoreSummary *)((CamelMapiStore *)folder->parent_store)->summary);
+	camel_store_summary_save ((CamelStoreSummary *)((CamelMapiStore *)folder->parent_store)->summary);
+}
+
+static void
+mapi_utils_do_flags_diff (flags_diff_t *diff, guint32 old, guint32 _new)
+{
+	diff->changed = old ^ _new;
+	diff->bits = _new & diff->changed;
+}
+
+static void
+mapi_sync (CamelFolder *folder, gboolean expunge, CamelException *ex)
+{
+	CamelMapiStore *mapi_store = CAMEL_MAPI_STORE (folder->parent_store);
+	CamelMapiFolder *mapi_folder = CAMEL_MAPI_FOLDER (folder);
+	CamelMessageInfo *info = NULL;
+	CamelMapiMessageInfo *mapi_info = NULL;
+
+	GSList *read_items = NULL, *unread_items = NULL;
+	flags_diff_t diff, unset_flags;
+	const char *folder_id;
+	mapi_id_t fid, deleted_items_fid;
+	int count, i;
+	guint32 options =0;
+
+	GSList *deleted_items, *deleted_head;
+	deleted_items = deleted_head = NULL;
+
+	if (((CamelOfflineStore *) mapi_store)->state == CAMEL_OFFLINE_STORE_NETWORK_UNAVAIL || 
+			((CamelService *)mapi_store)->status == CAMEL_SERVICE_DISCONNECTED) {
+		mapi_sync_summary (folder, ex);
+		return;
+	}
+
+	if (((CamelMapiFolder *)folder)->type == MAPI_FAVOURITE_FOLDER){
+		options |= MAPI_OPTIONS_USE_PFSTORE;
+	} 
+
+	folder_id =  camel_mapi_store_folder_id_lookup (mapi_store, folder->full_name) ;
+	exchange_mapi_util_mapi_id_from_string (folder_id, &fid);
+
+	CAMEL_SERVICE_REC_LOCK (mapi_store, connect_lock);
+	if (!camel_mapi_store_connected (mapi_store, ex)) {
+		CAMEL_SERVICE_REC_UNLOCK (mapi_store, connect_lock);
+		camel_exception_clear (ex);
+		return;
+	}
+	CAMEL_SERVICE_REC_UNLOCK (mapi_store, connect_lock);
+
+	count = camel_folder_summary_count (folder->summary);
+	CAMEL_MAPI_FOLDER_REC_LOCK (folder, cache_lock);
+	for (i=0 ; i < count ; i++) {
+		info = camel_folder_summary_index (folder->summary, i);
+		mapi_info = (CamelMapiMessageInfo *) info;
+
+		if (mapi_info && (mapi_info->info.flags & CAMEL_MESSAGE_FOLDER_FLAGGED)) {
+			const char *uid;
+			mapi_id_t *mid = g_new0 (mapi_id_t, 1); /* FIXME : */
+			mapi_id_t temp_fid;
+
+			uid = camel_message_info_uid (info);
+			guint32 flags= camel_message_info_flags (info);
+
+			/* Why are we getting so much noise here :-/ */
+			if (!exchange_mapi_util_mapi_ids_from_uid (uid, &temp_fid, mid))
+				continue;
+
+			mapi_utils_do_flags_diff (&diff, mapi_info->server_flags, mapi_info->info.flags);
+			mapi_utils_do_flags_diff (&unset_flags, flags, mapi_info->server_flags);
+
+			diff.changed &= folder->permanent_flags;
+			if (!diff.changed) {
+				camel_message_info_free(info);
+				continue;
+			} else {
+				if (diff.bits & CAMEL_MESSAGE_DELETED) {
+					if (diff.bits & CAMEL_MESSAGE_SEEN) 
+						read_items = g_slist_prepend (read_items, mid);
+					if (deleted_items)
+						deleted_items = g_slist_prepend (deleted_items, mid);
+					else {
+						g_slist_free (deleted_head);
+						deleted_head = NULL;
+						deleted_head = deleted_items = g_slist_prepend (deleted_items, mid);
+					}
+
+					CAMEL_SERVICE_REC_LOCK (mapi_store, connect_lock);
+
+					}
+				}
+				
+				if (diff.bits & CAMEL_MESSAGE_SEEN) {
+					read_items = g_slist_prepend (read_items, mid);
+				} else if (unset_flags.bits & CAMEL_MESSAGE_SEEN) {
+					unread_items = g_slist_prepend (unread_items, mid);
+				}
+		}
+		camel_message_info_free (info);
+	}
+	
+	CAMEL_MAPI_FOLDER_REC_UNLOCK (folder, cache_lock);
+
+	/* 
+	   Sync up the READ changes before deleting the message. 
+	   Note that if a message is marked as unread and then deleted,
+	   Evo doesnt not take care of it, as I find that scenario to be impractical.
+	*/
+
+	if (read_items) {
+		CAMEL_SERVICE_REC_LOCK (mapi_store, connect_lock);
+		exchange_mapi_set_flags (0, fid, read_items, 0, options);
+		CAMEL_SERVICE_REC_UNLOCK (mapi_store, connect_lock);
+		g_slist_free (read_items);
+	}
+
+	if (deleted_items) {
+		CAMEL_SERVICE_REC_LOCK (mapi_store, connect_lock);
+		if (mapi_folder->type & CAMEL_FOLDER_TYPE_TRASH) {
+			exchange_mapi_remove_items (0, fid, deleted_items);
+		} else {
+			exchange_mapi_util_mapi_id_from_string (camel_mapi_store_system_folder_fid (mapi_store, olFolderDeletedItems), &deleted_items_fid);
+			exchange_mapi_move_items(fid, deleted_items_fid, deleted_items);
+		}
+
+		CAMEL_SERVICE_REC_UNLOCK (mapi_store, connect_lock);
+	}
+	/*Remove them from cache*/
+	while (deleted_items) {
+		char* deleted_msg_uid = g_strdup_printf ("%016llX%016llX", fid, *(mapi_id_t *)deleted_items->data);
+
+		CAMEL_MAPI_FOLDER_REC_LOCK (folder, cache_lock);
+		camel_folder_summary_remove_uid (folder->summary, deleted_msg_uid);
+		camel_data_cache_remove(mapi_folder->cache, "cache", deleted_msg_uid, NULL);
+		CAMEL_MAPI_FOLDER_REC_UNLOCK (folder, cache_lock);
+
+		deleted_items = g_slist_next (deleted_items);
+	}
+
+
+	if (unread_items) {
+		CAMEL_SERVICE_REC_LOCK (mapi_store, connect_lock);
+		/* TODO */
+		CAMEL_SERVICE_REC_UNLOCK (mapi_store, connect_lock);
+		g_slist_free (unread_items);
+	}
+
+	if (expunge) {
+		CAMEL_SERVICE_REC_LOCK (mapi_store, connect_lock);
+		/* TODO */
+		CAMEL_SERVICE_REC_UNLOCK (mapi_store, connect_lock);
+	}
+
+	CAMEL_SERVICE_REC_LOCK (mapi_store, connect_lock);
+	mapi_sync_summary (folder, ex);
+	CAMEL_SERVICE_REC_UNLOCK (mapi_store, connect_lock);
+}
+
+
+void
+mapi_refresh_folder(CamelFolder *folder, CamelException *ex)
+{
+
+	CamelMapiStore *mapi_store = CAMEL_MAPI_STORE (folder->parent_store);
+	CamelMapiFolder *mapi_folder = CAMEL_MAPI_FOLDER (folder);
+	CamelMapiSummary *mapi_summary = CAMEL_MAPI_SUMMARY (folder->summary);
+	gboolean is_proxy = folder->parent_store->flags & CAMEL_STORE_PROXY;
+	gboolean is_locked = TRUE;
+	gboolean status;
+
+	struct mapi_SRestriction *res = NULL;
+	fetch_items_data *fetch_data = g_new0 (fetch_items_data, 1);
+
+	const gchar *folder_id = NULL;
+
+	const guint32 summary_prop_list[] = {
+		PR_NORMALIZED_SUBJECT,
+		PR_MESSAGE_SIZE,
+		PR_MESSAGE_DELIVERY_TIME,
+		PR_MESSAGE_FLAGS,
+		PR_SENT_REPRESENTING_NAME,
+		PR_LAST_MODIFICATION_TIME,
+		PR_DISPLAY_TO,
+		PR_DISPLAY_CC,
+		PR_DISPLAY_BCC
+	};
+
+	if (((CamelOfflineStore *) mapi_store)->state == CAMEL_OFFLINE_STORE_NETWORK_UNAVAIL) 
+		return;
+
+	/* Sync-up the (un)read changes before getting updates,
+	so that the getFolderList will reflect the most recent changes too */
+	mapi_sync (folder, FALSE, ex);
+
+	//creating a copy
+	folder_id = camel_mapi_store_folder_id_lookup (mapi_store, folder->full_name);
+	if (!folder_id) {
+		d(printf ("\nERROR - Folder id not present. Cannot refresh info for %s\n", folder->full_name));
+		return;
+	}
+
+	if (camel_folder_is_frozen (folder) ) {
+		mapi_folder->need_refresh = TRUE;
+	}
+
+	CAMEL_SERVICE_REC_LOCK (mapi_store, connect_lock);
+
+	if (!camel_mapi_store_connected (mapi_store, ex))
+		goto end1;
+
+	/*Get the New Items*/
+	if (!is_proxy) {
+		mapi_id_t temp_folder_id;
+		guint32 options = 0;
+
+		fetch_data->last_modification_time = g_new0 (struct timeval, 1); /*First Sync*/
+
+		if (mapi_summary->sync_time_stamp && *mapi_summary->sync_time_stamp &&
+		    g_time_val_from_iso8601 (mapi_summary->sync_time_stamp, fetch_data->last_modification_time)) {
+			struct SPropValue sprop;
+			struct timeval t;
+
+			res = g_new0 (struct mapi_SRestriction, 1);
+			res->rt = RES_PROPERTY;
+			/*RELOP_GE acts more like >=. Few extra items are being fetched.*/
+			res->res.resProperty.relop = RELOP_GE;
+			res->res.resProperty.ulPropTag = PR_LAST_MODIFICATION_TIME;
+
+			t.tv_sec = fetch_data->last_modification_time->tv_sec;
+			t.tv_usec = fetch_data->last_modification_time->tv_usec;
+
+			//Creation time ? 
+			set_SPropValue_proptag_date_timeval (&sprop, PR_LAST_MODIFICATION_TIME, &t);
+			cast_mapi_SPropValue (&(res->res.resProperty.lpProp), &sprop);
+		} 
+
+		exchange_mapi_util_mapi_id_from_string (folder_id, &temp_folder_id);
+
+		if (!camel_mapi_store_connected (mapi_store, ex)) {
+			/*BUG : Fix exception string.*/
+			camel_exception_set (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE,
+					     _("This message is not available in offline mode."));
+			goto end2;
+		}
+
+		if (((CamelMapiFolder *)folder)->type == MAPI_FAVOURITE_FOLDER)
+			options |= MAPI_OPTIONS_USE_PFSTORE;
+
+		camel_operation_start (NULL, _("Fetching summary information for new messages in %s"), folder->name);
+
+		status = exchange_mapi_connection_fetch_items  (temp_folder_id, res, 
+								summary_prop_list, G_N_ELEMENTS (summary_prop_list), 
+								NULL, NULL, 
+								fetch_items_cb, fetch_data, 
+								options);
+		camel_operation_end (NULL);
+
+		if (!status) {
+			camel_exception_set (ex, CAMEL_EXCEPTION_SERVICE_INVALID, _("Fetch items failed"));
+			goto end2;
+		}
+
+		/*Preserve last_modification_time from this fetch for later use with restrictions.*/
+		mapi_summary->sync_time_stamp = g_time_val_to_iso8601 (fetch_data->last_modification_time);
+
+		camel_folder_summary_touch (folder->summary);
+		mapi_sync_summary (folder, ex);
+
+		if (fetch_data->items_list)
+			mapi_update_cache (folder, fetch_data->items_list, ex, FALSE);
+	}
+
+
+	CAMEL_SERVICE_REC_UNLOCK (mapi_store, connect_lock);
+	is_locked = FALSE;
+
+	g_slist_foreach (fetch_data->items_list, (GFunc) mapi_item_free, NULL);
+	g_slist_free (fetch_data->items_list);
+end2:
+	//TODO:
+end1:
+	if (is_locked)
+		CAMEL_SERVICE_REC_UNLOCK (mapi_store, connect_lock);
+	return;
+
+}
+
+static const uint32_t camel_GetPropsList[] = {
+	PR_FID, 
+	PR_MID, 
+
+	PR_MESSAGE_CLASS, 
+	PR_MESSAGE_CLASS_UNICODE, 
+	PR_MESSAGE_SIZE, 
+	PR_MESSAGE_FLAGS, 
+	PR_MESSAGE_DELIVERY_TIME, 
+	PR_MSG_EDITOR_FORMAT, 
+
+	PR_SUBJECT, 
+	PR_SUBJECT_UNICODE, 
+	PR_NORMALIZED_SUBJECT, 
+	PR_NORMALIZED_SUBJECT_UNICODE, 
+	PR_CONVERSATION_TOPIC, 
+	PR_CONVERSATION_TOPIC_UNICODE, 
+
+	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, 
+	PR_DISPLAY_TO_UNICODE, 
+	PR_DISPLAY_CC, 
+	PR_DISPLAY_CC_UNICODE, 
+	PR_DISPLAY_BCC, 
+	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, 
+	PR_SENT_REPRESENTING_NAME_UNICODE, 
+	PR_SENT_REPRESENTING_ADDRTYPE, 
+	PR_SENT_REPRESENTING_ADDRTYPE_UNICODE, 
+	PR_SENT_REPRESENTING_EMAIL_ADDRESS, 
+	PR_SENT_REPRESENTING_EMAIL_ADDRESS_UNICODE, 
+
+	PR_SENDER_NAME, 
+	PR_SENDER_NAME_UNICODE, 
+	PR_SENDER_ADDRTYPE, 
+	PR_SENDER_ADDRTYPE_UNICODE, 
+	PR_SENDER_EMAIL_ADDRESS, 
+	PR_SENDER_EMAIL_ADDRESS_UNICODE, 
+
+	PR_RCVD_REPRESENTING_NAME, 
+	PR_RCVD_REPRESENTING_NAME_UNICODE, 
+	PR_RCVD_REPRESENTING_ADDRTYPE, 
+	PR_RCVD_REPRESENTING_ADDRTYPE_UNICODE, 
+	PR_RCVD_REPRESENTING_EMAIL_ADDRESS, 
+	PR_RCVD_REPRESENTING_EMAIL_ADDRESS_UNICODE
+};
+
+static gboolean 
+camel_build_name_id (struct mapi_nameid *nameid, gpointer data)
+{
+	mapi_nameid_lid_add(nameid, 0x8501, PSETID_Common); 	// PT_LONG - ReminderMinutesBeforeStart
+	mapi_nameid_lid_add(nameid, 0x8502, PSETID_Common); 	// PT_SYSTIME - ReminderTime
+	mapi_nameid_lid_add(nameid, 0x8503, PSETID_Common); 	// PT_BOOLEAN - ReminderSet
+	mapi_nameid_lid_add(nameid, 0x8506, PSETID_Common); 	// PT_BOOLEAN - Private
+	mapi_nameid_lid_add(nameid, 0x8510, PSETID_Common); 	// PT_LONG - (context menu flags)
+	mapi_nameid_lid_add(nameid, 0x8516, PSETID_Common); 	// PT_SYSTIME - CommonStart
+	mapi_nameid_lid_add(nameid, 0x8517, PSETID_Common); 	// PT_SYSTIME - CommonEnd
+	mapi_nameid_lid_add(nameid, 0x8560, PSETID_Common); 	// PT_SYSTIME - ReminderNextTime
+
+	mapi_nameid_lid_add(nameid, 0x8201, PSETID_Appointment); 	// PT_LONG - ApptSequence
+	mapi_nameid_lid_add(nameid, 0x8205, PSETID_Appointment); 	// PT_LONG - BusyStatus
+	mapi_nameid_lid_add(nameid, 0x8208, PSETID_Appointment); 	// PT_UNICODE - Location
+	mapi_nameid_lid_add(nameid, 0x820D, PSETID_Appointment); 	// PT_SYSTIME - Start/ApptStartWhole
+	mapi_nameid_lid_add(nameid, 0x820E, PSETID_Appointment); 	// PT_SYSTIME - End/ApptEndWhole
+	mapi_nameid_lid_add(nameid, 0x8213, PSETID_Appointment); 	// PT_LONG - Duration/ApptDuration
+	mapi_nameid_lid_add(nameid, 0x8215, PSETID_Appointment); 	// PT_BOOLEAN - AllDayEvent (also called ApptSubType)
+	mapi_nameid_lid_add(nameid, 0x8216, PSETID_Appointment); 	// PT_BINARY - (recurrence blob)
+	mapi_nameid_lid_add(nameid, 0x8217, PSETID_Appointment); 	// PT_LONG - MeetingStatus
+	mapi_nameid_lid_add(nameid, 0x8218, PSETID_Appointment); 	// PT_LONG - ResponseStatus
+	mapi_nameid_lid_add(nameid, 0x8223, PSETID_Appointment); 	// PT_BOOLEAN - Recurring
+	mapi_nameid_lid_add(nameid, 0x8224, PSETID_Appointment); 	// PT_LONG - IntendedBusyStatus
+	mapi_nameid_lid_add(nameid, 0x8228, PSETID_Appointment); 	// PT_SYSTIME - RecurrenceBase
+	mapi_nameid_lid_add(nameid, 0x8229, PSETID_Appointment); 	// PT_BOOLEAN - FInvited
+	mapi_nameid_lid_add(nameid, 0x8231, PSETID_Appointment); 	// PT_LONG - RecurrenceType
+	mapi_nameid_lid_add(nameid, 0x8232, PSETID_Appointment); 	// PT_STRING8 - RecurrencePattern
+	mapi_nameid_lid_add(nameid, 0x8235, PSETID_Appointment); 	// PT_SYSTIME - (dtstart)(for recurring events UTC 12 AM of day of start)
+	mapi_nameid_lid_add(nameid, 0x8236, PSETID_Appointment); 	// PT_SYSTIME - (dtend)(for recurring events UTC 12 AM of day of end)
+	mapi_nameid_lid_add(nameid, 0x823A, PSETID_Appointment); 	// PT_BOOLEAN - AutoFillLocation
+	mapi_nameid_lid_add(nameid, 0x8240, PSETID_Appointment); 	// PT_BOOLEAN - IsOnlineMeeting
+	mapi_nameid_lid_add(nameid, 0x8257, PSETID_Appointment); 	// PT_BOOLEAN - ApptCounterProposal
+	mapi_nameid_lid_add(nameid, 0x825E, PSETID_Appointment); 	// PT_BINARY - (timezone for dtstart)
+	mapi_nameid_lid_add(nameid, 0x825F, PSETID_Appointment); 	// PT_BINARY - (timezone for dtend)
+
+	mapi_nameid_lid_add(nameid, 0x0002, PSETID_Meeting); 		// PT_UNICODE - Where
+	mapi_nameid_lid_add(nameid, 0x0003, PSETID_Meeting); 		// PT_BINARY - GlobalObjectId
+	mapi_nameid_lid_add(nameid, 0x0005, PSETID_Meeting); 		// PT_BOOLEAN - IsRecurring
+	mapi_nameid_lid_add(nameid, 0x000a, PSETID_Meeting); 		// PT_BOOLEAN - IsException 
+	mapi_nameid_lid_add(nameid, 0x0023, PSETID_Meeting); 		// PT_BINARY - CleanGlobalObjectId
+	mapi_nameid_lid_add(nameid, 0x0024, PSETID_Meeting); 		// PT_STRING8 - AppointmentMessageClass 
+	mapi_nameid_lid_add(nameid, 0x0026, PSETID_Meeting); 		// PT_LONG - MeetingType
+
+	/* These probably would never be used from Evolution */
+//	mapi_nameid_lid_add(nameid, 0x8200, PSETID_Appointment); 	// PT_BOOLEAN - SendAsICAL
+//	mapi_nameid_lid_add(nameid, 0x8202, PSETID_Appointment); 	// PT_SYSTIME - ApptSequenceTime
+//	mapi_nameid_lid_add(nameid, 0x8214, PSETID_Appointment); 	// PT_LONG - Label
+//	mapi_nameid_lid_add(nameid, 0x8234, PSETID_Appointment); 	// PT_STRING8 - display TimeZone
+//	mapi_nameid_lid_add(nameid, 0x8238, PSETID_Appointment); 	// PT_STRING8 - AllAttendees
+//	mapi_nameid_lid_add(nameid, 0x823B, PSETID_Appointment); 	// PT_STRING8 - ToAttendeesString (dupe PR_DISPLAY_TO)
+//	mapi_nameid_lid_add(nameid, 0x823C, PSETID_Appointment); 	// PT_STRING8 - CCAttendeesString (dupe PR_DISPLAY_CC)
+
+	mapi_nameid_lid_add(nameid, 0x8101, PSETID_Task); 	// PT_LONG - Status
+	mapi_nameid_lid_add(nameid, 0x8102, PSETID_Task); 	// PT_DOUBLE - PercentComplete
+	mapi_nameid_lid_add(nameid, 0x8103, PSETID_Task); 	// PT_BOOLEAN - TeamTask
+	mapi_nameid_lid_add(nameid, 0x8104, PSETID_Task); 	// PT_SYSTIME - StartDate/TaskStartDate
+	mapi_nameid_lid_add(nameid, 0x8105, PSETID_Task); 	// PT_SYSTIME - DueDate/TaskDueDate
+	mapi_nameid_lid_add(nameid, 0x810F, PSETID_Task); 	// PT_SYSTIME - DateCompleted
+//	mapi_nameid_lid_add(nameid, 0x8116, PSETID_Task); 	// PT_BINARY - (recurrence blob)
+	mapi_nameid_lid_add(nameid, 0x811C, PSETID_Task); 	// PT_BOOLEAN - Complete
+	mapi_nameid_lid_add(nameid, 0x811F, PSETID_Task); 	// PT_STRING8 - Owner
+	mapi_nameid_lid_add(nameid, 0x8121, PSETID_Task); 	// PT_STRING8 - Delegator
+	mapi_nameid_lid_add(nameid, 0x8126, PSETID_Task); 	// PT_BOOLEAN - IsRecurring/TaskFRecur
+	mapi_nameid_lid_add(nameid, 0x8127, PSETID_Task); 	// PT_STRING8 - Role
+	mapi_nameid_lid_add(nameid, 0x8129, PSETID_Task); 	// PT_LONG - Ownership
+	mapi_nameid_lid_add(nameid, 0x812A, PSETID_Task); 	// PT_LONG - DelegationState
+
+	/* These probably would never be used from Evolution */
+//	mapi_nameid_lid_add(nameid, 0x8110, PSETID_Task); 	// PT_LONG - ActualWork/TaskActualEffort
+//	mapi_nameid_lid_add(nameid, 0x8111, PSETID_Task); 	// PT_LONG - TotalWork/TaskEstimatedEffort
+
+	/* These probably would never be used from Evolution */
+//	mapi_nameid_lid_add(nameid, 0x8B00, PSETID_Note); 	// PT_LONG - Color
+
+	return TRUE;
+}
+
+static gboolean
+fetch_item_cb (FetchItemsCallbackData *item_data, gpointer data)
+{
+	long *flags;
+	struct FILETIME *delivery_date;
+	const char *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;
+
+
+	for (j = 0; j < item_data->properties->cValues; j++) {
+
+		gpointer prop_data = get_mapi_SPropValue_data(&item_data->properties->lpProps[j]);
+
+		switch (item_data->properties->lpProps[j].ulPropTag) {
+		/*FIXME : Instead of duping. Use talloc_steal to reuse the memory*/
+		case PR_NORMALIZED_SUBJECT:
+		case PR_NORMALIZED_SUBJECT_UNICODE :
+			item->header.subject = g_strdup (prop_data);
+			break;
+		case PR_DISPLAY_TO :
+		case PR_DISPLAY_TO_UNICODE :
+			item->header.to = g_strdup (prop_data);
+			break;
+		case PR_DISPLAY_CC:
+		case PR_DISPLAY_CC_UNICODE:
+			item->header.cc = g_strdup (prop_data);
+			break;
+		case PR_DISPLAY_BCC:
+		case PR_DISPLAY_BCC_UNICODE:
+			item->header.bcc = g_strdup (prop_data);
+			break;
+		case PR_SENT_REPRESENTING_NAME:
+		case PR_SENT_REPRESENTING_NAME_UNICODE:
+			item->header.from = g_strdup (prop_data);
+			break;
+		case PR_MESSAGE_SIZE:
+			item->header.size = *(glong *)prop_data;
+			break;
+		case PR_MESSAGE_CLASS:
+		case PR_MESSAGE_CLASS_UNICODE:
+			msg_class = (const char *) 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;
+		}
+	}
+
+	if (g_str_has_prefix (msg_class, IPM_SCHEDULE_MEETING_PREFIX)) {
+		gchar *appointment_body_str = (gchar *) exchange_mapi_cal_util_camel_helper (item_data->properties, 
+											     item_data->streams, 
+											     item_data->recipients, item_data->attachments);
+
+		body = g_new0(ExchangeMAPIStream, 1);
+		body->proptag = PR_BODY;
+		body->value = g_byte_array_new ();
+		body->value = g_byte_array_append (body->value, appointment_body_str, g_utf8_strlen (appointment_body_str, -1));
+
+		item->msg.body_parts = g_slist_append (item->msg.body_parts, body);
+
+		item->is_cal = TRUE;
+	} else { 
+		if (!((body = exchange_mapi_util_find_stream (item_data->streams, PR_HTML)) || 
+		      (body = exchange_mapi_util_find_stream (item_data->streams, PR_BODY))))
+			body = exchange_mapi_util_find_stream (item_data->streams, PR_BODY_UNICODE);
+
+		item->msg.body_parts = g_slist_append (item->msg.body_parts, body);
+
+		item->is_cal = FALSE;
+	}
+
+	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_msg_set_recipient_list (CamelMimeMessage *msg, MapiItem *item)
+{
+	CamelInternetAddress *addr = NULL;
+	{
+		char *tmp_addr = NULL;
+		int index, len;
+		
+		addr = camel_internet_address_new();
+		for (index = 0; item->header.to[index]; index += len){
+			if (item->header.to[index] == ';')
+				index++;
+			for (len = 0; item->header.to[index + len] &&
+				     item->header.to[index + len] != ';'; len++)
+				;
+			tmp_addr = malloc(/* tmp_addr, */ len + 1);
+			memcpy(tmp_addr, item->header.to + index, len);
+			tmp_addr[len] = 0;
+			if (len) camel_internet_address_add(addr, tmp_addr, tmp_addr);
+		}
+		if (index != 0)
+			camel_mime_message_set_recipients(msg, "To", addr);
+	}
+        /* modifing cc */
+	{
+		char *tmp_addr = NULL;
+		int index, len;
+		
+		addr = camel_internet_address_new();
+		for (index = 0; item->header.cc[index]; index += len){
+			if (item->header.cc[index] == ';')
+				index++;
+			for (len = 0; item->header.cc[index + len] &&
+				     item->header.cc[index + len] != ';'; len++)
+				;
+			tmp_addr = malloc(/* tmp_addr, */ len + 1);
+			memcpy(tmp_addr, item->header.cc + index, len);
+			tmp_addr[len] = 0;
+			if (len) camel_internet_address_add(addr, tmp_addr, tmp_addr);
+		}
+		if (index != 0)
+			camel_mime_message_set_recipients(msg, "Cc", addr);
+	}
+}
+
+
+static void
+mapi_populate_details_from_item (CamelMimeMessage *msg, MapiItem *item)
+{
+	char *temp_str = NULL;
+	time_t recieved_time;
+	CamelInternetAddress *addr = NULL;
+
+	temp_str = item->header.subject;
+	if(temp_str) 
+		camel_mime_message_set_subject (msg, temp_str);
+
+	recieved_time = item->header.recieved_time;
+
+	int offset = 0;
+	time_t actual_time = camel_header_decode_date (ctime(&recieved_time), &offset);
+	camel_mime_message_set_date (msg, actual_time, offset);
+
+	if (item->header.from) {
+		/* add reply to */
+		addr = camel_internet_address_new();
+		camel_internet_address_add(addr, item->header.from, item->header.from);
+		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);
+		camel_mime_message_set_from(msg, addr);
+	}
+}
+
+
+static void
+mapi_populate_msg_body_from_item (CamelMultipart *multipart, MapiItem *item, ExchangeMAPIStream *body)
+{
+	CamelMimePart *part;
+
+	part = camel_mime_part_new ();
+	camel_mime_part_set_encoding(part, CAMEL_TRANSFER_ENCODING_8BIT);
+	const char* type = NULL;
+	
+	if (body) { 
+		if (item->is_cal)
+			camel_mime_part_set_content(part, body->value->data, body->value->len, "text/calendar");
+		else {
+			type = (body->proptag == PR_BODY || body->proptag == PR_BODY_UNICODE) ? 
+				"text/plain" : "text/html";
+
+			camel_mime_part_set_content(part, body->value->data, body->value->len, type );
+		}
+	} else
+		camel_mime_part_set_content(part, " ", strlen(" "), "text/html");
+
+	camel_multipart_set_boundary (multipart, NULL);
+	camel_multipart_add_part (multipart, part);
+	camel_object_unref (part);
+}
+
+
+static CamelMimeMessage *
+mapi_folder_item_to_msg( CamelFolder *folder,
+		MapiItem *item,
+		CamelException *ex )
+{
+	CamelMimeMessage *msg = NULL;
+	CamelMultipart *multipart = NULL;
+
+	GSList *attach_list = NULL;
+	int errno;
+	/* char *body = NULL; */
+	ExchangeMAPIStream *body = NULL;
+	GSList *body_part_list = NULL;
+	const char *uid = NULL;
+
+	attach_list = item->attachments;
+
+	msg = camel_mime_message_new ();
+
+	multipart = camel_multipart_new ();
+
+	camel_mime_message_set_message_id (msg, uid);
+	body_part_list = item->msg.body_parts;
+	while (body_part_list){
+	       body = body_part_list->data;
+	       mapi_populate_msg_body_from_item (multipart, item, body);	       
+	       body_part_list = g_slist_next (body_part_list);
+	}
+
+
+	/*Set recipient details*/
+	mapi_msg_set_recipient_list (msg, item);
+	mapi_populate_details_from_item (msg, item);
+
+	if (attach_list) {
+		GSList *al = attach_list;
+		for (al = attach_list; al != NULL; al = al->next) {
+			ExchangeMAPIAttachment *attach = (ExchangeMAPIAttachment *)al->data;
+			ExchangeMAPIStream *stream = NULL;
+			const char *filename, *mime_type; 
+			CamelMimePart *part;
+
+			filename = (const char *) exchange_mapi_util_find_SPropVal_array_propval(attach->lpProps, PR_ATTACH_LONG_FILENAME);
+			if (!(filename && *filename))
+				filename = (const char *) exchange_mapi_util_find_SPropVal_array_propval(attach->lpProps, PR_ATTACH_FILENAME);
+
+			mime_type = (const char *) exchange_mapi_util_find_SPropVal_array_propval(attach->lpProps, PR_ATTACH_MIME_TAG);
+
+			stream = exchange_mapi_util_find_stream (attach->streams, PR_ATTACH_DATA_BIN);
+
+			if (!stream || stream->value->len <= 0) {
+				continue;
+			}
+			part = camel_mime_part_new ();
+
+			camel_mime_part_set_filename(part, g_strdup(filename));
+			//Auto generate content-id
+			camel_mime_part_set_content_id (part, NULL);
+			camel_mime_part_set_content(part, stream->value->data, stream->value->len, mime_type);
+			camel_content_type_set_param (((CamelDataWrapper *) part)->mime_type, "name", filename);
+
+			camel_multipart_set_boundary(multipart, NULL);
+			camel_multipart_add_part (multipart, part);
+			camel_object_unref (part);
+			
+		}
+		exchange_mapi_util_free_attachment_list (&attach_list);
+	}
+
+	camel_medium_set_content_object(CAMEL_MEDIUM (msg), CAMEL_DATA_WRAPPER(multipart));
+	camel_object_unref (multipart);
+
+	if (body)
+		g_free (body);
+
+	return msg;
+}
+
+
+static CamelMimeMessage *
+mapi_folder_get_message( CamelFolder *folder, const char *uid, CamelException *ex )
+{
+	CamelMimeMessage *msg = NULL;
+	CamelMapiFolder *mapi_folder = CAMEL_MAPI_FOLDER(folder);
+	CamelMapiStore *mapi_store = CAMEL_MAPI_STORE(folder->parent_store);
+	CamelMapiMessageInfo *mi = NULL;
+
+	CamelStream *stream, *cache_stream;
+	int errno;
+
+	/* see if it is there in cache */
+
+	mi = (CamelMapiMessageInfo *) camel_folder_summary_uid (folder->summary, uid);
+	if (mi == NULL) {
+		camel_exception_setv(ex, CAMEL_EXCEPTION_FOLDER_INVALID_UID,
+				_("Cannot get message: %s\n  %s"), uid, _("No such message"));
+		return NULL;
+	}
+	cache_stream  = camel_data_cache_get (mapi_folder->cache, "cache", uid, ex);
+	stream = camel_stream_mem_new ();
+	if (cache_stream) {
+		msg = camel_mime_message_new ();
+		camel_stream_reset (stream);
+		camel_stream_write_to_stream (cache_stream, stream);
+		camel_stream_reset (stream);
+		if (camel_data_wrapper_construct_from_stream ((CamelDataWrapper *) msg, stream) == -1) {
+			if (errno == EINTR) {
+				camel_exception_setv (ex, CAMEL_EXCEPTION_USER_CANCEL, _("User canceled"));
+				camel_object_unref (msg);
+				camel_object_unref (cache_stream);
+				camel_object_unref (stream);
+				camel_message_info_free (&mi->info);
+				return NULL;
+			} else {
+				camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, _("Cannot get message %s: %s"),
+						uid, g_strerror (errno));
+				camel_object_unref (msg);
+				msg = NULL;
+			}
+		}
+		camel_object_unref (cache_stream);
+	}
+	camel_object_unref (stream);
+
+	if (msg != NULL) {
+		camel_message_info_free (&mi->info);
+		return msg;
+	}
+
+	if (((CamelOfflineStore *) mapi_store)->state == CAMEL_OFFLINE_STORE_NETWORK_UNAVAIL) {
+		camel_exception_set (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE,
+				_("This message is not available in offline mode."));
+		camel_message_info_free (&mi->info);
+		return NULL;
+	}
+
+	/* Check if we are really offline */
+	if (!camel_mapi_store_connected (mapi_store, ex)) {
+		camel_exception_set (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE,
+				_("This message is not available in offline mode."));
+		camel_message_info_free (&mi->info);
+		return NULL;
+	}
+
+	mapi_id_t id_folder;
+	mapi_id_t id_message;
+	MapiItem *item = NULL;
+	guint32 options = 0;
+
+	options = MAPI_OPTIONS_FETCH_ALL | MAPI_OPTIONS_FETCH_BODY_STREAM | MAPI_OPTIONS_GETBESTBODY ;
+	exchange_mapi_util_mapi_ids_from_uid (uid, &id_folder, &id_message);
+
+	if (((CamelMapiFolder *)folder)->type == MAPI_FAVOURITE_FOLDER){
+		options |= MAPI_OPTIONS_USE_PFSTORE;
+	} 
+
+	exchange_mapi_connection_fetch_item (id_folder, id_message, 
+					camel_GetPropsList, G_N_ELEMENTS (camel_GetPropsList), 
+					camel_build_name_id, NULL, 
+					fetch_item_cb, &item, 
+					options);
+
+	if (item == NULL) {
+		camel_exception_set (ex, CAMEL_EXCEPTION_SERVICE_INVALID, _("Could not get message"));
+		camel_message_info_free (&mi->info);
+		return NULL;
+	}
+
+	msg = mapi_folder_item_to_msg (folder, item, ex);
+
+	g_free (item);
+
+	if (!msg) {
+		camel_exception_set (ex, CAMEL_EXCEPTION_SERVICE_INVALID, _("Could not get message"));
+		camel_message_info_free (&mi->info);
+
+		return NULL;
+	}
+
+	/* add to cache */
+	CAMEL_MAPI_FOLDER_REC_LOCK (folder, cache_lock);
+	if ((cache_stream = camel_data_cache_add (mapi_folder->cache, "cache", uid, NULL))) {
+		if (camel_data_wrapper_write_to_stream ((CamelDataWrapper *) msg, cache_stream) == -1
+				|| camel_stream_flush (cache_stream) == -1)
+			camel_data_cache_remove (mapi_folder->cache, "cache", uid, NULL);
+		camel_object_unref (cache_stream);
+	}
+
+	CAMEL_MAPI_FOLDER_REC_UNLOCK (folder, cache_lock);
+
+	camel_message_info_free (&mi->info);
+
+	return msg;
+}
+
+static void
+mapi_folder_search_free (CamelFolder *folder, GPtrArray *uids)
+{
+	CamelMapiFolder *mapi_folder = CAMEL_MAPI_FOLDER(folder);
+
+	g_return_if_fail (mapi_folder->search);
+
+	CAMEL_MAPI_FOLDER_LOCK(mapi_folder, search_lock);
+
+	camel_folder_search_free_result (mapi_folder->search, uids);
+
+	CAMEL_MAPI_FOLDER_UNLOCK(mapi_folder, search_lock);
+
+}
+
+static void
+camel_mapi_folder_finalize (CamelObject *object)
+{
+	CamelMapiFolder *mapi_folder = CAMEL_MAPI_FOLDER (object);
+
+	if (mapi_folder->priv)
+		g_free(mapi_folder->priv);
+	if (mapi_folder->cache)
+		camel_object_unref (mapi_folder->cache);
+}
+
+
+static CamelMessageInfo*
+mapi_get_message_info(CamelFolder *folder, const char *uid)
+{ 
+#if 0
+	CamelMessageInfo	*msg_info = NULL;
+	CamelMessageInfoBase	*mi = (CamelMessageInfoBase *)msg ;
+	int			status = 0;
+	oc_message_headers_t	headers;
+
+	if (folder->summary) {
+		msg_info = camel_folder_summary_uid(folder->summary, uid);
+	}
+	if (msg_info != NULL) {
+		mi = (CamelMessageInfoBase *)msg_info ;
+		return (msg_info);
+	}
+	msg_info = camel_message_info_new(folder->summary);
+	mi = (CamelMessageInfoBase *)msg_info ;
+	//TODO :
+/* 	oc_message_headers_init(&headers); */
+/* 	oc_thread_connect_lock(); */
+/* 	status = oc_message_headers_get_by_id(&headers, uid); */
+/* 	oc_thread_connect_unlock(); */
+
+	if (headers.subject) mi->subject = (char *)camel_pstring_strdup(headers.subject);
+	if (headers.from) mi->from = (char *)camel_pstring_strdup(headers.from);
+	if (headers.to) mi->to = (char *)camel_pstring_strdup(headers.to);
+	if (headers.cc) mi->cc = (char *)camel_pstring_strdup(headers.cc);
+	mi->flags = headers.flags;
+
+
+	mi->user_flags = NULL;
+	mi->user_tags = NULL;
+	mi->date_received = 0;
+	mi->date_sent = headers.send;
+	mi->content = NULL;
+	mi->summary = folder->summary;
+	if (uid) mi->uid = g_strdup(uid);
+	oc_message_headers_release(&headers);
+	return (msg);
+#endif
+	return NULL;
+}
+
+static void
+mapi_expunge (CamelFolder *folder, CamelException *ex)
+{
+	CamelMapiStore *mapi_store = CAMEL_MAPI_STORE(folder->parent_store);
+	CamelMapiFolder *mapi_folder = CAMEL_MAPI_FOLDER (folder);
+	CamelMapiMessageInfo *minfo;
+	CamelMessageInfo *info;
+	CamelFolderChangeInfo *changes;
+
+	mapi_id_t fid;
+
+	int i, count;
+	gboolean delete = FALSE, status = FALSE;
+	gchar *folder_id;
+	GSList *deleted_items, *deleted_head;
+	GSList *deleted_items_uid, *deleted_items_uid_head;
+
+	deleted_items = deleted_head = NULL;
+	deleted_items_uid = deleted_items_uid_head = NULL;
+
+	folder_id =  g_strdup (camel_mapi_store_folder_id_lookup (mapi_store, folder->full_name)) ;
+	exchange_mapi_util_mapi_id_from_string (folder_id, &fid);
+
+	if (mapi_folder->type & CAMEL_FOLDER_TYPE_TRASH) {
+		CAMEL_SERVICE_REC_LOCK (mapi_store, connect_lock);
+		status = exchange_mapi_empty_folder (fid);
+		CAMEL_SERVICE_REC_UNLOCK (mapi_store, connect_lock);
+
+		if (status) {
+			camel_folder_freeze (folder);
+			mapi_summary_clear (folder->summary, TRUE);
+			camel_folder_thaw (folder);
+		} else
+			g_warning ("Could not Empty Trash\n");
+
+		return;
+	}
+
+	changes = camel_folder_change_info_new ();
+	count = camel_folder_summary_count (folder->summary);
+
+	/*Collect UIDs of deleted messages.*/
+	for (i = 0; i < count; i++) {
+		info = camel_folder_summary_index (folder->summary, i);
+		minfo = (CamelMapiMessageInfo *) info;
+		if (minfo && (minfo->info.flags & CAMEL_MESSAGE_DELETED)) {
+			const gchar *uid = camel_message_info_uid (info);
+			mapi_id_t *mid = g_new0 (mapi_id_t, 1);
+
+			if (!exchange_mapi_util_mapi_ids_from_uid (uid, &fid, mid))
+				continue;
+			
+			if (deleted_items)
+				deleted_items = g_slist_prepend (deleted_items, mid);
+			else {
+				g_slist_free (deleted_head);
+				deleted_head = NULL;
+				deleted_head = deleted_items = g_slist_prepend (deleted_items, mid);
+			}
+			deleted_items_uid = g_slist_prepend (deleted_items_uid, uid);
+		}
+		camel_message_info_free (info);
+	}
+
+	deleted_items_uid_head = deleted_items_uid;
+
+	if (deleted_items) {
+		CAMEL_SERVICE_REC_LOCK (mapi_store, connect_lock);
+
+		status = exchange_mapi_remove_items(0, fid, deleted_items);
+
+		CAMEL_SERVICE_REC_UNLOCK (mapi_store, connect_lock);
+
+		if (status) {
+			while (deleted_items_uid) {
+				const gchar *uid = (gchar *)deleted_items_uid->data;
+				CAMEL_MAPI_FOLDER_REC_LOCK (folder, cache_lock);
+				camel_folder_change_info_remove_uid (changes, uid);
+				camel_folder_summary_remove_uid (folder->summary, uid);
+				camel_data_cache_remove(mapi_folder->cache, "cache", uid, NULL);
+				CAMEL_MAPI_FOLDER_REC_UNLOCK (folder, cache_lock);
+				deleted_items_uid = g_slist_next (deleted_items_uid);
+			}
+		}
+		delete = TRUE;
+
+		g_slist_foreach (deleted_head, (GFunc)g_free, NULL);
+		g_slist_free (deleted_head);
+		g_slist_free (deleted_items_uid_head);
+	}
+
+	if (delete)
+		camel_object_trigger_event (CAMEL_OBJECT (folder), "folder_changed", changes);
+
+	g_free (folder_id);
+	camel_folder_change_info_free (changes);
+}
+
+static void
+mapi_transfer_messages_to (CamelFolder *source, GPtrArray *uids, 
+		CamelFolder *destination, GPtrArray **transferred_uids, 
+		gboolean delete_originals, CamelException *ex)
+{
+	mapi_id_t src_fid, dest_fid;
+
+	CamelOfflineStore *offline = (CamelOfflineStore *) destination->parent_store;
+	CamelMapiStore *mapi_store= CAMEL_MAPI_STORE(source->parent_store);
+	CamelFolderChangeInfo *changes = NULL;
+
+	char *folder_id = NULL;
+	int i = 0;
+
+	GSList *src_msg_ids = NULL;
+
+
+	/* check for offline operation */
+	if (offline->state == CAMEL_OFFLINE_STORE_NETWORK_UNAVAIL) 
+		return;
+
+	folder_id =  camel_mapi_store_folder_id_lookup (mapi_store, source->full_name) ;
+	exchange_mapi_util_mapi_id_from_string (folder_id, &src_fid);
+
+	folder_id =  camel_mapi_store_folder_id_lookup (mapi_store, destination->full_name) ;
+	exchange_mapi_util_mapi_id_from_string (folder_id, &dest_fid);
+
+	for (i=0; i < uids->len; i++) {
+		mapi_id_t *mid = g_new0 (mapi_id_t, 1); /* FIXME : */
+		if (!exchange_mapi_util_mapi_ids_from_uid (g_ptr_array_index (uids, i), &src_fid, mid)) 
+			continue;
+
+		src_msg_ids = g_slist_prepend (src_msg_ids, mid);
+	}
+
+	if (delete_originals) {
+		if (!exchange_mapi_move_items (src_fid, dest_fid, src_msg_ids)) {
+			//TODO : Set exception. 
+		} else {
+			changes = camel_folder_change_info_new ();
+
+			for (i=0; i < uids->len; i++) {
+				camel_folder_summary_remove_uid (source->summary, uids->pdata[i]);
+				camel_folder_change_info_remove_uid (changes, uids->pdata[i]);
+			}
+			camel_object_trigger_event (source, "folder_changed", changes);
+			camel_folder_change_info_free (changes);
+
+		}
+	} else {
+		if (!exchange_mapi_copy_items (src_fid, dest_fid, src_msg_ids)) {
+			//TODO : Set exception. 
+		}
+	}
+
+	g_slist_foreach (src_msg_ids, (GFunc) g_free, NULL);
+	g_slist_free (src_msg_ids);
+
+	return;
+}
+
+static void
+camel_mapi_folder_class_init (CamelMapiFolderClass *camel_mapi_folder_class)
+{
+	CamelFolderClass *camel_folder_class = CAMEL_FOLDER_CLASS (camel_mapi_folder_class);
+
+	parent_class = CAMEL_OFFLINE_FOLDER_CLASS (camel_type_get_global_classfuncs (camel_offline_folder_get_type ()));
+
+	((CamelObjectClass *) camel_mapi_folder_class)->getv = mapi_getv;
+
+	camel_folder_class->get_message = mapi_folder_get_message;
+/*  	camel_folder_class->rename = mapi_folder_rename; */
+	camel_folder_class->search_by_expression = mapi_folder_search_by_expression;
+/* 	camel_folder_class->get_message_info = mapi_get_message_info; */
+/* 	camel_folder_class->search_by_uids = mapi_folder_search_by_uids;  */
+	camel_folder_class->search_free = mapi_folder_search_free;
+/* 	camel_folder_class->append_message = mapi_append_message; */
+	camel_folder_class->refresh_info = mapi_refresh_info;
+	camel_folder_class->sync = mapi_sync;
+	camel_folder_class->expunge = mapi_expunge;
+	camel_folder_class->transfer_messages_to = mapi_transfer_messages_to;
+}
+
+static void
+camel_mapi_folder_init (gpointer object, gpointer klass)
+{
+	CamelMapiFolder *mapi_folder = CAMEL_MAPI_FOLDER (object);
+	CamelFolder *folder = CAMEL_FOLDER (object);
+
+
+	folder->permanent_flags = CAMEL_MESSAGE_ANSWERED | CAMEL_MESSAGE_DELETED |
+		CAMEL_MESSAGE_DRAFT | CAMEL_MESSAGE_FLAGGED | CAMEL_MESSAGE_SEEN;
+
+	folder->folder_flags = CAMEL_FOLDER_HAS_SUMMARY_CAPABILITY | CAMEL_FOLDER_HAS_SEARCH_CAPABILITY;
+
+	mapi_folder->priv = g_malloc0 (sizeof(*mapi_folder->priv));
+
+#ifdef ENABLE_THREADS
+	g_static_mutex_init(&mapi_folder->priv->search_lock);
+	g_static_rec_mutex_init(&mapi_folder->priv->cache_lock);
+#endif
+
+	mapi_folder->need_rescan = TRUE;
+}
+
+CamelType
+camel_mapi_folder_get_type (void)
+{
+	static CamelType camel_mapi_folder_type = CAMEL_INVALID_TYPE;
+
+
+	if (camel_mapi_folder_type == CAMEL_INVALID_TYPE) {
+		camel_mapi_folder_type =
+			camel_type_register (camel_offline_folder_get_type (),
+					"CamelMapiFolder",
+					sizeof (CamelMapiFolder),
+					sizeof (CamelMapiFolderClass),
+					(CamelObjectClassInitFunc) camel_mapi_folder_class_init,
+					NULL,
+					(CamelObjectInitFunc) camel_mapi_folder_init,
+					(CamelObjectFinalizeFunc) camel_mapi_folder_finalize);
+	}
+
+	return camel_mapi_folder_type;
+}
+
+CamelFolder *
+camel_mapi_folder_new(CamelStore *store, const char *folder_name, const char *folder_dir, guint32 flags, CamelException *ex)
+{
+
+	CamelFolder	*folder = NULL;
+	CamelMapiFolder *mapi_folder;
+	CamelMapiStore  *mapi_store = (CamelMapiStore *) store;
+
+	char *summary_file, *state_file;
+	char *short_name;
+	guint32 i = 0;
+
+	folder = CAMEL_FOLDER (camel_object_new(camel_mapi_folder_get_type ()) );
+
+	mapi_folder = CAMEL_MAPI_FOLDER(folder);
+	short_name = strrchr (folder_name, '/');
+	if (short_name)
+		short_name++;
+	else
+		short_name = (char *) folder_name;
+	camel_folder_construct (folder, store, folder_name, short_name);
+
+	summary_file = g_strdup_printf ("%s/%s/summary",folder_dir, folder_name);
+
+	folder->summary = camel_mapi_summary_new(folder, summary_file);
+	g_free(summary_file);
+
+	if (!folder->summary) {
+		camel_object_unref (CAMEL_OBJECT (folder));
+		camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
+				_("Could not load summary for %s"),
+				folder_name);
+		return NULL;
+	}
+
+	/* set/load persistent state */
+	state_file = g_strdup_printf ("%s/cmeta", g_strdup_printf ("%s/%s",folder_dir, folder_name));
+	camel_object_set(folder, NULL, CAMEL_OBJECT_STATE_FILE, state_file, NULL);
+	g_free(state_file);
+	camel_object_state_read(folder);
+
+	mapi_folder->cache = camel_data_cache_new (g_strdup_printf ("%s/%s",folder_dir, folder_name),0 ,ex);
+	if (!mapi_folder->cache) {
+		camel_object_unref (folder);
+		return NULL;
+	}
+
+/* 	journal_file = g_strdup_printf ("%s/journal", g_strdup_printf ("%s-%s",folder_name, "dir")); */
+/* 	mapi_folder->journal = camel_mapi_journal_new (mapi_folder, journal_file); */
+/* 	g_free (journal_file); */
+/* 	if (!mapi_folder->journal) { */
+/* 		camel_object_unref (folder); */
+/* 		return NULL; */
+/* 	} */
+
+	if (!strcmp (folder_name, "Mailbox")) {
+		if (camel_url_get_param (((CamelService *) store)->url, "filter"))
+			folder->folder_flags |= CAMEL_FOLDER_FILTER_RECENT;
+	}
+
+	mapi_folder->search = camel_folder_search_new ();
+	if (!mapi_folder->search) {
+		camel_object_unref (folder);
+		return NULL;
+	}
+
+	for (i=0;i<camel_store_summary_count((CamelStoreSummary *)mapi_store->summary);i++) {
+		CamelStoreInfo *si = camel_store_summary_index((CamelStoreSummary *)mapi_store->summary, i);
+		if (si == NULL) 
+			continue;
+
+		if (!strcmp(folder_name, camel_mapi_store_info_full_name (mapi_store->summary, si))) {
+			mapi_folder->type = si->flags;
+		}
+
+		camel_store_summary_info_free((CamelStoreSummary *)mapi_store->summary, si);
+	}
+	return folder;
+}
+
+

Added: trunk/src/camel/camel-mapi-folder.h
==============================================================================
--- (empty file)
+++ trunk/src/camel/camel-mapi-folder.h	Wed Nov 19 04:28:20 2008
@@ -0,0 +1,133 @@
+/* -*- 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/>  
+ *
+ *
+ * Authors:
+ *     Johnny Jacob <jjohnny novell com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef __MAPI_FOLDER_H__
+#define __MAPI_FOLDER_H__
+
+
+#include <camel/camel-folder.h>
+#include <camel/camel-offline-folder.h>
+#include <camel/camel-data-cache.h>
+#include <camel/camel-offline-folder.h>
+#include <camel/camel-offline-journal.h>
+#include <libmapi/libmapi.h>
+#include <exchange-mapi-connection.h>
+
+#define PATH_FOLDER ".evolution/mail/mapi"
+
+#define CAMEL_MAPI_FOLDER_TYPE     (camel_mapi_folder_get_type ())
+#define CAMEL_MAPI_FOLDER(obj)     (CAMEL_CHECK_CAST((obj), CAMEL_MAPI_FOLDER_TYPE, CamelMapiFolder))
+#define CAMEL_MAPI_FOLDER_CLASS(k) (CAMEL_CHECK_CLASS_CAST ((k), CAMEL_MAPI_FOLDER_TYPE, CamelMapiFolderClass))
+#define CAMEL_IS_MAPI_FOLDER(o)    (CAMEL_CHECK_TYPE((o), CAMEL_MAPI_FOLDER_TYPE))
+
+/**
+ * DATA STRUCTURES
+ */
+
+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 *to;
+	gchar *cc;
+	gchar *bcc;
+
+	int flags;
+	glong size;
+	time_t recieved_time;
+	time_t send_time;
+} 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 *attachments;
+	GSList *generic_streams;
+}MapiItem;
+
+
+typedef struct  _CamelMapiFolder CamelMapiFolder;
+typedef struct  _CamelMapiFolderClass CamelMapiFolderClass;
+
+struct _CamelMapiFolder {
+	CamelOfflineFolder parent_object;
+
+	struct _CamelMapiFolderPrivate *priv;
+
+	CamelFolderSearch *search;
+
+	CamelOfflineJournal *journal;
+	CamelDataCache *cache;
+
+	guint32 type;
+
+	unsigned int need_rescan:1;
+	unsigned int need_refresh:1;
+	unsigned int read_only:1;
+};
+
+struct _CamelMapiFolderClass {
+	CamelOfflineFolderClass parent_class;
+
+	/* Virtual methods */	
+	
+} ;
+
+
+/* Standard Camel function */
+CamelType camel_mapi_folder_get_type (void);
+
+/* implemented */
+CamelFolder *
+camel_mapi_folder_new(CamelStore *store, const char *folder_name, const char *folder_dir, guint32 flags, CamelException *ex);
+
+void mapi_update_summary ( CamelFolder *folder, GList *item_list,CamelException *ex) ;
+void mapi_refresh_folder(CamelFolder *folder, CamelException *ex);
+
+G_END_DECLS
+
+#endif /* CAMEL_GROUPWISE_FOLDER_H */

Added: trunk/src/camel/camel-mapi-private.h
==============================================================================
--- (empty file)
+++ trunk/src/camel/camel-mapi-private.h	Wed Nov 19 04:28:20 2008
@@ -0,0 +1,50 @@
+/* -*- 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/>  
+ *
+ *
+ * Authors:
+ *     Johnny Jacob <jjohnny novell com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef CAMEL_MAPI_PRIVATE_H
+#define CAMEL_MAPI_PRIVATE_H 1
+
+/* need a way to configure and save this data, if this header is to
+   be installed.  For now, dont install it */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+//#ifdef ENABLE_THREADS
+#define CAMEL_MAPI_FOLDER_LOCK(f, l) \
+	(g_static_mutex_lock(&((CamelMapiFolder *)f)->priv->l))
+#define CAMEL_MAPI_FOLDER_UNLOCK(f, l) \
+	(g_static_mutex_unlock(&((CamelMapiFolder *)f)->priv->l))
+#define CAMEL_MAPI_FOLDER_REC_LOCK(f, l) \
+	(g_static_rec_mutex_lock(&((CamelMapiFolder *)f)->priv->l))
+#define CAMEL_MAPI_FOLDER_REC_UNLOCK(f, l) \
+	(g_static_rec_mutex_unlock(&((CamelMapiFolder *)f)->priv->l))
+//#else
+#define MAPI_FOLDER_LOCK(f, l)
+#define MAPI_FOLDER_UNLOCK(f, l)
+#define MAPI_FOLDER_REC_LOCK(f, l)
+#define MAPI_FOLDER_REC_UNLOCK(f, l)
+//#endif
+
+#endif /* CAMEL_IMAP_PRIVATE_H */

Added: trunk/src/camel/camel-mapi-provider.c
==============================================================================
--- (empty file)
+++ trunk/src/camel/camel-mapi-provider.c	Wed Nov 19 04:28:20 2008
@@ -0,0 +1,191 @@
+/* -*- 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/>  
+ *
+ *
+ * Authors:
+ *     Johnny Jacob <jjohnny novell com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <sys/types.h>
+#include <string.h>
+
+#include <gmodule.h>
+
+#include <camel/camel-provider.h>
+#include <camel/camel-session.h>
+#include <camel/camel-url.h>
+#include <camel/camel-sasl.h>
+#include <camel/camel-i18n.h>
+
+#include "camel-mapi-store.h"
+#include "camel-mapi-transport.h"
+
+#define d(x) x
+
+static void add_hash (guint *, char *);
+static guint mapi_url_hash (gconstpointer);
+static gint check_equal (char *, char *);
+static gint mapi_url_equal (gconstpointer, gconstpointer);
+
+static CamelProviderConfEntry mapi_conf_entries[] = {
+	{ CAMEL_PROVIDER_CONF_SECTION_START, "mailcheck", NULL,
+	  N_("Checking for New Mail") },
+	{ CAMEL_PROVIDER_CONF_CHECKBOX, "check_all", NULL,
+	  N_("C_heck for new messages in all folders"), "1" },
+	{ CAMEL_PROVIDER_CONF_SECTION_END },
+
+/* 	/\* override the labels/defaults of the standard settings *\/ */
+/* 	{ CAMEL_PROVIDER_CONF_LABEL, "username", NULL, */
+/* 	  /\* i18n: the '_' should appear before the same letter it */
+/* 	     does in the evolution:mail-config.glade "User_name" */
+/* 	     translation (or not at all) *\/ */
+/* 	  N_("Windows User_name:") }, */
+
+	/* extra Exchange configuration settings */
+	{ CAMEL_PROVIDER_CONF_SECTION_START, "activedirectory", NULL,
+	  /* i18n: GAL is an Outlookism, AD is a Windowsism */
+	  N_("Global Address List / Active Directory") },
+	{ CAMEL_PROVIDER_CONF_ENTRY, "ad_server", NULL,
+	  /* i18n: "Global Catalog" is a Windowsism, but it's a
+	     technical term and may not have translations? */
+	  N_("_Global Catalog server name:") },
+	{ CAMEL_PROVIDER_CONF_CHECKSPIN, "ad_limit", NULL,
+	  N_("_Limit number of GAL responses: %s"), "y:1:500:10000" },
+	{ CAMEL_PROVIDER_CONF_SECTION_END },
+	{ CAMEL_PROVIDER_CONF_SECTION_START, "generals", NULL,
+	  N_("Options") },
+	{ CAMEL_PROVIDER_CONF_CHECKBOX, "sync_offline", NULL,
+	  N_("Automatically synchroni_ze account locally"), "0" },
+	{ CAMEL_PROVIDER_CONF_CHECKBOX, "filter", NULL,
+	  /* i18n: copy from evolution:camel-imap-provider.c */
+	  N_("_Apply filters to new messages in Inbox on this server"), "0" },
+	{ CAMEL_PROVIDER_CONF_CHECKBOX, "filter_junk", NULL,
+	  N_("Check new messages for _Junk contents"), "0" },
+	{ CAMEL_PROVIDER_CONF_CHECKBOX, "filter_junk_inbox", "filter_junk",
+	  N_("Only check for Junk messag_es in the Inbox folder"), "0" },
+
+	 	
+	{ CAMEL_PROVIDER_CONF_SECTION_END },
+	{ CAMEL_PROVIDER_CONF_END }
+};
+
+static CamelProvider mapi_provider = {
+	"mapi",	
+
+	"Exchange MAPI", 
+
+	N_("For accessing Microsoft Exchange / OpenChange servers using MAPI"),	
+
+	"mail",	
+
+	CAMEL_PROVIDER_IS_REMOTE | CAMEL_PROVIDER_IS_SOURCE |
+	CAMEL_PROVIDER_IS_STORAGE | CAMEL_PROVIDER_DISABLE_SENT_FOLDER | CAMEL_PROVIDER_IS_EXTERNAL, 
+
+	CAMEL_URL_NEED_USER | CAMEL_URL_NEED_HOST,
+
+	mapi_conf_entries,
+
+	/* ... */
+};
+
+CamelServiceAuthType camel_mapi_password_authtype = {
+	N_("Password"),
+	N_("This option will connect to the Openchange server using a plaintext password."),
+	"",
+	TRUE
+};
+
+static int 
+mapi_auto_detect_cb(CamelURL *url, GHashTable **auto_detected, CamelException *ex)
+{
+        d (printf("mapi_auto_detect_cb\n"));
+	*auto_detected = g_hash_table_new (g_str_hash, g_str_equal);
+	g_hash_table_insert (*auto_detected, g_strdup ("poa"), g_strdup (url->host));
+
+	return 0;
+}
+
+void
+camel_provider_module_init(void)
+{
+	mapi_provider.name = "Exchange MAPI";
+	mapi_provider.auto_detect = mapi_auto_detect_cb;
+	mapi_provider.authtypes = g_list_prepend (mapi_provider.authtypes, &camel_mapi_password_authtype);
+	mapi_provider.url_hash = mapi_url_hash;
+	mapi_provider.url_equal = mapi_url_equal;
+	mapi_provider.license = "LGPL";
+	mapi_provider.object_types[CAMEL_PROVIDER_STORE] = camel_mapi_store_get_type();
+	mapi_provider.object_types[CAMEL_PROVIDER_TRANSPORT] = camel_mapi_transport_get_type();
+	camel_provider_register (&mapi_provider);
+}
+
+static void
+add_hash(guint *hash, char *s)
+{
+	if (s) {
+		*hash ^= g_str_hash(s);
+	}
+}
+
+static guint
+mapi_url_hash(gconstpointer key)
+{
+	const CamelURL	*u = (CamelURL *)key;
+	guint		hash = 0;
+
+	add_hash (&hash, u->user);
+	add_hash (&hash, u->authmech);
+	add_hash (&hash, u->host);
+	hash ^= u->port;
+
+	return hash;
+}
+
+static gint
+check_equal(char *s1, char *s2)
+{
+	if (s1 == NULL) {
+		if (s2 == NULL) {
+			return TRUE;
+		} else {
+			return FALSE;
+		}
+	}
+	if (s2 == NULL) {
+		return FALSE;
+	}
+
+	return strcmp (s1, s2) == 0;
+}
+
+static gint
+mapi_url_equal (gconstpointer a, gconstpointer b)
+{
+	const CamelURL	*u1 = a;
+	const CamelURL	*u2 = b;
+  
+	return check_equal (u1->protocol, u2->protocol)
+		&& check_equal (u1->user, u2->user)
+		&& check_equal (u1->authmech, u2->authmech)
+		&& check_equal (u1->host, u2->host)
+		&& u1->port == u2->port;
+}

Added: trunk/src/camel/camel-mapi-store-summary.c
==============================================================================
--- (empty file)
+++ trunk/src/camel/camel-mapi-store-summary.c	Wed Nov 19 04:28:20 2008
@@ -0,0 +1,315 @@
+/* -*- 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/>  
+ *
+ *
+ * Authors:
+ *     Johnny Jacob <jjohnny novell com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#include <ctype.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <glib.h>
+
+#include <libedataserver/e-memory.h>
+#include <libedataserver/md5-utils.h>
+
+#include <camel/camel-file-utils.h>
+#include <camel/camel-utf8.h>
+
+#include "camel-private.h"
+#include "camel-mapi-store.h"
+#include "camel-mapi-store-summary.h"
+
+#define d(x) 
+
+static int summary_header_load(CamelStoreSummary *, FILE *);
+static int summary_header_save(CamelStoreSummary *, FILE *);
+
+static CamelStoreInfo *store_info_load(CamelStoreSummary *s, FILE *in) ;
+static int store_info_save(CamelStoreSummary *s, FILE *out, CamelStoreInfo *mi) ;
+static void store_info_free(CamelStoreSummary *s, CamelStoreInfo *mi) ;
+static void store_info_set_string(CamelStoreSummary *s, CamelStoreInfo *mi, int type, const char *str) ;
+
+static const char *store_info_string(CamelStoreSummary *s, const CamelStoreInfo *mi, int type) ;
+
+static void camel_mapi_store_summary_class_init (CamelMapiStoreSummaryClass *klass);
+static void camel_mapi_store_summary_init       (CamelMapiStoreSummary *obj);
+static void camel_mapi_store_summary_finalise   (CamelObject *obj);
+
+static CamelStoreSummaryClass *camel_mapi_store_summary_parent;
+
+
+static void
+camel_mapi_store_summary_class_init (CamelMapiStoreSummaryClass *klass)
+{
+	CamelStoreSummaryClass *ssklass = (CamelStoreSummaryClass *)klass;
+
+	ssklass->summary_header_load = summary_header_load;
+	ssklass->summary_header_save = summary_header_save;
+	
+	ssklass->store_info_load = store_info_load;
+	ssklass->store_info_save = store_info_save;
+	ssklass->store_info_free = store_info_free;
+
+	ssklass->store_info_string = store_info_string;
+	ssklass->store_info_set_string = store_info_set_string;
+
+
+}
+
+static void
+camel_mapi_store_summary_init (CamelMapiStoreSummary *s)
+{
+
+	((CamelStoreSummary *)s)->store_info_size = sizeof(CamelMapiStoreInfo);
+	s->version = CAMEL_MAPI_STORE_SUMMARY_VERSION;
+}
+
+
+static void
+camel_mapi_store_summary_finalise (CamelObject *obj)
+{
+}
+
+
+CamelType
+camel_mapi_store_summary_get_type (void)
+{
+	static CamelType type = CAMEL_INVALID_TYPE;
+
+	if (type == CAMEL_INVALID_TYPE) {
+		camel_mapi_store_summary_parent = (CamelStoreSummaryClass *)camel_store_summary_get_type();
+		type = camel_type_register((CamelType)camel_mapi_store_summary_parent, "CamelMapiStoreSummary",
+				sizeof (CamelMapiStoreSummary),
+				sizeof (CamelMapiStoreSummaryClass),
+				(CamelObjectClassInitFunc) camel_mapi_store_summary_class_init,
+				NULL,
+				(CamelObjectInitFunc) camel_mapi_store_summary_init,
+				(CamelObjectFinalizeFunc) camel_mapi_store_summary_finalise);
+	}
+
+	return type;
+}
+
+
+CamelMapiStoreSummary *
+camel_mapi_store_summary_new (void)
+{
+	CamelMapiStoreSummary *new = CAMEL_MAPI_STORE_SUMMARY ( camel_object_new (camel_mapi_store_summary_get_type ()));
+
+	return new;
+}
+
+
+static int
+summary_header_load(CamelStoreSummary *s, FILE *in)
+{
+	CamelMapiStoreSummary *summary = (CamelMapiStoreSummary *)s ;
+
+	/* TODO */
+	if (camel_mapi_store_summary_parent->summary_header_load ((CamelStoreSummary *)s, in) == -1)
+			/* || camel_file_util_decode_fixed_int32(in, &version) == -1) */
+		return -1 ;
+
+	summary->version = 0 ;
+
+	return 0 ;
+}
+
+
+static int
+summary_header_save(CamelStoreSummary *s, FILE *out)
+{
+
+	if (camel_mapi_store_summary_parent->summary_header_save((CamelStoreSummary *)s, out) == -1)
+		return -1;
+
+	return 0 ;
+}
+
+static CamelStoreInfo *
+store_info_load(CamelStoreSummary *s, FILE *in)
+{
+	CamelMapiStoreInfo *si;
+
+	si = (CamelMapiStoreInfo *)camel_mapi_store_summary_parent->store_info_load(s, in);
+	if (si) {
+		if (camel_file_util_decode_string(in, &si->full_name) == -1) {
+			camel_store_summary_info_free(s, (CamelStoreInfo *)si);
+			si = NULL;
+		}
+	}
+	return (CamelStoreInfo *)si;
+}
+
+static int
+store_info_save(CamelStoreSummary *s, FILE *out, CamelStoreInfo *mi)
+{
+	CamelMapiStoreInfo *summary = (CamelMapiStoreInfo *)mi;
+	if (camel_mapi_store_summary_parent->store_info_save(s, out, mi) == -1
+	    || camel_file_util_encode_string(out, summary->full_name) == -1) 
+		return -1;
+
+	return 0;
+}
+
+
+static void
+store_info_free(CamelStoreSummary *s, CamelStoreInfo *mi)
+{
+	CamelMapiStoreInfo *si = (CamelMapiStoreInfo *)mi;
+
+	g_free(si->full_name);
+	camel_mapi_store_summary_parent->store_info_free(s, mi);
+}
+
+
+
+
+
+static const char *
+store_info_string(CamelStoreSummary *s, const CamelStoreInfo *mi, int type)
+{
+	CamelMapiStoreInfo *isi = (CamelMapiStoreInfo *)mi;
+
+	/* FIXME: Locks? */
+
+	g_assert (mi != NULL);
+
+	switch (type) {
+		case CAMEL_STORE_INFO_LAST:
+			return isi->full_name;
+		default:
+			return camel_mapi_store_summary_parent->store_info_string(s, mi, type);
+	}
+}
+
+static void
+store_info_set_string(CamelStoreSummary *s, CamelStoreInfo *mi, int type, const char *str)
+{
+	CamelMapiStoreInfo *isi = (CamelMapiStoreInfo *)mi;
+
+	g_assert(mi != NULL);
+
+	switch(type) {
+		case CAMEL_STORE_INFO_LAST:
+			d(printf("Set full name %s -> %s\n", isi->full_name, str));
+			CAMEL_STORE_SUMMARY_LOCK(s, summary_lock);
+			g_free(isi->full_name);
+			isi->full_name = g_strdup(str);
+			CAMEL_STORE_SUMMARY_UNLOCK(s, summary_lock);
+			break;
+		default:
+			camel_mapi_store_summary_parent->store_info_set_string(s, mi, type, str);
+			break;
+	}
+}
+
+CamelMapiStoreInfo *
+camel_mapi_store_summary_full_name(CamelMapiStoreSummary *s, const char *full_name)
+{
+	int count, i;
+	CamelMapiStoreInfo *info;
+
+	count = camel_store_summary_count((CamelStoreSummary *)s);
+	for (i=0;i<count;i++) {
+		info = (CamelMapiStoreInfo *)camel_store_summary_index((CamelStoreSummary *)s, i);
+		if (info) {
+			if (strcmp(info->full_name, full_name) == 0)
+				return info;
+			camel_store_summary_info_free((CamelStoreSummary *)s, (CamelStoreInfo *)info);
+		}
+	}
+
+	return NULL;
+
+}
+
+char *
+camel_mapi_store_summary_full_to_path(CamelMapiStoreSummary *s, const char *full_name, char dir_sep)
+{
+	char *path, *p;
+	int c;
+	const char *f;
+
+	if (dir_sep != '/') {
+		p = path = alloca(strlen(full_name)*3+1);
+		f = full_name;
+		while ( (c = *f++ & 0xff) ) {
+			if (c == dir_sep)
+				*p++ = '/';
+//FIXME : why ?? :(
+/* 			else if (c == '/' || c == '%') */
+/* 				p += sprintf(p, "%%%02X", c); */
+			else
+				*p++ = c;
+		}
+		*p = 0;
+	} else
+		path = (char *)full_name;
+
+	return g_strdup (path);
+}
+
+
+CamelMapiStoreInfo *
+camel_mapi_store_summary_add_from_full(CamelMapiStoreSummary *s, const char *full, char dir_sep)
+{
+	CamelMapiStoreInfo *info;
+	char *pathu8;
+	int len;
+	char *full_name;
+
+	d(printf("adding full name '%s' '%c'\n", full, dir_sep));
+	len = strlen(full);
+	full_name = alloca(len+1);
+	strcpy(full_name, full);
+
+	if (full_name[len-1] == dir_sep)
+		full_name[len-1] = 0;
+
+	info = camel_mapi_store_summary_full_name(s, full_name);
+	if (info) {
+		camel_store_summary_info_free((CamelStoreSummary *)s, (CamelStoreInfo *)info);
+		d(printf("  already there\n"));
+		return info;
+	}
+	pathu8 = camel_mapi_store_summary_full_to_path(s, full_name, '/');
+	info = (CamelMapiStoreInfo *)camel_store_summary_add_from_path((CamelStoreSummary *)s, pathu8);
+	if (info) 
+		camel_store_info_set_string((CamelStoreSummary *)s, (CamelStoreInfo *)info, CAMEL_STORE_INFO_LAST, full_name);
+
+	return info;
+}
+
+char *
+camel_mapi_store_summary_full_from_path(CamelMapiStoreSummary *s, const char *path)
+{
+	char *name = NULL;
+
+/* 	ns = camel_mapi_store_summary_namespace_find_path(s, path); */
+/* 	if (ns) */
+/* 		name = camel_mapi_store_summary_path_to_full(s, path, ns->sep); */
+
+	d(printf("looking up path %s -> %s\n", path, name?name:"not found"));
+
+	return name;
+}

Added: trunk/src/camel/camel-mapi-store-summary.h
==============================================================================
--- (empty file)
+++ trunk/src/camel/camel-mapi-store-summary.h	Wed Nov 19 04:28:20 2008
@@ -0,0 +1,80 @@
+/* -*- 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/>  
+ *
+ *
+ * Authors:
+ *     Johnny Jacob <jjohnny novell com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef _CAMEL_MAPI_STORE_SUMMARY_H
+#define _CAMEL_MAPI_STORE_SUMMARY_H
+
+#include <camel/camel-object.h>
+#include <camel/camel-store-summary.h>
+
+#define CAMEL_MAPI_STORE_SUMMARY_VERSION (0)
+
+#define CAMEL_MAPI_STORE_SUMMARY(obj)         CAMEL_CHECK_CAST (obj, camel_mapi_store_summary_get_type (), CamelMapiStoreSummary)
+#define CAMEL_MAPI_STORE_SUMMARY_CLASS(klass) CAMEL_CHECK_CLASS_CAST (klass, camel_mapi_store_summary_get_type (), CamelMapiStoreSummaryClass)
+#define CAMEL_IS_MAPI_STORE_SUMMARY(obj)      CAMEL_CHECK_TYPE (obj, camel_mapi_store_summary_get_type ())
+
+G_BEGIN_DECLS
+
+typedef struct _CamelMapiStoreSummary      CamelMapiStoreSummary;
+typedef struct _CamelMapiStoreSummaryClass CamelMapiStoreSummaryClass;
+
+typedef struct _CamelMapiStoreInfo CamelMapiStoreInfo;
+
+enum {
+	CAMEL_MAPI_STORE_INFO_FULL_NAME = CAMEL_STORE_INFO_LAST,
+	CAMEL_MAPI_STORE_INFO_LAST,
+};
+
+struct _CamelMapiStoreInfo {
+	CamelStoreInfo info;
+	char *full_name;
+};
+
+struct _CamelMapiStoreSummary {
+	CamelStoreSummary summary;
+
+	struct _CamelMapiStoreSummaryPrivate *priv;
+
+	/* header info */
+	guint32 version;        /* version of base part of file */
+	guint32 capabilities;
+};
+
+struct _CamelMapiStoreSummaryClass {
+	CamelStoreSummaryClass summary_class;
+};
+
+CamelType                        camel_mapi_store_summary_get_type      (void);
+CamelMapiStoreSummary      *camel_mapi_store_summary_new        (void);
+CamelMapiStoreInfo *camel_mapi_store_summary_full_name(CamelMapiStoreSummary *s, const char *full_name) ;
+CamelMapiStoreInfo *camel_mapi_store_summary_add_from_full(CamelMapiStoreSummary *s, const char *full, char dir_sep) ;
+
+char *camel_mapi_store_summary_full_to_path(CamelMapiStoreSummary *s, const char *full_name, char dir_sep) ;
+char *camel_mapi_store_summary_path_to_full(CamelMapiStoreSummary *s, const char *path, char dir_sep) ;
+char *camel_mapi_store_summary_full_from_path(CamelMapiStoreSummary *s, const char *path) ;
+
+#define camel_mapi_store_info_full_name(s, i) (camel_store_info_string((CamelStoreSummary *)s, (const CamelStoreInfo *)i, CAMEL_STORE_INFO_LAST))
+
+G_END_DECLS
+
+#endif /* ! _CAMEL_MAPI_STORE_SUMMARY_H */

Added: trunk/src/camel/camel-mapi-store.c
==============================================================================
--- (empty file)
+++ trunk/src/camel/camel-mapi-store.c	Wed Nov 19 04:28:20 2008
@@ -0,0 +1,1351 @@
+/* -*- 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/>  
+ *
+ *
+ * Authors:
+ *     Johnny Jacob <jjohnny novell com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+
+#include <glib/gstdio.h>
+
+#include <camel/camel-sasl.h>
+#include <camel/camel-utf8.h>
+#include <camel/camel-tcp-stream-raw.h>
+
+#ifdef HAVE_SSL
+#include <camel/camel-tcp-stream-ssl.h>
+#endif
+
+#include <camel/camel-private.h>
+#include <camel/camel-session.h>
+#include <camel/camel-service.h>
+#include <camel/camel-store-summary.h>
+#include <camel/camel-i18n.h>
+#include <camel/camel-net-utils.h>
+
+#include "camel-mapi-store.h"
+#include "camel-mapi-folder.h"
+#include "camel-mapi-store-summary.h"
+#include "camel-mapi-summary.h"
+
+#include <exchange-mapi-utils.h>
+//#define d(x) x
+
+/* This definition should be in-sync with those in exchange-mapi-account-setup.c and exchange-account-listener.c */
+#define E_PASSWORD_COMPONENT "ExchangeMAPI"
+
+#define DISPLAY_NAME_FAVOURITES _("Favourites")
+#define DISPLAY_NAME_ALL_PUBLIC_FOLDERS _("All Public Folders")
+
+#include <sys/types.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <libmapi/libmapi.h>
+#include <param.h>
+
+#define d(x) printf("%s(%d):%s:%s \n", __FILE__, __LINE__, __PRETTY_FUNCTION__, x)
+
+struct _CamelMapiStorePrivate {
+	char *user;
+	const char *profile;
+	char *base_url;
+	char *storage_path;
+
+	GHashTable *id_hash; /*get names from ids*/
+	GHashTable *name_hash;/*get ids from names*/
+	GHashTable *parent_hash;
+	GHashTable *default_folders; /*Default Type : Folder ID*/
+};
+
+static CamelOfflineStoreClass *parent_class = NULL;
+
+static void	camel_mapi_store_class_init(CamelMapiStoreClass *);
+CamelType	camel_mapi_store_get_type(void);
+static void	camel_mapi_store_init(CamelMapiStore *, CamelMapiStoreClass *);
+static void	camel_mapi_store_finalize(CamelObject *);
+
+/* service methods */
+static void	mapi_construct(CamelService *, CamelSession *,
+				     CamelProvider *, CamelURL *,
+				     CamelException *);
+static char	*mapi_get_name(CamelService *, gboolean );
+static gboolean	mapi_connect(CamelService *, CamelException *);
+static gboolean	mapi_disconnect(CamelService *, gboolean , CamelException *);
+static GList	*mapi_query_auth_types(CamelService *, CamelException *);
+
+/* store methods */
+static CamelFolder	*mapi_get_folder(CamelStore *, const char *, guint32, CamelException *);
+static CamelFolderInfo	*mapi_create_folder(CamelStore *, const char *, const char *, CamelException *);
+static void		mapi_delete_folder(CamelStore *, const char *, CamelException *);
+static void		mapi_rename_folder(CamelStore *, const char *, const char *, CamelException *);
+static CamelFolderInfo	*mapi_get_folder_info(CamelStore *, const char *, guint32, CamelException *);
+static void		mapi_subscribe_folder(CamelStore *, const char *, CamelException *);
+static gboolean mapi_folder_subscribed (CamelStore *store, const char *folder_name);
+static void		mapi_unsubscribe_folder(CamelStore *, const char *, CamelException *);
+static void		mapi_noop(CamelStore *, CamelException *);
+static CamelFolderInfo * mapi_build_folder_info(CamelMapiStore *mapi_store, const char *parent_name, const char *folder_name);
+static void mapi_folders_sync (CamelMapiStore *store, CamelException *ex);
+static gboolean mapi_fid_is_system_folder (CamelMapiStore *mapi_store, const char *fid);
+
+static guint
+mapi_hash_folder_name(gconstpointer key)
+{
+	return g_str_hash(key);
+}
+
+static gint
+mapi_compare_folder_name(gconstpointer a, gconstpointer b)
+{
+	gconstpointer	aname = a; 
+	gconstpointer	bname = b;
+  
+	return g_str_equal(aname, bname);
+}
+
+static void
+camel_mapi_store_class_init(CamelMapiStoreClass *klass)
+{
+	CamelServiceClass	*service_class = 
+		CAMEL_SERVICE_CLASS (klass);
+	CamelStoreClass		*store_class = (CamelStoreClass *) klass;
+
+	parent_class = (CamelOfflineStoreClass *) camel_type_get_global_classfuncs(CAMEL_TYPE_OFFLINE_STORE);
+
+	service_class->construct = mapi_construct;
+	service_class->get_name = mapi_get_name;
+	service_class->connect = mapi_connect;
+	service_class->disconnect = mapi_disconnect;
+	service_class->query_auth_types = mapi_query_auth_types;
+
+	store_class->hash_folder_name = mapi_hash_folder_name;
+	store_class->compare_folder_name = mapi_compare_folder_name;
+	/* store_class->get_inbox = mapi_get_inbox; */
+	store_class->get_folder = mapi_get_folder;
+	store_class->create_folder = mapi_create_folder;
+	store_class->delete_folder = mapi_delete_folder;
+	store_class->rename_folder = mapi_rename_folder;
+	store_class->get_folder_info = mapi_get_folder_info;
+	store_class->subscribe_folder = mapi_subscribe_folder;
+	store_class->folder_subscribed = mapi_folder_subscribed;
+	store_class->unsubscribe_folder = mapi_unsubscribe_folder;
+	store_class->noop = mapi_noop;
+}
+
+CamelType 
+camel_mapi_store_get_type(void)
+{
+	static CamelType camel_mapi_store_type = CAMEL_INVALID_TYPE;
+  
+	if (camel_mapi_store_type == CAMEL_INVALID_TYPE) {
+		camel_mapi_store_type = camel_type_register(camel_offline_store_get_type (),
+							    "CamelMapiStores",
+							    sizeof (CamelMapiStore),
+							    sizeof (CamelMapiStoreClass),
+							    (CamelObjectClassInitFunc) camel_mapi_store_class_init,
+							    NULL,
+							    (CamelObjectInitFunc) camel_mapi_store_init,
+							    (CamelObjectFinalizeFunc) camel_mapi_store_finalize);
+	}
+
+	return camel_mapi_store_type;
+}
+
+/*
+** store is already initilyse to NULL or 0 value
+** klass already have a parent_class
+** nothing must be doing here
+*/
+static void camel_mapi_store_init(CamelMapiStore *store, CamelMapiStoreClass *klass)
+{
+	CamelMapiStore *mapi_store = CAMEL_MAPI_STORE (store);
+	CamelMapiStorePrivate *priv = g_new0 (CamelMapiStorePrivate, 1);
+
+	mapi_store->summary = NULL;
+
+	priv->storage_path = NULL;
+	priv->base_url = NULL;
+
+	mapi_store->priv = priv;
+
+}
+
+static void camel_mapi_store_finalize(CamelObject *object)
+{
+}
+
+/* service methods */
+static void mapi_construct(CamelService *service, CamelSession *session,
+				 CamelProvider *provider, CamelURL *url,
+				 CamelException *ex)
+{
+	CamelMapiStore	*mapi_store = CAMEL_MAPI_STORE (service);
+	CamelStore *store = CAMEL_STORE (service);
+	CamelMapiStorePrivate *priv = mapi_store->priv;
+	char *path = NULL;
+	
+	CAMEL_SERVICE_CLASS (parent_class)->construct (service, session, provider, url, ex);
+
+	if (camel_exception_is_set (ex))
+		return;
+	
+/* 	if (!(url->host || url->user)) { */
+/* 		camel_exception_set (ex, CAMEL_EXCEPTION_SERVICE_INVALID, */
+/* 				     _("Host or user not available in url")); */
+/* 	} */
+
+	/*storage path*/
+	priv->storage_path = camel_session_get_storage_path (session, service, ex);
+	if (!priv->storage_path)
+		return;
+	
+	/*store summary*/
+	path = g_alloca (strlen (priv->storage_path) + 32);
+	sprintf (path, "%s/.summary", priv->storage_path);
+
+	mapi_store->summary = camel_mapi_store_summary_new ();
+	camel_store_summary_set_filename ((CamelStoreSummary *)mapi_store->summary, path);
+
+	camel_store_summary_touch ((CamelStoreSummary *)mapi_store->summary);
+	camel_store_summary_load ((CamelStoreSummary *) mapi_store->summary);
+
+	/*user and profile*/
+	priv->user = g_strdup (url->user);
+	priv->profile = g_strdup (camel_url_get_param(url, "profile"));
+
+	/*base url*/
+	priv->base_url = camel_url_to_string (service->url, (CAMEL_URL_HIDE_PASSWORD |
+						       CAMEL_URL_HIDE_PARAMS   |
+						       CAMEL_URL_HIDE_AUTH)  );
+
+	/*Hash Table*/	
+	priv->id_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
+	priv->name_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
+	priv->parent_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
+	priv->default_folders = g_hash_table_new_full (g_int_hash, g_str_equal, g_free, g_free);
+
+	store->flags &= ~CAMEL_STORE_VJUNK;
+	store->flags &= ~CAMEL_STORE_VTRASH;
+
+	store->flags |= CAMEL_STORE_SUBSCRIPTIONS;
+
+}
+
+static char
+*mapi_get_name(CamelService *service, gboolean brief)
+{
+	if (brief) {
+		return g_strdup_printf(_("Exchange MAPI server %s"), service->url->host);
+	} else {
+		return g_strdup_printf(_("Exchange MAPI for %s on %s"),
+				       service->url->user, service->url->host);
+	}
+}
+
+static gboolean
+check_for_connection (CamelService *service, CamelException *ex)
+{
+	/*Fixme : What happens when the network connection drops. 
+	  will mapi subsystem handle that ?*/
+	return exchange_mapi_connection_exists ();
+}
+
+static gboolean
+mapi_auth_loop (CamelService *service, CamelException *ex)
+{
+	CamelSession *session = camel_service_get_session (service);
+
+	char *errbuf = NULL;
+	gboolean authenticated = FALSE;
+
+	service->url->passwd = NULL;
+
+	while (!authenticated) {
+		if (errbuf) {
+			/* We need to un-cache the password before prompting again */
+			camel_session_forget_password (session, service, E_PASSWORD_COMPONENT, "password", ex);
+			g_free (service->url->passwd);
+			service->url->passwd = NULL;
+		}
+	
+		if (!service->url->passwd ){
+			char *prompt;
+			
+			prompt = g_strdup_printf (_("%sPlease enter the MAPI "
+						    "password for %s %s"),
+						  errbuf ? errbuf : "",
+						  service->url->user,
+						  service->url->host);
+			service->url->passwd =
+				camel_session_get_password (session, service, E_PASSWORD_COMPONENT,
+							    prompt, "password", CAMEL_SESSION_PASSWORD_SECRET, ex);
+			g_free (prompt);
+			g_free (errbuf);
+			errbuf = NULL;
+			
+			if (!service->url->passwd) {
+				camel_exception_set (ex, CAMEL_EXCEPTION_USER_CANCEL,
+						     _("You did not enter a password."));
+				return FALSE;
+			}
+		}
+		
+		exchange_mapi_connection_new (NULL,service->url->passwd);
+
+		if (!exchange_mapi_connection_exists ()) {
+			errbuf = g_strdup_printf (_("Unable to authenticate "
+					    "to Exchange MAPI server. "));
+						  
+			camel_exception_clear (ex);
+		} else 
+			authenticated = TRUE;
+		
+	}
+	return TRUE;
+}
+
+
+static gboolean
+mapi_connect(CamelService *service, CamelException *ex)
+{
+	CamelMapiStore *store = CAMEL_MAPI_STORE (service);
+	CamelMapiStorePrivate *priv = store->priv;
+
+	if (service->status == CAMEL_SERVICE_DISCONNECTED) {
+		return FALSE;
+	}
+
+	if (!priv) {
+		store->priv = g_new0 (CamelMapiStorePrivate, 1);
+		priv = store->priv;
+		camel_service_construct (service, service->session, service->provider, service->url, ex);
+	}
+
+	CAMEL_SERVICE_REC_LOCK (service, connect_lock);
+	if (check_for_connection (service, ex)) {
+		CAMEL_SERVICE_REC_UNLOCK (service, connect_lock);
+		return TRUE;
+	}
+
+	if (!mapi_auth_loop (service, ex)) {
+		CAMEL_SERVICE_REC_UNLOCK (service, connect_lock);
+		camel_service_disconnect (service, TRUE, NULL);
+		return FALSE;
+	}
+	
+	service->status = CAMEL_SERVICE_CONNECTED;
+	((CamelOfflineStore *) store)->state = CAMEL_OFFLINE_STORE_NETWORK_AVAIL;
+
+	camel_store_summary_save ((CamelStoreSummary *) store->summary);
+
+	CAMEL_SERVICE_REC_UNLOCK (service, connect_lock);
+
+	return TRUE;
+}
+
+static gboolean 
+mapi_disconnect(CamelService *service, gboolean clean, CamelException *ex)
+{
+	CamelMapiStore *store = CAMEL_MAPI_STORE (service);
+	CamelMapiStorePrivate *priv = store->priv;
+
+	/* Close the mapi subsystem */
+	exchange_mapi_connection_close ();
+
+	((CamelOfflineStore *) store)->state = CAMEL_OFFLINE_STORE_NETWORK_UNAVAIL;
+	service->status = CAMEL_SERVICE_DISCONNECTED;
+
+	return TRUE;
+}
+
+static GList *mapi_query_auth_types(CamelService *service, CamelException *ex)
+{
+	return NULL;
+}
+
+
+static gboolean 
+hash_check_fid_presence (gpointer key, gpointer value, gpointer folder_id)
+{
+	return (g_ascii_strcasecmp (value, folder_id) == 0);
+}
+
+static gboolean
+mapi_fid_is_system_folder (CamelMapiStore *mapi_store, const char *fid)
+{
+	CamelMapiStorePrivate *priv = mapi_store->priv;
+
+	if (!(fid && *fid)) 
+		return FALSE;
+
+	return (g_hash_table_find (priv->default_folders, hash_check_fid_presence, fid) != NULL);
+}
+
+static const gchar*
+mapi_system_folder_fid (CamelMapiStore *mapi_store, int folder_type)
+{ 
+	CamelMapiStorePrivate *priv = mapi_store->priv;
+
+	return g_hash_table_lookup (priv->default_folders, &folder_type); 
+}
+
+static CamelFolder *
+mapi_get_folder(CamelStore *store, const char *folder_name, guint32 flags, CamelException *ex)
+{
+	CamelMapiStore *mapi_store = CAMEL_MAPI_STORE (store);
+	CamelMapiStorePrivate *priv = mapi_store->priv;
+	char *storage_path = NULL;
+
+	storage_path = g_strdup_printf("%s/folders", priv->storage_path);
+
+	return camel_mapi_folder_new(store, folder_name, storage_path, flags, ex);
+}
+
+static CamelFolderInfo*
+mapi_create_folder(CamelStore *store, const char *parent_name, const char *folder_name, CamelException *ex)
+{
+	CamelMapiStore *mapi_store = CAMEL_MAPI_STORE (store);
+	CamelMapiStorePrivate  *priv = mapi_store->priv;
+	CamelFolderInfo *root = NULL;
+	char *parent_id;
+	mapi_id_t parent_fid, new_folder_id;
+
+	if (((CamelOfflineStore *) store)->state == CAMEL_OFFLINE_STORE_NETWORK_UNAVAIL) {
+		camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Cannot create MAPI folders in offline mode."));
+		return NULL;
+	}
+
+	if (mapi_fid_is_system_folder (mapi_store, camel_mapi_store_folder_id_lookup (mapi_store, folder_name))) {
+		camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, _("Cannot create new folder `%s'"),
+				      folder_name);
+		return NULL;
+	}
+	
+	if (parent_name && (strlen(parent_name) > 0) )
+		parent_id = g_hash_table_lookup (priv->name_hash, parent_name);
+	else
+		parent_id = "";
+
+	if (!mapi_connect (CAMEL_SERVICE(store), ex)) {
+			camel_exception_set (ex, CAMEL_EXCEPTION_SERVICE_CANT_AUTHENTICATE, _("Authentication failed"));
+			return NULL;
+	}
+
+	CAMEL_SERVICE_REC_LOCK (store, connect_lock);
+
+
+	exchange_mapi_util_mapi_id_from_string (parent_id, &parent_fid);
+	new_folder_id = exchange_mapi_create_folder(olFolderInbox, parent_fid, folder_name);
+	if (new_folder_id != 0) {
+		CamelMapiStoreInfo *si;
+
+		root = mapi_build_folder_info(mapi_store, parent_name, folder_name);
+
+		si = camel_mapi_store_summary_add_from_full(mapi_store->summary, root->full_name, '/');
+		camel_store_summary_save((CamelStoreSummary *)mapi_store->summary);
+
+		g_hash_table_insert (priv->id_hash, g_strdup_printf ("%016llX", new_folder_id), g_strdup(folder_name));
+		g_hash_table_insert (priv->name_hash, g_strdup(root->full_name), g_strdup_printf ("%016llX", new_folder_id));
+		g_hash_table_insert (priv->parent_hash, g_strdup_printf ("%016llX", new_folder_id), g_strdup(parent_id));
+
+		camel_object_trigger_event (CAMEL_OBJECT (store), "folder_created", root);
+	}
+
+	CAMEL_SERVICE_REC_UNLOCK (store, connect_lock);
+	return root;
+
+}
+
+static void
+mapi_forget_folder (CamelMapiStore *mapi_store, const char *folder_name, CamelException *ex)
+{
+	CamelFolderSummary *summary;
+	CamelMapiStorePrivate *priv = mapi_store->priv;
+	char *summary_file, *state_file;
+	char *folder_dir, *storage_path;
+	CamelFolderInfo *fi;
+	const char *name;
+
+	name = folder_name;
+
+	storage_path = g_strdup_printf ("%s/folders", priv->storage_path);
+
+	/* Fixme Path - e_*-to_path */
+	folder_dir = g_strdup(g_strconcat (storage_path, "/", folder_name, NULL));
+
+	if (g_access(folder_dir, F_OK) != 0) {
+		g_free(folder_dir);
+		return;
+	}
+
+	summary_file = g_strdup_printf ("%s/summary", folder_dir);
+	summary = camel_mapi_summary_new(NULL,summary_file);
+	if(!summary) {
+		g_free(summary_file);
+		g_free(folder_dir);
+		return;
+	}
+
+	camel_object_unref (summary);
+	g_unlink (summary_file);
+	g_free (summary_file);
+
+	state_file = g_strdup_printf ("%s/cmeta", folder_dir);
+	g_unlink (state_file);
+	g_free (state_file);
+
+	g_rmdir (folder_dir);
+	g_free (folder_dir);
+
+	camel_store_summary_remove_path ( (CamelStoreSummary *)mapi_store->summary, folder_name);
+	camel_store_summary_save ( (CamelStoreSummary *)mapi_store->summary);
+
+	fi = mapi_build_folder_info(mapi_store, NULL, folder_name);
+	camel_object_trigger_event (CAMEL_OBJECT (mapi_store), "folder_deleted", fi);
+	camel_folder_info_free (fi);
+}
+
+static void 
+mapi_delete_folder(CamelStore *store, const char *folder_name, CamelException *ex)
+{
+	CamelMapiStore *mapi_store = CAMEL_MAPI_STORE (store);
+	CamelMapiStorePrivate  *priv = mapi_store->priv;
+
+	const char *folder_id; 
+	mapi_id_t folder_fid;
+	gboolean status = FALSE;
+	
+	CAMEL_SERVICE_REC_LOCK (store, connect_lock);
+	
+	if (!camel_mapi_store_connected ((CamelMapiStore *)store, ex)) {
+		CAMEL_SERVICE_REC_UNLOCK (store, connect_lock);
+		return;
+	}
+
+	folder_id = g_hash_table_lookup (priv->name_hash, folder_name);
+	exchange_mapi_util_mapi_id_from_string (folder_id, &folder_fid);
+	status = exchange_mapi_remove_folder (0, folder_fid);
+
+	if (status) {
+		/* Fixme ??  */
+/* 		if (mapi_store->current_folder) */
+/* 			camel_object_unref (mapi_store->current_folder); */
+		mapi_forget_folder(mapi_store,folder_name,ex);
+
+		g_hash_table_remove (priv->id_hash, folder_id);
+		g_hash_table_remove (priv->name_hash, folder_name);
+		
+		g_hash_table_remove (priv->parent_hash, folder_id);
+	} 
+
+	CAMEL_SERVICE_REC_UNLOCK (store, connect_lock);
+
+}
+
+//FIXME : Moves this function to toplevel camel. same is used in GW.
+
+static char *
+mapi_path_to_physical (const char *prefix, const char *vpath)
+{
+	const char *p, *newp;
+	char *dp;
+	char *ppath;
+	int ppath_len;
+	int prefix_len;
+
+	while (*vpath == '/')
+		vpath++;
+	if (!prefix)
+		prefix = "";
+
+	/* Calculate the length of the real path. */
+	ppath_len = strlen (vpath);
+	ppath_len++;	/* For the ending zero.  */
+
+	prefix_len = strlen (prefix);
+	ppath_len += prefix_len;
+	ppath_len++;	/* For the separating slash.  */
+
+	p = vpath;
+	while (1) {
+		newp = strchr (p, '/');
+		if (newp == NULL)
+			break;
+
+		/* Skip consecutive slashes.  */
+		while (*newp == '/')
+			newp++;
+
+		p = newp;
+	};
+
+	ppath = g_malloc (ppath_len);
+	dp = ppath;
+
+	memcpy (dp, prefix, prefix_len);
+	dp += prefix_len;
+	*(dp++) = '/';
+
+	/* Copy the mangled path.  */
+	p = vpath;
+ 	while (1) {
+		newp = strchr (p, '/');
+		if (newp == NULL) {
+			strcpy (dp, p);
+			break;
+		}
+
+		memcpy (dp, p, newp - p + 1); /* `+ 1' to copy the slash too.  */
+		dp += newp - p + 1;
+
+		*(dp++) = '/';
+
+		/* Skip consecutive slashes.  */
+		while (*newp == '/')
+			newp++;
+
+		p = newp;
+	}
+
+	return ppath;
+}
+
+static void 
+mapi_rename_folder(CamelStore *store, const char *old_name, const char *new_name, CamelException *ex)
+{
+	CamelMapiStore *mapi_store = CAMEL_MAPI_STORE (store);
+	CamelMapiStorePrivate  *priv = mapi_store->priv;
+	char *oldpath, *newpath, *storepath;
+	const char *folder_id;
+	char *temp = NULL;
+	mapi_id_t fid;
+
+
+	CAMEL_SERVICE_REC_LOCK (mapi_store, connect_lock);
+	
+	if (!camel_mapi_store_connected ((CamelMapiStore *)store, ex)) {
+		CAMEL_SERVICE_REC_UNLOCK (mapi_store, connect_lock);
+		return;
+	}
+	
+	temp = strrchr (old_name, '/');
+	if (temp) 
+		temp++;
+	else
+		temp = (char *)old_name;
+
+	folder_id = camel_mapi_store_folder_id_lookup (mapi_store, temp);
+	if (!folder_id) {
+		camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, _("Cannot rename MAPI folder `%s'. Folder doesn't exist"),
+				      old_name);
+		CAMEL_SERVICE_REC_UNLOCK (mapi_store, connect_lock);
+		return;
+	}
+
+	/*Do not allow rename for system folders.*/
+	if (mapi_fid_is_system_folder (mapi_store, folder_id)) {
+		camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, _("Cannot rename Mapi folder `%s' to `%s'. Default folder."),
+				      old_name, new_name);
+		return;
+	}
+
+
+	exchange_mapi_util_mapi_id_from_string (folder_id, &fid);
+		
+	temp = strrchr (new_name, '/');
+	if (temp) 
+		temp++;
+	else
+		temp = (char *)new_name;
+	
+	if (!exchange_mapi_rename_folder (fid , temp))
+	{
+		camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, _("Cannot rename MAPI folder `%s' to `%s'"),
+				      old_name, new_name);
+		CAMEL_SERVICE_REC_UNLOCK (mapi_store, connect_lock);
+		return;
+	}
+
+	g_hash_table_replace (priv->id_hash, g_strdup(folder_id), g_strdup(temp));
+
+	g_hash_table_insert (priv->name_hash, g_strdup(new_name), g_strdup(folder_id));
+	g_hash_table_remove (priv->name_hash, old_name);
+
+	storepath = g_strdup_printf ("%s/folders", priv->storage_path);
+	oldpath = mapi_path_to_physical (storepath, old_name);
+	newpath = mapi_path_to_physical (storepath, new_name);
+	g_free (storepath);
+
+	/*XXX: make sure the summary is also renamed*/
+	if (g_rename (oldpath, newpath) == -1) {
+		g_warning ("Could not rename message cache '%s' to '%s': %s: cache reset",
+				oldpath, newpath, strerror (errno));
+	}
+
+	g_free (oldpath);
+	g_free (newpath);
+	CAMEL_SERVICE_REC_UNLOCK (mapi_store, connect_lock);
+}
+
+static guint32 hexnib(guint32 c)
+{
+	if (c >= '0' && c <= '9')
+		return c-'0';
+	else if (c>='A' && c <= 'Z')
+		return c-'A'+10;
+	else
+		return 0;
+}
+
+char *
+camel_mapi_store_summary_path_to_full(CamelMapiStoreSummary *s, const char *path, char dir_sep)
+{
+	unsigned char *full, *f;
+	guint32 c, v = 0;
+	const char *p;
+	int state=0;
+	char *subpath, *last = NULL;
+	CamelStoreInfo *si;
+
+	/* check to see if we have a subpath of path already defined */
+	subpath = alloca(strlen(path)+1);
+	strcpy(subpath, path);
+	do {
+		si = camel_store_summary_path((CamelStoreSummary *)s, subpath);
+		if (si == NULL) {
+			last = strrchr(subpath, '/');
+			if (last)
+				*last = 0;
+		}
+	} while (si == NULL && last);
+
+	/* path is already present, use the raw version we have */
+	if (si && strlen(subpath) == strlen(path)) {
+		f = g_strdup(camel_mapi_store_info_full_name(s, si));
+		camel_store_summary_info_free((CamelStoreSummary *)s, si);
+		return f;
+	}
+
+	f = full = alloca(strlen(path)*2+1);
+	if (si)
+		p = path + strlen(subpath);
+	else
+		p = path;
+
+	while ( (c = camel_utf8_getc((const unsigned char **)&p)) ) {
+		switch(state) {
+			case 0:
+				if (c == '%')
+					state = 1;
+				else {
+					if (c == '/')
+						c = dir_sep;
+					camel_utf8_putc(&f, c);
+				}
+				break;
+			case 1:
+				state = 2;
+				v = hexnib(c)<<4;
+				break;
+			case 2:
+				state = 0;
+				v |= hexnib(c);
+				camel_utf8_putc(&f, v);
+				break;
+		}
+	}
+	camel_utf8_putc(&f, c);
+
+	/* merge old path part if required */
+	f = g_strdup (full);
+	if (si) {
+		full = g_strdup_printf("%s%s", camel_mapi_store_info_full_name(s, si), f);
+		g_free(f);
+		camel_store_summary_info_free((CamelStoreSummary *)s, si);
+		f = full;
+	} 
+
+	return f ;
+}
+
+
+//do we realy need this. move to utils then ! 
+static int 
+match_path(const char *path, const char *name)
+{
+	char p, n;
+
+	p = *path++;
+	n = *name++;
+	while (n && p) {
+		if (n == p) {
+			p = *path++;
+			n = *name++;
+		} else if (p == '%') {
+			if (n != '/') {
+				n = *name++;
+			} else {
+				p = *path++;
+			}
+		} else if (p == '*') {
+			return TRUE;
+		} else
+			return FALSE;
+	}
+
+	return n == 0 && (p == '%' || p == 0);
+}
+
+static char *
+mapi_concat ( const char *prefix, const char *suffix)
+{
+	size_t len;
+
+	len = strlen (prefix);
+	if (len == 0 || prefix[len - 1] == '/')
+		return g_strdup_printf ("%s%s", prefix, suffix);
+	else
+		return g_strdup_printf ("%s%c%s", prefix, '/', suffix);
+}
+
+static CamelFolderInfo *
+mapi_build_folder_info(CamelMapiStore *mapi_store, const char *parent_name, const char *folder_name)
+{
+	CamelURL *url;
+	const char *name;
+	CamelFolderInfo *fi;
+	CamelMapiStorePrivate *priv = mapi_store->priv;
+
+	fi = g_malloc0(sizeof(*fi));
+	
+	fi->unread = -1;
+	fi->total = -1;
+
+	if (parent_name) {
+		if (strlen(parent_name) > 0) 
+			fi->full_name = g_strconcat(parent_name, "/", folder_name, NULL);
+		else
+			fi->full_name = g_strdup (folder_name);
+	} else 
+		fi->full_name = g_strdup(folder_name);
+ 
+	url = camel_url_new(priv->base_url,NULL);
+	//g_free(url->path);
+	url->path = g_strdup_printf("/%s", fi->full_name);
+	fi->uri = camel_url_to_string(url,CAMEL_URL_HIDE_ALL);
+	//camel_url_free(url);
+
+	name = strrchr(fi->full_name,'/');
+	if(name == NULL)
+		name = fi->full_name;
+	else
+		name++;
+
+	/*Fixme : Mark system folders.*/
+
+	fi->name = g_strdup(name);
+	return fi;
+}
+
+static CamelFolderInfo *
+mapi_get_folder_info_offline (CamelStore *store, const char *top,
+			 guint32 flags, CamelException *ex)
+{
+	CamelMapiStore *mapi_store = CAMEL_MAPI_STORE (store);
+	CamelFolderInfo *fi;
+	GPtrArray *folders;
+	char *path, *name;
+	int i;
+	gboolean recursive, subscribed, info_fast, favourites = false;
+
+	recursive = (flags & CAMEL_STORE_FOLDER_INFO_RECURSIVE);
+	subscribed = (flags & CAMEL_STORE_FOLDER_INFO_SUBSCRIBED);
+	info_fast = (flags & CAMEL_STORE_FOLDER_INFO_FAST);
+
+	folders = g_ptr_array_new ();
+
+	if (top == NULL)
+		top = "";
+
+	/* get starting point */
+	if (top[0] == 0) {
+			name = g_strdup("");
+	} else {
+		name = camel_mapi_store_summary_full_from_path(mapi_store->summary, top);
+		if (name == NULL)
+			name = camel_mapi_store_summary_path_to_full(mapi_store->summary, top, '/');
+	}
+
+	path = mapi_concat (name, "*");
+
+
+	for (i=0;i<camel_store_summary_count((CamelStoreSummary *)mapi_store->summary);i++) {
+		CamelStoreInfo *si = camel_store_summary_index((CamelStoreSummary *)mapi_store->summary, i);
+
+		if (si == NULL) 
+			continue;
+
+		/* Based on exchange connector. Allow only All Public Folders heirarchy */
+		if ((!subscribed) && info_fast) 
+			if (!(si->flags & CAMEL_MAPI_FOLDER_PUBLIC)) continue;
+
+		/*Allow Mailbox and Favourites (Subscribed public folders)*/
+		if (subscribed)
+			if (!(si->flags & CAMEL_STORE_INFO_FOLDER_SUBSCRIBED)) continue;
+
+		if ( !strcmp(name, camel_mapi_store_info_full_name (mapi_store->summary, si))
+		     || match_path (path, camel_mapi_store_info_full_name (mapi_store->summary, si))) {
+
+			gchar *store_info_path = camel_store_info_path((CamelStoreSummary *)mapi_store->summary, si);
+			gchar *parent_name = NULL;
+			gchar *folder_name = NULL;
+
+			/* TODO : UTF8 / i18n*/
+			if (g_str_has_prefix (store_info_path, DISPLAY_NAME_ALL_PUBLIC_FOLDERS) && subscribed) {
+				parent_name = DISPLAY_NAME_FAVOURITES;
+
+				folder_name = strrchr(store_info_path,'/');
+				if(folder_name != NULL)
+					store_info_path = ++folder_name;
+
+				favourites = true;
+			}
+
+			fi = mapi_build_folder_info(mapi_store, parent_name, store_info_path);
+			if (favourites) {
+				CamelURL *url;
+				url = camel_url_new(mapi_store->priv->base_url,NULL);
+				url->path = g_strdup_printf("/%s", camel_store_info_path((CamelStoreSummary *)mapi_store->summary, si));
+				fi->uri = camel_url_to_string(url,CAMEL_URL_HIDE_ALL);
+			}
+				
+			fi->unread = si->unread;
+			fi->total = si->total;
+			fi->flags = si->flags;
+
+			g_ptr_array_add (folders, fi);
+		}
+		camel_store_summary_info_free((CamelStoreSummary *)mapi_store->summary, si);
+	}
+
+	/*FIXME*/
+	if (!((!subscribed) && info_fast) ) {
+		fi = mapi_build_folder_info(mapi_store, NULL, DISPLAY_NAME_FAVOURITES);
+		fi->flags |= CAMEL_FOLDER_NOSELECT;
+		fi->flags |= CAMEL_FOLDER_SYSTEM;
+		
+		g_ptr_array_add (folders, fi);
+	}
+
+	g_free(name);
+	g_free (path);
+	fi = camel_folder_info_build (folders, top, '/', TRUE);
+	g_ptr_array_free (folders, TRUE);
+	return fi;
+}
+
+static CamelFolderInfo *
+mapi_convert_to_folder_info (CamelMapiStore *store, ExchangeMAPIFolder *folder, const char *url, CamelException *ex)
+{
+	const char *name = NULL;
+	gchar *parent, *id = NULL;
+	mapi_id_t mapi_id_folder;
+
+	char *par_name = NULL;
+	CamelFolderInfo *fi;
+	CamelMapiStorePrivate *priv = store->priv;
+
+	name = exchange_mapi_folder_get_name (folder);
+
+	id = g_strdup_printf ("%016llX", exchange_mapi_folder_get_fid (folder));
+		
+	fi = g_new0 (CamelFolderInfo, 1);
+
+	if (folder->is_default) {
+		switch (folder->default_type) {
+		case olFolderTopInformationStore:
+			fi->flags |= CAMEL_FOLDER_NOSELECT;
+			break;
+		case olFolderInbox:
+			fi->flags |= CAMEL_FOLDER_TYPE_INBOX;
+			break;
+		case olFolderSentMail:
+			fi->flags |= CAMEL_FOLDER_TYPE_SENT;
+			break;
+		case olFolderDeletedItems:
+			fi->flags |= CAMEL_FOLDER_TYPE_TRASH;
+			break;
+		/*TODO : case olFolderJunkMail */
+		}
+
+		fi->flags |= CAMEL_FOLDER_SYSTEM;
+	}
+
+	if (folder->category == MAPI_PERSONAL_FOLDER) {
+		fi->flags |= CAMEL_MAPI_FOLDER_PERSONAL;
+		fi->flags |= CAMEL_STORE_INFO_FOLDER_SUBSCRIBED; /*Set this default for mailbox.*/
+	} else if (folder->category == MAPI_FAVOURITE_FOLDER)
+		fi->flags |= CAMEL_MAPI_FOLDER_PUBLIC;
+
+	if (folder->child_count <=0)
+		fi->flags |= CAMEL_FOLDER_NOCHILDREN;
+	/*
+	   parent_hash contains the "parent id <-> folder id" combination. So we form
+	   the path for the full name in camelfolder info by looking up the hash table until
+	   NULL is found
+	 */
+
+	mapi_id_folder = exchange_mapi_folder_get_parent_id (folder);
+	parent = g_strdup_printf ("%016llX", mapi_id_folder);
+	par_name = g_hash_table_lookup (priv->id_hash, parent);
+
+	if (par_name != NULL) {
+		gchar *temp_parent = NULL;
+		gchar *temp = NULL;
+		gchar *str = g_strconcat (par_name, "/", name, NULL);
+
+		fi->name = g_strdup (name);
+
+		temp_parent = g_hash_table_lookup (priv->parent_hash, parent);
+		while (temp_parent) {
+			temp = g_hash_table_lookup (priv->id_hash, temp_parent );
+			if (temp == NULL) {
+				break;
+			}	
+			str = g_strconcat ( temp, "/", str, NULL);
+
+			temp_parent = g_hash_table_lookup (priv->parent_hash, temp_parent);
+
+		} 
+		fi->full_name = g_strdup (str);
+		fi->uri = g_strconcat (url, str, NULL);
+		g_free (str);
+	}
+	else {
+		fi->name =  g_strdup (name);
+		fi->full_name = g_strdup (name);
+		fi->uri = g_strconcat (url, "", name, NULL);
+	}
+
+	/*name_hash returns the container id given the name */
+	g_hash_table_insert (priv->name_hash, g_strdup(fi->full_name), id);
+
+	fi->total = folder->total;
+	fi->unread = folder->unread_count;
+
+	return fi;
+}
+
+gboolean
+camel_mapi_store_connected (CamelMapiStore *store, CamelException *ex)
+{
+	if (((CamelOfflineStore *) store)->state == CAMEL_OFFLINE_STORE_NETWORK_AVAIL
+	    && camel_service_connect ((CamelService *)store, ex)) 
+
+		return TRUE;
+
+	return FALSE;
+}
+
+static void
+mapi_folders_sync (CamelMapiStore *store, CamelException *ex)
+{
+	CamelMapiStorePrivate  *priv = store->priv;
+	gboolean status;
+	GSList *folder_list = NULL, *temp_list = NULL, *list = NULL;
+	char *url, *temp_url;
+	CamelFolderInfo *info = NULL;
+	CamelMapiStoreInfo *mapi_si = NULL;
+
+	if (((CamelOfflineStore *) store)->state == CAMEL_OFFLINE_STORE_NETWORK_AVAIL) {
+		if (((CamelService *)store)->status == CAMEL_SERVICE_DISCONNECTED){
+			((CamelService *)store)->status = CAMEL_SERVICE_CONNECTING;
+			mapi_connect ((CamelService *)store, ex);
+		}
+	}
+
+	if (!camel_mapi_store_connected (store, ex)) {
+		camel_exception_set (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE,
+				_("Folder list not available in offline mode."));
+		return;
+	}
+
+	status = exchange_mapi_get_folders_list (&folder_list);
+	if (!status) {
+		g_warning ("Could not get folder list..\n");
+		return;
+	}
+
+	status = exchange_mapi_get_pf_folders_list (&folder_list);
+	if (!status) {
+		g_warning ("Could not get Public folder list..\n");
+//		return;
+	}
+
+	temp_list = folder_list;
+	list = folder_list;
+
+	url = camel_url_to_string (CAMEL_SERVICE(store)->url,
+				   (CAMEL_URL_HIDE_PASSWORD|
+				    CAMEL_URL_HIDE_PARAMS|
+				    CAMEL_URL_HIDE_AUTH) );
+
+	if ( url[strlen(url) - 1] != '/') {
+		temp_url = g_strconcat (url, "/", NULL);
+		g_free ((char *)url);
+		url = temp_url;
+	}
+	
+	/*populate the hash table for finding the mapping from container id <-> folder name*/
+	for (;temp_list != NULL ; temp_list = g_slist_next (temp_list) ) {
+		const char *name;
+		gchar *fid = NULL, *parent_id = NULL;
+
+		name = exchange_mapi_folder_get_name ((ExchangeMAPIFolder *)(temp_list->data));
+		fid = g_strdup_printf ("%016llX", exchange_mapi_folder_get_fid((ExchangeMAPIFolder *)(temp_list->data)));
+		parent_id = g_strdup_printf ("%016llX", exchange_mapi_folder_get_parent_id ((ExchangeMAPIFolder *)(temp_list->data)));
+
+		/*id_hash returns the name for a given container id*/
+		g_hash_table_insert (priv->id_hash, g_strdup (fid), g_strdup(name)); 
+
+		/* name_hash : name <-> fid mapping */
+		g_hash_table_insert (priv->name_hash, g_strdup(name), g_strdup (fid));
+
+		/*parent_hash returns the parent container id, given an id*/
+		g_hash_table_insert (priv->parent_hash, g_strdup(fid), g_strdup(parent_id));
+
+		if (((ExchangeMAPIFolder *)(temp_list->data))->is_default) {
+			guint *type = g_new0 (guint, 1);
+			*type = ((ExchangeMAPIFolder *)(temp_list->data))->default_type;
+			g_hash_table_insert (priv->default_folders, type,
+					     g_strdup(fid));
+		}
+	}
+
+	for (;folder_list != NULL; folder_list = g_slist_next (folder_list)) {
+		ExchangeMAPIFolder *folder = (ExchangeMAPIFolder *) folder_list->data;
+		
+		if (exchange_mapi_folder_is_root ((ExchangeMAPIFolder *)(folder)))
+			continue;
+
+		if ( folder->container_class != MAPI_FOLDER_TYPE_MAIL) 
+			continue;
+
+		info = mapi_convert_to_folder_info (store, folder, (const char *)url, ex);
+		if (!(mapi_si = camel_store_summary_path ((CamelStoreSummary *)store->summary, info->full_name))){
+			mapi_si = camel_mapi_store_summary_add_from_full (store->summary, info->full_name, '/');
+			if (mapi_si == NULL) {
+				continue;
+			}
+		}
+
+		mapi_si->info.flags |= info->flags;
+		mapi_si->info.total = info->total;
+		mapi_si->info.unread = info->unread;
+	}
+
+	camel_store_summary_touch ((CamelStoreSummary *)store->summary);
+	camel_store_summary_save ((CamelStoreSummary *)store->summary);
+
+	g_free ((char *)url);
+
+	//	g_hash_table_foreach (present, get_folders_free, NULL);
+	//	g_hash_table_destroy (present);
+
+}
+
+static CamelFolderInfo*
+mapi_get_folder_info(CamelStore *store, const char *top, guint32 flags, CamelException *ex)
+{
+	CamelMapiStore *mapi_store = CAMEL_MAPI_STORE (store);
+	CamelFolderInfo *info = NULL;
+	int s_count = 0;	
+
+	/*
+	 * Thanks to Michael, for his cached folders implementation in IMAP
+	 * is used as is here.
+	 */
+
+	if (((CamelOfflineStore *) store)->state == CAMEL_OFFLINE_STORE_NETWORK_AVAIL) {
+		if (((CamelService *)store)->status == CAMEL_SERVICE_DISCONNECTED){
+			((CamelService *)store)->status = CAMEL_SERVICE_CONNECTING;
+			mapi_connect ((CamelService *)store, ex);
+		}
+	}
+
+	if (check_for_connection((CamelService *)store, ex)) {
+		mapi_folders_sync (mapi_store, ex);
+		if (camel_exception_is_set (ex)) {
+			CAMEL_SERVICE_REC_UNLOCK (store, connect_lock);
+			return NULL;
+		}
+		camel_store_summary_touch ((CamelStoreSummary *)mapi_store->summary);
+		camel_store_summary_save ((CamelStoreSummary *)mapi_store->summary);
+	} 
+
+	/*camel_exception_clear (ex);*/
+end_r:
+	s_count = camel_store_summary_count((CamelStoreSummary *)mapi_store->summary);
+	info = mapi_get_folder_info_offline (store, top, flags, ex);
+	return info;
+}
+
+const gchar *
+camel_mapi_store_folder_id_lookup (CamelMapiStore *mapi_store, const char *folder_name)
+{
+	CamelMapiStorePrivate *priv = mapi_store->priv;
+
+	return g_hash_table_lookup (priv->name_hash, folder_name);
+}
+
+const gchar *
+camel_mapi_store_system_folder_fid (CamelMapiStore *mapi_store, guint folder_type)
+{
+	return mapi_system_folder_fid (mapi_store, folder_type);
+}
+
+const gchar *
+camel_mapi_store_folder_lookup (CamelMapiStore *mapi_store, const char *folder_id)
+{
+	CamelMapiStorePrivate *priv = mapi_store->priv;
+
+	return g_hash_table_lookup (priv->id_hash, folder_id);
+}
+
+const gchar *
+camel_mapi_store_get_profile_name (CamelMapiStore *mapi_store)
+{
+	CamelMapiStorePrivate *priv;
+
+	g_return_val_if_fail (CAMEL_IS_MAPI_STORE (mapi_store), NULL);
+
+	priv = mapi_store->priv;
+
+	return priv->profile;
+}
+
+static void
+mapi_subscribe_folder(CamelStore *store, const char *folder_name, CamelException *ex)
+{
+	CamelMapiStore *mapi_store = CAMEL_MAPI_STORE (store);
+
+	CamelFolderInfo *fi;
+	CamelStoreInfo *si;
+	gchar *parent_name = NULL;
+	gchar *f_name = NULL;
+	CamelURL *url;
+	/* TODO : exchange_mapi_add_to_favorites (); */
+
+	if (si = camel_store_summary_path((CamelStoreSummary *)mapi_store->summary, folder_name)) {
+		if ((si->flags & CAMEL_STORE_INFO_FOLDER_SUBSCRIBED) == 0) {
+			si->flags |= CAMEL_STORE_INFO_FOLDER_SUBSCRIBED;
+			si->flags |= CAMEL_FOLDER_SUBSCRIBED;
+			camel_store_summary_touch((CamelStoreSummary *)mapi_store->summary);
+		}
+		camel_store_summary_info_free((CamelStoreSummary *)mapi_store->summary, si);
+	}
+
+	if (g_str_has_prefix (folder_name, DISPLAY_NAME_ALL_PUBLIC_FOLDERS) ) {
+		parent_name = DISPLAY_NAME_FAVOURITES;
+
+		f_name = strrchr(folder_name,'/');
+		if(f_name != NULL)
+			folder_name = ++f_name;
+	}
+
+	fi = mapi_build_folder_info(mapi_store, parent_name, g_strdup (folder_name)); /* FIXME */
+
+	url = camel_url_new(mapi_store->priv->base_url,NULL);
+	url->path = g_strdup_printf("/%s", camel_store_info_path((CamelStoreSummary *)mapi_store->summary, si));
+	fi->uri = camel_url_to_string(url,CAMEL_URL_HIDE_ALL);
+
+	fi->flags |= CAMEL_FOLDER_SUBSCRIBED;
+	fi->flags |= CAMEL_FOLDER_NOCHILDREN;
+	fi->flags |= CAMEL_STORE_INFO_FOLDER_SUBSCRIBED;
+
+	camel_object_trigger_event (CAMEL_OBJECT (store), "folder_subscribed", fi);
+}
+
+static gboolean
+mapi_folder_subscribed (CamelStore *store, const char *folder_name)
+{
+	CamelMapiStore *mapi_store = (CamelMapiStore *) store;
+	CamelStoreInfo *si;
+	int truth = FALSE;
+
+	if ((si = camel_store_summary_path ((CamelStoreSummary *) mapi_store->summary, folder_name))) {
+		truth = (si->flags & CAMEL_STORE_INFO_FOLDER_SUBSCRIBED) != 0;
+		camel_store_summary_info_free ((CamelStoreSummary *) mapi_store->summary, si);
+	}
+
+	return truth;
+}
+
+static void 
+mapi_unsubscribe_folder(CamelStore *store, const char *folder_name, CamelException *ex)
+{
+	CamelFolderInfo *fi;
+	CamelStoreInfo *si;
+	gchar *parent_name = NULL;
+	gchar *f_name = NULL;
+	CamelURL *url;
+
+	CamelMapiStore *mapi_store = CAMEL_MAPI_STORE (store);
+
+	si = camel_store_summary_path((CamelStoreSummary *)mapi_store->summary, folder_name);
+	if (si) {
+		if (si->flags & CAMEL_STORE_INFO_FOLDER_SUBSCRIBED) {
+			si->flags &= ~CAMEL_STORE_INFO_FOLDER_SUBSCRIBED;
+			camel_store_summary_touch((CamelStoreSummary *)mapi_store->summary);
+			camel_store_summary_save((CamelStoreSummary *)mapi_store->summary);
+		}
+		camel_store_summary_info_free((CamelStoreSummary *)mapi_store->summary, si);
+	}
+
+	if (g_str_has_prefix (folder_name, DISPLAY_NAME_ALL_PUBLIC_FOLDERS) ) {
+		parent_name = DISPLAY_NAME_FAVOURITES;
+
+		f_name = strrchr(folder_name,'/');
+		if(f_name != NULL)
+			folder_name = ++f_name;
+	}
+
+	fi = mapi_build_folder_info(mapi_store, parent_name, g_strdup (folder_name)); /* FIXME */
+
+	url = camel_url_new(mapi_store->priv->base_url,NULL);
+	url->path = g_strdup_printf("/%s", camel_store_info_path((CamelStoreSummary *)mapi_store->summary, si));
+	fi->uri = camel_url_to_string(url,CAMEL_URL_HIDE_ALL);
+
+	camel_object_trigger_event (CAMEL_OBJECT (store), "folder_unsubscribed", fi);
+}
+
+static void
+mapi_noop(CamelStore *store, CamelException *ex)
+{
+
+}
+

Added: trunk/src/camel/camel-mapi-store.h
==============================================================================
--- (empty file)
+++ trunk/src/camel/camel-mapi-store.h	Wed Nov 19 04:28:20 2008
@@ -0,0 +1,101 @@
+/* -*- 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/>  
+ *
+ *
+ * Authors:
+ *     Johnny Jacob <jjohnny novell com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef __CAMEL_MAPI_STORE_H__
+#define __CAMEL_MAPI_STORE_H__
+
+#include <camel/camel-store.h>
+#include <camel/camel-offline-store.h>
+#include <camel-mapi-store-summary.h>
+#include <camel/camel-net-utils.h>
+#include <camel/camel-i18n.h>
+
+#include <exchange-mapi-folder.h>
+
+#define CAMEL_MAPI_STORE_TYPE     (camel_mapi_store_get_type ())
+#define CAMEL_MAPI_STORE(obj)     (CAMEL_CHECK_CAST((obj), CAMEL_MAPI_STORE_TYPE, CamelMapiStore))
+#define CAMEL_MAPI_STORE_CLASS(k) (CAMEL_CHECK_CLASS_CAST ((k), CAMEL_MAPI_STORE_TYPE, CamelMapiStoreClass))
+#define CAMEL_IS_MAPI_STORE(o)    (CAMEL_CHECK_TYPE((o), CAMEL_MAPI_STORE_TYPE))
+
+/* TODO : Move this to libcamel. Task when merging */
+#define CAMEL_FOLDER_FLAGS_LAST (1<<13)
+
+#define CAMEL_MAPI_FOLDER_PUBLIC (CAMEL_FOLDER_FLAGS_LAST << 1)
+#define CAMEL_MAPI_FOLDER_PERSONAL (CAMEL_FOLDER_FLAGS_LAST << 2)
+#define CAMEL_MAPI_FOLDER_FORIEGN (CAMEL_FOLDER_FLAGS_LAST << 3)
+
+/**
+ * definition of CamelMAPIStore
+ */
+typedef struct _CamelMapiStore CamelMapiStore;
+typedef struct _CamelMapiStoreClass CamelMapiStoreClass;
+typedef struct _CamelMapiStorePrivate CamelMapiStorePrivate;
+
+struct _CamelMapiStore{
+	CamelOfflineStore parent_object;	
+
+	struct _CamelMapiStoreSummary *summary;
+	CamelMapiStorePrivate *priv;
+/* 	char			*base_url; */
+/* 	CamelURL		*camel_url; */
+/* 	CamelFolderInfo		*fi; */
+/* 	GHashTable		*folders; */
+/* 	GMutex			*folders_lock; */
+/* 	GMutex			*connect_lock; */
+};
+
+
+
+
+struct _CamelMapiStoreClass {
+	CamelOfflineStoreClass		parent_class;
+};
+
+
+/**
+ * PROTOTYPES
+ */
+
+#ifndef __BEGIN_DECLS
+#ifdef __cplusplus
+#define __BEGIN_DECLS		extern "C" {
+#define __END_DECLS		}
+#else
+#define __BEGIN_DECLS
+#define __END_DECLS
+#endif
+#endif
+
+__BEGIN_DECLS
+/* Standard Camel function */
+CamelType camel_mapi_store_get_type(void);
+gboolean camel_mapi_store_connected(CamelMapiStore *, CamelException *);
+
+const gchar* camel_mapi_store_folder_id_lookup (CamelMapiStore *mapi_store, const char *folder_name);
+const gchar* camel_mapi_store_folder_lookup (CamelMapiStore *mapi_store, const char *folder_id);
+const gchar* camel_mapi_store_get_profile_name (CamelMapiStore *mapi_store);
+const gchar *camel_mapi_store_system_folder_fid (CamelMapiStore *mapi_store, guint folder_type);
+
+__END_DECLS
+
+#endif /* __CAMEL_OPENCHANGE_STORE_H__ */

Added: trunk/src/camel/camel-mapi-summary.c
==============================================================================
--- (empty file)
+++ trunk/src/camel/camel-mapi-summary.c	Wed Nov 19 04:28:20 2008
@@ -0,0 +1,284 @@
+/* -*- 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/>  
+ *
+ *
+ * Authors:
+ *     Johnny Jacob <jjohnny novell com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <camel/camel-db.h>
+#include <camel/camel-data-cache.h>
+#include <camel/camel-file-utils.h>
+#include <camel/camel-folder.h>
+
+#include "camel-mapi-folder.h"
+#include "camel-mapi-summary.h"
+
+#define CAMEL_MAPI_SUMMARY_VERSION (1)
+
+/* Macros for DB Summary */
+#define MS_EXTRACT_FIRST_DIGIT(val) val=strtoul (part, &part, 10);
+
+/*Prototypes*/
+static CamelFIRecord* mapi_summary_header_to_db (CamelFolderSummary *, CamelException *ex);
+static int mapi_summary_header_from_db (CamelFolderSummary *, CamelFIRecord *fir);
+
+static CamelMessageInfo *mapi_message_info_from_db (CamelFolderSummary *s, CamelMIRecord *mir) ;
+static CamelMIRecord *mapi_message_info_to_db (CamelFolderSummary *s, CamelMessageInfo *info) ;
+
+static CamelMessageContentInfo * mapi_content_info_from_db (CamelFolderSummary *s, CamelMIRecord *mir) ;
+static int mapi_content_info_to_db (CamelFolderSummary *s, CamelMessageContentInfo *info, CamelMIRecord *mir) ;
+
+static void camel_mapi_summary_class_init (CamelMapiSummaryClass *klass);
+static void camel_mapi_summary_init       (CamelMapiSummary *obj);
+
+
+/*End of Prototypes*/
+
+
+static CamelFolderSummaryClass *camel_mapi_summary_parent ;
+
+
+CamelType
+camel_mapi_summary_get_type (void)
+{
+	static CamelType type = CAMEL_INVALID_TYPE;
+
+	if (type == CAMEL_INVALID_TYPE) {
+		type = camel_type_register(
+				camel_folder_summary_get_type(), "CamelMapiSummary",
+				sizeof (CamelMapiSummary),
+				sizeof (CamelMapiSummaryClass),
+				(CamelObjectClassInitFunc) camel_mapi_summary_class_init,
+				NULL,
+				(CamelObjectInitFunc) camel_mapi_summary_init,
+				NULL);
+	}
+
+	return type;
+}
+
+static CamelMessageInfo *
+mapi_message_info_clone(CamelFolderSummary *s, const CamelMessageInfo *mi)
+{
+	CamelMapiMessageInfo *to;
+	const CamelMapiMessageInfo *from = (const CamelMapiMessageInfo *)mi;
+
+	to = (CamelMapiMessageInfo *)camel_mapi_summary_parent->message_info_clone(s, mi);
+	to->server_flags = from->server_flags;
+
+	/* FIXME: parent clone should do this */
+	to->info.content = camel_folder_summary_content_info_new(s);
+
+	return (CamelMessageInfo *)to;
+}
+
+static void
+camel_mapi_summary_class_init (CamelMapiSummaryClass *klass)
+{
+	CamelFolderSummaryClass *cfs_class = (CamelFolderSummaryClass *) klass;
+
+	camel_mapi_summary_parent = CAMEL_FOLDER_SUMMARY_CLASS (camel_type_get_global_classfuncs (camel_folder_summary_get_type()));
+
+	cfs_class->message_info_clone = mapi_message_info_clone ;
+
+	cfs_class->summary_header_to_db = mapi_summary_header_to_db;
+	cfs_class->summary_header_from_db = mapi_summary_header_from_db;
+	cfs_class->message_info_to_db = mapi_message_info_to_db;
+	cfs_class->message_info_from_db = mapi_message_info_from_db;
+	cfs_class->content_info_to_db = mapi_content_info_to_db;
+	cfs_class->content_info_from_db = mapi_content_info_from_db;
+}
+
+
+static void
+camel_mapi_summary_init (CamelMapiSummary *obj)
+{
+	CamelFolderSummary *s = (CamelFolderSummary *)obj;
+
+	/* subclasses need to set the right instance data sizes */
+	s->message_info_size = sizeof(CamelMapiMessageInfo);
+	s->content_info_size = sizeof(CamelMapiMessageContentInfo);
+	
+	/* Meta-summary - Overriding UID len */
+	s->meta_summary->uid_len = 2048;
+}
+
+
+/**
+ * camel_mapi_summary_new:
+ * @filename: the file to store the summary in.
+ *
+ * This will create a new CamelMapiSummary object and read in the
+ * summary data from disk, if it exists.
+ *
+ * Return value: A new CamelMapiSummary object.
+ **/
+CamelFolderSummary *
+camel_mapi_summary_new (struct _CamelFolder *folder, const char *filename)
+{
+	CamelException ex;
+
+	CamelFolderSummary *summary = CAMEL_FOLDER_SUMMARY (
+			camel_object_new (camel_mapi_summary_get_type ()));
+
+	camel_exception_init (&ex);
+	
+	summary->folder = folder ;
+	camel_folder_summary_set_build_content (summary, TRUE);
+	camel_folder_summary_set_filename (summary, filename);
+
+	if (camel_folder_summary_load_from_db (summary, &ex) == -1) {
+		/* FIXME: Isn't this dangerous ? We clear the summary
+		if it cannot be loaded, for some random reason.
+		We need to pass the ex and find out why it is not loaded etc. ? */
+		camel_folder_summary_clear_db (summary);
+		g_warning ("Unable to load summary %s\n", camel_exception_get_description (&ex));
+		camel_exception_clear (&ex);
+	}
+
+	return summary;
+}
+
+static int
+mapi_summary_header_from_db (CamelFolderSummary *summary, CamelFIRecord *fir) 
+{
+	CamelMapiSummary *mapi_summary = CAMEL_MAPI_SUMMARY (summary);
+	gchar *part;
+
+	if (camel_mapi_summary_parent->summary_header_from_db (summary, fir) == -1)
+		return -1 ;
+
+	part = fir->bdata;
+
+	if (part)
+		MS_EXTRACT_FIRST_DIGIT(mapi_summary->version);
+
+	if (part && part++) {
+		mapi_summary->sync_time_stamp = g_strdup (part);
+	}
+
+	return 0;
+}
+static CamelFIRecord *
+mapi_summary_header_to_db (CamelFolderSummary *summary, CamelException *ex) 
+{
+	CamelMapiSummary *mapi_summary = CAMEL_MAPI_SUMMARY(summary);
+	struct _CamelFIRecord *fir;
+
+	fir = camel_mapi_summary_parent->summary_header_to_db (summary, ex);
+
+	if(!fir)
+		return NULL;
+
+	fir->bdata = g_strdup_printf ("%d %s", CAMEL_MAPI_SUMMARY_VERSION, mapi_summary->sync_time_stamp);
+
+	return fir;
+}
+
+static CamelMessageInfo*
+mapi_message_info_from_db (CamelFolderSummary *s, CamelMIRecord *mir) 
+{
+	CamelMessageInfo *info ;
+
+	info = camel_mapi_summary_parent->message_info_from_db (s, mir) ;
+
+	return info ;
+}
+
+static CamelMIRecord *
+mapi_message_info_to_db (CamelFolderSummary *s, CamelMessageInfo *info) 
+{
+	struct _CamelMIRecord *mir;
+
+	mir = camel_mapi_summary_parent->message_info_to_db (s, info);
+
+	return mir;
+}
+
+static CamelMessageContentInfo* 
+mapi_content_info_from_db (CamelFolderSummary *s, CamelMIRecord *mir) 
+{
+	char *part = mir->cinfo;
+	guint32 type=0;
+	
+	if (part) 
+		MS_EXTRACT_FIRST_DIGIT (type);
+
+	mir->cinfo = part;
+
+	if (type)
+		return camel_mapi_summary_parent->content_info_from_db (s, mir);
+	else
+		return camel_folder_summary_content_info_new (s);
+}
+
+static int
+mapi_content_info_to_db (CamelFolderSummary *s, CamelMessageContentInfo *info, CamelMIRecord *mir)
+{
+	if (info->type) {
+		mir->cinfo = g_strdup ("1");
+		return camel_mapi_summary_parent->content_info_to_db (s, info, mir);
+	} else {
+		mir->cinfo = g_strdup ("0");
+		return 0;
+	}
+}
+
+void
+mapi_summary_clear (CamelFolderSummary *summary, gboolean uncache)
+{
+	CamelFolderChangeInfo *changes;
+	CamelMessageInfo *info;
+	CamelException ex;
+	int i, count;
+	const char *uid;
+
+	changes = camel_folder_change_info_new ();
+	count = camel_folder_summary_count (summary);
+	for (i = 0; i < count; i++) {
+		if (!(info = camel_folder_summary_index (summary, i)))
+			continue;
+
+		uid = camel_message_info_uid (info);
+		camel_folder_change_info_remove_uid (changes, uid);
+		camel_folder_summary_remove_uid (summary, uid);
+		camel_message_info_free(info);
+	}
+
+	camel_folder_summary_clear (summary);
+	camel_exception_init (&ex);
+	/*TODO : Test exception */
+	camel_folder_summary_save_to_db (summary, &ex);
+
+	if (uncache)
+		camel_data_cache_clear (((CamelMapiFolder *) summary->folder)->cache, "cache", NULL);
+
+	if (camel_folder_change_info_changed (changes))
+		camel_object_trigger_event (summary->folder, "folder_changed", changes);
+	camel_folder_change_info_free (changes);
+}

Added: trunk/src/camel/camel-mapi-summary.h
==============================================================================
--- (empty file)
+++ trunk/src/camel/camel-mapi-summary.h	Wed Nov 19 04:28:20 2008
@@ -0,0 +1,82 @@
+/* -*- 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/>  
+ *
+ *
+ * Authors:
+ *     Johnny Jacob <jjohnny novell com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef _CAMEL_MAPI_SUMMARY_H
+#define _CAMEL_MAPI_SUMMARY_H
+
+#include <camel/camel-folder-summary.h>
+#include <camel/camel-exception.h>
+#include <camel/camel-store.h>
+
+#define CAMEL_MAPI_SUMMARY(obj)         CAMEL_CHECK_CAST (obj, camel_mapi_summary_get_type (), CamelMapiSummary)
+#define CAMEL_MAPI_SUMMARY_CLASS(klass) CAMEL_CHECK_CLASS_CAST (klass, camel_mapi_summary_get_type (), CamelMapiSummaryClass)
+#define CAMEL_IS_MAPI_SUMMARY(obj)      CAMEL_CHECK_TYPE (obj, camel_mapi_summary_get_type ())
+
+G_BEGIN_DECLS
+
+typedef struct _CamelMapiSummary CamelMapiSummary ;
+typedef struct _CamelMapiSummaryClass CamelMapiSummaryClass ;
+typedef struct _CamelMapiMessageInfo CamelMapiMessageInfo ;
+typedef struct _CamelMapiMessageContentInfo CamelMapiMessageContentInfo ;
+
+/* extra summary flags*/
+enum {
+	CAMEL_GW_MESSAGE_JUNK = 1<<17,
+	CAMEL_GW_MESSAGE_NOJUNK = 1<<18,
+};
+
+struct _CamelMapiMessageInfo {
+	CamelMessageInfoBase info;
+
+	guint32 server_flags;
+} ;
+
+
+struct _CamelMapiMessageContentInfo {
+	CamelMessageContentInfo info ;
+} ; 
+
+
+struct _CamelMapiSummary {
+	CamelFolderSummary parent ;
+
+	gchar *sync_time_stamp;
+	guint32 version ;
+	guint32 validity ;
+} ;
+
+
+struct _CamelMapiSummaryClass {
+	CamelFolderSummaryClass parent_class ;
+} ;
+
+
+CamelType camel_mapi_summary_get_type (void) ;
+
+CamelFolderSummary *camel_mapi_summary_new (struct _CamelFolder *folder, const char *filename) ;
+
+void mapi_summary_clear (CamelFolderSummary *summary, gboolean uncache);
+
+G_END_DECLS
+
+#endif /*_CAMEL_GW_SUMMARY_H*/

Added: trunk/src/camel/camel-mapi-transport.c
==============================================================================
--- (empty file)
+++ trunk/src/camel/camel-mapi-transport.c	Wed Nov 19 04:28:20 2008
@@ -0,0 +1,454 @@
+/* -*- 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/>  
+ *
+ *
+ * Authors:
+ *     Johnny Jacob <jjohnny novell com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+
+#include <libmapi/libmapi.h>
+#include <gen_ndr/exchange.h>
+
+#include <camel/camel-data-wrapper.h>
+#include <camel/camel-exception.h>
+#include <camel/camel-mime-filter-crlf.h>
+#include <camel/camel-mime-message.h>
+#include <camel/camel-multipart.h>
+#include <camel/camel-session.h>
+#include <camel/camel-stream-filter.h>
+#include <camel/camel-stream-mem.h>
+
+
+#include "camel-mapi-transport.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+
+#include <camel/camel-sasl.h>
+#include <camel/camel-utf8.h>
+#include <camel/camel-tcp-stream-raw.h>
+
+#ifdef HAVE_SSL
+#include <camel/camel-tcp-stream-ssl.h>
+#endif
+
+
+#include <camel/camel-private.h>
+#include <camel/camel-i18n.h>
+#include <camel/camel-net-utils.h>
+#include "camel-mapi-store.h"
+#include "camel-mapi-folder.h"
+#include "camel-mapi-store-summary.h"
+#include <camel/camel-session.h>
+#include <camel/camel-store-summary.h>
+#define d(x) x
+
+#include <camel/camel-seekable-stream.h>
+#include <exchange-mapi-defs.h>
+
+#define STREAM_SIZE 4000
+
+CamelStore *get_store(void);
+
+void	set_store(CamelStore *);
+
+static void
+mapi_item_add_recipient (const char *recipients, OlMailRecipientType type, GSList **recipient_list);
+static int
+mapi_message_item_send (MapiItem *item, GSList *attachments, GSList *recipients);
+
+
+static void
+mapi_item_debug_dump (MapiItem *item)
+{
+	printf("-----------------\n\n");
+        printf("%s(%d):%s: \n", __FILE__, __LINE__, __PRETTY_FUNCTION__);
+	printf("item->header.from : %s\n",item->header.from);
+	//Use Recipient List
+	printf("item->header.subject : %s\n",item->header.subject);
+	//printf("item->msg.body_stream : %s\n",item->msg.body_stream);
+	printf("-----------------\n\n");
+}
+
+static void
+mapi_item_set_from(MapiItem *item, const char *from)
+{
+	if (item->header.from) { 
+		free(item->header.from);
+	}
+	item->header.from = strdup(from);
+}
+
+static void
+mapi_item_set_subject(MapiItem *item, const char *subject)
+{
+	if (item->header.subject)
+		free(item->header.subject);
+
+	item->header.subject = strdup(subject);
+}
+
+#define MAX_READ_SIZE 0x1000
+
+static void
+mapi_item_set_body_stream (MapiItem *item, CamelStream *body, MapiItemPartType part_type)
+{
+	guint8 *buf = g_new0 (guint8 , STREAM_SIZE);
+	guint32	read_size = 0;
+	ExchangeMAPIStream *stream = g_new0 (ExchangeMAPIStream, 1);
+
+	camel_seekable_stream_seek((CamelSeekableStream *)body, 0, CAMEL_STREAM_SET);
+
+	stream->value = g_byte_array_new ();
+
+	while((read_size = camel_stream_read(body, (char *)buf, STREAM_SIZE))){
+		if (read_size == -1) 
+			return;
+
+		stream->value = g_byte_array_append (stream->value, (char *) buf, read_size);
+	}
+
+	switch (part_type) {
+	case PART_TYPE_TEXT_HTML :
+		stream->proptag = PR_HTML;
+		break;
+	case PART_TYPE_PLAIN_TEXT:
+		stream->proptag = PR_BODY;
+		break;
+	}
+
+	if (stream->value->len < MAX_READ_SIZE)
+		item->msg.body_parts = g_slist_append (item->msg.body_parts, stream);
+	else
+		item->generic_streams = g_slist_append (item->generic_streams, stream);
+
+}
+
+static gboolean
+mapi_item_add_attach(MapiItem *item, const gchar *filename, const char *description, 
+		     CamelStream *content_stream, int content_size)
+{
+	guint8 *buf = g_new0 (guint8 , STREAM_SIZE);
+	guint32	read_size, flag;
+	ExchangeMAPIAttachment *item_attach;
+	ExchangeMAPIStream *stream; 
+
+	item_attach = g_new0 (ExchangeMAPIAttachment, 1);
+
+	item_attach->cValues = 4; 
+	item_attach->lpProps = g_new0 (struct SPropValue, 4); 
+
+	flag = ATTACH_BY_VALUE; 
+	set_SPropValue_proptag(&(item_attach->lpProps[0]), PR_ATTACH_METHOD, (const void *) (&flag));
+
+	/* MSDN Documentation: When the supplied offset is -1 (0xFFFFFFFF), the 
+	 * attachment is not rendered using the PR_RENDERING_POSITION property. 
+	 * All values other than -1 indicate the position within PR_BODY at which 
+	 * the attachment is to be rendered. 
+	 */
+	flag = 0xFFFFFFFF;
+	set_SPropValue_proptag(&(item_attach->lpProps[1]), PR_RENDERING_POSITION, (const void *) (&flag));
+
+	if (filename) {
+		set_SPropValue_proptag(&(item_attach->lpProps[2]), PR_ATTACH_FILENAME, (const void *) g_strdup(filename));
+		set_SPropValue_proptag(&(item_attach->lpProps[3]), PR_ATTACH_LONG_FILENAME, (const void *) g_strdup(filename));
+	}
+
+	stream = g_new0 (ExchangeMAPIStream, 1);
+	stream->proptag = PR_ATTACH_DATA_BIN; 
+	stream->value = g_byte_array_new ();
+	camel_seekable_stream_seek((CamelSeekableStream *)content_stream, 0, CAMEL_STREAM_SET);
+	while((read_size = camel_stream_read(content_stream, (char *)buf, STREAM_SIZE))){
+		stream->value = g_byte_array_append (stream->value, buf, read_size);
+	}
+	item_attach->streams = g_slist_append (item_attach->streams, stream); 
+
+	item->attachments = g_slist_append(item->attachments, item_attach);
+
+	return TRUE;
+}
+
+static gboolean 
+mapi_do_multipart(CamelMultipart *mp, MapiItem *item)
+{
+	CamelDataWrapper *dw;
+	CamelStream *content_stream;
+	CamelContentType *type;
+	CamelMimePart *part;
+	gint n_part, i_part;
+	const gchar *filename;
+	const gchar *description;
+	const gchar *content_id;
+	gint content_size;
+
+	n_part = camel_multipart_get_number(mp);
+	for (i_part = 0; i_part < n_part; i_part++) {
+		/* getting part */
+		part = camel_multipart_get_part(mp, i_part);
+		dw = camel_medium_get_content_object (CAMEL_MEDIUM (part));
+		if (CAMEL_IS_MULTIPART(dw)) {
+			/* recursive */
+			if (!mapi_do_multipart(CAMEL_MULTIPART(dw), item))
+				return FALSE;
+			continue ;
+		}
+		/* filename */
+		filename = camel_mime_part_get_filename(part);
+
+		dw = camel_medium_get_content_object(CAMEL_MEDIUM(part));
+		content_stream = camel_stream_mem_new();
+		content_size = camel_data_wrapper_decode_to_stream (dw, (CamelStream *) content_stream);
+		camel_seekable_stream_seek((CamelSeekableStream *)content_stream, 0, CAMEL_STREAM_SET);
+
+		description = camel_mime_part_get_description(part);
+		content_id = camel_mime_part_get_content_id(part);
+		
+		type = camel_mime_part_get_content_type(part);
+
+		if (i_part == 0 && camel_content_type_is (type, "text", "plain")) {
+			mapi_item_set_body_stream (item, content_stream, PART_TYPE_PLAIN_TEXT);
+		} else if (camel_content_type_is (type, "text", "html")) {
+			mapi_item_set_body_stream (item, content_stream, PART_TYPE_TEXT_HTML);
+		} else {
+			mapi_item_add_attach(item, filename, description, 
+					     content_stream, content_size);
+		}
+	}
+
+	return TRUE;
+}
+
+
+static gboolean
+mapi_send_to (CamelTransport *transport, CamelMimeMessage *message,
+	      CamelAddress *from, CamelAddress *recipients, CamelException *ex)
+{
+	CamelDataWrapper *dw = NULL;
+	CamelContentType *type;
+	CamelStream *content_stream;
+	CamelMultipart *multipart;
+	const CamelInternetAddress *to, *cc, *bcc;
+	MapiItem *item = g_new0 (MapiItem, 1);
+	const char *namep;
+	const char *addressp;
+	const char *content_type;		
+	gint st;
+	ssize_t	content_size;
+	GSList *recipient_list = NULL;
+	GSList *attach_list = NULL;
+	gint i = 0;
+	/* headers */
+
+	if (!camel_internet_address_get((const CamelInternetAddress *)from, 0, &namep, &addressp)) {
+		printf("index\n");
+		return (FALSE);
+	}
+	/** WARNING: double check **/
+	mapi_item_set_from (item, namep);
+
+	to = camel_mime_message_get_recipients(message, CAMEL_RECIPIENT_TYPE_TO);
+	for (i = 0; camel_internet_address_get(to, i, &namep, &addressp); i++){
+		mapi_item_add_recipient (addressp, olTo, &recipient_list);
+	}
+
+	cc = camel_mime_message_get_recipients(message, CAMEL_RECIPIENT_TYPE_CC);
+	for (i = 0; camel_internet_address_get(cc, i, &namep, &addressp); i++) {
+		mapi_item_add_recipient (addressp, olCC, &recipient_list);
+	}
+
+	bcc = camel_mime_message_get_recipients(message, CAMEL_RECIPIENT_TYPE_BCC);
+	for (i = 0; camel_internet_address_get(bcc, i, &namep, &addressp); i++) {
+		mapi_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));
+	}
+
+	/* contents body */
+	multipart = (CamelMultipart *)camel_medium_get_content_object (CAMEL_MEDIUM (message));
+
+	if (CAMEL_IS_MULTIPART(multipart)) {
+		if (mapi_do_multipart(CAMEL_MULTIPART(multipart), item))
+			printf("camel message multi part error\n");
+	} else {
+		content_stream = (CamelStream *)camel_stream_mem_new();
+		dw = camel_medium_get_content_object (CAMEL_MEDIUM (message));
+		type = camel_mime_part_get_content_type((CamelMimePart *)message);
+		content_type = camel_content_type_simple (type);
+		content_size = camel_data_wrapper_write_to_stream(dw, (CamelStream *)content_stream);
+		mapi_item_set_body_stream (item, content_stream, PART_TYPE_PLAIN_TEXT);
+	}
+	
+	mapi_item_debug_dump (item);
+
+	/* send */
+	st = mapi_message_item_send(item, attach_list, recipient_list);
+
+	if (st == -1) {
+		printf("[!] cannot send(%s)\n", item->header.to);
+		mapi_errstr("Cannot Send", GetLastError()); 
+		return (FALSE);
+	}
+	
+	return (TRUE);
+}
+
+
+static char*
+mapi_transport_get_name(CamelService *service, gboolean brief)
+{
+	if (brief) {
+		return g_strdup_printf (_("MAPI server %s"), service->url->host);
+	} else {
+		return g_strdup_printf (_("MAPI service for %s on %s"),
+					service->url->user, service->url->host);
+	}
+}
+
+
+static void
+camel_mapi_transport_class_init(CamelMapiTransportClass *camel_mapi_transport_class)
+{
+	CamelTransportClass *camel_transport_class =
+		CAMEL_TRANSPORT_CLASS (camel_mapi_transport_class);
+	CamelServiceClass *camel_service_class =
+		CAMEL_SERVICE_CLASS (camel_mapi_transport_class);
+  
+	camel_service_class->get_name = mapi_transport_get_name;
+	camel_transport_class->send_to = mapi_send_to;
+}
+
+static void
+camel_mapi_transport_init (CamelTransport *transport)
+{
+
+}
+
+CamelType
+camel_mapi_transport_get_type (void)
+{
+	static CamelType camel_mapi_transport_type = CAMEL_INVALID_TYPE;
+  
+	if (camel_mapi_transport_type == CAMEL_INVALID_TYPE) {
+		camel_mapi_transport_type =
+			camel_type_register (CAMEL_TRANSPORT_TYPE,
+					     "CamelMapiTransport",
+					     sizeof (CamelMapiTransport),
+					     sizeof (CamelMapiTransportClass),
+					     (CamelObjectClassInitFunc) camel_mapi_transport_class_init,
+					     NULL,
+					     (CamelObjectInitFunc) camel_mapi_transport_init,
+					     NULL);
+	}
+
+	return camel_mapi_transport_type;
+}
+
+static gint
+mail_build_props (struct SPropValue **value, struct SPropTagArray *SPropTagArray, gpointer data)
+{
+
+	MapiItem *item = (MapiItem *) data;
+	struct SPropValue *props;
+	GSList *l;
+
+	uint32_t *msgflag = g_new0 (uint32_t, 1);
+	int i=0;
+
+	props = g_new0 (struct SPropValue, 6);
+
+	set_SPropValue_proptag(&props[i++], PR_CONVERSATION_TOPIC, g_strdup (item->header.subject));
+	set_SPropValue_proptag(&props[i++], PR_NORMALIZED_SUBJECT, g_strdup (item->header.subject));
+
+	*msgflag = MSGFLAG_UNSENT;
+	set_SPropValue_proptag(&props[i++], PR_MESSAGE_FLAGS, (void *)msgflag);
+
+	for (l = item->msg.body_parts; l; l = l->next) {
+		ExchangeMAPIStream *stream = (ExchangeMAPIStream *) (l->data);
+		struct SBinary_short *bin = g_new0 (struct SBinary_short, 1);
+
+		bin->cb = stream->value->len;
+		bin->lpb = (uint8_t *)stream->value->data;
+		if (stream->proptag == PR_HTML)
+			set_SPropValue_proptag(&props[i++], stream->proptag, (void *)bin);
+		else if (stream->proptag == PR_BODY)
+			set_SPropValue_proptag(&props[i++], stream->proptag, (void *)stream->value->data);
+	}
+
+	/*  FIXME : */
+	/* editor = EDITOR_FORMAT_PLAINTEXT; */
+	/* set_SPropValue_proptag(&props[i++], PR_MSG_EDITOR_FORMAT, (const void *)editor); */
+
+	*value = props;
+	return i;
+}
+
+static void
+mapi_item_add_recipient (const char *recipients, OlMailRecipientType type, GSList **recipient_list)
+{
+	uint32_t val = 0;
+	const char *str = NULL;
+
+	if (!recipients)
+		return ;
+
+	ExchangeMAPIRecipient *recipient = g_new0 (ExchangeMAPIRecipient, 1);
+
+	recipient->email_id = recipients;
+
+	/* this memory should be freed somewhere, perhaps in the existing
+	 * exchange_mapi_util_free_recipient_list() */
+	recipient->in.req_lpProps = g_new0 (struct SPropValue, 1);
+	recipient->in.req_cValues = 1;
+	set_SPropValue_proptag (&(recipient->in.req_lpProps[0]), PR_RECIPIENT_TYPE, (const void *) &type);
+
+	/* External recipient properties - set them only when the recipient is unresolved */
+	recipient->in.ext_lpProps = g_new0 (struct SPropValue, 5);
+	recipient->in.ext_cValues = 5;
+
+	val = DT_MAILUSER;
+	set_SPropValue_proptag (&(recipient->in.ext_lpProps[0]), PR_DISPLAY_TYPE, (const void *)&val);
+	val = MAPI_MAILUSER;
+	set_SPropValue_proptag (&(recipient->in.ext_lpProps[1]), PR_OBJECT_TYPE, (const void *)&val);
+	str = "SMTP";
+	set_SPropValue_proptag (&(recipient->in.ext_lpProps[2]), PR_ADDRTYPE, (const void *)(str));
+	str = recipient->email_id;
+	set_SPropValue_proptag (&(recipient->in.ext_lpProps[3]), PR_SMTP_ADDRESS, (const void *)(str));
+	set_SPropValue_proptag (&(recipient->in.ext_lpProps[4]), PR_DISPLAY_NAME, (const void *)(str));
+
+	*recipient_list = g_slist_append (*recipient_list, recipient);
+}
+
+static int
+mapi_message_item_send (MapiItem *item, GSList *attachments, GSList *recipients)
+{
+	guint64 fid = 0;
+
+	exchange_mapi_create_item (olFolderOutbox, fid, NULL, NULL, mail_build_props, item, recipients, item->attachments, item->generic_streams, 0);
+
+	return 0;
+}

Added: trunk/src/camel/camel-mapi-transport.h
==============================================================================
--- (empty file)
+++ trunk/src/camel/camel-mapi-transport.h	Wed Nov 19 04:28:20 2008
@@ -0,0 +1,56 @@
+/* -*- 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/>  
+ *
+ *
+ * Authors:
+ *     Johnny Jacob <jjohnny novell com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef CAMEL_MAPI_TRANSPORT_H
+#define CAMEL_MAPI_TRANSPORT_H 1
+
+#include <libmapi/libmapi.h>
+#include <camel/camel-transport.h>
+#include <exchange-mapi-connection.h>
+
+#define CAMEL_MAPI_TRANSPORT_TYPE     (camel_mapi_transport_get_type ())
+#define CAMEL_MAPI_TRANSPORT(obj)     (CAMEL_CHECK_CAST((obj), CAMEL_MAPI_TRANSPORT_TYPE, CamelMapiTransport))
+#define CAMEL_MAPI_TRANSPORT_CLASS(k) (CAMEL_CHECK_CLASS_CAST ((k), CAMEL_MAPI_TRANSPORT_TYPE, CamelMapiTransportClass))
+#define CAMEL_IS_MAPI_TRANSPORT(o)    (CAMEL_CHECK_TYPE((o), CAMEL_MAPI_TRANSPORT_TYPE))
+
+G_BEGIN_DECLS
+
+typedef struct {
+	CamelTransport parent_object;
+	gboolean connected ;
+
+} CamelMapiTransport;
+
+
+typedef struct {
+	CamelTransportClass parent_class;
+
+} CamelMapiTransportClass;
+
+
+/* Standard Camel function */
+CamelType camel_mapi_transport_get_type (void);
+
+G_END_DECLS
+
+#endif /* CAMEL_MAPI_TRANSPORT_H */

Added: trunk/src/camel/camel-private.h
==============================================================================
--- (empty file)
+++ trunk/src/camel/camel-private.h	Wed Nov 19 04:28:20 2008
@@ -0,0 +1,194 @@
+/* -*- 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/>  
+ *
+ *
+ * Authors:
+ *     Michael Zucchi <notzed ximian com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef CAMEL_PRIVATE_H
+#define CAMEL_PRIVATE_H 1
+
+/* need a way to configure and save this data, if this header is to
+   be installed.  For now, dont install it */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <pthread.h>
+#include <libedataserver/e-msgport.h>
+
+G_BEGIN_DECLS
+
+struct _CamelFolderPrivate {
+	GStaticRecMutex lock;
+	GStaticMutex change_lock;
+	/* must require the 'change_lock' to access this */
+	int frozen;
+	struct _CamelFolderChangeInfo *changed_frozen; /* queues changed events */
+};
+
+#define CAMEL_FOLDER_LOCK(f, l) \
+	(g_static_mutex_lock(&((CamelFolder *)f)->priv->l))
+#define CAMEL_FOLDER_UNLOCK(f, l) \
+	(g_static_mutex_unlock(&((CamelFolder *)f)->priv->l))
+#define CAMEL_FOLDER_REC_LOCK(f, l) \
+	(g_static_rec_mutex_lock(&((CamelFolder *)f)->priv->l))
+#define CAMEL_FOLDER_REC_UNLOCK(f, l) \
+	(g_static_rec_mutex_unlock(&((CamelFolder *)f)->priv->l))
+
+
+struct _CamelStorePrivate {
+	GStaticRecMutex folder_lock;	/* for locking folder operations */
+};
+
+#define CAMEL_STORE_LOCK(f, l) \
+	(g_static_rec_mutex_lock(&((CamelStore *)f)->priv->l))
+#define CAMEL_STORE_UNLOCK(f, l) \
+	(g_static_rec_mutex_unlock(&((CamelStore *)f)->priv->l))
+
+
+struct _CamelTransportPrivate {
+	GMutex *send_lock;   /* for locking send operations */
+};
+
+#define CAMEL_TRANSPORT_LOCK(f, l) (g_mutex_lock(((CamelTransport *)f)->priv->l))
+#define CAMEL_TRANSPORT_UNLOCK(f, l) (g_mutex_unlock(((CamelTransport *)f)->priv->l))
+
+
+struct _CamelServicePrivate {
+	GStaticRecMutex connect_lock;	/* for locking connection operations */
+	GStaticMutex connect_op_lock;	/* for locking the connection_op */
+};
+
+#define CAMEL_SERVICE_LOCK(f, l) \
+	(g_static_mutex_lock(&((CamelService *)f)->priv->l))
+#define CAMEL_SERVICE_UNLOCK(f, l) \
+	(g_static_mutex_unlock(&((CamelService *)f)->priv->l))
+#define CAMEL_SERVICE_REC_LOCK(f, l) \
+	(g_static_rec_mutex_lock(&((CamelService *)f)->priv->l))
+#define CAMEL_SERVICE_REC_UNLOCK(f, l) \
+	(g_static_rec_mutex_unlock(&((CamelService *)f)->priv->l))
+
+
+struct _CamelSessionPrivate {
+	GMutex *lock;		/* for locking everything basically */
+	GMutex *thread_lock;	/* locking threads */
+
+	int thread_id;
+	GHashTable *thread_active;
+	GThreadPool *thread_pool;
+
+	GHashTable *thread_msg_op;
+};
+
+#define CAMEL_SESSION_LOCK(f, l) (g_mutex_lock(((CamelSession *)f)->priv->l))
+#define CAMEL_SESSION_UNLOCK(f, l) (g_mutex_unlock(((CamelSession *)f)->priv->l))
+
+
+/* most of this stuff really is private, but the lock can be used by subordinate classes */
+struct _CamelFolderSummaryPrivate {
+	GHashTable *filter_charset;	/* CamelMimeFilterCharset's indexed by source charset */
+
+	struct _CamelMimeFilterIndex *filter_index;
+	struct _CamelMimeFilterBasic *filter_64;
+	struct _CamelMimeFilterBasic *filter_qp;
+	struct _CamelMimeFilterBasic *filter_uu;
+	struct _CamelMimeFilterSave *filter_save;
+	struct _CamelMimeFilterHTML *filter_html;
+
+	struct _CamelStreamFilter *filter_stream;
+
+	struct _CamelIndex *index;
+	
+	GMutex *summary_lock;	/* for the summary hashtable/array */
+	GMutex *io_lock;	/* load/save lock, for access to saved_count, etc */
+	GMutex *filter_lock;	/* for accessing any of the filtering/indexing stuff, since we share them */
+	GMutex *alloc_lock;	/* for setting up and using allocators */
+	GMutex *ref_lock;	/* for reffing/unreffing messageinfo's ALWAYS obtain before summary_lock */
+};
+
+#define CAMEL_SUMMARY_LOCK(f, l) (g_mutex_lock(((CamelFolderSummary *)f)->priv->l))
+#define CAMEL_SUMMARY_UNLOCK(f, l) (g_mutex_unlock(((CamelFolderSummary *)f)->priv->l))
+
+
+struct _CamelStoreSummaryPrivate {
+	GMutex *summary_lock;	/* for the summary hashtable/array */
+	GMutex *io_lock;	/* load/save lock, for access to saved_count, etc */
+	GMutex *alloc_lock;	/* for setting up and using allocators */
+	GMutex *ref_lock;	/* for reffing/unreffing messageinfo's ALWAYS obtain before summary_lock */
+};
+
+#define CAMEL_STORE_SUMMARY_LOCK(f, l) (g_mutex_lock(((CamelStoreSummary *)f)->priv->l))
+#define CAMEL_STORE_SUMMARY_UNLOCK(f, l) (g_mutex_unlock(((CamelStoreSummary *)f)->priv->l))
+
+
+struct _CamelVeeFolderPrivate {
+	GList *folders;			/* lock using subfolder_lock before changing/accessing */
+	GList *folders_changed;		/* for list of folders that have changed between updates */
+	
+	GMutex *summary_lock;		/* for locking vfolder summary */
+	GMutex *subfolder_lock;		/* for locking the subfolder list */
+	GMutex *changed_lock;		/* for locking the folders-changed list */
+};
+
+#define CAMEL_VEE_FOLDER_LOCK(f, l) (g_mutex_lock(((CamelVeeFolder *)f)->priv->l))
+#define CAMEL_VEE_FOLDER_UNLOCK(f, l) (g_mutex_unlock(((CamelVeeFolder *)f)->priv->l))
+
+
+struct _CamelDataWrapperPrivate {
+	pthread_mutex_t stream_lock;
+};
+
+#define CAMEL_DATA_WRAPPER_LOCK(dw, l)   (pthread_mutex_lock(&((CamelDataWrapper *)dw)->priv->l))
+#define CAMEL_DATA_WRAPPER_UNLOCK(dw, l) (pthread_mutex_unlock(&((CamelDataWrapper *)dw)->priv->l))
+
+
+/* most of this stuff really is private, but the lock can be used by subordinate classes */
+struct _CamelCertDBPrivate {
+	GMutex *db_lock;	/* for the db hashtable/array */
+	GMutex *io_lock;	/* load/save lock, for access to saved_count, etc */
+	GMutex *alloc_lock;	/* for setting up and using allocators */
+	GMutex *ref_lock;	/* for reffing/unreffing certs */
+};
+
+#define CAMEL_CERTDB_LOCK(db, l) (g_mutex_lock (((CamelCertDB *) db)->priv->l))
+#define CAMEL_CERTDB_UNLOCK(db, l) (g_mutex_unlock (((CamelCertDB *) db)->priv->l))
+
+#ifdef G_OS_WIN32
+int fsync (int fd);
+
+const char *_camel_get_localedir (void) G_GNUC_CONST;
+const char *_camel_get_libexecdir (void) G_GNUC_CONST;
+const char *_camel_get_providerdir (void) G_GNUC_CONST;
+
+#undef EVOLUTION_LOCALEDIR
+#define EVOLUTION_LOCALEDIR _camel_get_localedir ()
+
+#undef CAMEL_LIBEXECDIR
+#define CAMEL_LIBEXECDIR _camel_get_libexecdir ()
+
+#undef CAMEL_PROVIDERDIR
+#define CAMEL_PROVIDERDIR _camel_get_providerdir ()
+
+#endif /* G_OS_WIN32 */
+
+G_END_DECLS
+
+#endif /* CAMEL_PRIVATE_H */

Added: trunk/src/camel/libcamelmapi.urls
==============================================================================
--- (empty file)
+++ trunk/src/camel/libcamelmapi.urls	Wed Nov 19 04:28:20 2008
@@ -0,0 +1 @@
+mapi

Added: trunk/src/libexchangemapi/Makefile.am
==============================================================================
--- (empty file)
+++ trunk/src/libexchangemapi/Makefile.am	Wed Nov 19 04:28:20 2008
@@ -0,0 +1,60 @@
+INCLUDES =					\
+	-DG_LOG_DOMAIN=\"libexchangemapi\"	\
+	-DMAPI_DATADIR=\""$(mapidatadir)"\"	\
+	$(EVOLUTION_DATA_SERVER_CFLAGS)		\
+	$(LIBEDATASERVER_CFLAGS)		\
+	-I$(top_srcdir)				\
+	$(EVOLUTION_CALENDAR_CFLAGS)		\
+	$(LIBMAPI_CFLAGS)
+
+
+lib_LTLIBRARIES = libexchangemapi-1.0.la
+
+mapidata_DATA = 				\
+	tz-mapi-to-ical 			\
+	tz-ical-to-mapi 
+
+libexchangemapi_1_0_la_SOURCES =		\
+	exchange-mapi-defs.h			\
+	exchange-mapi-folder.c			\
+	exchange-mapi-folder.h			\
+	exchange-mapi-connection.c		\
+	exchange-mapi-connection.h		\
+	exchange-mapi-utils.c			\
+	exchange-mapi-utils.h			\
+	exchange-mapi-cal-utils.c		\
+	exchange-mapi-cal-utils.h		\
+	exchange-mapi-cal-tz-utils.c		\
+	exchange-mapi-cal-tz-utils.h		\
+	exchange-mapi-cal-recur-utils.c		\
+	exchange-mapi-cal-recur-utils.h
+
+
+libexchangemapi_1_0_la_LIBADD =			\
+	$(EVOLUTION_DATA_SERVER_LIBS)			\
+	$(EVOLUTION_CALENDAR_LIBS)		\
+	$(LIBMAPI_LIBS)
+
+libexchangemapiincludedir = $(edataserver_privincludedir)/mapi
+
+libexchangemapiinclude_HEADERS = 		\
+	exchange-mapi-defs.h			\
+	exchange-mapi-folder.h			\
+	exchange-mapi-connection.h		\
+	exchange-mapi-utils.h			\
+	exchange-mapi-cal-utils.h		\
+	exchange-mapi-cal-tz-utils.h		\
+	exchange-mapi-cal-recur-utils.h
+
+%-1.0.pc: %.pc.in
+	 cp $< $@
+
+pkgconfigdir = $(libdir)/pkgconfig
+pkgconfig_DATA = libexchangemapi-1.0.pc
+
+EXTRA_DIST = 						\
+	$(pkgconfig_DATA:-$(API_VERSION).pc=.pc.in) 	\
+	$(mapidata_DATA)
+
+DISTCLEANFILES = $(pkgconfig_DATA)
+

Added: trunk/src/libexchangemapi/exchange-mapi-cal-recur-utils.c
==============================================================================
--- (empty file)
+++ trunk/src/libexchangemapi/exchange-mapi-cal-recur-utils.c	Wed Nov 19 04:28:20 2008
@@ -0,0 +1,1150 @@
+/* -*- 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/>  
+ *
+ *
+ * Authors:
+ *    Suman Manjunath <msuman novell com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#include "exchange-mapi-cal-recur-utils.h"
+
+/* Reader/Writer versions */
+#define READER_VERSION 	0x3004
+#define WRITER_VERSION 	0x3004
+#define READER_VERSION2 0x3006
+#define WRITER_VERSION2 0x3009
+
+#if 0
+struct ChangeHighlight {
+	uint32_t Size; 
+	uint32_t Value; 
+	uint32_t Reserved; 
+};
+
+struct ExtendedException {
+	struct ChangeHighlight ch; 
+	uint32_t ReservedEE1Size;
+	uint32_t ReservedEE1;
+	uint32_t StartDateTime; 
+	uint32_t EndDateTime; 
+	uint32_t OrigStartDate; 
+	uint16_t WideCharSubjectLength; 
+	gchar *WideCharSubject; 
+	uint16_t WideCharLocationLength; 
+	gchar *WideCharLocation; 
+	uint32_t ReservedEE2Size;
+	uint32_t ReservedEE2;
+};
+
+struct ExceptionInfo {
+	uint32_t StartDateTime; 
+	uint32_t EndDateTime; 
+	uint32_t OrigStartDate; 
+	uint16_t OverrideFlags; 
+	uint16_t SubjectLength; 
+	uint16_t SubjectLength2; 
+	gchar *Subject; 
+	uint32_t MeetingType; 
+	uint32_t ReminderDelta; 
+	uint32_t ReminderSet; 
+	uint16_t LocationLength; 
+	uint16_t LocationLength2; 
+	gchar *Location; 
+	uint32_t BusyStatus; 
+	uint32_t Attachment; 
+	uint32_t SubType; 
+	uint32_t AppointmentColor; 
+};
+#endif
+
+static icalrecurrencetype_weekday 
+get_ical_weekstart (uint32_t fdow) 
+{
+	switch (fdow) {
+		case FirstDOW_Sunday 	: return ICAL_SUNDAY_WEEKDAY;
+		case FirstDOW_Monday 	: return ICAL_MONDAY_WEEKDAY;
+		case FirstDOW_Tuesday 	: return ICAL_TUESDAY_WEEKDAY;
+		case FirstDOW_Wednesday : return ICAL_WEDNESDAY_WEEKDAY;
+		case FirstDOW_Thursday 	: return ICAL_THURSDAY_WEEKDAY;
+		case FirstDOW_Friday 	: return ICAL_FRIDAY_WEEKDAY;
+		case FirstDOW_Saturday 	: return ICAL_SATURDAY_WEEKDAY;
+		default 		: return ICAL_SUNDAY_WEEKDAY;
+	}
+}
+
+static uint32_t 
+get_mapi_weekstart (icalrecurrencetype_weekday weekstart) 
+{
+	switch (weekstart) {
+		case ICAL_SUNDAY_WEEKDAY   : return FirstDOW_Sunday;
+		case ICAL_MONDAY_WEEKDAY   : return FirstDOW_Monday;
+		case ICAL_TUESDAY_WEEKDAY  : return FirstDOW_Tuesday;
+		case ICAL_WEDNESDAY_WEEKDAY: return FirstDOW_Wednesday;
+		case ICAL_THURSDAY_WEEKDAY : return FirstDOW_Thursday;
+		case ICAL_FRIDAY_WEEKDAY   : return FirstDOW_Friday;
+		case ICAL_SATURDAY_WEEKDAY : return FirstDOW_Saturday;
+		default 		   : return FirstDOW_Sunday;
+	}
+}
+
+static uint32_t 
+get_mapi_day (icalrecurrencetype_weekday someday)
+{
+	switch (someday) {
+		case ICAL_SUNDAY_WEEKDAY   : return olSunday;
+		case ICAL_MONDAY_WEEKDAY   : return olMonday;
+		case ICAL_TUESDAY_WEEKDAY  : return olTuesday;
+		case ICAL_WEDNESDAY_WEEKDAY: return olWednesday;
+		case ICAL_THURSDAY_WEEKDAY : return olThursday;
+		case ICAL_FRIDAY_WEEKDAY   : return olFriday;
+		case ICAL_SATURDAY_WEEKDAY : return olSaturday;
+		default 		   : return 0;
+	}
+}
+
+static int32_t 
+get_ical_pos (uint32_t pos) 
+{
+	switch (pos) {
+		case RecurrenceN_First 	: return 1;
+		case RecurrenceN_Second : return 2;
+		case RecurrenceN_Third 	: return 3;
+		case RecurrenceN_Fourth : return 4;
+		case RecurrenceN_Last 	: return (-1);
+		default 		: return 0;
+	}
+}
+
+static uint32_t 
+get_mapi_pos (int32_t pos) 
+{
+	switch (pos) {
+		case 1 	: return RecurrenceN_First;
+		case 2 	: return RecurrenceN_Second;
+		case 3 	: return RecurrenceN_Third;
+		case 4 	: return RecurrenceN_Fourth;
+		case -1 : return RecurrenceN_Last;
+		default : return 0;
+	}
+}
+
+#define cFileTimeUnitsPerSecond 10000000
+
+static void
+convert_recurrence_minutes_to_date (uint32_t minutes, struct FILETIME *ft)
+{
+	NTTIME nt; 
+
+	nt = (NTTIME) minutes * (60 * cFileTimeUnitsPerSecond); 
+
+	ft->dwLowDateTime = (uint32_t)((nt << 32) >> 32); 
+	ft->dwHighDateTime = (uint32_t)(nt >> 32); 
+}
+
+static uint32_t
+convert_date_to_recurrence_minutes (const struct FILETIME *ft)
+{
+	NTTIME minutes;
+
+	minutes = ft->dwHighDateTime; 
+	minutes = minutes << 32;
+	minutes |= ft->dwLowDateTime;
+
+	minutes = minutes / (60 * cFileTimeUnitsPerSecond); 
+
+	return (uint32_t)(minutes);
+}
+
+static time_t 
+convert_filetime_to_timet (const struct FILETIME *ft)
+{
+	NTTIME time; 
+
+	time = ft->dwHighDateTime;
+	time = time << 32;
+	time |= ft->dwLowDateTime;
+
+	return nt_time_to_unix (time);
+}
+
+static void 
+convert_timet_to_filetime (time_t t, struct FILETIME *ft)
+{
+	NTTIME nt; 
+
+	unix_to_nt_time (&nt, t);
+
+	ft->dwLowDateTime = (uint32_t)((nt << 32) >> 32); 
+	ft->dwHighDateTime = (uint32_t)(nt >> 32); 
+}
+
+static time_t
+convert_recurrence_minutes_to_timet (uint32_t minutes)
+{
+	NTTIME nt; 
+
+	nt = (NTTIME) minutes * (60 * cFileTimeUnitsPerSecond); 
+
+	return nt_time_to_unix (nt);
+}
+
+static uint32_t
+convert_timet_to_recurrence_minutes (time_t t)
+{
+	NTTIME minutes;
+
+	unix_to_nt_time (&minutes, t);
+
+	minutes = minutes / (60 * cFileTimeUnitsPerSecond); 
+
+	return (uint32_t)(minutes);
+}
+
+static gboolean 
+check_calendar_type (guint16 type) 
+{
+	/* Calendar Type - We support Gregorian only. */
+	if (type == CAL_DEFAULT || type == CAL_GREGORIAN)
+		return TRUE; 
+	else {
+		g_warning ("Calendar type = 0x%04X - Evolution does not handle such calendar types.", type); 
+		return FALSE; 
+	}
+}
+
+gboolean
+exchange_mapi_cal_util_bin_to_rrule (GByteArray *ba, ECalComponent *comp)
+{
+	struct icalrecurrencetype rt;
+	guint16 flag16;
+	guint32 flag32;
+	guint8 *ptr = ba->data;
+	gint i;
+	GSList *exdate_list = NULL, *modified_list = NULL; 
+	gboolean repeats_until_date = FALSE; 
+
+	icalrecurrencetype_clear (&rt);
+
+	/* Reader version */
+	flag16 = *((guint16 *)ptr);
+	ptr += sizeof (guint16);
+	if (READER_VERSION != flag16)
+		return FALSE;
+
+	/* Writer version */
+	flag16 = *((guint16 *)ptr);
+	ptr += sizeof (guint16);
+	if (WRITER_VERSION != flag16)
+		return FALSE;
+
+	/* FREQUENCY */
+	flag16 = *((guint16 *)ptr);
+	ptr += sizeof (guint16);
+	if (flag16 == RecurFrequency_Daily) {
+		rt.freq = ICAL_DAILY_RECURRENCE;
+
+		flag16 = *((guint16 *)ptr);
+		ptr += sizeof (guint16);
+		if (flag16 == PatternType_Day) {
+			/* Daily every N days */
+
+			/* Calendar Type */
+			flag16 = *((guint16 *)ptr);
+			ptr += sizeof (guint16);
+			if (!check_calendar_type (flag16))
+				return FALSE;
+
+			/* FirstDateTime (some crappy mod here) */
+			flag32 = *((guint32 *)ptr);
+			ptr += sizeof (guint32);
+
+			/* INTERVAL */
+			flag32 = *((guint32 *)ptr);
+			ptr += sizeof (guint32);
+			rt.interval = (short) (flag32 / (24 * 60));
+
+			/* some constant 0 for the stuff we handle */
+			flag32 = *((guint32 *)ptr);
+			ptr += sizeof (guint32);
+			if (flag32)
+				return FALSE;
+
+		} else if (flag16 == PatternType_Week) {
+			/* Daily every weekday */
+
+			/* Calendar Type */
+			flag16 = *((guint16 *)ptr);
+			ptr += sizeof (guint16);
+			if (!check_calendar_type (flag16))
+				return FALSE;
+
+	/* NOTE: Evolution does not handle daily-every-weekday any different 
+	 * from a weekly recurrence.
+	 */
+			rt.freq = ICAL_WEEKLY_RECURRENCE;
+
+			/* FirstDateTime (some crappy mod here) */
+			flag32 = *((guint32 *)ptr);
+			ptr += sizeof (guint32);
+
+			/* INTERVAL */
+			flag32 = *((guint32 *)ptr);
+			ptr += sizeof (guint32);
+			rt.interval = (short) (flag32);
+
+			/* some constant 0 for the stuff we handle */
+			flag32 = *((guint32 *)ptr);
+			ptr += sizeof (guint32);
+			if (flag32)
+				return FALSE;
+
+			/* BITMASK */
+			flag32 = *((guint32 *)ptr);
+			ptr += sizeof (guint32);
+
+			i = 0;
+			if (flag32 & olSunday)
+				rt.by_day[i++] = ICAL_SUNDAY_WEEKDAY;
+			if (flag32 & olMonday)
+				rt.by_day[i++] = ICAL_MONDAY_WEEKDAY;
+			if (flag32 & olTuesday)
+				rt.by_day[i++] = ICAL_TUESDAY_WEEKDAY;
+			if (flag32 & olWednesday)
+				rt.by_day[i++] = ICAL_WEDNESDAY_WEEKDAY;
+			if (flag32 & olThursday)
+				rt.by_day[i++] = ICAL_THURSDAY_WEEKDAY;
+			if (flag32 & olFriday)
+				rt.by_day[i++] = ICAL_FRIDAY_WEEKDAY;
+			if (flag32 & olSaturday)
+				rt.by_day[i++] = ICAL_SATURDAY_WEEKDAY;
+		}
+
+	} else if (flag16 == RecurFrequency_Weekly) {
+		rt.freq = ICAL_WEEKLY_RECURRENCE;
+
+		flag16 = *((guint16 *)ptr);
+		ptr += sizeof (guint16);
+		if (flag16 == PatternType_Week) {
+			/* weekly every N weeks (for all events and non-regenerating tasks) */
+
+			/* Calendar Type */
+			flag16 = *((guint16 *)ptr);
+			ptr += sizeof (guint16);
+			if (!check_calendar_type (flag16))
+				return FALSE;
+
+			/* FirstDateTime (some crappy mod here) */
+			flag32 = *((guint32 *)ptr);
+			ptr += sizeof (guint32);
+
+			/* INTERVAL */
+			flag32 = *((guint32 *)ptr);
+			ptr += sizeof (guint32);
+			rt.interval = (short) (flag32);
+
+			/* some constant 0 */
+			flag32 = *((guint32 *)ptr);
+			ptr += sizeof (guint32);
+			if (flag32)
+				return FALSE;
+
+			/* BITMASK */
+			flag32 = *((guint32 *)ptr);
+			ptr += sizeof (guint32);
+
+			i = 0;
+			if (flag32 & olSunday)
+				rt.by_day[i++] = ICAL_SUNDAY_WEEKDAY;
+			if (flag32 & olMonday)
+				rt.by_day[i++] = ICAL_MONDAY_WEEKDAY;
+			if (flag32 & olTuesday)
+				rt.by_day[i++] = ICAL_TUESDAY_WEEKDAY;
+			if (flag32 & olWednesday)
+				rt.by_day[i++] = ICAL_WEDNESDAY_WEEKDAY;
+			if (flag32 & olThursday)
+				rt.by_day[i++] = ICAL_THURSDAY_WEEKDAY;
+			if (flag32 & olFriday)
+				rt.by_day[i++] = ICAL_FRIDAY_WEEKDAY;
+			if (flag32 & olSaturday)
+				rt.by_day[i++] = ICAL_SATURDAY_WEEKDAY;
+
+		} else if (flag16 == 0x0) {
+			/* weekly every N weeks (for all regenerating tasks) */
+
+			/* Calendar Type */
+			flag16 = *((guint16 *)ptr);
+			ptr += sizeof (guint16);
+			if (!check_calendar_type (flag16))
+				return FALSE;
+
+			/* FIXME: we don't handle regenerating tasks */
+			g_warning ("Evolution does not handle recurring tasks."); 
+			return FALSE;
+		}
+
+	} else if (flag16 == RecurFrequency_Monthly) {
+		rt.freq = ICAL_MONTHLY_RECURRENCE;
+
+		flag16 = *((guint16 *)ptr);
+		ptr += sizeof (guint16);
+		if (flag16 == PatternType_Month || flag16 == PatternType_MonthEnd) {
+			guint16 pattern = flag16; 
+			/* Monthly every N months on day D or last day. */
+
+			/* Calendar Type */
+			flag16 = *((guint16 *)ptr);
+			ptr += sizeof (guint16);
+			if (!check_calendar_type (flag16))
+				return FALSE;
+
+			/* FirstDateTime (some crappy mod here) */
+			flag32 = *((guint32 *)ptr);
+			ptr += sizeof (guint32);
+
+			/* INTERVAL */
+			flag32 = *((guint32 *)ptr);
+			ptr += sizeof (guint32);
+			rt.interval = (short) (flag32);
+
+			/* some constant 0 for the stuff we handle */
+			flag32 = *((guint32 *)ptr);
+			ptr += sizeof (guint32);
+			if (flag32)
+				return FALSE;
+
+			/* MONTH_DAY */ 
+			flag32 = *((guint32 *)ptr);
+			ptr += sizeof (guint32);
+			if (pattern == PatternType_Month)
+				rt.by_month_day[0] = (short) (flag32);
+			else if (pattern == PatternType_MonthEnd)
+				rt.by_month_day[0] = (short) (-1);
+
+		} else if (flag16 == PatternType_MonthNth) {
+			gboolean post_process = FALSE; 
+			guint32 mask = 0;
+			/* Monthly every N months on the Xth Y */
+
+			/* Calendar Type */
+			flag16 = *((guint16 *)ptr);
+			ptr += sizeof (guint16);
+			if (!check_calendar_type (flag16))
+				return FALSE;
+
+			/* FirstDateTime (some crappy mod here) */
+			flag32 = *((guint32 *)ptr);
+			ptr += sizeof (guint32);
+
+			/* INTERVAL */
+			flag32 = *((guint32 *)ptr);
+			ptr += sizeof (guint32);
+			rt.interval = (short) (flag32);
+
+			/* some constant 0 for the stuff we handle */
+			flag32 = *((guint32 *)ptr);
+			ptr += sizeof (guint32);
+			if (flag32)
+				return FALSE;
+			
+			/* BITMASK */
+			flag32 = *((guint32 *)ptr);
+			ptr += sizeof (guint32);
+			if (flag32 == olSunday)
+				rt.by_day[0] = ICAL_SUNDAY_WEEKDAY;
+			else if (flag32 == olMonday)
+				rt.by_day[0] = ICAL_MONDAY_WEEKDAY;
+			else if (flag32 == olTuesday)
+				rt.by_day[0] = ICAL_TUESDAY_WEEKDAY;
+			else if (flag32 == olWednesday)
+				rt.by_day[0] = ICAL_WEDNESDAY_WEEKDAY;
+			else if (flag32 == olThursday)
+				rt.by_day[0] = ICAL_THURSDAY_WEEKDAY;
+			else if (flag32 == olFriday)
+				rt.by_day[0] = ICAL_FRIDAY_WEEKDAY;
+			else if (flag32 == olSaturday)
+				rt.by_day[0] = ICAL_SATURDAY_WEEKDAY;
+			else {
+				post_process = TRUE; 
+				mask = flag32; 
+			}
+				
+			/* RecurrenceN */
+			flag32 = *((guint32 *)ptr);
+			ptr += sizeof (guint32);
+			if (!post_process) {
+				rt.by_set_pos[0] = get_ical_pos (flag32); 
+				if (rt.by_set_pos[0] == 0)
+					return FALSE; 
+			} else {
+				if (mask == (olSunday | olMonday | olTuesday | olWednesday | olThursday | olFriday | olSaturday)) {
+					rt.by_month_day[0] = get_ical_pos (flag32); 
+					if (rt.by_month_day[0] == 0)
+						return FALSE; 
+				} else {
+				/* FIXME: Can we/LibICAL support any other types here? Namely, weekday and weekend-day */
+					g_warning ("Encountered a recurrence type Evolution cannot handle. "); 
+					return FALSE;
+				}
+			}
+		}
+
+	} else if (flag16 == RecurFrequency_Yearly) {
+		rt.freq = ICAL_YEARLY_RECURRENCE;
+
+		flag16 = *((guint16 *)ptr);
+		ptr += sizeof (guint16);
+		if (flag16 == PatternType_Month) {
+			/* Yearly on day D of month M */
+
+			/* Calendar Type */
+			flag16 = *((guint16 *)ptr);
+			ptr += sizeof (guint16);
+			if (!check_calendar_type (flag16))
+				return FALSE;
+
+			/* FirstDateTime (some crappy mod here) */
+			flag32 = *((guint32 *)ptr);
+			ptr += sizeof (guint32);
+
+			/* INTERVAL */
+			flag32 = *((guint32 *)ptr);
+			ptr += sizeof (guint32);
+			rt.interval = (short) (flag32 / 12);
+
+			/* some constant 0 for the stuff we handle */
+			flag32 = *((guint32 *)ptr);
+			ptr += sizeof (guint32);
+			if (flag32)
+				return FALSE;
+
+			/* MONTH_DAY - but we don't need this */
+			flag32 = *((guint32 *)ptr);
+			ptr += sizeof (guint32);
+
+		} else if (flag16 == PatternType_MonthNth) {
+			/* Yearly on the Xth Y of month M */
+
+			g_warning ("Encountered a recurrence pattern Evolution cannot handle.");
+
+			/* Calendar Type */
+			flag16 = *((guint16 *)ptr);
+			ptr += sizeof (guint16);
+			if (!check_calendar_type (flag16))
+				return FALSE;
+
+			/* FirstDateTime (some crappy mod here) */
+			flag32 = *((guint32 *)ptr);
+			ptr += sizeof (guint32);
+
+			/* INTERVAL */
+			flag32 = *((guint32 *)ptr);
+			ptr += sizeof (guint32);
+			rt.interval = (short) (flag32 / 12);
+
+			/* some constant 0 */
+			flag32 = *((guint32 *)ptr);
+			ptr += sizeof (guint32);
+			if (flag32)
+				return FALSE;
+
+			/* BITMASK */
+			flag32 = *((guint32 *)ptr);
+			ptr += sizeof (guint32);
+
+			/* RecurrenceN */
+			flag32 = *((guint32 *)ptr);
+			ptr += sizeof (guint32);
+
+			/* TODO: Add support for this kinda recurrence in Evolution */
+			return FALSE;
+		}
+	} else 
+		return FALSE;
+
+	/* End Type - followed by Occurence count */
+	flag32 = *((guint32 *)ptr);
+	ptr += sizeof (guint32);
+	if (flag32 == END_AFTER_DATE) {
+		flag32 = *((guint32 *)ptr);
+		ptr += sizeof (guint32);
+
+		repeats_until_date = TRUE;
+	} else if (flag32 == END_AFTER_N_OCCURRENCES) {
+		flag32 = *((guint32 *)ptr);
+		ptr += sizeof (guint32);
+
+		rt.count = flag32;
+	} else if (flag32 == END_NEVER_END) {
+		flag32 = *((guint32 *)ptr);
+		ptr += sizeof (guint32);
+	}
+
+	/* week_start */
+	flag32 = *((guint32 *)ptr);
+	ptr += sizeof (guint32);
+	rt.week_start = get_ical_weekstart (flag32);
+
+	/* number of exceptions */
+	flag32 = *((guint32 *)ptr);
+	ptr += sizeof (guint32);
+	if (flag32) {
+		for (i = 0; i < flag32; ++i) {
+			uint32_t exdate; 
+			struct icaltimetype tt, *val; 
+			ECalComponentDateTime *dt = g_new0 (ECalComponentDateTime, 1); 
+
+			exdate = *((guint32 *)ptr);
+			ptr += sizeof (guint32);
+
+			tt = icaltime_from_timet_with_zone (convert_recurrence_minutes_to_timet (exdate), 1, 0);
+
+			val = g_new0(struct icaltimetype, 1); 
+			memcpy (val, &tt, sizeof(struct icaltimetype)); 
+
+			dt->value = val; 
+			dt->tzid = g_strdup ("UTC"); 
+
+			exdate_list = g_slist_append (exdate_list, dt); 
+		}
+	}
+
+	/* number of changed exceptions */
+	flag32 = *((guint32 *)ptr);
+	ptr += sizeof (guint32);
+	/* FIXME: Parse modified instances */
+	if (flag32) 
+		ptr += flag32 * sizeof (guint32);
+	
+	/* start date */
+	flag32 = *((guint32 *)ptr);
+	ptr += sizeof (guint32);
+
+	/* end date */
+	flag32 = *((guint32 *)ptr);
+	ptr += sizeof (guint32);
+	if (repeats_until_date) {
+		rt.until = icaltime_from_timet_with_zone (convert_recurrence_minutes_to_timet (flag32), 1, 0);
+	}
+
+	/* some constant */
+	flag32 = *((guint32 *)ptr);
+	ptr += sizeof (guint32);
+	if (flag32 != READER_VERSION2)
+		return FALSE;
+
+	/* some constant */
+	flag32 = *((guint32 *)ptr);
+	ptr += sizeof (guint32);
+	if (flag32 != WRITER_VERSION2)
+		return FALSE;
+
+	/* start time in mins */
+	flag32 = *((guint32 *)ptr);
+	ptr += sizeof (guint32);
+
+	/* end time in mins */
+	flag32 = *((guint32 *)ptr);
+	ptr += sizeof (guint32);
+
+	/* modified exceptions */
+	flag16 = *((guint16 *)ptr);
+	ptr += sizeof (guint16);
+	if (flag16 != 0x0)
+		return FALSE;
+
+	/* reserved block1 size - has to be 0 */
+	flag32 = *((guint32 *)ptr);
+	ptr += sizeof (guint32);
+	if (flag32 != 0x0)
+		return FALSE;
+
+	/* reserved block2 size - has to be 0 */
+	flag32 = *((guint32 *)ptr);
+	ptr += sizeof (guint32);
+	if (flag32 != 0x0)
+		return FALSE;
+
+	/* Set the recurrence */
+	{
+		GSList l;
+
+		l.data = &rt; 
+		l.next = NULL;
+
+		e_cal_component_set_rrule_list (comp, &l);
+	}
+
+	/* FIXME: this also has modified instances */
+	e_cal_component_set_exdate_list (comp, exdate_list); 
+
+	g_print ("\n== MAPI to ICAL == The recurrence blob data is as follows:\n");
+	for (i = 0; i < ba->len; ++i)
+		g_print ("0x%02X ", ba->data[i]);
+	g_print("\n== End of stream ==\n"); 
+
+	return TRUE;
+}
+
+static guint32
+compute_startdate (ECalComponent *comp)
+{
+	ECalComponentDateTime dtstart; 
+	guint32 flag32; 
+
+	e_cal_component_get_dtstart (comp, &dtstart);
+	dtstart.value->hour = dtstart.value->minute = dtstart.value->second = 0; 
+	flag32 = convert_timet_to_recurrence_minutes (icaltime_as_timet_with_zone (*(dtstart.value), 0));
+
+	e_cal_component_free_datetime (&dtstart); 
+
+	return flag32; 
+}
+
+static guint32
+compute_rdaily_firstdatetime (ECalComponent *comp, guint32 period)
+{
+	return (compute_startdate (comp) % period);
+}
+
+static guint32
+compute_rweekly_firstdatetime (ECalComponent *comp, icalrecurrencetype_weekday week_start, guint32 period)
+{
+	ECalComponentDateTime dtstart; 
+	guint32 flag32; 
+	int cur_weekday = 0, weekstart_weekday = 0, diff = 0;
+	time_t t; 
+
+	e_cal_component_get_dtstart (comp, &dtstart);
+	dtstart.value->hour = dtstart.value->minute = dtstart.value->second = 0; 
+	cur_weekday = icaltime_day_of_week (*(dtstart.value));
+	t = icaltime_as_timet_with_zone (*(dtstart.value), 0);
+	e_cal_component_free_datetime (&dtstart); 
+
+	switch (week_start) {
+		case ICAL_SUNDAY_WEEKDAY 	: weekstart_weekday = 1; break; 
+		case ICAL_MONDAY_WEEKDAY 	: weekstart_weekday = 2; break; 
+		case ICAL_TUESDAY_WEEKDAY 	: weekstart_weekday = 3; break; 
+		case ICAL_WEDNESDAY_WEEKDAY 	: weekstart_weekday = 4; break; 
+		case ICAL_THURSDAY_WEEKDAY 	: weekstart_weekday = 5; break; 
+		case ICAL_FRIDAY_WEEKDAY 	: weekstart_weekday = 6; break; 
+		case ICAL_SATURDAY_WEEKDAY 	: weekstart_weekday = 7; break; 
+		default 			: weekstart_weekday = 1; break; 
+	};
+
+	diff = cur_weekday - weekstart_weekday; 
+
+	if (diff == 0); 
+	else if (diff > 0)
+		t -= (diff * 24 * 60 * 60);
+	else if (diff < 0)
+		t -= ((diff + 7) * 24 * 60 * 60);
+
+	flag32 = convert_timet_to_recurrence_minutes (t);
+
+	return (flag32 % period);
+}
+
+/* The most fucked up algorithm ever conceived by (..you know who..) */
+static guint32
+compute_rmonthly_firstdatetime (ECalComponent *comp, guint32 period)
+{
+	const guint8 dinm[] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
+	ECalComponentDateTime dtstart; 
+	guint32 flag32, monthindex, i; 
+
+	e_cal_component_get_dtstart (comp, &dtstart);
+	monthindex = (guint32)((((guint64)(12) * (dtstart.value->year - 1601)) + (dtstart.value->month - 1)) % period); 
+	e_cal_component_free_datetime (&dtstart); 
+
+	for (flag32 = 0, i = 0; i < monthindex; ++i)
+		flag32 += dinm[(i % 12) + 1] * 24 * 60;
+
+	return flag32; 
+}
+
+static guint32
+calculate_no_of_occurrences (ECalComponent *comp, const struct icalrecurrencetype *rt)
+{
+	ECalComponentDateTime dtstart; 
+	icalrecur_iterator *iter; 
+	struct icaltimetype next; 
+	guint32 count = 1; 
+
+	e_cal_component_get_dtstart (comp, &dtstart);
+
+	for (iter = icalrecur_iterator_new (*rt, *(dtstart.value)), 
+	     next = icalrecur_iterator_next(iter);
+	     !icaltime_is_null_time(next);
+	     next = icalrecur_iterator_next(iter))
+		++count; 
+
+	icalrecur_iterator_free (iter); 
+	e_cal_component_free_datetime (&dtstart); 
+
+	return count; 
+}
+
+static gint 
+compare_guint32 (gconstpointer a, gconstpointer b, gpointer user_data)
+{
+	return (*((guint32 *) a) - *((guint32 *) b));
+}
+
+GByteArray *
+exchange_mapi_cal_util_rrule_to_bin (ECalComponent *comp, GSList *modified_comps)
+{
+	struct icalrecurrencetype *rt;
+	guint16 flag16;
+	guint32 flag32, end_type;
+	gint i; 
+	GSList *rrule_list = NULL, *exdate_list = NULL; 
+	GByteArray *ba = NULL;
+
+	if (!e_cal_component_has_recurrences (comp))
+		return NULL; 
+
+	e_cal_component_get_rrule_list (comp, &rrule_list); 
+	e_cal_component_get_exdate_list (comp, &exdate_list); 
+
+	if (g_slist_length (rrule_list) != 1)
+		goto cleanup; 
+
+	rt = (struct icalrecurrencetype *)(rrule_list->data);
+
+	ba = g_byte_array_new (); 
+
+	/* Reader Version */
+	flag16 = READER_VERSION;
+	ba = g_byte_array_append (ba, &flag16, sizeof (guint16));
+
+	/* Writer Version */
+	flag16 = WRITER_VERSION;
+	ba = g_byte_array_append (ba, &flag16, sizeof (guint16));
+
+	if (rt->freq == ICAL_DAILY_RECURRENCE) {
+		flag16 = RecurFrequency_Daily;
+		ba = g_byte_array_append (ba, &flag16, sizeof (guint16));
+
+		/* Pattern Type - it would be PatternType_Day since we have only "Daily every N days" 
+		 * The other type would be parsed as a weekly recurrence. 
+		 */
+		flag16 = PatternType_Day;
+		ba = g_byte_array_append (ba, &flag16, sizeof (guint16));
+
+		/* Calendar Type */
+		flag16 = CAL_DEFAULT; 
+		ba = g_byte_array_append (ba, &flag16, sizeof (guint16));
+
+		/* FirstDateTime */
+		flag32 = compute_rdaily_firstdatetime (comp, (rt->interval * (60 * 24)));
+		ba = g_byte_array_append (ba, &flag32, sizeof (guint32));
+
+		/* INTERVAL */
+		flag32 = (rt->interval * (60 * 24)); 
+		ba = g_byte_array_append (ba, &flag32, sizeof (guint32));
+
+		/* This would be 0 for the stuff we handle */
+		flag32 = 0x0;
+		ba = g_byte_array_append (ba, &flag32, sizeof (guint32));
+
+		/* No PatternTypeSpecific for PatternType_Day */
+
+	} else if (rt->freq == ICAL_WEEKLY_RECURRENCE) {
+		flag16 = RecurFrequency_Weekly;
+		ba = g_byte_array_append (ba, &flag16, sizeof (guint16));
+
+		/* Pattern Type - it would be PatternType_Week since we don't support any other type. */
+		flag16 = PatternType_Week;
+		ba = g_byte_array_append (ba, &flag16, sizeof (guint16));
+
+		/* Calendar Type */
+		flag16 = CAL_DEFAULT; 
+		ba = g_byte_array_append (ba, &flag16, sizeof (guint16));
+
+		/* FirstDateTime */
+		flag32 = compute_rweekly_firstdatetime (comp, rt->week_start, (rt->interval * (60 * 24 * 7)));
+		ba = g_byte_array_append (ba, &flag32, sizeof (guint32));
+
+		/* INTERVAL */
+		flag32 = rt->interval; 
+		ba = g_byte_array_append (ba, &flag32, sizeof (guint32));
+
+		/* This would be 0 for the stuff we handle */
+		flag32 = 0x0;
+		ba = g_byte_array_append (ba, &flag32, sizeof (guint32));
+
+		/* BITMASK */
+		for (flag32 = 0x0, i = 0; i < ICAL_BY_DAY_SIZE; ++i) {
+			if (rt->by_day[i] == ICAL_SUNDAY_WEEKDAY)
+				flag32 |= olSunday; 
+			else if (rt->by_day[i] == ICAL_MONDAY_WEEKDAY)
+				flag32 |= olMonday; 
+			else if (rt->by_day[i] == ICAL_TUESDAY_WEEKDAY)
+				flag32 |= olTuesday; 
+			else if (rt->by_day[i] == ICAL_WEDNESDAY_WEEKDAY)
+				flag32 |= olWednesday; 
+			else if (rt->by_day[i] == ICAL_THURSDAY_WEEKDAY)
+				flag32 |= olThursday; 
+			else if (rt->by_day[i] == ICAL_FRIDAY_WEEKDAY)
+				flag32 |= olFriday; 
+			else if (rt->by_day[i] == ICAL_SATURDAY_WEEKDAY)
+				flag32 |= olSaturday; 
+			else 
+				break; 
+		}
+		ba = g_byte_array_append (ba, &flag32, sizeof (guint32));
+
+	} else if (rt->freq == ICAL_MONTHLY_RECURRENCE) {
+		guint16 pattern = 0x0; guint32 mask = 0x0, flag = 0x0; 
+
+		flag16 = RecurFrequency_Monthly;
+		ba = g_byte_array_append (ba, &flag16, sizeof (guint16));
+
+		if (rt->by_month_day[0] >= 1 && rt->by_month_day[0] <= 31) {
+			pattern = PatternType_Month;
+			flag = rt->by_month_day[0]; 
+		} else if (rt->by_month_day[0] == -1) {
+			pattern = PatternType_MonthNth; 
+			mask = (olSunday | olMonday | olTuesday | olWednesday | olThursday | olFriday | olSaturday); 
+			flag = RecurrenceN_Last; 
+		} else if (rt->by_day[0] >= ICAL_SUNDAY_WEEKDAY && rt->by_day[0] <= ICAL_SATURDAY_WEEKDAY) {
+			pattern = PatternType_MonthNth;
+			mask = get_mapi_day (rt->by_day[0]);
+			flag = get_mapi_pos (rt->by_set_pos[0]);
+		}
+
+		/* Pattern Type */
+		flag16 = pattern;
+		ba = g_byte_array_append (ba, &flag16, sizeof (guint16));
+
+		/* Calendar Type */
+		flag16 = CAL_DEFAULT; 
+		ba = g_byte_array_append (ba, &flag16, sizeof (guint16));
+
+		/* FirstDateTime */
+		flag32 = compute_rmonthly_firstdatetime (comp, rt->interval);
+		ba = g_byte_array_append (ba, &flag32, sizeof (guint32));
+
+		/* INTERVAL */
+		flag32 = rt->interval; 
+		ba = g_byte_array_append (ba, &flag32, sizeof (guint32));
+
+		/* This would be 0 for the stuff we handle */
+		flag32 = 0x0;
+		ba = g_byte_array_append (ba, &flag32, sizeof (guint32));
+
+		if (pattern == PatternType_Month) {
+			flag32 = flag;
+			ba = g_byte_array_append (ba, &flag32, sizeof (guint32));
+
+			if (!(flag))
+				g_warning ("Possibly setting incorrect values in the stream. "); 
+		} else if (pattern == PatternType_MonthNth) {
+			flag32 = mask;
+			ba = g_byte_array_append (ba, &flag32, sizeof (guint32));
+
+			flag32 = flag;
+			ba = g_byte_array_append (ba, &flag32, sizeof (guint32));
+
+			if (!(flag && mask))
+				g_warning ("Possibly setting incorrect values in the stream. "); 
+		} else 
+			g_warning ("Possibly setting incorrect values in the stream. "); 
+
+	} else if (rt->freq == ICAL_YEARLY_RECURRENCE) {
+		flag16 = RecurFrequency_Yearly;
+		ba = g_byte_array_append (ba, &flag16, sizeof (guint16));
+
+		/* Pattern Type - it would be PatternType_Month since we don't support any other type. */
+		flag16 = PatternType_Month;
+		ba = g_byte_array_append (ba, &flag16, sizeof (guint16));
+
+		/* Calendar Type */
+		flag16 = CAL_DEFAULT; 
+		ba = g_byte_array_append (ba, &flag16, sizeof (guint16));
+
+		/* FirstDateTime - uses the same function as monthly recurrence */
+		flag32 = compute_rmonthly_firstdatetime (comp, 0xC);
+		ba = g_byte_array_append (ba, &flag32, sizeof (guint32));
+
+		/* INTERVAL - should be 12 for yearly recurrence */
+		flag32 = 0xC; 
+		ba = g_byte_array_append (ba, &flag32, sizeof (guint32));
+
+		/* This would be 0 for the stuff we handle */
+		flag32 = 0x0;
+		ba = g_byte_array_append (ba, &flag32, sizeof (guint32));
+
+		/* MONTH_DAY */
+		{
+			ECalComponentDateTime dtstart; 
+			e_cal_component_get_dtstart (comp, &dtstart);
+			flag32 = dtstart.value->day; 
+			e_cal_component_free_datetime (&dtstart); 
+		}
+		ba = g_byte_array_append (ba, &flag32, sizeof (guint32));
+
+	} 
+
+	/* End Type followed by Occurence count */
+	if (!icaltime_is_null_time (rt->until)) {
+		flag32 = END_AFTER_DATE;
+		ba = g_byte_array_append (ba, &flag32, sizeof (guint32));
+
+		flag32 = calculate_no_of_occurrences (comp, rt); 
+		ba = g_byte_array_append (ba, &flag32, sizeof (guint32));
+
+		end_type = END_AFTER_DATE;
+	} else if (rt->count) {
+		flag32 = END_AFTER_N_OCCURRENCES;
+		ba = g_byte_array_append (ba, &flag32, sizeof (guint32));
+
+		flag32 = rt->count;
+		ba = g_byte_array_append (ba, &flag32, sizeof (guint32));
+
+		end_type = END_AFTER_N_OCCURRENCES;
+	} else {
+		flag32 = END_NEVER_END;
+		ba = g_byte_array_append (ba, &flag32, sizeof (guint32));
+
+		flag32 = 0x0;
+		ba = g_byte_array_append (ba, &flag32, sizeof (guint32));
+
+		end_type = END_NEVER_END;
+	}
+
+	/* FirstDOW */
+	flag32 = get_mapi_weekstart (rt->week_start); 
+	ba = g_byte_array_append (ba, &flag32, sizeof (guint32));
+
+	/* DeletedInstances */
+	flag32 = g_slist_length (exdate_list);
+	ba = g_byte_array_append (ba, &flag32, sizeof (guint32));
+	if (flag32) {
+		GSList *l; 
+		guint32 *sorted_list = g_new0(guint32, flag32);
+		/* FIXME: This should include modified dates */
+		for (i = 0, l = exdate_list; l; ++i, l = l->next) {
+			ECalComponentDateTime *dt = (ECalComponentDateTime *)(l->data); 
+			dt->value->hour = dt->value->minute = dt->value->second = 0; 
+			sorted_list[i] = convert_timet_to_recurrence_minutes (icaltime_as_timet_with_zone (*(dt->value), 0)); 
+		}
+
+		g_qsort_with_data (sorted_list, flag32, sizeof (guint32), compare_guint32, NULL); 
+
+		for (i = 0; i < flag32; ++i)
+			ba = g_byte_array_append (ba, &(sorted_list[i]), sizeof (guint32));
+
+		g_free (sorted_list);
+	}
+
+	/* FIXME: Add support for modified instances */
+	/* ModifiedInstanceCount */
+	flag32 = 0x0;
+	ba = g_byte_array_append (ba, &flag32, sizeof (guint32));
+	if (flag32) {
+	}
+
+	/* StartDate */
+	flag32 = compute_startdate (comp); 
+	ba = g_byte_array_append (ba, &flag32, sizeof (guint32));
+
+	/* EndDate */
+	{
+		if (end_type == END_NEVER_END) 
+			flag32 = 0x5AE980DF; 
+		else if (end_type == END_AFTER_N_OCCURRENCES) {
+			ECalComponentDateTime dtstart; 
+			gchar *rrule_str = icalrecurrencetype_as_string (rt); 
+			time_t *array = g_new0 (time_t, rt->count); 
+
+			e_cal_component_get_dtstart (comp, &dtstart);
+			dtstart.value->hour = dtstart.value->minute = dtstart.value->second = 0; 
+
+			icalrecur_expand_recurrence (rrule_str, icaltime_as_timet_with_zone (*(dtstart.value), 0), rt->count, array); 
+
+			flag32 = convert_timet_to_recurrence_minutes (array[(rt->count) - 1]); 
+
+			g_free (array); 
+			g_free (rrule_str); 
+			e_cal_component_free_datetime (&dtstart); 
+		} else if (end_type == END_AFTER_DATE) {
+			struct icaltimetype until; 
+			memcpy (&until, &(rt->until), sizeof(struct icaltimetype));
+			until.hour = until.minute = until.second = 0; 
+			flag32 = convert_timet_to_recurrence_minutes (icaltime_as_timet_with_zone (until, 0));
+		} else 
+			flag32 = 0x0; 
+	}
+	ba = g_byte_array_append (ba, &flag32, sizeof (guint32));
+
+	/* Reader Version 2 */
+	flag32 = READER_VERSION2;
+	ba = g_byte_array_append (ba, &flag32, sizeof (guint32));
+
+	/* Writer Version 2 */
+	flag32 = WRITER_VERSION2;
+	ba = g_byte_array_append (ba, &flag32, sizeof (guint32));
+
+	/* StartTimeOffset */
+	{
+		ECalComponentDateTime dtstart; 
+		e_cal_component_get_dtstart (comp, &dtstart);
+		flag32 = (dtstart.value->hour * 60) + dtstart.value->minute; 
+		e_cal_component_free_datetime (&dtstart); 
+	}
+	ba = g_byte_array_append (ba, &flag32, sizeof (guint32));
+
+	/* EndTimeOffset */
+	{
+		ECalComponentDateTime dtend; 
+		e_cal_component_get_dtend (comp, &dtend);
+		flag32 = (dtend.value->hour * 60) + dtend.value->minute; 
+		e_cal_component_free_datetime (&dtend); 
+	}
+	ba = g_byte_array_append (ba, &flag32, sizeof (guint32));
+
+	/* FIXME: Add support for modified instances */
+	/* ModifiedExceptionCount */
+	flag16 = 0x0; 
+	ba = g_byte_array_append (ba, &flag16, sizeof (guint16));
+
+	/* FIXME: Add the ExceptionInfo here */
+
+	/* Reserved Block 1 Size */
+	flag32 = 0x0;
+	ba = g_byte_array_append (ba, &flag32, sizeof (guint32));
+
+	/* FIXME: Add the ExtendedExceptionInfo here */
+
+	/* Reserved Block 2 Size */
+	flag32 = 0x0;
+	ba = g_byte_array_append (ba, &flag32, sizeof (guint32));
+
+cleanup: 
+	e_cal_component_free_exdate_list (exdate_list);
+	e_cal_component_free_recur_list (rrule_list);
+
+	g_print ("\n== ICAL to MAPI == The recurrence blob data is as follows:\n");
+	for (i = 0; i < ba->len; ++i)
+		g_print ("0x%02X ", ba->data[i]);
+	g_print("\n== End of stream ==\n"); 
+
+	return ba; 
+}
+

Added: trunk/src/libexchangemapi/exchange-mapi-cal-recur-utils.h
==============================================================================
--- (empty file)
+++ trunk/src/libexchangemapi/exchange-mapi-cal-recur-utils.h	Wed Nov 19 04:28:20 2008
@@ -0,0 +1,42 @@
+/* -*- 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/>  
+ *
+ *
+ * Authors:
+ *    Suman Manjunath <msuman novell com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef EXCHANGE_MAPI_CAL_RECUR_UTILS_H
+#define EXCHANGE_MAPI_CAL_RECUR_UTILS_H
+
+#include <glib.h>
+
+#include "exchange-mapi-cal-utils.h"
+
+G_BEGIN_DECLS
+
+gboolean
+exchange_mapi_cal_util_bin_to_rrule (GByteArray *ba, ECalComponent *comp);
+
+GByteArray *
+exchange_mapi_cal_util_rrule_to_bin (ECalComponent *comp, GSList *modified_comps);
+
+G_END_DECLS
+
+#endif
+

Added: trunk/src/libexchangemapi/exchange-mapi-cal-tz-utils.c
==============================================================================
--- (empty file)
+++ trunk/src/libexchangemapi/exchange-mapi-cal-tz-utils.c	Wed Nov 19 04:28:20 2008
@@ -0,0 +1,548 @@
+/* -*- 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/>  
+ *
+ *
+ * Authors:
+ *    Suman Manjunath <msuman novell com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#include "exchange-mapi-cal-tz-utils.h"
+
+#define d(x) 
+
+#define MAPPING_SEPARATOR "~~~"
+
+static GStaticRecMutex mutex = G_STATIC_REC_MUTEX_INIT;
+
+static GHashTable *mapi_to_ical = NULL;
+static GHashTable *ical_to_mapi = NULL;
+
+const gchar *
+exchange_mapi_cal_tz_util_get_mapi_equivalent (const gchar *ical_tzid)
+{
+	const gchar *retval = NULL;
+
+	g_return_val_if_fail ((ical_tzid && *ical_tzid), NULL);
+
+	g_static_rec_mutex_lock(&mutex);
+	if (!exchange_mapi_cal_tz_util_populate()) {
+		g_static_rec_mutex_unlock(&mutex);
+		return NULL;
+	}
+
+	d(g_message("%s(%d): %s of '%s' ", __FILE__, __LINE__, __PRETTY_FUNCTION__, ical_tzid));
+
+	retval = g_hash_table_lookup (ical_to_mapi, ical_tzid);
+
+	g_static_rec_mutex_unlock(&mutex);
+
+	return retval;
+}
+
+const gchar *
+exchange_mapi_cal_tz_util_get_ical_equivalent (const gchar *mapi_tzid)
+{
+	const gchar *retval = NULL;
+
+	g_return_val_if_fail ((mapi_tzid && *mapi_tzid), NULL);
+
+	g_static_rec_mutex_lock(&mutex);
+	if (!exchange_mapi_cal_tz_util_populate()) {
+		g_static_rec_mutex_unlock(&mutex);
+		return NULL;
+	}
+
+	d(g_message("%s(%d): %s of '%s' ", __FILE__, __LINE__, __PRETTY_FUNCTION__, mapi_tzid));
+
+	retval = g_hash_table_lookup (mapi_to_ical, mapi_tzid);
+
+	g_static_rec_mutex_unlock(&mutex);
+
+	return retval;
+}
+
+void
+exchange_mapi_cal_tz_util_destroy ()
+{
+	g_static_rec_mutex_lock(&mutex);
+	if (!(mapi_to_ical && ical_to_mapi)) {
+		g_static_rec_mutex_unlock(&mutex);
+		return;
+	}
+
+	g_hash_table_destroy (mapi_to_ical);
+	g_hash_table_destroy (ical_to_mapi);
+
+	/* Reset all the values */
+	mapi_to_ical = NULL;
+	ical_to_mapi = NULL;
+
+	g_static_rec_mutex_unlock(&mutex);
+}
+
+static void 
+file_contents_to_hashtable (const char *contents, GHashTable *table) 
+{
+	gchar **array = NULL;
+	guint len = 0, i;
+
+	array = g_strsplit (contents, "\n", -1);
+	len = g_strv_length (array);
+
+	for (i=0; i < len-1; ++i) {
+		gchar **mapping = g_strsplit (array[i], MAPPING_SEPARATOR, -1);
+		if (g_strv_length (mapping) == 2) 
+			g_hash_table_insert (table, g_strdup (mapping[0]), g_strdup (mapping[1]));
+		g_strfreev (mapping);
+	}
+
+	g_strfreev (array);
+}
+
+gboolean
+exchange_mapi_cal_tz_util_populate ()
+{
+	gchar *mtoi_fn = NULL, *itom_fn = NULL;
+	GMappedFile *mtoi_mf = NULL, *itom_mf = NULL;
+
+	g_static_rec_mutex_lock(&mutex);
+	if (mapi_to_ical && ical_to_mapi) {
+		g_static_rec_mutex_unlock(&mutex);
+		return TRUE;
+	}
+
+	mtoi_fn = g_build_filename (MAPI_DATADIR, "tz-mapi-to-ical", NULL);
+	itom_fn = g_build_filename (MAPI_DATADIR, "tz-ical-to-mapi", NULL);
+
+	mtoi_mf = g_mapped_file_new (mtoi_fn, FALSE, NULL);
+	itom_mf = g_mapped_file_new (itom_fn, FALSE, NULL);
+
+	g_free (mtoi_fn);
+	g_free (itom_fn);
+
+	if (!(mtoi_mf && itom_mf)) {
+		g_warning ("Could not map Exchange MAPI timezone files.");
+
+		if (mtoi_mf)
+			g_mapped_file_free (mtoi_mf);
+		if (itom_mf)
+			g_mapped_file_free (itom_mf);
+
+		g_static_rec_mutex_unlock(&mutex);
+		return FALSE;
+	}
+
+	mapi_to_ical = g_hash_table_new_full   ((GHashFunc) g_str_hash, 
+						(GEqualFunc) g_str_equal, 
+						(GDestroyNotify) g_free, 
+						(GDestroyNotify) g_free);
+
+	file_contents_to_hashtable (g_mapped_file_get_contents (mtoi_mf), mapi_to_ical);
+
+	ical_to_mapi = g_hash_table_new_full   ((GHashFunc) g_str_hash, 
+						(GEqualFunc) g_str_equal, 
+						(GDestroyNotify) g_free, 
+						(GDestroyNotify) g_free);
+
+	file_contents_to_hashtable (g_mapped_file_get_contents (itom_mf), ical_to_mapi);
+
+	if (!(g_hash_table_size (mapi_to_ical) && g_hash_table_size (ical_to_mapi))) {
+		g_warning ("Exchange MAPI timezone files are not valid.");
+
+		exchange_mapi_cal_tz_util_destroy ();
+
+		g_mapped_file_free (mtoi_mf);
+		g_mapped_file_free (itom_mf);
+
+		g_static_rec_mutex_unlock(&mutex);
+		return FALSE;
+	} 
+
+	g_mapped_file_free (mtoi_mf);
+	g_mapped_file_free (itom_mf);
+
+	d(exchange_mapi_cal_tz_util_dump ());
+
+	g_static_rec_mutex_unlock(&mutex);
+
+	return TRUE;
+}
+
+static void 
+exchange_mapi_cal_tz_util_dump_ical_tzs ()
+{
+	guint i;
+	icalarray *zones;
+	GList *l, *list_items = NULL;
+	
+	/* Get the array of builtin timezones. */
+	zones = icaltimezone_get_builtin_timezones ();
+
+	g_message("%s(%d): %s: ", __FILE__, __LINE__, __PRETTY_FUNCTION__);
+	for (i = 0; i < zones->num_elements; i++) {
+		icaltimezone *zone;
+		char *tzid = NULL;
+
+		zone = icalarray_element_at (zones, i);
+
+		tzid = icaltimezone_get_tzid (zone);
+
+		list_items = g_list_prepend (list_items, tzid);
+	}
+
+	list_items = g_list_sort (list_items, (GCompareFunc) g_ascii_strcasecmp);
+
+	/* Put the "UTC" entry at the top of the combo's list. */
+	list_items = g_list_prepend (list_items, "UTC");
+
+	for (l = list_items, i = 0; l != NULL; l = l->next, ++i) 
+		g_print ("[%3d]\t%s\n", (i+1), (gchar *)(l->data));
+
+//	icaltimezone_free_builtin_timezones ();
+
+	g_list_free (list_items);
+}
+
+void
+exchange_mapi_cal_tz_util_dump ()
+{
+	guint i;
+	GList *keys, *values, *l, *m;
+
+	g_static_rec_mutex_lock(&mutex);
+
+	exchange_mapi_cal_tz_util_dump_ical_tzs ();
+
+	if (!(mapi_to_ical && ical_to_mapi)) {
+		g_static_rec_mutex_unlock(&mutex);
+		return;
+	}
+
+	g_message("%s(%d): %s: ", __FILE__, __LINE__, __PRETTY_FUNCTION__);
+
+	g_message ("Dumping #table mapi_to_ical");
+	keys = g_hash_table_get_keys (mapi_to_ical);
+	values = g_hash_table_get_values (mapi_to_ical);
+	l = g_list_first (keys);
+	m = g_list_first (values);
+	for (i=0; l && m; ++i, l=l->next, m=m->next)
+		g_print ("[%3d]\t%s\t%s\t%s\n", (i+1), (gchar *)(l->data), MAPPING_SEPARATOR, (gchar *)(m->data));
+	g_message ("Dumping differences in #tables");
+	l = g_list_first (keys);
+	m = g_list_first (values);
+	for (i=0; l && m; ++i, l=l->next, m=m->next)
+		if (g_ascii_strcasecmp ((gchar *)(l->data), (gchar *) g_hash_table_lookup (ical_to_mapi, (m->data))))
+			g_print ("[%3d] Possible mis-match for %s\n", (i+1), (gchar *)(l->data));
+	g_list_free (keys);
+	g_list_free (values);
+
+	g_message ("Dumping #table ical_to_mapi");
+	keys = g_hash_table_get_keys (ical_to_mapi);
+	values = g_hash_table_get_values (ical_to_mapi);
+	l = g_list_first (keys);
+	m = g_list_first (values);
+	for (i=0; l && m; ++i, l=l->next, m=m->next)
+		g_print ("[%3d]\t%s\t%s\t%s\n", (i+1), (gchar *)(l->data), MAPPING_SEPARATOR, (gchar *)(m->data));
+	g_list_free (keys);
+	g_list_free (values);
+
+	g_static_rec_mutex_unlock(&mutex);
+}
+
+#if 0
+const WORD TZRULE_FLAG_RECUR_CURRENT_TZREG  = 0x0001; // see dispidApptTZDefRecur
+const WORD TZRULE_FLAG_EFFECTIVE_TZREG      = 0x0002;
+
+// Allocates return value with new.
+// clean up with delete[].
+TZDEFINITION* BinToTZDEFINITION(ULONG cbDef, LPBYTE lpbDef)
+{
+    if (!lpbDef) return NULL;
+
+    // Update this if parsing code is changed!
+    // this checks the size up to the flags member
+    if (cbDef < 2*sizeof(BYTE) + 2*sizeof(WORD)) return NULL;
+
+    TZDEFINITION tzDef;
+    TZRULE* lpRules = NULL;
+    LPBYTE lpPtr = lpbDef;
+    WORD cchKeyName = 0;
+    WCHAR* szKeyName = NULL;
+    WORD i = 0;
+
+    BYTE bMajorVersion = *((BYTE*)lpPtr);
+    lpPtr += sizeof(BYTE);
+    BYTE bMinorVersion = *((BYTE*)lpPtr);
+    lpPtr += sizeof(BYTE);
+
+    // We only understand TZ_BIN_VERSION_MAJOR
+    if (TZ_BIN_VERSION_MAJOR != bMajorVersion) return NULL;
+
+    // We only understand if >= TZ_BIN_VERSION_MINOR
+    if (TZ_BIN_VERSION_MINOR > bMinorVersion) return NULL;
+
+    WORD cbHeader = *((WORD*)lpPtr);
+    lpPtr += sizeof(WORD);
+
+    tzDef.wFlags = *((WORD*)lpPtr);
+    lpPtr += sizeof(WORD);
+
+    if (TZDEFINITION_FLAG_VALID_GUID & tzDef.wFlags)
+    {
+        if (lpbDef + cbDef - lpPtr < sizeof(GUID)) return NULL;
+        tzDef.guidTZID = *((GUID*)lpPtr);
+        lpPtr += sizeof(GUID);
+    }
+
+    if (TZDEFINITION_FLAG_VALID_KEYNAME & tzDef.wFlags)
+    {
+        if (lpbDef + cbDef - lpPtr < sizeof(WORD)) return NULL;
+        cchKeyName = *((WORD*)lpPtr);
+        lpPtr += sizeof(WORD);
+        if (cchKeyName)
+        {
+            if (lpbDef + cbDef - lpPtr < (BYTE)sizeof(WORD)*cchKeyName) return NULL;
+            szKeyName = (WCHAR*)lpPtr;
+            lpPtr += cchKeyName*sizeof(WORD);
+        }
+    }
+
+    if (lpbDef+ cbDef - lpPtr < sizeof(WORD)) return NULL;
+    tzDef.cRules = *((WORD*)lpPtr);
+    lpPtr += sizeof(WORD);
+
+    /* FIXME: parse rules */
+    if (tzDef.cRules) tzDef.cRules = 0;
+#if 0
+    if (tzDef.cRules)
+    {
+        lpRules = new TZRULE[tzDef.cRules];
+        if (!lpRules) return NULL;
+
+        LPBYTE lpNextRule = lpPtr;
+        BOOL bRuleOK = false;
+		
+        for (i = 0;i < tzDef.cRules;i++)
+        {
+            bRuleOK = false;
+            lpPtr = lpNextRule;
+			
+            if (lpbDef + cbDef - lpPtr < 
+                2*sizeof(BYTE) + 2*sizeof(WORD) + 3*sizeof(long) + 2*sizeof(SYSTEMTIME)) return NULL;
+            bRuleOK = true;
+            BYTE bRuleMajorVersion = *((BYTE*)lpPtr);
+            lpPtr += sizeof(BYTE);
+            BYTE bRuleMinorVersion = *((BYTE*)lpPtr);
+            lpPtr += sizeof(BYTE);
+			
+            // We only understand TZ_BIN_VERSION_MAJOR
+            if (TZ_BIN_VERSION_MAJOR != bRuleMajorVersion) return NULL;
+			
+            // We only understand if >= TZ_BIN_VERSION_MINOR
+            if (TZ_BIN_VERSION_MINOR > bRuleMinorVersion) return NULL;
+			
+            WORD cbRule = *((WORD*)lpPtr);
+            lpPtr += sizeof(WORD);
+			
+            lpNextRule = lpPtr + cbRule;
+			
+            lpRules[i].wFlags = *((WORD*)lpPtr);
+            lpPtr += sizeof(WORD);
+			
+            lpRules[i].stStart = *((SYSTEMTIME*)lpPtr);
+            lpPtr += sizeof(SYSTEMTIME);
+			
+            lpRules[i].TZReg.lBias = *((long*)lpPtr);
+            lpPtr += sizeof(long);
+            lpRules[i].TZReg.lStandardBias = *((long*)lpPtr);
+            lpPtr += sizeof(long);
+            lpRules[i].TZReg.lDaylightBias = *((long*)lpPtr);
+            lpPtr += sizeof(long);
+			
+            lpRules[i].TZReg.stStandardDate = *((SYSTEMTIME*)lpPtr);
+            lpPtr += sizeof(SYSTEMTIME);
+            lpRules[i].TZReg.stDaylightDate = *((SYSTEMTIME*)lpPtr);
+            lpPtr += sizeof(SYSTEMTIME);
+        }
+        if (!bRuleOK)
+        {
+            delete[] lpRules;
+            return NULL;			
+        }
+    }
+#endif 
+    // Now we've read everything - allocate a structure and copy it in
+    size_t cbTZDef = sizeof(TZDEFINITION) +
+        sizeof(WCHAR)*(cchKeyName+1) +
+        sizeof(TZRULE)*tzDef.cRules;
+
+    TZDEFINITION* ptzDef = (TZDEFINITION*) malloc (cbTZDef);
+    
+    if (ptzDef)
+    {
+        // Copy main struct over
+        *ptzDef = tzDef;
+        lpPtr = (LPBYTE) ptzDef;
+        lpPtr += sizeof(TZDEFINITION);
+
+        if (szKeyName)
+        {
+            ptzDef->pwszKeyName = (WCHAR*)lpPtr;
+            memcpy(lpPtr,szKeyName,cchKeyName*sizeof(WCHAR));
+            ptzDef->pwszKeyName[cchKeyName] = 0;
+            lpPtr += (cchKeyName+1)*sizeof(WCHAR);
+        }
+
+        if (ptzDef -> cRules)
+        {
+            ptzDef -> rgRules = (TZRULE*)lpPtr;
+            for (i = 0;i < ptzDef -> cRules;i++)
+            {
+                ptzDef -> rgRules[i] = lpRules[i];
+            }
+        }
+    }
+//    delete[] lpRules;
+
+   free (ptzDef);
+   ptzDef = NULL;
+
+    return ptzDef;
+}
+#endif
+
+#define TZDEFINITION_FLAG_VALID_GUID     0x0001 // the guid is valid
+#define TZDEFINITION_FLAG_VALID_KEYNAME  0x0002 // the keyname is valid
+#define TZ_MAX_RULES          1024 
+#define TZ_BIN_VERSION_MAJOR  0x02 
+#define TZ_BIN_VERSION_MINOR  0x01 
+
+void
+exchange_mapi_cal_util_mapi_tz_to_bin (const char *mapi_tzid, struct SBinary *sb)
+{
+	GByteArray *ba;
+	guint8 flag8;
+	guint16 flag16;
+	gunichar2 *buf;
+	glong items_written;
+	guint32 i;
+
+	ba = g_byte_array_new ();
+
+	/* UTF-8 length of the keyname */
+	flag16 = g_utf8_strlen (mapi_tzid, -1);
+	ba = g_byte_array_append (ba, &flag16, sizeof (guint16));
+	/* Keyname */
+	buf = g_utf8_to_utf16 (mapi_tzid, flag16, NULL, &items_written, NULL);
+	ba = g_byte_array_append (ba, buf, (sizeof (gunichar2) * items_written));
+	g_free (buf);
+
+	/* number of rules *//* FIXME: Need to support rules */
+	flag16 = 0x0000;
+	ba = g_byte_array_append (ba, &flag16, sizeof (guint16));
+
+	/* wFlags: we know only keyname based names */
+	flag16 = TZDEFINITION_FLAG_VALID_KEYNAME;
+	ba = g_byte_array_prepend (ba, &flag16, sizeof (guint16));
+
+	/* Length in bytes until rules info */
+	flag16 = (guint16) (ba->len);
+	ba = g_byte_array_prepend (ba, &flag16, sizeof (guint16));
+
+	/* Minor version */
+	flag8 = TZ_BIN_VERSION_MINOR;
+	ba = g_byte_array_prepend (ba, &flag8, sizeof (guint8));
+
+	/* Major version */
+	flag8 = TZ_BIN_VERSION_MAJOR;
+	ba = g_byte_array_prepend (ba, &flag8, sizeof (guint8));
+
+	/* Rules may now be appended here */
+
+	sb->lpb = ba->data;
+	sb->cb = ba->len;
+
+	d(g_message ("New timezone stream.. Length: %d bytes.. Hex-data follows:", ba->len));
+	d(for (i = 0; i < ba->len; i++) 
+		g_print("0x%.2X ", ba->data[i]));
+
+	g_byte_array_free (ba, FALSE);
+}
+
+gchar *
+exchange_mapi_cal_util_bin_to_mapi_tz (GByteArray *ba)
+{
+	guint8 flag8;
+	guint16 flag16, cbHeader = 0;
+	guint8 *ptr = ba->data;
+//	guint len = ba->len;
+	gchar *buf = NULL;
+
+	d(g_message ("New timezone stream.. Length: %d bytes.. Info follows:", ba->len));
+
+	/* Major version */
+	flag8 = *((guint8 *)ptr);
+	ptr += sizeof (guint8);
+	d(g_print ("Major version: %d\n", flag8));
+	if (TZ_BIN_VERSION_MAJOR != flag8)
+		return NULL;
+
+	/* Minor version */
+	flag8 = *((guint8 *)ptr);
+	ptr += sizeof (guint8);
+	d(g_print ("Minor version: %d\n", flag8));
+	if (TZ_BIN_VERSION_MINOR > flag8)
+		return NULL;
+
+	/* Length in bytes until rules info */
+	flag16 = *((guint16 *)ptr);
+	ptr += sizeof (guint16);
+	d(g_print ("Length in bytes until rules: %d\n", flag16));
+	cbHeader = flag16;
+
+	/* wFlags: we don't yet understand GUID based names */
+	flag16 = *((guint16 *)ptr);
+	ptr += sizeof (guint16);
+	d(g_print ("wFlags: %d\n", flag16));
+	cbHeader -= sizeof (guint16);
+	if (TZDEFINITION_FLAG_VALID_KEYNAME != flag16)
+		return NULL;
+
+	/* UTF-8 length of the keyname */
+	flag16 = *((guint16 *)ptr);
+	ptr += sizeof (guint16);
+	d(g_print ("UTF8 length of keyname: %d\n", flag16));
+	cbHeader -= sizeof (guint16);
+
+	/* number of rules is at the end of the header.. we'll parse and use later */
+	cbHeader -= sizeof (guint16);
+
+	/* Keyname */
+	buf = g_utf16_to_utf8 ((const gunichar2 *)ptr, cbHeader/sizeof (gunichar2), NULL, NULL, NULL);
+	ptr += cbHeader;
+	d(g_print ("Keyname: %s\n", buf));
+
+	/* number of rules */
+	flag16 = *((guint16 *)ptr);
+	ptr += sizeof (guint16);
+	d(g_print ("Number of rules: %d\n", flag16));
+
+	/* FIXME: Need to support rules */
+
+	return buf;
+}

Added: trunk/src/libexchangemapi/exchange-mapi-cal-tz-utils.h
==============================================================================
--- (empty file)
+++ trunk/src/libexchangemapi/exchange-mapi-cal-tz-utils.h	Wed Nov 19 04:28:20 2008
@@ -0,0 +1,116 @@
+/* -*- 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/>  
+ *
+ *
+ * Authors:
+ *    Suman Manjunath <msuman novell com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef EXCHANGE_MAPI_CAL_TZ_UTILS_H
+#define EXCHANGE_MAPI_CAL_TZ_UTILS_H
+
+#include <glib.h>
+
+#include "exchange-mapi-cal-utils.h"
+
+G_BEGIN_DECLS
+
+const gchar *
+exchange_mapi_cal_tz_util_get_mapi_equivalent (const gchar *ical_tzid);
+
+const gchar *
+exchange_mapi_cal_tz_util_get_ical_equivalent (const gchar *mapi_tzid);
+
+gboolean
+exchange_mapi_cal_tz_util_populate (void);
+
+void
+exchange_mapi_cal_tz_util_destroy (void);
+
+void
+exchange_mapi_cal_tz_util_dump (void);
+
+void
+exchange_mapi_cal_util_mapi_tz_to_bin (const char *mapi_tzid, struct SBinary *sb);
+
+gchar *
+exchange_mapi_cal_util_bin_to_mapi_tz (GByteArray *ba);
+
+G_END_DECLS
+
+#if 0
+typedef int16_t WORD;
+typedef int8_t BYTE;
+typedef uint32_t GUID;
+typedef uint64_t ULONG;
+typedef time_t SYSTEMTIME;
+typedef uint8_t* LPBYTE;
+typedef char* LPWSTR;
+typedef char WCHAR;
+
+// TZREG
+// =====================
+//   This is an individual description that defines when a daylight
+//   saving shift, and the return to standard time occurs, and how
+//   far the shift is.  This is basically the same as
+//   TIME_ZONE_INFORMATION documented in MSDN, except that the strings
+//   describing the names "daylight" and "standard" time are omitted.
+//
+typedef struct RenTimeZone
+{
+    long        lBias;           // offset from GMT
+    long        lStandardBias;   // offset from bias during standard time
+    long        lDaylightBias;   // offset from bias during daylight time
+    SYSTEMTIME  stStandardDate;  // time to switch to standard time
+    SYSTEMTIME  stDaylightDate;  // time to switch to daylight time
+} TZREG;
+
+// TZRULE
+// =====================
+//   This structure represents both a description when a daylight. 
+//   saving shift occurs, and in addition, the year in which that
+//   timezone rule came into effect. 
+//
+typedef struct
+{
+    WORD        wFlags;   // indicates which rule matches legacy recur
+    SYSTEMTIME  stStart;  // indicates when the rule starts
+    TZREG       TZReg;    // the timezone info
+} TZRULE;
+
+// TZDEFINITION
+// =====================
+//   This represents an entire timezone including all historical, current
+//   and future timezone shift rules for daylight saving time, etc.  It's
+//   identified by a unique GUID.
+//
+typedef struct
+{
+    WORD     wFlags;       // indicates which fields are valid
+    GUID     guidTZID;     // guid uniquely identifying this timezone
+    LPWSTR   pwszKeyName;  // the name of the key for this timezone
+    WORD     cRules;       // the number of timezone rules for this definition
+    TZRULE*  rgRules;      // an array of rules describing when shifts occur
+} TZDEFINITION;
+
+// Allocates return value with new.
+// clean up with delete[].
+TZDEFINITION* BinToTZDEFINITION(ULONG cbDef, LPBYTE lpbDef);
+#endif
+
+#endif

Added: trunk/src/libexchangemapi/exchange-mapi-cal-utils.c
==============================================================================
--- (empty file)
+++ trunk/src/libexchangemapi/exchange-mapi-cal-utils.c	Wed Nov 19 04:28:20 2008
@@ -0,0 +1,2115 @@
+/* -*- 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/>  
+ *
+ *
+ * Authors:
+ *    Suman Manjunath <msuman novell com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#include <glib/gstdio.h>
+#include <fcntl.h>
+#include <libecal/e-cal-util.h>
+#include "exchange-mapi-cal-utils.h"
+
+#ifndef O_BINARY
+#define O_BINARY 0
+#endif
+
+#define d(x) 
+
+static void appt_build_name_id (struct mapi_nameid *nameid);
+static void task_build_name_id (struct mapi_nameid *nameid);
+static void note_build_name_id (struct mapi_nameid *nameid);
+
+static icalparameter_role
+get_role_from_type (OlMailRecipientType type)
+{
+	switch (type) {
+		case olCC   : return ICAL_ROLE_OPTPARTICIPANT;
+		case olOriginator : 
+		case olTo   : 
+		case olBCC  : 
+		default     : return ICAL_ROLE_REQPARTICIPANT;
+	}
+}
+
+static OlMailRecipientType
+get_type_from_role (icalparameter_role role)
+{
+	switch (role) {
+		case ICAL_ROLE_OPTPARTICIPANT 	: return olCC;
+		case ICAL_ROLE_CHAIR 		:
+		case ICAL_ROLE_REQPARTICIPANT 	:
+		case ICAL_ROLE_NONPARTICIPANT 	: 
+		default 			: return olTo;
+	}
+} 
+
+static icalparameter_partstat
+get_partstat_from_trackstatus (uint32_t trackstatus)
+{
+	switch (trackstatus) {
+		case olResponseOrganized : 
+		case olResponseAccepted  : return ICAL_PARTSTAT_ACCEPTED;
+		case olResponseTentative : return ICAL_PARTSTAT_TENTATIVE;
+		case olResponseDeclined  : return ICAL_PARTSTAT_DECLINED;
+		default 		 : return ICAL_PARTSTAT_NEEDSACTION;
+	}
+}
+
+static uint32_t 
+get_trackstatus_from_partstat (icalparameter_partstat partstat)
+{
+	switch (partstat) {
+		case ICAL_PARTSTAT_ACCEPTED 	: return olResponseAccepted;
+		case ICAL_PARTSTAT_TENTATIVE 	: return olResponseTentative;
+		case ICAL_PARTSTAT_DECLINED 	: return olResponseDeclined;
+		default 			: return olResponseNone;
+	}
+}
+
+static icalproperty_transp
+get_transp_from_prop (uint32_t prop) 
+{
+	/* FIXME: is this mapping correct ? */
+	switch (prop) {
+		case olFree 		:
+		case olTentative 	: return ICAL_TRANSP_TRANSPARENT;
+		case olBusy 		:
+		case olOutOfOffice 	:
+		default 		: return ICAL_TRANSP_OPAQUE;
+	}
+}
+
+static uint32_t 
+get_prop_from_transp (icalproperty_transp transp)
+{
+	/* FIXME: is this mapping correct ? */
+	switch (transp) {
+		case ICAL_TRANSP_TRANSPARENT 		:
+		case ICAL_TRANSP_TRANSPARENTNOCONFLICT 	: return olFree; 
+		case ICAL_TRANSP_OPAQUE 		: 
+		case ICAL_TRANSP_OPAQUENOCONFLICT 	:
+		default 				: return olBusy;
+	}
+}
+
+static icalproperty_status
+get_taskstatus_from_prop (uint32_t prop)
+{
+	/* FIXME: is this mapping correct ? */
+	switch (prop) {
+		case olTaskComplete 	: return ICAL_STATUS_COMPLETED;
+		case olTaskWaiting 	:
+		case olTaskInProgress 	: return ICAL_STATUS_INPROCESS;
+		case olTaskDeferred 	: return ICAL_STATUS_CANCELLED;
+		case olTaskNotStarted 	: 
+		default 		: return ICAL_STATUS_NEEDSACTION;
+	}
+}
+
+static uint32_t
+get_prop_from_taskstatus (icalproperty_status status)
+{
+	/* FIXME: is this mapping correct ? */
+	switch (status) {
+		case ICAL_STATUS_INPROCESS 	: return olTaskInProgress;
+		case ICAL_STATUS_COMPLETED 	: return olTaskComplete;
+		case ICAL_STATUS_CANCELLED 	: return olTaskDeferred;
+		default 			: return olTaskNotStarted;
+	}
+}
+
+static icalproperty_class
+get_class_from_prop (uint32_t prop)
+{
+	/* FIXME: is this mapping correct ? */
+	switch (prop) {
+		case olPersonal 	:
+		case olPrivate 		: return ICAL_CLASS_PRIVATE;
+		case olConfidential 	: return ICAL_CLASS_CONFIDENTIAL;
+		case olNormal 		: 
+		default 		: return ICAL_CLASS_PUBLIC;
+	}
+}
+
+static uint32_t 
+get_prop_from_class (icalproperty_class class)
+{
+	/* FIXME: is this mapping correct ? */
+	switch (class) {
+		case ICAL_CLASS_PRIVATE 	: return olPrivate;
+		case ICAL_CLASS_CONFIDENTIAL 	: return olConfidential;
+		default 			: return olNormal;
+	}
+}
+
+static int
+get_priority_from_prop (uint32_t prop)
+{
+	switch (prop) {
+		case PRIORITY_LOW 	: return 7;
+		case PRIORITY_HIGH 	: return 1;
+		case PRIORITY_NORMAL 	: 
+		default 		: return 5;
+	}
+}
+
+static uint32_t
+get_prio_prop_from_priority (int priority)
+{
+	if (priority > 0 && priority <= 4)
+		return PRIORITY_HIGH;
+	else if (priority > 5 && priority <= 9)
+		return PRIORITY_LOW;
+	else
+		return PRIORITY_NORMAL;
+}
+
+static uint32_t
+get_imp_prop_from_priority (int priority)
+{
+	if (priority > 0 && priority <= 4)
+		return IMPORTANCE_HIGH;
+	else if (priority > 5 && priority <= 9)
+		return IMPORTANCE_LOW;
+	else
+		return IMPORTANCE_NORMAL;
+}
+
+void
+exchange_mapi_cal_util_fetch_attachments (ECalComponent *comp, GSList **attach_list, const char *local_store_uri)
+{
+	GSList *comp_attach_list = NULL, *new_attach_list = NULL;
+	GSList *l;
+	const char *uid;
+
+	e_cal_component_get_attachment_list (comp, &comp_attach_list);
+	e_cal_component_get_uid (comp, &uid);
+
+	for (l = comp_attach_list; l ; l = l->next) {
+		gchar *sfname_uri = (gchar *) l->data;
+		gchar *sfname = NULL, *filename = NULL;
+		GMappedFile *mapped_file;
+		GError *error = NULL;
+
+		sfname = g_filename_from_uri (sfname_uri, NULL, NULL);
+		mapped_file = g_mapped_file_new (sfname, FALSE, &error);
+		filename = g_path_get_basename (sfname);
+
+		if (mapped_file && g_str_has_prefix (filename, uid)) {
+			ExchangeMAPIAttachment *attach_item;
+			ExchangeMAPIStream *stream; 
+			gchar *attach = g_mapped_file_get_contents (mapped_file);
+			guint filelength = g_mapped_file_get_length (mapped_file);
+			const gchar *split_name = (filename + strlen (uid) + strlen ("-"));
+			uint32_t flag; 
+
+			new_attach_list = g_slist_append (new_attach_list, g_strdup (sfname_uri));
+
+			attach_item = g_new0 (ExchangeMAPIAttachment, 1);
+
+			attach_item->cValues = 4; 
+			attach_item->lpProps = g_new0 (struct SPropValue, 4); 
+
+			flag = ATTACH_BY_VALUE; 
+			set_SPropValue_proptag(&(attach_item->lpProps[0]), PR_ATTACH_METHOD, (const void *) (&flag));
+
+			/* MSDN Documentation: When the supplied offset is -1 (0xFFFFFFFF), the 
+			 * attachment is not rendered using the PR_RENDERING_POSITION property. 
+			 * All values other than -1 indicate the position within PR_BODY at which 
+			 * the attachment is to be rendered. 
+			 */
+			flag = 0xFFFFFFFF;
+			set_SPropValue_proptag(&(attach_item->lpProps[1]), PR_RENDERING_POSITION, (const void *) (&flag));
+
+			set_SPropValue_proptag(&(attach_item->lpProps[2]), PR_ATTACH_FILENAME, (const void *) g_strdup(split_name));
+			set_SPropValue_proptag(&(attach_item->lpProps[3]), PR_ATTACH_LONG_FILENAME, (const void *) g_strdup(split_name));
+
+			stream = g_new0 (ExchangeMAPIStream, 1);
+			stream->proptag = PR_ATTACH_DATA_BIN; 
+			stream->value = g_byte_array_sized_new (filelength);
+			stream->value = g_byte_array_append (stream->value, attach, filelength);
+			attach_item->streams = g_slist_append (attach_item->streams, stream); 
+
+			*attach_list = g_slist_append (*attach_list, attach_item);
+
+			g_mapped_file_free (mapped_file);
+		} else {
+			g_debug ("Could not map %s: %s \n", sfname_uri, error->message);
+			g_error_free (error);
+		}
+
+		g_free (filename);
+	}
+
+	e_cal_component_set_attachment_list (comp, new_attach_list);
+
+	for (l = new_attach_list; l != NULL; l = l->next)
+		g_free (l->data);
+	g_slist_free (new_attach_list);
+}
+
+#define RECIP_SENDABLE  0x1
+#define RECIP_ORGANIZER 0x2
+
+void
+exchange_mapi_cal_util_fetch_organizer (ECalComponent *comp, GSList **recip_list)
+{
+	icalcomponent *icalcomp = e_cal_component_get_icalcomponent (comp);
+	icalproperty *org_prop = NULL; 
+	const gchar *org = NULL;
+
+	org_prop = icalcomponent_get_first_property (icalcomp, ICAL_ORGANIZER_PROPERTY);
+	org = icalproperty_get_organizer (org_prop);
+	if (org && *org) {
+		ExchangeMAPIRecipient *recipient;
+		uint32_t val = 0;
+		const char *str = NULL;
+		icalparameter *param;
+
+		recipient = g_new0 (ExchangeMAPIRecipient, 1);
+
+		if (!g_ascii_strncasecmp (org, "mailto:";, 7)) 
+			recipient->email_id = (org) + 7;
+		else 
+			recipient->email_id = (org);
+
+		/* Required properties - set them always */
+		recipient->in.req_lpProps = g_new0 (struct SPropValue, 5);
+		recipient->in.req_cValues = 5;
+
+		val = 0;
+		set_SPropValue_proptag (&(recipient->in.req_lpProps[0]), PR_SEND_INTERNET_ENCODING, (const void *)&val);
+
+		val = RECIP_SENDABLE | RECIP_ORGANIZER;
+		set_SPropValue_proptag (&(recipient->in.req_lpProps[1]), PR_RECIPIENTS_FLAGS, (const void *)&val);
+
+		val = olResponseNone;
+		set_SPropValue_proptag (&(recipient->in.req_lpProps[2]), PR_RECIPIENT_TRACKSTATUS, (const void *)&val);
+
+		val = olTo;
+		set_SPropValue_proptag (&(recipient->in.req_lpProps[3]), PR_RECIPIENT_TYPE, (const void *) &val);
+
+		param = icalproperty_get_first_parameter (org_prop, ICAL_CN_PARAMETER);
+		str = icalparameter_get_cn (param);
+		if (!(str && *str)) 
+			str = "";
+		set_SPropValue_proptag (&(recipient->in.req_lpProps[4]), PR_RECIPIENT_DISPLAY_NAME, (const void *)(str));
+
+		/* External recipient properties - set them only when the recipient is unresolved */
+		recipient->in.ext_lpProps = g_new0 (struct SPropValue, 5);
+		recipient->in.ext_cValues = 5;
+
+		val = DT_MAILUSER;
+		set_SPropValue_proptag (&(recipient->in.ext_lpProps[0]), PR_DISPLAY_TYPE, (const void *)&val);
+		val = MAPI_MAILUSER;
+		set_SPropValue_proptag (&(recipient->in.ext_lpProps[1]), PR_OBJECT_TYPE, (const void *)&val);
+		str = "SMTP";
+		set_SPropValue_proptag (&(recipient->in.ext_lpProps[2]), PR_ADDRTYPE, (const void *)(str));
+		str = recipient->email_id;
+		set_SPropValue_proptag (&(recipient->in.ext_lpProps[3]), PR_SMTP_ADDRESS, (const void *)(str));
+
+		param = icalproperty_get_first_parameter (org_prop, ICAL_CN_PARAMETER);
+		str = icalparameter_get_cn (param);
+		if (!(str && *str)) 
+			str = "";
+		set_SPropValue_proptag (&(recipient->in.ext_lpProps[4]), PR_DISPLAY_NAME, (const void *)(str));
+
+		*recip_list = g_slist_append (*recip_list, recipient);
+	}
+}
+
+void
+exchange_mapi_cal_util_fetch_recipients (ECalComponent *comp, GSList **recip_list)
+{
+	icalcomponent *icalcomp = e_cal_component_get_icalcomponent (comp);
+	icalproperty *org_prop = NULL, *att_prop = NULL; 
+	const gchar *org = NULL;
+
+	org_prop = icalcomponent_get_first_property (icalcomp, ICAL_ORGANIZER_PROPERTY);
+	org = icalproperty_get_organizer (org_prop);
+	if (!org)
+		org = "";
+
+	att_prop = icalcomponent_get_first_property (icalcomp, ICAL_ATTENDEE_PROPERTY);
+	while (att_prop) {
+		ExchangeMAPIRecipient *recipient;
+		uint32_t val = 0;
+		const char *str = NULL;
+		icalparameter *param;
+
+		recipient = g_new0 (ExchangeMAPIRecipient, 1);
+
+		str = icalproperty_get_attendee (att_prop);
+		if (!g_ascii_strncasecmp (str, "mailto:";, 7)) 
+			recipient->email_id = (str) + 7;
+		else 
+			recipient->email_id = (str);
+
+		/* Required properties - set them always */
+		recipient->in.req_lpProps = g_new0 (struct SPropValue, 5);
+		recipient->in.req_cValues = 5;
+
+		val = 0;
+		set_SPropValue_proptag (&(recipient->in.req_lpProps[0]), PR_SEND_INTERNET_ENCODING, (const void *)&val);
+
+		val = RECIP_SENDABLE | (!g_ascii_strcasecmp(str, org) ? RECIP_ORGANIZER : 0);
+		set_SPropValue_proptag (&(recipient->in.req_lpProps[1]), PR_RECIPIENTS_FLAGS, (const void *)&val);
+
+		param = icalproperty_get_first_parameter (att_prop, ICAL_PARTSTAT_PARAMETER);
+		val = get_trackstatus_from_partstat (icalparameter_get_partstat(param));
+		set_SPropValue_proptag (&(recipient->in.req_lpProps[2]), PR_RECIPIENT_TRACKSTATUS, (const void *)&val);
+
+		param = icalproperty_get_first_parameter (att_prop, ICAL_ROLE_PARAMETER);
+		val = get_type_from_role (icalparameter_get_role(param));
+		set_SPropValue_proptag (&(recipient->in.req_lpProps[3]), PR_RECIPIENT_TYPE, (const void *) &val);
+
+		param = icalproperty_get_first_parameter (att_prop, ICAL_CN_PARAMETER);
+		str = icalparameter_get_cn (param);
+		if (!(str && *str)) 
+			str = "";
+		set_SPropValue_proptag (&(recipient->in.req_lpProps[4]), PR_RECIPIENT_DISPLAY_NAME, (const void *)(str));
+
+		/* External recipient properties - set them only when the recipient is unresolved */
+		recipient->in.ext_lpProps = g_new0 (struct SPropValue, 5);
+		recipient->in.ext_cValues = 5;
+
+		val = DT_MAILUSER;
+		set_SPropValue_proptag (&(recipient->in.ext_lpProps[0]), PR_DISPLAY_TYPE, (const void *)&val);
+		val = MAPI_MAILUSER;
+		set_SPropValue_proptag (&(recipient->in.ext_lpProps[1]), PR_OBJECT_TYPE, (const void *)&val);
+		str = "SMTP";
+		set_SPropValue_proptag (&(recipient->in.ext_lpProps[2]), PR_ADDRTYPE, (const void *)(str));
+		str = recipient->email_id;
+		set_SPropValue_proptag (&(recipient->in.ext_lpProps[3]), PR_SMTP_ADDRESS, (const void *)(str));
+
+		param = icalproperty_get_first_parameter (att_prop, ICAL_CN_PARAMETER);
+		str = icalparameter_get_cn (param);
+		if (!(str && *str)) 
+			str = "";
+		set_SPropValue_proptag (&(recipient->in.ext_lpProps[4]), PR_DISPLAY_NAME, (const void *)(str));
+
+		*recip_list = g_slist_append (*recip_list, recipient);
+
+		att_prop = icalcomponent_get_next_property (icalcomp, ICAL_ATTENDEE_PROPERTY);
+	}
+}
+
+static void
+set_attachments_to_cal_component (ECalComponent *comp, GSList *attach_list, const char *local_store_uri)
+{
+	GSList *comp_attach_list = NULL, *l;
+	const char *uid;
+
+	g_return_if_fail (comp != NULL);
+
+	e_cal_component_get_uid (comp, &uid);
+	for (l = attach_list; l ; l = l->next) {
+		ExchangeMAPIAttachment *attach_item = (ExchangeMAPIAttachment *) (l->data);
+		ExchangeMAPIStream *stream; 
+		gchar *attach_file_url, *filename; 
+		const char *str, *attach;
+		guint len;
+		int fd = -1;
+
+		stream = exchange_mapi_util_find_stream (attach_item->streams, PR_ATTACH_DATA_BIN);
+		if (!stream)
+			continue;
+
+		attach = (const char *)stream->value->data;
+		len = stream->value->len;
+
+		str = (const char *) exchange_mapi_util_find_SPropVal_array_propval(attach_item->lpProps, PR_ATTACH_LONG_FILENAME);
+		if (!(str && *str))
+			str = (const char *) exchange_mapi_util_find_SPropVal_array_propval(attach_item->lpProps, PR_ATTACH_FILENAME);
+		attach_file_url = g_strconcat (local_store_uri, G_DIR_SEPARATOR_S, uid, "-", str, NULL);
+		filename = g_filename_from_uri (attach_file_url, NULL, NULL);
+
+		fd = g_open (filename, O_RDWR|O_CREAT|O_TRUNC|O_BINARY, 0600);
+		if (fd == -1) { 
+			/* skip gracefully */
+			g_debug ("Could not open %s for writing \n", filename);
+		} else if (len && write (fd, attach, len) == -1) {
+			/* skip gracefully */
+			g_debug ("Attachment write failed \n");
+		}
+		if (fd != -1) {
+			close (fd);
+			comp_attach_list = g_slist_append (comp_attach_list, g_strdup (attach_file_url));
+		}
+
+		g_free (filename);
+		g_free (attach_file_url);
+	}
+
+	e_cal_component_set_attachment_list (comp, comp_attach_list);
+}
+
+static void 
+ical_attendees_from_props (icalcomponent *ical_comp, GSList *recipients, gboolean rsvp)
+{
+	GSList *l;
+	for (l=recipients; l; l=l->next) {
+		ExchangeMAPIRecipient *recip = (ExchangeMAPIRecipient *)(l->data);
+		icalproperty *prop = NULL;
+		icalparameter *param;
+		gchar *val;
+		const uint32_t *ui32;
+		const char *str;
+		const uint32_t *flags; 
+
+		if (recip->email_id)
+			val = g_strdup_printf ("MAILTO:%s", recip->email_id);
+		else 
+			continue;
+
+		flags = (const uint32_t *) get_SPropValue(recip->out.all_lpProps, PR_RECIPIENTS_FLAGS);
+
+		if (flags && (*flags & RECIP_ORGANIZER)) {
+			prop = icalproperty_new_organizer (val);
+
+			/* CN */
+			str = (const char *) exchange_mapi_util_find_SPropVal_array_propval(recip->out.all_lpProps, PR_RECIPIENT_DISPLAY_NAME);
+			if (!str)
+				str = (const char *) exchange_mapi_util_find_SPropVal_array_propval(recip->out.all_lpProps, PR_DISPLAY_NAME);
+			if (str) {
+				param = icalparameter_new_cn (str);
+				icalproperty_add_parameter (prop, param);
+			}
+		} else {
+			prop = icalproperty_new_attendee (val);
+
+			/* CN */
+			str = (const char *) exchange_mapi_util_find_SPropVal_array_propval(recip->out.all_lpProps, PR_RECIPIENT_DISPLAY_NAME);
+			if (!str)
+				str = (const char *) exchange_mapi_util_find_SPropVal_array_propval(recip->out.all_lpProps, PR_DISPLAY_NAME);
+			if (str) {
+				param = icalparameter_new_cn (str);
+				icalproperty_add_parameter (prop, param);
+			}
+			/* RSVP */
+			param = icalparameter_new_rsvp (rsvp ? ICAL_RSVP_TRUE : ICAL_RSVP_FALSE);
+			icalproperty_add_parameter (prop, param);
+			/* PARTSTAT */
+			ui32 = (const uint32_t *) get_SPropValue(recip->out.all_lpProps, PR_RECIPIENT_TRACKSTATUS);
+			if (ui32) {
+				param = icalparameter_new_partstat (get_partstat_from_trackstatus (*ui32));
+				icalproperty_add_parameter (prop, param);
+			}
+			/* ROLE */
+			ui32 = (const uint32_t *) get_SPropValue(recip->out.all_lpProps, PR_RECIPIENT_TYPE);
+			if (ui32) {
+				param = icalparameter_new_role (get_role_from_type (*ui32));
+				icalproperty_add_parameter (prop, param);
+			}
+#if 0
+			/* CALENDAR USER TYPE */
+			param = icalparameter_new_cutype ();
+			icalproperty_add_parameter (prop, param);
+#endif
+		}
+
+		if (prop)
+			icalcomponent_add_property (ical_comp, prop);
+
+		g_free (val);
+	}
+}
+
+static const uint8_t GID_START_SEQ[] = {
+	0x04, 0x00, 0x00, 0x00, 0x82, 0x00, 0xe0, 0x00,
+	0x74, 0xc5, 0xb7, 0x10, 0x1a, 0x82, 0xe0, 0x08
+};
+
+void
+exchange_mapi_cal_util_generate_globalobjectid (gboolean is_clean, const char *uid, struct SBinary *sb)
+{
+	GByteArray *ba;
+	guint32 flag32;
+	guchar *buf = NULL;
+	gsize len;
+	d(guint32 i);
+
+	ba = g_byte_array_new ();
+
+	ba = g_byte_array_append (ba, GID_START_SEQ, (sizeof (GID_START_SEQ) / sizeof (GID_START_SEQ[0])));
+
+	/* FIXME for exceptions */
+	if (is_clean || TRUE) {
+		flag32 = 0;
+		ba = g_byte_array_append (ba, &flag32, sizeof (guint32));
+	}
+
+	/* creation time - may be all 0's  */
+	flag32 = 0;
+	ba = g_byte_array_append (ba, &flag32, sizeof (guint32));
+	flag32 = 0;
+	ba = g_byte_array_append (ba, &flag32, sizeof (guint32));
+
+	/* RESERVED - should be all 0's  */
+	flag32 = 0;
+	ba = g_byte_array_append (ba, &flag32, sizeof (guint32));
+	flag32 = 0;
+	ba = g_byte_array_append (ba, &flag32, sizeof (guint32));
+
+	/* FIXME: cleanup the UID first */
+
+	/* We put Evolution's UID in base64 here */
+	buf = g_base64_decode (uid, &len);
+	if (len % 2 != 0)
+		--len;
+	flag32 = len;
+
+	/* Size in bytes of the following data */
+	ba = g_byte_array_append (ba, &flag32, sizeof (guint32));
+	/* Data */
+	ba = g_byte_array_append (ba, buf, flag32);
+	g_free (buf);
+
+	sb->lpb = ba->data;
+	sb->cb = ba->len;
+
+	d(g_message ("New GlobalObjectId.. Length: %d bytes.. Hex-data follows:", ba->len));
+	d(for (i = 0; i < ba->len; i++) 
+		g_print("0x%02X ", ba->data[i]));
+
+	g_byte_array_free (ba, FALSE);
+}
+
+static gchar *
+id_to_string (GByteArray *ba)
+{
+	guint8 *ptr;
+	guint len;
+	gchar *buf = NULL;
+	guint32 flag32, i, j;
+
+	g_return_val_if_fail (ba != NULL, NULL);
+	/* MSDN docs: the globalID must have an even number of bytes */
+	if ((ba->len)%2 != 0)
+		return NULL;
+
+	ptr = ba->data;
+	len = ba->len;
+
+	/* starting seq - len = 16 bytes */
+	for (i = 0, j = 0;(i < len) && (j < sizeof (GID_START_SEQ)); ++i, ++ptr, ++j)
+		if (*ptr != GID_START_SEQ[j])
+			return NULL;
+
+	/* FIXME: for exceptions - len = 4 bytes */
+	flag32 = *((guint32 *)ptr);
+	i += sizeof (guint32);
+	if (!(i < len) || flag32 != 0)
+		return NULL;
+	ptr += sizeof (guint32);
+
+	/* Creation time - len = 8 bytes - skip it */
+	flag32 = *((guint32 *)ptr);
+	i += sizeof (guint32);
+	if (!(i < len))
+		return NULL;
+	ptr += sizeof (guint32);
+
+	flag32 = *((guint32 *)ptr);
+	i += sizeof (guint32);
+	if (!(i < len))
+		return NULL;
+	ptr += sizeof (guint32);
+
+	/* Reserved bytes - len = 8 bytes */
+	flag32 = *((guint32 *)ptr);
+	i += sizeof (guint32);
+	if (!(i < len) || flag32 != 0)
+		return NULL;
+	ptr += sizeof (guint32);
+
+	flag32 = *((guint32 *)ptr);
+	i += sizeof (guint32);
+	if (!(i < len) || flag32 != 0)
+		return NULL;
+	ptr += sizeof (guint32);
+
+	/* This is the real data */
+	flag32 = *((guint32 *)ptr);
+	i += sizeof (guint32);
+	if (!(i < len) || flag32 != (len - i))
+		return NULL;
+	ptr += sizeof (guint32);
+
+	buf = g_base64_encode (ptr, flag32);
+
+	return buf;
+}
+
+ECalComponent *
+exchange_mapi_cal_util_mapi_props_to_comp (icalcomponent_kind kind, const gchar *mid, struct mapi_SPropValue_array *properties, 
+					   GSList *streams, GSList *recipients, GSList *attachments, 
+					   const char *local_store_uri, const icaltimezone *default_zone)
+{
+	ECalComponent *comp = NULL;
+	struct timeval t;
+	ExchangeMAPIStream *body_stream; 
+	const gchar *subject = NULL, *body = NULL;
+	const uint32_t *ui32;
+	const bool *b;
+	icalcomponent *ical_comp;
+	icalproperty *prop = NULL;
+	icalparameter *param = NULL;
+	const icaltimezone *utc_zone;
+
+	switch (kind) {
+		case ICAL_VEVENT_COMPONENT:
+		case ICAL_VTODO_COMPONENT:
+		case ICAL_VJOURNAL_COMPONENT:
+			comp = e_cal_component_new ();
+			ical_comp = icalcomponent_new (kind);
+			e_cal_component_set_icalcomponent (comp, ical_comp);
+			icalcomponent_set_uid (ical_comp, mid);
+			e_cal_component_set_uid (comp, mid);
+			break;
+		default:
+			return NULL;
+	}
+
+	utc_zone = icaltimezone_get_utc_timezone ();
+
+	subject = (const gchar *)exchange_mapi_util_find_array_propval(properties, PR_SUBJECT);
+	if (!subject)
+		subject = (const gchar *)exchange_mapi_util_find_array_propval(properties, PR_NORMALIZED_SUBJECT);
+	if (!subject)
+		subject = (const gchar *)exchange_mapi_util_find_array_propval(properties, PR_CONVERSATION_TOPIC);
+	if (!subject)
+		subject = ""; 
+
+	body = (const gchar *)exchange_mapi_util_find_array_propval(properties, PR_BODY);
+	if (!body) {
+		body_stream = exchange_mapi_util_find_stream (streams, PR_HTML);
+		body = body_stream ? (const gchar *) body_stream->value->data : ""; 
+	}
+
+	/* set dtstamp - in UTC */
+	if (get_mapi_SPropValue_array_date_timeval (&t, properties, PR_CREATION_TIME) == MAPI_E_SUCCESS)
+		icalcomponent_set_dtstamp (ical_comp, icaltime_from_timet_with_zone (t.tv_sec, 0, utc_zone));
+
+	/* created - in UTC */
+	prop = icalproperty_new_created (icaltime_current_time_with_zone (icaltimezone_get_utc_timezone ()));
+	icalcomponent_add_property (ical_comp, prop);
+	
+	/* last modified - in UTC */
+	if (get_mapi_SPropValue_array_date_timeval (&t, properties, PR_LAST_MODIFICATION_TIME) == MAPI_E_SUCCESS) {
+		prop = icalproperty_new_lastmodified (icaltime_from_timet_with_zone (t.tv_sec, 0, utc_zone));
+		icalcomponent_add_property (ical_comp, prop);
+	}
+
+	icalcomponent_set_summary (ical_comp, subject);
+	icalcomponent_set_description (ical_comp, body);
+
+	if (icalcomponent_isa (ical_comp) == ICAL_VEVENT_COMPONENT) {
+		const char *location = NULL;
+		const gchar *dtstart_tz = NULL, *dtend_tz = NULL;
+		ExchangeMAPIStream *stream;
+
+		/* CleanGlobalObjectId */
+		stream = exchange_mapi_util_find_stream (streams, PROP_TAG(PT_BINARY, 0x0023));
+		if (stream) {
+			gchar *value = id_to_string (stream->value);
+			prop = icalproperty_new_x (value);
+			icalproperty_set_x_name (prop, "X-EVOLUTION-MAPI-CLEAN-GLOBALID");
+			icalcomponent_add_property (ical_comp, prop);
+			g_free (value);
+		}
+
+		/* GlobalObjectId */
+		stream = exchange_mapi_util_find_stream (streams, PROP_TAG(PT_BINARY, 0x0003));
+		if (stream) {
+			gchar *value = id_to_string (stream->value);
+			prop = icalproperty_new_x (value);
+			icalproperty_set_x_name (prop, "X-EVOLUTION-MAPI-GLOBALID");
+			icalcomponent_add_property (ical_comp, prop);
+			g_free (value);
+		}
+
+		/* AppointmentSequence */
+		ui32 = (const uint32_t *)find_mapi_SPropValue_data(properties, PROP_TAG(PT_LONG, 0x8201));
+		if (ui32) {
+			gchar *value = g_strdup_printf ("%d", *ui32);
+			prop = icalproperty_new_x (value);
+			icalproperty_set_x_name (prop, "X-EVOLUTION-MAPI-APPTSEQ");
+			icalcomponent_add_property (ical_comp, prop);
+			g_free (value);
+		}
+
+		location = (const char *)exchange_mapi_util_find_array_propval(properties, PROP_TAG(PT_STRING8, 0x8208));
+		if (location && *location)
+			icalcomponent_set_location (ical_comp, location);
+
+		b = (const bool *)find_mapi_SPropValue_data(properties, PROP_TAG(PT_BOOLEAN, 0x8215));
+
+		stream = exchange_mapi_util_find_stream (streams, PROP_TAG(PT_BINARY, 0x825E));
+		if (stream) {
+			gchar *buf = exchange_mapi_cal_util_bin_to_mapi_tz (stream->value);
+			dtstart_tz = exchange_mapi_cal_tz_util_get_ical_equivalent (buf);
+			g_free (buf);
+		}
+
+		if (get_mapi_SPropValue_array_date_timeval (&t, properties, PROP_TAG(PT_SYSTIME, 0x820D)) == MAPI_E_SUCCESS) {
+			icaltimezone *zone = dtstart_tz ? icaltimezone_get_builtin_timezone_from_tzid (dtstart_tz) : default_zone;
+			prop = icalproperty_new_dtstart (icaltime_from_timet_with_zone (t.tv_sec, (b && *b), zone));
+			icalproperty_add_parameter (prop, icalparameter_new_tzid(dtstart_tz));
+			icalcomponent_add_property (ical_comp, prop);
+		}
+
+		stream = exchange_mapi_util_find_stream (streams, PROP_TAG(PT_BINARY, 0x825F));
+		if (stream) {
+			gchar *buf = exchange_mapi_cal_util_bin_to_mapi_tz (stream->value);
+			dtend_tz = exchange_mapi_cal_tz_util_get_ical_equivalent (buf);
+			g_free (buf);
+		}
+
+		if (get_mapi_SPropValue_array_date_timeval (&t, properties, PROP_TAG(PT_SYSTIME, 0x820E)) == MAPI_E_SUCCESS) {
+			icaltimezone *zone = dtend_tz ? icaltimezone_get_builtin_timezone_from_tzid (dtend_tz) : default_zone;
+			prop = icalproperty_new_dtend (icaltime_from_timet_with_zone (t.tv_sec, (b && *b), zone));
+			icalproperty_add_parameter (prop, icalparameter_new_tzid(dtend_tz));
+			icalcomponent_add_property (ical_comp, prop);
+		}
+
+		ui32 = (const uint32_t *)find_mapi_SPropValue_data(properties, PROP_TAG(PT_LONG, 0x8205));
+		if (ui32) {
+			prop = icalproperty_new_transp (get_transp_from_prop (*ui32));
+			icalcomponent_add_property (ical_comp, prop);
+		}
+
+		if (recipients) {
+			b = (const bool *)find_mapi_SPropValue_data(properties, PR_RESPONSE_REQUESTED);
+			ical_attendees_from_props (ical_comp, recipients, (b && *b));
+			if (icalcomponent_get_first_property (ical_comp, ICAL_ORGANIZER_PROPERTY) == NULL) {
+				gchar *val;
+//				const char *sender_name = (const char *) exchange_mapi_util_find_array_propval (properties, PR_SENDER_NAME);
+				const char *sender_email_type = (const char *) exchange_mapi_util_find_array_propval (properties, PR_SENDER_ADDRTYPE);
+				const char *sender_email = (const char *) exchange_mapi_util_find_array_propval (properties, PR_SENDER_EMAIL_ADDRESS);
+				const char *sent_name = (const char *) exchange_mapi_util_find_array_propval (properties, PR_SENT_REPRESENTING_NAME);
+				const char *sent_email_type = (const char *) exchange_mapi_util_find_array_propval (properties, PR_SENT_REPRESENTING_ADDRTYPE);
+				const char *sent_email = (const char *) exchange_mapi_util_find_array_propval (properties, PR_SENT_REPRESENTING_EMAIL_ADDRESS);
+
+				if (!g_utf8_collate (sender_email_type, "EX"))
+					sender_email = exchange_mapi_util_ex_to_smtp (sender_email);
+				if (!g_utf8_collate (sent_email_type, "EX"))
+					sent_email = exchange_mapi_util_ex_to_smtp (sent_email);
+
+				val = g_strdup_printf ("MAILTO:%s", sent_email);
+				prop = icalproperty_new_organizer (val);
+				g_free (val);
+				/* CN */
+				param = icalparameter_new_cn (sent_name);
+				icalproperty_add_parameter (prop, param);
+				/* SENTBY */
+				if (g_utf8_collate (sent_email, sender_email)) {
+					val = g_strdup_printf ("MAILTO:%s", sender_email);
+					param = icalparameter_new_sentby (val);
+					icalproperty_add_parameter (prop, param);
+					g_free (val);
+				}
+
+				icalcomponent_add_property (ical_comp, prop);
+			}
+		}
+
+		b = (const bool *)find_mapi_SPropValue_data(properties, PROP_TAG(PT_BOOLEAN, 0x8223));
+		if (b && *b) {
+			stream = exchange_mapi_util_find_stream (streams, PROP_TAG(PT_BINARY, 0x8216));
+			if (stream) {
+				exchange_mapi_cal_util_bin_to_rrule (stream->value, comp);
+			}
+		} 
+
+		b = (const bool *)find_mapi_SPropValue_data(properties, PROP_TAG(PT_BOOLEAN, 0x8503));
+		if (b && *b) {
+			struct timeval start, displaytime;
+
+			if ((get_mapi_SPropValue_array_date_timeval (&start, properties, PROP_TAG(PT_SYSTIME, 0x8502)) == MAPI_E_SUCCESS) 
+			 && (get_mapi_SPropValue_array_date_timeval (&displaytime, properties, PROP_TAG(PT_SYSTIME, 0x8560)) == MAPI_E_SUCCESS)) {
+				ECalComponentAlarm *e_alarm = e_cal_component_alarm_new ();
+				ECalComponentAlarmTrigger trigger;
+
+				trigger.type = E_CAL_COMPONENT_ALARM_TRIGGER_RELATIVE_START;
+				trigger.u.rel_duration = icaltime_subtract (icaltime_from_timet_with_zone (displaytime.tv_sec, 0, 0), 
+									    icaltime_from_timet_with_zone (start.tv_sec, 0, 0));
+
+				e_cal_component_alarm_set_action (e_alarm, E_CAL_COMPONENT_ALARM_DISPLAY);
+				e_cal_component_alarm_set_trigger (e_alarm, trigger);
+
+				e_cal_component_add_alarm (comp, e_alarm);
+			}
+		} else
+			e_cal_component_remove_all_alarms (comp);
+
+	} else if (icalcomponent_isa (ical_comp) == ICAL_VTODO_COMPONENT) {
+		const double *complete = 0;
+
+		/* NOTE: Exchange tasks are DATE values, not DATE-TIME values, but maybe someday, we could expect Exchange to support it ;) */
+		if (get_mapi_SPropValue_array_date_timeval (&t, properties, PROP_TAG(PT_SYSTIME, 0x8104)) == MAPI_E_SUCCESS)
+			icalcomponent_set_dtstart (ical_comp, icaltime_from_timet_with_zone (t.tv_sec, 1, default_zone));
+		if (get_mapi_SPropValue_array_date_timeval (&t, properties, PROP_TAG(PT_SYSTIME, 0x8105)) == MAPI_E_SUCCESS)
+			icalcomponent_set_due (ical_comp, icaltime_from_timet_with_zone (t.tv_sec, 1, default_zone));
+
+		ui32 = (const uint32_t *)find_mapi_SPropValue_data(properties, PROP_TAG(PT_LONG, 0x8101));
+		if (ui32) {
+			icalcomponent_set_status (ical_comp, get_taskstatus_from_prop(*ui32));
+			if (*ui32 == olTaskComplete 
+			&& get_mapi_SPropValue_array_date_timeval (&t, properties, PROP_TAG(PT_SYSTIME, 0x810F)) == MAPI_E_SUCCESS) {
+				prop = icalproperty_new_completed (icaltime_from_timet_with_zone (t.tv_sec, 1, default_zone));
+				icalcomponent_add_property (ical_comp, prop);
+			}
+		}
+
+		complete = (const double *)find_mapi_SPropValue_data(properties, PROP_TAG(PT_DOUBLE, 0x8102));
+		if (complete) {
+			prop = icalproperty_new_percentcomplete ((int)(*complete * 100));
+			icalcomponent_add_property (ical_comp, prop);
+		}
+
+		b = (const bool *)find_mapi_SPropValue_data(properties, PROP_TAG(PT_BOOLEAN, 0x8126));
+		if (b && *b) {
+			/* FIXME: Evolution does not support recurring tasks */
+			g_warning ("Encountered a recurring task.");
+		}
+
+		b = (const bool *)find_mapi_SPropValue_data(properties, PROP_TAG(PT_BOOLEAN, 0x8503));
+		if (b && *b) {
+			struct timeval abs;
+
+			if (get_mapi_SPropValue_array_date_timeval (&abs, properties, PROP_TAG(PT_SYSTIME, 0x8502)) == MAPI_E_SUCCESS) {
+				ECalComponentAlarm *e_alarm = e_cal_component_alarm_new ();
+				ECalComponentAlarmTrigger trigger;
+
+				trigger.type = E_CAL_COMPONENT_ALARM_TRIGGER_ABSOLUTE;
+				trigger.u.abs_time = icaltime_from_timet_with_zone (abs.tv_sec, 0, default_zone);
+
+				e_cal_component_alarm_set_action (e_alarm, E_CAL_COMPONENT_ALARM_DISPLAY);
+				e_cal_component_alarm_set_trigger (e_alarm, trigger);
+
+				e_cal_component_add_alarm (comp, e_alarm);
+			}
+		} else
+			e_cal_component_remove_all_alarms (comp);
+
+	} else if (icalcomponent_isa (ical_comp) == ICAL_VJOURNAL_COMPONENT) {
+		if (get_mapi_SPropValue_array_date_timeval (&t, properties, PR_LAST_MODIFICATION_TIME) == MAPI_E_SUCCESS)
+			icalcomponent_set_dtstart (ical_comp, icaltime_from_timet_with_zone (t.tv_sec, 1, default_zone));
+	}
+
+	if (icalcomponent_isa (ical_comp) == ICAL_VEVENT_COMPONENT || icalcomponent_isa (ical_comp) == ICAL_VTODO_COMPONENT) {
+		/* priority */
+		ui32 = (const uint32_t *)find_mapi_SPropValue_data(properties, PR_PRIORITY);
+		if (ui32) {
+			prop = icalproperty_new_priority (get_priority_from_prop (*ui32));
+			icalcomponent_add_property (ical_comp, prop);
+		}
+	}
+
+	/* classification */
+	ui32 = (const uint32_t *)find_mapi_SPropValue_data(properties, PR_SENSITIVITY);
+	if (ui32) {
+		prop = icalproperty_new_class (get_class_from_prop (*ui32));
+		icalcomponent_add_property (ical_comp, prop);
+	}
+
+	/* FIXME: categories */
+
+	set_attachments_to_cal_component (comp, attachments, local_store_uri);
+
+	e_cal_component_rescan (comp);
+
+	return comp;
+}
+
+#define TEMP_ATTACH_STORE ".evolution/cache/tmp"
+
+static void
+change_partstat (ECalComponent *comp, const gchar *att, const gchar *sentby, icalparameter_partstat partstat)
+{
+	icalcomponent *icalcomp = e_cal_component_get_icalcomponent (comp);
+	icalproperty *attendee; 
+	gboolean found = FALSE;
+
+	attendee = icalcomponent_get_first_property (icalcomp, ICAL_ATTENDEE_PROPERTY);
+	while (attendee) {
+		const char *value = icalproperty_get_attendee (attendee);
+		if (!g_ascii_strcasecmp (value, att)) {
+			icalparameter *param = icalparameter_new_partstat (partstat);
+			icalproperty_set_parameter (attendee, param);
+			if (g_ascii_strcasecmp(att, sentby)) {
+				icalparameter *sentby_param = icalparameter_new_sentby (sentby);
+				icalproperty_set_parameter (attendee, sentby_param);
+			}
+			found = TRUE;
+			break;
+		}
+		attendee = icalcomponent_get_next_property (icalcomp, ICAL_ATTENDEE_PROPERTY);
+	}
+
+	if (found) {
+		icalproperty *prop = icalproperty_new_x ("1");
+		icalproperty_set_x_name (prop, "X-EVOLUTION-IS-REPLY");
+		icalcomponent_add_property (icalcomp, prop);
+	}
+
+	e_cal_component_set_icalcomponent (comp, icalcomp);
+}
+
+static void
+remove_other_attendees (ECalComponent *comp, const gchar *att)
+{
+	icalcomponent *icalcomp = e_cal_component_get_icalcomponent (comp);
+	icalproperty *attendee; 
+
+	attendee = icalcomponent_get_first_property (icalcomp, ICAL_ATTENDEE_PROPERTY);
+	while (attendee) {
+		const char *value = icalproperty_get_attendee (attendee);
+		if (g_ascii_strcasecmp (value, att))
+			icalcomponent_remove_property (icalcomp, attendee);
+
+		attendee = icalcomponent_get_next_property (icalcomp, ICAL_ATTENDEE_PROPERTY);
+	}
+
+	e_cal_component_set_icalcomponent (comp, icalcomp);
+}
+
+static gboolean
+fetch_server_data_cb (struct mapi_SPropValue_array *properties, const mapi_id_t fid, const mapi_id_t mid, 
+	GSList *streams, GSList *recipients, GSList *attachments, gpointer data) 
+{
+	icalcomponent_kind kind = ICAL_VEVENT_COMPONENT;
+	gchar *filename = g_build_filename (g_get_home_dir (), TEMP_ATTACH_STORE, NULL);
+	gchar *fileuri = g_filename_to_uri (filename, NULL, NULL);
+	gchar *smid = exchange_mapi_util_mapi_id_to_string (mid);
+	ECalComponent *comp = exchange_mapi_cal_util_mapi_props_to_comp (kind, smid, properties, streams, recipients, attachments, fileuri, NULL);
+	struct cbdata *cbdata = (struct cbdata *)(data);
+	const uint32_t *ui32;
+
+	ui32 = (const uint32_t *)find_mapi_SPropValue_data(properties, PR_OWNER_APPT_ID);
+	cbdata->appt_id = ui32 ? *ui32 : 0;
+	ui32 = (const uint32_t *)find_mapi_SPropValue_data(properties, PROP_TAG(PT_LONG, 0x8201));
+	cbdata->appt_seq = ui32 ? *ui32 : 0;
+	cbdata->username = exchange_mapi_util_find_array_propval (properties, PR_SENT_REPRESENTING_NAME);
+	cbdata->useridtype = exchange_mapi_util_find_array_propval (properties, PR_SENT_REPRESENTING_ADDRTYPE);
+	cbdata->userid = exchange_mapi_util_find_array_propval (properties, PR_SENT_REPRESENTING_EMAIL_ADDRESS);
+	cbdata->ownername = exchange_mapi_util_find_array_propval (properties, PR_SENDER_NAME);
+	cbdata->owneridtype = exchange_mapi_util_find_array_propval (properties, PR_SENDER_ADDRTYPE);
+	cbdata->ownerid = exchange_mapi_util_find_array_propval (properties, PR_SENDER_EMAIL_ADDRESS);
+
+	cbdata->comp = comp; 
+
+	g_free (smid);
+	g_free (fileuri);
+	g_free (filename);
+
+	return TRUE;
+}
+
+static void
+fetch_server_data (mapi_id_t mid, struct cbdata *cbd) 
+{
+	icalcomponent_kind kind = ICAL_VEVENT_COMPONENT;
+	mapi_id_t fid;
+
+	fid = exchange_mapi_get_default_folder_id (olFolderCalendar);
+
+	exchange_mapi_connection_fetch_item (fid, mid, 
+					cal_GetPropsList, G_N_ELEMENTS (cal_GetPropsList), 
+					exchange_mapi_cal_util_build_name_id, GINT_TO_POINTER (kind), 
+					fetch_server_data_cb, cbd, 
+					MAPI_OPTIONS_FETCH_RECIPIENTS | MAPI_OPTIONS_FETCH_GENERIC_STREAMS);
+
+}
+
+static ECalComponent * 
+update_attendee_status (struct mapi_SPropValue_array *properties, mapi_id_t mid) 
+{
+	const gchar *att, *att_sentby, *addrtype;
+	icalparameter_partstat partstat = ICAL_PARTSTAT_NONE;
+	const gchar *state = (const gchar *) exchange_mapi_util_find_array_propval (properties, PR_MESSAGE_CLASS);
+	struct cbdata cbdata; 
+	gchar *matt, *matt_sentby;
+	uint32_t cur_seq;
+	const uint32_t *ui32;
+
+	if (!(state && *state))
+		return NULL;
+
+	if (!g_ascii_strcasecmp (state, IPM_SCHEDULE_MEETING_RESP_POS))
+		partstat = ICAL_PARTSTAT_ACCEPTED;
+	else if (!g_ascii_strcasecmp (state, IPM_SCHEDULE_MEETING_RESP_TENT))
+		partstat = ICAL_PARTSTAT_TENTATIVE;
+	else if (!g_ascii_strcasecmp (state, IPM_SCHEDULE_MEETING_RESP_NEG))
+		partstat = ICAL_PARTSTAT_DECLINED;
+	else
+		return NULL;
+
+	fetch_server_data (mid, &cbdata);
+
+	att = exchange_mapi_util_find_array_propval (properties, PR_SENT_REPRESENTING_EMAIL_ADDRESS);
+	addrtype = exchange_mapi_util_find_array_propval (properties, PR_SENT_REPRESENTING_ADDRTYPE);
+	if (addrtype && !g_ascii_strcasecmp (addrtype, "EX"))
+		att = exchange_mapi_util_ex_to_smtp (att);
+
+	att_sentby = exchange_mapi_util_find_array_propval (properties, PR_SENDER_EMAIL_ADDRESS);
+	addrtype = exchange_mapi_util_find_array_propval (properties, PR_SENDER_ADDRTYPE);
+	if (addrtype && !g_ascii_strcasecmp (addrtype, "EX"))
+		att_sentby = exchange_mapi_util_ex_to_smtp (att_sentby);
+
+	matt = g_strdup_printf ("MAILTO:%s", att);
+	matt_sentby = g_strdup_printf ("MAILTO:%s", att_sentby);
+
+	change_partstat (cbdata.comp, matt, matt_sentby, partstat);
+
+	ui32 = (const uint32_t *) find_mapi_SPropValue_data(properties, PROP_TAG(PT_LONG, 0x8201));
+	cur_seq = ui32 ? *ui32 : 0;
+
+	if (cbdata.appt_seq == cur_seq) {
+
+/* 
+ * The itip-formatter provides an option to update the attendee's status.
+ * Hence, we need not update the server straight away. 
+ */
+#if 0
+		gchar *filename = g_build_filename (g_get_home_dir (), TEMP_ATTACH_STORE, NULL);
+		gchar *fileuri = g_filename_to_uri (filename, NULL, NULL);
+		GSList *attachments = NULL, *recipients = NULL, *streams = NULL;
+
+		if (e_cal_component_has_attachments (cbdata.comp))
+			exchange_mapi_cal_util_fetch_attachments (cbdata.comp, &attachments, fileuri);
+
+		if (e_cal_component_has_attendees (cbdata.comp))
+			exchange_mapi_cal_util_fetch_recipients (cbdata.comp, &recipients);
+
+		cbdata.meeting_type = (recipients != NULL) ? MEETING_OBJECT : NOT_A_MEETING;
+		cbdata.resp = (recipients != NULL) ? olResponseOrganized : olResponseNone;
+		cbdata.msgflags = MSGFLAG_READ;
+		cbdata.is_modify = TRUE;
+		cbdata.cleanglobalid = (const struct SBinary *)find_mapi_SPropValue_data(properties, PROP_TAG(PT_BINARY, 0x0023));
+		cbdata.globalid = (const struct SBinary *)find_mapi_SPropValue_data(properties, PROP_TAG(PT_BINARY, 0x0003));
+
+		status = exchange_mapi_modify_item (olFolderCalendar, fid, mid, 
+				exchange_mapi_cal_util_build_name_id, GINT_TO_POINTER (kind), 
+				exchange_mapi_cal_util_build_props, &cbdata, 
+				recipients, attachments, streams, MAPI_OPTIONS_DONT_SUBMIT);
+		g_free (cbdata.props);
+
+		exchange_mapi_util_free_recipient_list (&recipients);
+		exchange_mapi_util_free_attachment_list (&attachments);
+		g_free (fileuri);
+		g_free (filename);
+#endif 
+
+		/* remove the other attendees so not to confuse itip-formatter */
+		remove_other_attendees (cbdata.comp, matt);
+	} else { 
+		g_object_unref (cbdata.comp);
+		cbdata.comp = NULL;
+	}
+
+	g_free (matt);
+	g_free (matt_sentby);
+
+	return cbdata.comp;
+}
+
+static void 
+update_server_object (struct mapi_SPropValue_array *properties, GSList *attachments, ECalComponent *comp, mapi_id_t *mid)
+{
+	const uint32_t *ui32 = NULL;
+	uint32_t cur_seq;
+	mapi_id_t fid;
+	gboolean create_new = TRUE;
+
+	fid = exchange_mapi_get_default_folder_id (olFolderCalendar);
+
+	ui32 = (const uint32_t *) find_mapi_SPropValue_data(properties, PROP_TAG(PT_LONG, 0x8201));
+	cur_seq = ui32 ? *ui32 : 0;
+
+	if (*mid) {
+		struct cbdata server_cbd;
+		fetch_server_data (*mid, &server_cbd);
+
+		if (cur_seq > server_cbd.appt_seq) {
+			struct id_list idlist; 
+			GSList *ids = NULL;
+
+			idlist.id = *mid;
+			ids = g_slist_append (ids, &idlist);
+
+			exchange_mapi_remove_items (olFolderCalendar, fid, ids);
+			g_slist_free (ids);
+		} else 
+			create_new = FALSE;
+	}
+
+	if (create_new) {
+		struct cbdata cbdata;
+		GSList *myrecipients = NULL;
+		GSList *myattachments = NULL;
+		icalcomponent_kind kind = icalcomponent_isa (e_cal_component_get_icalcomponent(comp));
+
+		cbdata.comp = comp;
+		cbdata.username = (const char *) exchange_mapi_util_find_array_propval (properties, PR_SENDER_NAME);
+		cbdata.useridtype = (const char *) exchange_mapi_util_find_array_propval (properties, PR_SENDER_ADDRTYPE);
+		cbdata.userid = (const char *) exchange_mapi_util_find_array_propval (properties, PR_SENDER_EMAIL_ADDRESS);
+		cbdata.ownername = (const char *) exchange_mapi_util_find_array_propval (properties, PR_SENT_REPRESENTING_NAME);
+		cbdata.owneridtype = (const char *) exchange_mapi_util_find_array_propval (properties, PR_SENT_REPRESENTING_ADDRTYPE);
+		cbdata.ownerid = (const char *) exchange_mapi_util_find_array_propval (properties, PR_SENT_REPRESENTING_EMAIL_ADDRESS);
+		cbdata.is_modify = FALSE;
+		cbdata.msgflags = MSGFLAG_READ;
+		cbdata.meeting_type = MEETING_REQUEST_RCVD;
+		cbdata.resp = olResponseNone;
+		cbdata.appt_seq = (*(const uint32_t *)find_mapi_SPropValue_data(properties, PROP_TAG(PT_LONG, 0x8201)));
+		cbdata.appt_id = (*(const uint32_t *)find_mapi_SPropValue_data(properties, PR_OWNER_APPT_ID));
+		cbdata.globalid = (const struct SBinary *)find_mapi_SPropValue_data(properties, PROP_TAG(PT_BINARY, 0x0003));
+		cbdata.cleanglobalid = (const struct SBinary *)find_mapi_SPropValue_data(properties, PROP_TAG(PT_BINARY, 0x0023));
+
+		exchange_mapi_cal_util_fetch_recipients (comp, &myrecipients);
+		myattachments = attachments;
+		*mid = exchange_mapi_create_item (olFolderCalendar, 0, 
+					exchange_mapi_cal_util_build_name_id, GINT_TO_POINTER(kind),
+					exchange_mapi_cal_util_build_props, &cbdata, 
+					myrecipients, myattachments, NULL, MAPI_OPTIONS_DONT_SUBMIT);
+		g_free (cbdata.props);
+		exchange_mapi_util_free_recipient_list (&myrecipients);
+	}
+}
+
+static void
+check_server_for_object (struct mapi_SPropValue_array *properties, mapi_id_t *mid)
+{
+	struct mapi_SRestriction res;
+	struct SPropValue sprop;
+	const struct SBinary *sb;
+	uint32_t proptag = 0x0;
+	struct SPropTagArray *array;
+	GSList *ids = NULL, *l;
+	mapi_id_t fid;
+
+	*mid = 0;
+
+	fid = exchange_mapi_get_default_folder_id (olFolderCalendar);
+
+	array = exchange_mapi_util_resolve_named_prop (olFolderCalendar, fid, 0x0023, PSETID_Meeting);
+	proptag = array->aulPropTag[0];
+
+	res.rt = RES_PROPERTY;
+	res.res.resProperty.relop = RELOP_EQ;
+	res.res.resProperty.ulPropTag = proptag;
+
+	sb = (const struct SBinary *)find_mapi_SPropValue_data(properties, PROP_TAG(PT_BINARY, 0x0023));
+
+	set_SPropValue_proptag (&sprop, proptag, (const void *) sb);
+	cast_mapi_SPropValue (&(res.res.resProperty.lpProp), &sprop);
+
+	ids = exchange_mapi_util_check_restriction (fid, &res);
+
+	if (ids && g_slist_length(ids) == 1) {
+		struct id_list *idlist = (struct id_list *)(ids->data);
+		*mid = idlist->id;
+	} else 
+	/* FIXME: what to do here? */
+	;
+
+	for (l = ids; l; l = l->next)
+		g_free(l->data);
+	g_slist_free(l);
+}
+
+char *
+exchange_mapi_cal_util_camel_helper (struct mapi_SPropValue_array *properties, 
+				   GSList *streams, GSList *recipients, GSList *attachments)
+{
+	ECalComponent *comp = NULL;
+	icalcomponent_kind kind = ICAL_NO_COMPONENT;
+	icalproperty_method method = ICAL_METHOD_NONE;
+	const char *msg_class = NULL;
+	mapi_id_t mid = 0;
+	icalcomponent *icalcomp = NULL;
+	gchar *str = NULL, *smid = NULL, *tmp, *filename, *fileuri;
+
+	msg_class = (const char *) exchange_mapi_util_find_array_propval (properties, PR_MESSAGE_CLASS);
+	g_return_val_if_fail (msg_class && *msg_class, NULL);
+	if (!g_ascii_strcasecmp (msg_class, IPM_SCHEDULE_MEETING_REQUEST)) {
+		method = ICAL_METHOD_REQUEST;
+		kind = ICAL_VEVENT_COMPONENT;
+	} else if (!g_ascii_strcasecmp (msg_class, IPM_SCHEDULE_MEETING_CANCELED)) {
+		method = ICAL_METHOD_CANCEL;
+		kind = ICAL_VEVENT_COMPONENT;
+	} else if (g_str_has_prefix (msg_class, IPM_SCHEDULE_MEETING_RESP_PREFIX)) {
+		method = ICAL_METHOD_REPLY;
+		kind = ICAL_VEVENT_COMPONENT;
+	} else
+		return (g_strdup (""));
+
+	filename = g_build_filename (g_get_home_dir (), TEMP_ATTACH_STORE, NULL);
+	fileuri = g_filename_to_uri (filename, NULL, NULL);
+
+	check_server_for_object (properties, &mid);
+
+	if (method == ICAL_METHOD_REPLY) {
+		if (mid) { 
+	 		comp = update_attendee_status (properties, mid);
+			set_attachments_to_cal_component (comp, attachments, fileuri);
+		} 
+	} else if (method == ICAL_METHOD_CANCEL) {
+		if (mid) {
+			struct cbdata server_cbd; 
+			fetch_server_data (mid, &server_cbd);
+			comp = server_cbd.comp;
+			set_attachments_to_cal_component (comp, attachments, fileuri);
+		}
+	} else if (method == ICAL_METHOD_REQUEST) { 
+		if (mid)
+			smid = exchange_mapi_util_mapi_id_to_string (mid);
+		else 
+			smid = e_cal_component_gen_uid();
+
+		comp = exchange_mapi_cal_util_mapi_props_to_comp (kind, smid, 
+							properties, streams, recipients, 
+							NULL, NULL, NULL);
+		set_attachments_to_cal_component (comp, attachments, fileuri);
+
+		update_server_object (properties, attachments, comp, &mid);
+
+		tmp = exchange_mapi_util_mapi_id_to_string (mid);
+		e_cal_component_set_uid (comp, tmp);
+		g_free (tmp);
+		g_free (smid);
+	}
+
+	g_free (fileuri);
+	g_free (filename);
+
+	icalcomp = e_cal_util_new_top_level ();
+	icalcomponent_set_method (icalcomp, method);
+	if (comp)
+		icalcomponent_add_component (icalcomp, 
+			icalcomponent_new_clone(e_cal_component_get_icalcomponent(comp)));
+	str = icalcomponent_as_ical_string (icalcomp);
+	icalcomponent_free (icalcomp);
+	if (comp)
+		g_object_unref (comp);
+
+	return str;
+}
+
+
+#define COMMON_NAMED_PROPS_N 9
+
+typedef enum 
+{
+	I_COMMON_REMMINS = 0 , 
+	I_COMMON_REMTIME , 
+	I_COMMON_REMSET , 
+	I_COMMON_ISPRIVATE , 
+	I_COMMON_SIDEEFFECTS , 
+	I_COMMON_START , 
+	I_COMMON_END , 
+	I_COMMON_TASKMODE , 
+	I_COMMON_REMNEXTTIME 
+} CommonNamedPropsIndex;
+
+gboolean
+exchange_mapi_cal_util_build_name_id (struct mapi_nameid *nameid, gpointer data)
+{
+	icalcomponent_kind kind = GPOINTER_TO_INT (data);
+
+	/* NOTE: Avoid using mapi_nameid_OOM_add because: 
+	 * a) its inefficient (uses strcmp) 
+	 * b) names may vary in different server/libmapi versions 
+	 */
+
+	mapi_nameid_lid_add(nameid, 0x8501, PSETID_Common); 	// PT_LONG - ReminderMinutesBeforeStart
+	mapi_nameid_lid_add(nameid, 0x8502, PSETID_Common); 	// PT_SYSTIME - ReminderTime
+	mapi_nameid_lid_add(nameid, 0x8503, PSETID_Common); 	// PT_BOOLEAN - ReminderSet
+	mapi_nameid_lid_add(nameid, 0x8506, PSETID_Common); 	// PT_BOOLEAN - Private
+	mapi_nameid_lid_add(nameid, 0x8510, PSETID_Common); 	// PT_LONG - (context menu flags)
+	mapi_nameid_lid_add(nameid, 0x8516, PSETID_Common); 	// PT_SYSTIME - CommonStart
+	mapi_nameid_lid_add(nameid, 0x8517, PSETID_Common); 	// PT_SYSTIME - CommonEnd
+	mapi_nameid_lid_add(nameid, 0x8518, PSETID_Common); 	// PT_LONG - TaskMode
+	mapi_nameid_lid_add(nameid, 0x8560, PSETID_Common); 	// PT_SYSTIME - ReminderNextTime
+
+	if (kind == ICAL_VEVENT_COMPONENT) 
+		appt_build_name_id (nameid);
+	else if (kind == ICAL_VTODO_COMPONENT)
+		task_build_name_id (nameid);
+	else if (kind == ICAL_VJOURNAL_COMPONENT)
+		note_build_name_id (nameid);
+
+	return TRUE;
+}
+
+/**
+ * NOTE: The enumerations '(Appt/Task/Note)NamedPropsIndex' have been defined 
+ * only to make life a little easier for developers. Here's the logic 
+ * behind the definition:
+     1) The first element is initialized with 'COMMON_NAMED_PROPS_N' : When 
+	adding named props, we add the common named props first and then the 
+	specific named props. So.. the index of the first specific 
+	named property = COMMON_NAMED_PROPS_N
+     2) The order in the enumeration 'must' be the same as that in the routine 
+	which adds the specific named props - (appt/task/note)_build_name_id
+     3) If a specific named prop is added/deleted, an index needs to
+	be created/deleted at the correct position. [Don't forget to update 
+	(APPT/TASK/NOTE)_NAMED_PROPS_N]. 
+
+ * To summarize the pros: 
+     1) Addition/deletion of a common-named-prop would not affect the indexes 
+	of the specific named props once COMMON_NAMED_PROPS_N is updated. 
+     2) Values of named props can be added in any order. 
+ */
+
+
+#define APPT_NAMED_PROPS_N  29
+#define DEFAULT_APPT_REMINDER_MINS 15
+
+typedef enum 
+{
+	I_APPT_SEQ = COMMON_NAMED_PROPS_N , 
+	I_APPT_BUSYSTATUS , 
+	I_APPT_LOCATION , 
+	I_APPT_START , 
+	I_APPT_END , 
+	I_APPT_DURATION , 
+	I_APPT_ALLDAY , 
+	I_APPT_RECURBLOB , 
+	I_APPT_STATEFLAGS , 
+	I_APPT_RESPONSESTATUS , 
+	I_APPT_RECURRING , 
+	I_APPT_INTENDEDBUSY , 
+	I_APPT_RECURBASE , 
+	I_APPT_INVITED , 
+	I_APPT_RECURTYPE , 
+	I_APPT_CLIPSTART , 
+	I_APPT_CLIPEND , 
+	I_APPT_AUTOLOCATION , 
+	I_APPT_ISCOUNTERPROPOSAL , 
+	I_APPT_NOTALLOWPROPOSE , 
+	I_APPT_STARTTZBLOB , 
+	I_APPT_ENDTZBLOB , 
+
+	I_MEET_WHERE , 
+	I_MEET_GUID , 
+	I_MEET_ISRECURRING , 
+	I_MEET_ISEXCEPTION , 
+	I_MEET_CLEANGUID , 
+	I_MEET_APPTMSGCLASS , 
+	I_MEET_TYPE
+
+//	I_APPT_SENDASICAL , 
+//	I_APPT_SEQTIME , 
+//	I_APPT_LABEL , 
+//	I_APPT_RECURPATTERN , 
+//	I_APPT_DISPTZ , 
+//	I_APPT_ALLATTENDEES , 
+//	I_APPT_TOATTENDEES , 
+//	I_APPT_CCATTENDEES , 
+} ApptNamedPropsIndex;
+
+static void 
+appt_build_name_id (struct mapi_nameid *nameid)
+{
+	mapi_nameid_lid_add(nameid, 0x8201, PSETID_Appointment); 	// PT_LONG - ApptSequence
+	mapi_nameid_lid_add(nameid, 0x8205, PSETID_Appointment); 	// PT_LONG - BusyStatus
+	mapi_nameid_lid_add(nameid, 0x8208, PSETID_Appointment); 	// PT_UNICODE - Location
+	mapi_nameid_lid_add(nameid, 0x820D, PSETID_Appointment); 	// PT_SYSTIME - Start/ApptStartWhole
+	mapi_nameid_lid_add(nameid, 0x820E, PSETID_Appointment); 	// PT_SYSTIME - End/ApptEndWhole
+	mapi_nameid_lid_add(nameid, 0x8213, PSETID_Appointment); 	// PT_LONG - Duration/ApptDuration
+	mapi_nameid_lid_add(nameid, 0x8215, PSETID_Appointment); 	// PT_BOOLEAN - AllDayEvent (also called ApptSubType)
+	mapi_nameid_lid_add(nameid, 0x8216, PSETID_Appointment); 	// PT_BINARY - (recurrence blob)
+	mapi_nameid_lid_add(nameid, 0x8217, PSETID_Appointment); 	// PT_LONG - ApptStateFlags
+	mapi_nameid_lid_add(nameid, 0x8218, PSETID_Appointment); 	// PT_LONG - ResponseStatus
+	mapi_nameid_lid_add(nameid, 0x8223, PSETID_Appointment); 	// PT_BOOLEAN - Recurring
+	mapi_nameid_lid_add(nameid, 0x8224, PSETID_Appointment); 	// PT_LONG - IntendedBusyStatus
+	mapi_nameid_lid_add(nameid, 0x8228, PSETID_Appointment); 	// PT_SYSTIME - RecurrenceBase
+	mapi_nameid_lid_add(nameid, 0x8229, PSETID_Appointment); 	// PT_BOOLEAN - FInvited
+	mapi_nameid_lid_add(nameid, 0x8231, PSETID_Appointment); 	// PT_LONG - RecurrenceType
+	mapi_nameid_lid_add(nameid, 0x8235, PSETID_Appointment); 	// PT_SYSTIME - (dtstart)(for recurring events UTC 12 AM of day of start)
+	mapi_nameid_lid_add(nameid, 0x8236, PSETID_Appointment); 	// PT_SYSTIME - (dtend)(for recurring events UTC 12 AM of day of end)
+	mapi_nameid_lid_add(nameid, 0x823A, PSETID_Appointment); 	// PT_BOOLEAN - AutoFillLocation
+	mapi_nameid_lid_add(nameid, 0x8257, PSETID_Appointment); 	// PT_BOOLEAN - ApptCounterProposal
+	mapi_nameid_lid_add(nameid, 0x825A, PSETID_Appointment); 	// PT_BOOLEAN - ApptNotAllowPropose
+	mapi_nameid_lid_add(nameid, 0x825E, PSETID_Appointment); 	// PT_BINARY - (timezone for dtstart)
+	mapi_nameid_lid_add(nameid, 0x825F, PSETID_Appointment); 	// PT_BINARY - (timezone for dtend)
+
+	mapi_nameid_lid_add(nameid, 0x0002, PSETID_Meeting); 		// PT_UNICODE - Where
+	mapi_nameid_lid_add(nameid, 0x0003, PSETID_Meeting); 		// PT_BINARY - GlobalObjectId
+	mapi_nameid_lid_add(nameid, 0x0005, PSETID_Meeting); 		// PT_BOOLEAN - IsRecurring
+	mapi_nameid_lid_add(nameid, 0x000A, PSETID_Meeting); 		// PT_BOOLEAN - IsException 
+	mapi_nameid_lid_add(nameid, 0x0023, PSETID_Meeting); 		// PT_BINARY - CleanGlobalObjectId
+	mapi_nameid_lid_add(nameid, 0x0024, PSETID_Meeting); 		// PT_STRING8 - AppointmentMessageClass 
+	mapi_nameid_lid_add(nameid, 0x0026, PSETID_Meeting); 		// PT_LONG - MeetingType
+
+	/* These probably would never be used from Evolution */
+//	mapi_nameid_lid_add(nameid, 0x8200, PSETID_Appointment); 	// PT_BOOLEAN - SendAsICAL
+//	mapi_nameid_lid_add(nameid, 0x8202, PSETID_Appointment); 	// PT_SYSTIME - ApptSequenceTime
+//	mapi_nameid_lid_add(nameid, 0x8214, PSETID_Appointment); 	// PT_LONG - Label
+//	mapi_nameid_lid_add(nameid, 0x8232, PSETID_Appointment); 	// PT_STRING8 - RecurrencePattern
+//	mapi_nameid_lid_add(nameid, 0x8234, PSETID_Appointment); 	// PT_STRING8 - display TimeZone
+//	mapi_nameid_lid_add(nameid, 0x8238, PSETID_Appointment); 	// PT_STRING8 - AllAttendees
+//	mapi_nameid_lid_add(nameid, 0x823B, PSETID_Appointment); 	// PT_STRING8 - ToAttendeesString (dupe PR_DISPLAY_TO)
+//	mapi_nameid_lid_add(nameid, 0x823C, PSETID_Appointment); 	// PT_STRING8 - CCAttendeesString (dupe PR_DISPLAY_CC)
+}
+
+#define TASK_NAMED_PROPS_N 13
+#define DEFAULT_TASK_REMINDER_MINS 1080
+
+typedef enum 
+{
+	I_TASK_STATUS = COMMON_NAMED_PROPS_N , 
+	I_TASK_PERCENT , 
+	I_TASK_ISTEAMTASK , 
+	I_TASK_START , 
+	I_TASK_DUE , 
+	I_TASK_COMPLETED , 
+//	I_TASK_RECURBLOB , 
+	I_TASK_ISCOMPLETE , 
+	I_TASK_OWNER , 
+	I_TASK_DELEGATOR , 
+	I_TASK_ISRECURRING , 
+	I_TASK_ROLE , 
+	I_TASK_OWNERSHIP , 
+	I_TASK_DELEGATIONSTATE , 
+//	I_TASK_ACTUALWORK , 
+//	I_TASK_TOTALWORK 
+} TaskNamedPropsIndex;
+
+static void 
+task_build_name_id (struct mapi_nameid *nameid)
+{
+	mapi_nameid_lid_add(nameid, 0x8101, PSETID_Task); 	// PT_LONG - Status
+	mapi_nameid_lid_add(nameid, 0x8102, PSETID_Task); 	// PT_DOUBLE - PercentComplete
+	mapi_nameid_lid_add(nameid, 0x8103, PSETID_Task); 	// PT_BOOLEAN - TeamTask
+	mapi_nameid_lid_add(nameid, 0x8104, PSETID_Task); 	// PT_SYSTIME - StartDate/TaskStartDate
+	mapi_nameid_lid_add(nameid, 0x8105, PSETID_Task); 	// PT_SYSTIME - DueDate/TaskDueDate
+	mapi_nameid_lid_add(nameid, 0x810F, PSETID_Task); 	// PT_SYSTIME - DateCompleted
+//	mapi_nameid_lid_add(nameid, 0x8116, PSETID_Task); 	// PT_BINARY - (recurrence blob)
+	mapi_nameid_lid_add(nameid, 0x811C, PSETID_Task); 	// PT_BOOLEAN - Complete
+	mapi_nameid_lid_add(nameid, 0x811F, PSETID_Task); 	// PT_STRING8 - Owner
+	mapi_nameid_lid_add(nameid, 0x8121, PSETID_Task); 	// PT_STRING8 - Delegator
+	mapi_nameid_lid_add(nameid, 0x8126, PSETID_Task); 	// PT_BOOLEAN - IsRecurring/TaskFRecur
+	mapi_nameid_lid_add(nameid, 0x8127, PSETID_Task); 	// PT_STRING8 - Role
+	mapi_nameid_lid_add(nameid, 0x8129, PSETID_Task); 	// PT_LONG - Ownership
+	mapi_nameid_lid_add(nameid, 0x812A, PSETID_Task); 	// PT_LONG - DelegationState
+
+	/* These probably would never be used from Evolution */
+//	mapi_nameid_lid_add(nameid, 0x8110, PSETID_Task); 	// PT_LONG - ActualWork/TaskActualEffort
+//	mapi_nameid_lid_add(nameid, 0x8111, PSETID_Task); 	// PT_LONG - TotalWork/TaskEstimatedEffort
+}
+
+
+#define NOTE_NAMED_PROPS_N 3
+
+typedef enum 
+{
+	I_NOTE_COLOR = COMMON_NAMED_PROPS_N , 
+	I_NOTE_WIDTH , 
+	I_NOTE_HEIGHT
+} NoteNamedPropsIndex;
+
+static void 
+note_build_name_id (struct mapi_nameid *nameid)
+{
+	mapi_nameid_lid_add(nameid, 0x8B00, PSETID_Note); 	// PT_LONG - Color
+	mapi_nameid_lid_add(nameid, 0x8B02, PSETID_Note); 	// PT_LONG - Width
+	mapi_nameid_lid_add(nameid, 0x8B03, PSETID_Note); 	// PT_LONG - Height
+}
+
+#define MINUTES_IN_HOUR 60
+#define SECS_IN_MINUTE 60
+
+/** 
+ * NOTE: When a new regular property (PR_***) is added, 'REGULAR_PROPS_N' 
+ * should be updated. 
+ */
+#define REGULAR_PROPS_N    22
+
+int
+exchange_mapi_cal_util_build_props (struct SPropValue **value, struct SPropTagArray *proptag_array, gpointer data)
+{
+	struct cbdata *cbdata = (struct cbdata *) data;
+	ECalComponent *comp = cbdata->comp;
+	icalcomponent *ical_comp = e_cal_component_get_icalcomponent (comp);
+	icalcomponent_kind  kind = icalcomponent_isa (ical_comp);
+	struct SPropValue *props = NULL;
+	int i=0;
+	uint32_t flag32;
+	bool b;
+	icalproperty *prop;
+	struct icaltimetype dtstart, dtend, utc_dtstart, utc_dtend;
+	const icaltimezone *utc_zone;
+	const char *dtstart_tzid, *dtend_tzid, *text = NULL;
+	struct timeval t;
+
+	flag32 = REGULAR_PROPS_N + COMMON_NAMED_PROPS_N;
+	switch (kind) {
+		case ICAL_VEVENT_COMPONENT:
+			flag32 += APPT_NAMED_PROPS_N;
+			break;
+		case ICAL_VTODO_COMPONENT:
+			flag32 += TASK_NAMED_PROPS_N;
+			break;
+		case ICAL_VJOURNAL_COMPONENT:
+			flag32 += NOTE_NAMED_PROPS_N;
+			break;
+		default:
+			return 0;
+	} 
+
+	d(g_debug ("Allocating space for %d props ", flag32));
+	props = g_new0 (struct SPropValue, flag32);
+
+	/* PR_MESSAGE_CLASS needs to be set appropriately */					/* propcount++ */
+
+	utc_zone = icaltimezone_get_utc_timezone ();
+
+	dtstart = icalcomponent_get_dtstart (ical_comp);
+
+	/* For VEVENTs */
+	if (icalcomponent_get_first_property (ical_comp, ICAL_DTEND_PROPERTY) != 0)
+		dtend = icalcomponent_get_dtend (ical_comp);
+	/* For VTODOs */
+	else if (icalcomponent_get_first_property (ical_comp, ICAL_DUE_PROPERTY) != 0)
+		dtend = icalcomponent_get_due (ical_comp);
+	else 
+		dtend = icalcomponent_get_dtstart (ical_comp);
+
+	dtstart_tzid = icaltime_get_tzid (dtstart);
+	dtend_tzid = icaltime_get_tzid (dtend);
+
+	utc_dtstart = icaltime_convert_to_zone (dtstart, utc_zone);
+	utc_dtend = icaltime_convert_to_zone (dtend, utc_zone);
+
+	text = icalcomponent_get_summary (ical_comp);
+	if (!(text && *text)) 
+		text = "";
+	set_SPropValue_proptag(&props[i++], PR_SUBJECT, 					/* propcount++ */ 
+					(const void *) text);
+	set_SPropValue_proptag(&props[i++], PR_NORMALIZED_SUBJECT, 				/* propcount++ */ 
+					(const void *) text);
+	if (cbdata->appt_seq == 0)
+		set_SPropValue_proptag(&props[i++], PR_CONVERSATION_TOPIC, 			/* propcount++ */
+						(const void *) text);
+	text = NULL;
+
+	/* we don't support HTML event/task/memo editor */
+	flag32 = olEditorText;
+	set_SPropValue_proptag(&props[i++], PR_MSG_EDITOR_FORMAT, &flag32); 			/* propcount++ */
+
+	/* it'd be better to convert, then set it in unicode */
+	text = icalcomponent_get_description (ical_comp);
+	if (!(text && *text) || !g_utf8_validate (text, -1, NULL)) 
+		text = "";
+	set_SPropValue_proptag(&props[i++], PR_BODY, 						/* propcount++ */
+					(const void *) text);
+	text = NULL;
+
+	/* Priority and Importance */
+	prop = icalcomponent_get_first_property (ical_comp, ICAL_PRIORITY_PROPERTY);
+	flag32 = prop ? get_prio_prop_from_priority (icalproperty_get_priority (prop)) : PRIORITY_NORMAL;
+	set_SPropValue_proptag(&props[i++], PR_PRIORITY, (const void *) &flag32); 		/* propcount++ */
+	flag32 = prop ? get_imp_prop_from_priority (icalproperty_get_priority (prop)) : IMPORTANCE_NORMAL;
+	set_SPropValue_proptag(&props[i++], PR_IMPORTANCE, (const void *) &flag32); 		/* propcount++ */
+
+	set_SPropValue_proptag(&props[i++], PR_SENT_REPRESENTING_NAME, 
+		(const void *) cbdata->ownername); 						/* propcount++ */
+	set_SPropValue_proptag(&props[i++], PR_SENT_REPRESENTING_ADDRTYPE, 
+		(const void *) cbdata->owneridtype); 						/* propcount++ */
+	set_SPropValue_proptag(&props[i++], PR_SENT_REPRESENTING_EMAIL_ADDRESS, 
+		(const void *) cbdata->ownerid); 						/* propcount++ */
+	set_SPropValue_proptag(&props[i++], PR_SENDER_NAME, 
+		(const void *) cbdata->username); 						/* propcount++ */
+	set_SPropValue_proptag(&props[i++], PR_SENDER_ADDRTYPE, 
+		(const void *) cbdata->useridtype); 						/* propcount++ */
+	set_SPropValue_proptag(&props[i++], PR_SENDER_EMAIL_ADDRESS, 
+		(const void *) cbdata->userid); 						/* propcount++ */
+
+	flag32 = cbdata->msgflags;
+	set_SPropValue_proptag(&props[i++], PR_MESSAGE_FLAGS, (const void *) &flag32); 		/* propcount++ */
+
+	flag32 = 0x0;
+	b = e_cal_component_has_alarms (comp);
+	if (b) {
+		/* We know there would be only a single alarm of type:DISPLAY [static properties of the backend] */
+		GList *alarm_uids = e_cal_component_get_alarm_uids (comp);
+		ECalComponentAlarm *alarm = e_cal_component_get_alarm (comp, (const char *)(alarm_uids->data));
+		ECalComponentAlarmAction action;
+		e_cal_component_alarm_get_action (alarm, &action);
+		if (action == E_CAL_COMPONENT_ALARM_DISPLAY) {
+			ECalComponentAlarmTrigger trigger;
+			e_cal_component_alarm_get_trigger (alarm, &trigger);
+			int dur_int = 0; 
+			switch (trigger.type) {
+			case E_CAL_COMPONENT_ALARM_TRIGGER_RELATIVE_START :
+				dur_int = (icaldurationtype_as_int (trigger.u.rel_duration)) / SECS_IN_MINUTE;
+			/* we cannot set an alarm to popup after the start of an appointment on Exchange */
+				flag32 = (dur_int < 0) ? -(dur_int) : 0;
+				break;
+			default :
+				break;
+			}
+		}
+		e_cal_component_alarm_free (alarm);
+		cal_obj_uid_list_free (alarm_uids);
+	} 
+	if (!flag32)
+		switch (kind) {
+			case ICAL_VEVENT_COMPONENT:
+				flag32 = DEFAULT_APPT_REMINDER_MINS;
+				break;
+			case ICAL_VTODO_COMPONENT:
+				flag32 = DEFAULT_TASK_REMINDER_MINS;
+				break;
+			default:
+				break;
+		}
+	set_SPropValue_proptag(&props[i++], proptag_array->aulPropTag[I_COMMON_REMSET], (const void *) &b);
+	set_SPropValue_proptag(&props[i++], proptag_array->aulPropTag[I_COMMON_REMMINS], (const void *) &flag32);
+	t.tv_sec = icaltime_as_timet (utc_dtstart);
+	t.tv_usec = 0;
+	set_SPropValue_proptag_date_timeval(&props[i++], proptag_array->aulPropTag[I_COMMON_REMTIME], &t);
+	t.tv_sec = icaltime_as_timet (utc_dtstart) - (flag32 * SECS_IN_MINUTE);
+	t.tv_usec = 0;
+	/* ReminderNextTime: FIXME for recurrence */
+	set_SPropValue_proptag_date_timeval(&props[i++], proptag_array->aulPropTag[I_COMMON_REMNEXTTIME], &t);
+
+	/* Sensitivity, Private */
+	flag32 = olNormal; 	/* default */
+	b = 0; 			/* default */
+	prop = icalcomponent_get_first_property (ical_comp, ICAL_CLASS_PROPERTY);
+	if (prop) 
+		flag32 = get_prop_from_class (icalproperty_get_class (prop));
+	if (flag32 == olPrivate || flag32 == olConfidential)
+		b = 1;
+	set_SPropValue_proptag(&props[i++], PR_SENSITIVITY, (const void *) &flag32); 		/* propcount++ */
+	set_SPropValue_proptag(&props[i++], proptag_array->aulPropTag[I_COMMON_ISPRIVATE], (const void *) &b);
+
+	t.tv_sec = icaltime_as_timet (utc_dtstart);
+	t.tv_usec = 0;
+	set_SPropValue_proptag_date_timeval(&props[i++], proptag_array->aulPropTag[I_COMMON_START], &t);
+	set_SPropValue_proptag_date_timeval(&props[i++], PR_START_DATE, &t); 			/* propcount++ */
+
+	t.tv_sec = icaltime_as_timet (utc_dtend);
+	t.tv_usec = 0;
+	set_SPropValue_proptag_date_timeval(&props[i++], proptag_array->aulPropTag[I_COMMON_END], &t);
+	set_SPropValue_proptag_date_timeval(&props[i++], PR_END_DATE, &t); 			/* propcount++ */
+
+	b = 1;
+	set_SPropValue_proptag(&props[i++], PR_RESPONSE_REQUESTED, (const void *) &b); 		/* propcount++ */
+
+	/* PR_OWNER_APPT_ID needs to be set in certain cases only */				/* propcount++ */
+	/* PR_ICON_INDEX needs to be set appropriately */					/* propcount++ */
+
+	b = 0;
+	set_SPropValue_proptag(&props[i++], PR_RTF_IN_SYNC, (const void *) &b); 		/* propcount++ */
+
+	if (kind == ICAL_VEVENT_COMPONENT) {
+		const char *mapi_tzid;
+		struct SBinary start_tz, end_tz; 
+
+		set_SPropValue_proptag(&props[i++], proptag_array->aulPropTag[I_MEET_APPTMSGCLASS], (const void *) IPM_APPOINTMENT);
+
+		/* Busy Status */
+		flag32 = olBusy; 	/* default */
+		prop = icalcomponent_get_first_property (ical_comp, ICAL_TRANSP_PROPERTY);
+		if (prop)
+			flag32 = get_prop_from_transp (icalproperty_get_transp (prop));
+		if (cbdata->meeting_type == MEETING_CANCEL)
+			flag32 = olFree;
+		set_SPropValue_proptag(&props[i++], proptag_array->aulPropTag[I_APPT_INTENDEDBUSY], (const void *) &flag32);
+
+		if (cbdata->meeting_type == MEETING_REQUEST || cbdata->meeting_type == MEETING_REQUEST_RCVD) {
+			flag32 = olTentative;
+			set_SPropValue_proptag(&props[i++], proptag_array->aulPropTag[I_APPT_BUSYSTATUS], (const void *) &flag32);
+		} else if (cbdata->meeting_type == MEETING_CANCEL) {
+			flag32 = olFree;
+			set_SPropValue_proptag(&props[i++], proptag_array->aulPropTag[I_APPT_BUSYSTATUS], (const void *) &flag32);
+		} else 
+			set_SPropValue_proptag(&props[i++], proptag_array->aulPropTag[I_APPT_BUSYSTATUS], (const void *) &flag32);
+
+		/* Location */
+		text = icalcomponent_get_location (ical_comp);
+		if (!(text && *text)) 
+			text = "";
+		set_SPropValue_proptag(&props[i++], proptag_array->aulPropTag[I_APPT_LOCATION], (const void *) text);
+		set_SPropValue_proptag(&props[i++], proptag_array->aulPropTag[I_MEET_WHERE], (const void *) text);
+		text = NULL;
+		/* Auto-Location is always FALSE - Evolution doesn't work that way */
+		b = 0; 
+		set_SPropValue_proptag(&props[i++], proptag_array->aulPropTag[I_APPT_AUTOLOCATION], (const void *) &b);
+
+		/* Start */
+		t.tv_sec = icaltime_as_timet (utc_dtstart);
+		t.tv_usec = 0;
+		set_SPropValue_proptag_date_timeval(&props[i++], proptag_array->aulPropTag[I_APPT_START], &t);
+		/* FIXME: for recurrence */
+		set_SPropValue_proptag_date_timeval(&props[i++], proptag_array->aulPropTag[I_APPT_CLIPSTART], &t);
+
+		/* Start TZ */
+		mapi_tzid = exchange_mapi_cal_tz_util_get_mapi_equivalent ((dtstart_tzid && *dtstart_tzid) ? dtstart_tzid : "UTC");
+		if (mapi_tzid && *mapi_tzid) {
+			exchange_mapi_cal_util_mapi_tz_to_bin (mapi_tzid, &start_tz);
+			set_SPropValue_proptag(&props[i++], proptag_array->aulPropTag[I_APPT_STARTTZBLOB], (const void *) &start_tz);
+		}
+
+		/* End */
+		t.tv_sec = icaltime_as_timet (utc_dtend);
+		t.tv_usec = 0;
+		set_SPropValue_proptag_date_timeval(&props[i++], proptag_array->aulPropTag[I_APPT_END], &t);
+		/* FIXME: for recurrence */
+		set_SPropValue_proptag_date_timeval(&props[i++], proptag_array->aulPropTag[I_APPT_CLIPEND], &t);
+
+		/* End TZ */
+		mapi_tzid = exchange_mapi_cal_tz_util_get_mapi_equivalent ((dtend_tzid && *dtend_tzid) ? dtend_tzid : "UTC");
+		if (mapi_tzid && *mapi_tzid) {
+			exchange_mapi_cal_util_mapi_tz_to_bin (mapi_tzid, &end_tz);
+			set_SPropValue_proptag(&props[i++], proptag_array->aulPropTag[I_APPT_ENDTZBLOB], (const void *) &end_tz);
+		}
+
+		/* Duration */
+		flag32 = icaldurationtype_as_int (icaltime_subtract (dtend, dtstart));
+		flag32 /= MINUTES_IN_HOUR;
+		set_SPropValue_proptag(&props[i++], proptag_array->aulPropTag[I_APPT_DURATION], (const void *) &flag32);
+
+		/* All-day event */
+		b = (icaltime_is_date (dtstart) && icaltime_is_date (dtend));
+		set_SPropValue_proptag(&props[i++], proptag_array->aulPropTag[I_APPT_ALLDAY], (const void *) &b);
+
+		if (e_cal_component_has_recurrences (comp)) {
+			GSList *rrule_list = NULL; 
+			struct icalrecurrencetype *rt = NULL;
+
+			e_cal_component_get_rrule_list (comp, &rrule_list); 
+			rt = (struct icalrecurrencetype *)(rrule_list->data);
+
+			if (rt->freq == ICAL_DAILY_RECURRENCE)
+				flag32 = rectypeDaily; 
+			else if (rt->freq == ICAL_WEEKLY_RECURRENCE)
+				flag32 = rectypeWeekly; 
+			else if (rt->freq == ICAL_MONTHLY_RECURRENCE)
+				flag32 = rectypeMonthly; 
+			else if (rt->freq == ICAL_YEARLY_RECURRENCE)
+				flag32 = rectypeYearly; 
+			else 
+				flag32 = rectypeNone;
+
+			e_cal_component_free_recur_list (rrule_list); 
+		} else 
+			flag32 = rectypeNone;
+		set_SPropValue_proptag(&props[i++], proptag_array->aulPropTag[I_APPT_RECURTYPE], (const void *) &flag32);
+
+		flag32 = cbdata->appt_id;
+		set_SPropValue_proptag(&props[i++], PR_OWNER_APPT_ID, (const void *) &flag32);
+
+		flag32 = cbdata->appt_seq;
+		set_SPropValue_proptag(&props[i++],  proptag_array->aulPropTag[I_APPT_SEQ], (const void *) &flag32);
+
+		set_SPropValue_proptag(&props[i++], proptag_array->aulPropTag[I_MEET_CLEANGUID], (const void *) cbdata->cleanglobalid);
+		set_SPropValue_proptag(&props[i++], proptag_array->aulPropTag[I_MEET_GUID], (const void *) cbdata->globalid);
+
+		flag32 = cbdata->resp;
+		set_SPropValue_proptag(&props[i++], proptag_array->aulPropTag[I_APPT_RESPONSESTATUS], (const void *) &flag32);
+
+		switch (cbdata->meeting_type) {
+		case MEETING_OBJECT :
+			set_SPropValue_proptag(&props[i++], PR_MESSAGE_CLASS, (const void *) IPM_APPOINTMENT);
+
+			flag32 = e_cal_component_has_recurrences (comp) ? RecurMeet : SingleMeet; 
+			set_SPropValue_proptag(&props[i++], PR_ICON_INDEX, (const void *) &flag32);
+
+			flag32 = 0x0171;
+			set_SPropValue_proptag(&props[i++], proptag_array->aulPropTag[I_COMMON_SIDEEFFECTS], (const void *) &flag32);
+
+			flag32 = asfMeeting;
+			set_SPropValue_proptag(&props[i++], proptag_array->aulPropTag[I_APPT_STATEFLAGS], (const void *) &flag32);
+
+			flag32 = mtgRequest; 
+			set_SPropValue_proptag(&props[i++], proptag_array->aulPropTag[I_MEET_TYPE], (const void *) &flag32);
+
+			b = 1;
+			set_SPropValue_proptag(&props[i++], proptag_array->aulPropTag[I_APPT_INVITED], (const void *) &b);
+
+			break;
+		case MEETING_OBJECT_RCVD :
+			set_SPropValue_proptag(&props[i++], PR_MESSAGE_CLASS, (const void *) IPM_APPOINTMENT);
+
+			flag32 = e_cal_component_has_recurrences (comp) ? RecurMeet : SingleMeet; 
+			set_SPropValue_proptag(&props[i++], PR_ICON_INDEX, (const void *) &flag32);
+
+			flag32 = 0x0171;
+			set_SPropValue_proptag(&props[i++], proptag_array->aulPropTag[I_COMMON_SIDEEFFECTS], (const void *) &flag32);
+
+			flag32 = asfMeeting | asfReceived;
+			set_SPropValue_proptag(&props[i++], proptag_array->aulPropTag[I_APPT_STATEFLAGS], (const void *) &flag32);
+
+			flag32 = mtgRequest; 
+			set_SPropValue_proptag(&props[i++], proptag_array->aulPropTag[I_MEET_TYPE], (const void *) &flag32);
+
+			b = 1;
+			set_SPropValue_proptag(&props[i++], proptag_array->aulPropTag[I_APPT_INVITED], (const void *) &b);
+
+			break;
+		case MEETING_REQUEST :
+			set_SPropValue_proptag(&props[i++], PR_MESSAGE_CLASS, (const void *) IPM_SCHEDULE_MEETING_REQUEST);
+
+			flag32 = 0xFFFFFFFF;  /* no idea why this has to be -1, but that's what the docs say */
+			set_SPropValue_proptag(&props[i++], PR_ICON_INDEX, (const void *) &flag32);
+
+			flag32 = 0x1C61;
+			set_SPropValue_proptag(&props[i++], proptag_array->aulPropTag[I_COMMON_SIDEEFFECTS], (const void *) &flag32);
+
+			flag32 = asfMeeting | asfReceived;
+			set_SPropValue_proptag(&props[i++], proptag_array->aulPropTag[I_APPT_STATEFLAGS], (const void *) &flag32);
+
+			flag32 = (cbdata->appt_seq == 0) ? mtgRequest : mtgFull; 
+			set_SPropValue_proptag(&props[i++], proptag_array->aulPropTag[I_MEET_TYPE], (const void *) &flag32);
+
+			b = 1;
+			set_SPropValue_proptag(&props[i++], proptag_array->aulPropTag[I_APPT_INVITED], (const void *) &b);
+
+			break;
+		case MEETING_REQUEST_RCVD :
+			set_SPropValue_proptag(&props[i++], PR_MESSAGE_CLASS, (const void *) IPM_APPOINTMENT);
+
+			flag32 = e_cal_component_has_recurrences (comp) ? RecurMeet : SingleMeet; 
+			set_SPropValue_proptag(&props[i++], PR_ICON_INDEX, (const void *) &flag32);
+
+			flag32 = 0x0171;
+			set_SPropValue_proptag(&props[i++], proptag_array->aulPropTag[I_COMMON_SIDEEFFECTS], (const void *) &flag32);
+
+			flag32 = asfMeeting | asfReceived;
+			set_SPropValue_proptag(&props[i++], proptag_array->aulPropTag[I_APPT_STATEFLAGS], (const void *) &flag32);
+
+			flag32 = mtgRequest; 
+			set_SPropValue_proptag(&props[i++], proptag_array->aulPropTag[I_MEET_TYPE], (const void *) &flag32);
+
+			b = 1;
+			set_SPropValue_proptag(&props[i++], proptag_array->aulPropTag[I_APPT_INVITED], (const void *) &b);
+
+			break;
+		case MEETING_CANCEL :
+			set_SPropValue_proptag(&props[i++], PR_MESSAGE_CLASS, (const void *) IPM_SCHEDULE_MEETING_CANCELED);
+
+			flag32 = 0xFFFFFFFF;  /* no idea why this has to be -1, but that's what the docs say */ 
+			set_SPropValue_proptag(&props[i++], PR_ICON_INDEX, (const void *) &flag32);
+
+			flag32 = 0x1C61;
+			set_SPropValue_proptag(&props[i++], proptag_array->aulPropTag[I_COMMON_SIDEEFFECTS], (const void *) &flag32);
+
+			flag32 = asfMeeting | asfReceived | asfCanceled;
+			set_SPropValue_proptag(&props[i++], proptag_array->aulPropTag[I_APPT_STATEFLAGS], (const void *) &flag32);
+
+			flag32 = mtgEmpty; 
+			set_SPropValue_proptag(&props[i++], proptag_array->aulPropTag[I_MEET_TYPE], (const void *) &flag32);
+
+			b = 1;
+			set_SPropValue_proptag(&props[i++], proptag_array->aulPropTag[I_APPT_INVITED], (const void *) &b);
+
+			break;
+		case MEETING_RESPONSE : 
+			if (cbdata->resp == olResponseAccepted) {
+				text = IPM_SCHEDULE_MEETING_RESP_POS; 
+			} else if (cbdata->resp == olResponseTentative) {
+				text = IPM_SCHEDULE_MEETING_RESP_TENT; 
+			} else if (cbdata->resp == olResponseDeclined) {
+				text = IPM_SCHEDULE_MEETING_RESP_NEG; 
+			} else {
+				text = ""; 
+			}
+			set_SPropValue_proptag(&props[i++], PR_MESSAGE_CLASS, (const void *) text);
+			text = NULL;
+
+			flag32 = 0xFFFFFFFF;  /* no idea why this has to be -1, but that's what the docs say */ 
+			set_SPropValue_proptag(&props[i++], PR_ICON_INDEX, (const void *) &flag32);
+
+			flag32 = 0x1C61;
+			set_SPropValue_proptag(&props[i++], proptag_array->aulPropTag[I_COMMON_SIDEEFFECTS], (const void *) &flag32);
+
+			flag32 = asfNone;
+			set_SPropValue_proptag(&props[i++], proptag_array->aulPropTag[I_APPT_STATEFLAGS], (const void *) &flag32);
+
+			flag32 = mtgEmpty; 
+			set_SPropValue_proptag(&props[i++], proptag_array->aulPropTag[I_MEET_TYPE], (const void *) &flag32);
+
+			break;
+		case NOT_A_MEETING :
+		default :
+			set_SPropValue_proptag(&props[i++], PR_MESSAGE_CLASS, (const void *) IPM_APPOINTMENT);
+
+			flag32 = e_cal_component_has_recurrences (comp) ? RecurAppt : SingleAppt; 
+			set_SPropValue_proptag(&props[i++], PR_ICON_INDEX, (const void *) &flag32);
+
+			flag32 = 0x0171;
+			set_SPropValue_proptag(&props[i++], proptag_array->aulPropTag[I_COMMON_SIDEEFFECTS], (const void *) &flag32);
+
+			flag32 = 0;
+			set_SPropValue_proptag(&props[i++], proptag_array->aulPropTag[I_APPT_STATEFLAGS], (const void *) &flag32);
+
+			b = 0;
+			set_SPropValue_proptag(&props[i++], proptag_array->aulPropTag[I_APPT_INVITED], (const void *) &b);
+
+			break;
+		}
+
+		b = e_cal_component_has_recurrences (comp);
+		set_SPropValue_proptag(&props[i++], proptag_array->aulPropTag[I_APPT_RECURRING], (const void *) &b);
+		set_SPropValue_proptag(&props[i++], proptag_array->aulPropTag[I_MEET_ISRECURRING], (const void *) &b);
+		/* FIXME: Modified exceptions */
+		b = e_cal_component_has_exceptions (comp) && FALSE; b = 0;
+		set_SPropValue_proptag(&props[i++], proptag_array->aulPropTag[I_MEET_ISEXCEPTION], (const void *) &b);
+
+		/* Counter Proposal for appointments : not supported */
+		b = 1;
+		set_SPropValue_proptag(&props[i++], proptag_array->aulPropTag[I_APPT_NOTALLOWPROPOSE], (const void *) &b);
+		b = 0;
+		set_SPropValue_proptag(&props[i++], proptag_array->aulPropTag[I_APPT_ISCOUNTERPROPOSAL], (const void *) &b);
+
+	} else if (kind == ICAL_VTODO_COMPONENT) {
+		double d;
+
+		set_SPropValue_proptag(&props[i++], PR_MESSAGE_CLASS, (const void *) IPM_TASK);
+
+		/* Context menu flags */ /* FIXME: for assigned tasks */
+		flag32 = 0x0110; 
+		set_SPropValue_proptag(&props[i++], proptag_array->aulPropTag[I_COMMON_SIDEEFFECTS], (const void *) &flag32);
+
+		/* Status, Percent complete, IsComplete */
+		flag32 = olTaskNotStarted; 	/* default */
+		b = 0; 				/* default */
+		d = 0.0;
+		prop = icalcomponent_get_first_property (ical_comp, ICAL_PERCENTCOMPLETE_PROPERTY);
+		if (prop)
+			d = 0.01 * icalproperty_get_percentcomplete (prop);
+
+		flag32 = get_prop_from_taskstatus (icalcomponent_get_status (ical_comp));
+		if (flag32 == olTaskComplete) {
+			b = 1;
+			d = 1.0;
+		}
+
+		set_SPropValue_proptag(&props[i++], proptag_array->aulPropTag[I_TASK_STATUS], (const void *) &flag32);
+
+		/* FIXME: bug in LibMAPI - does not handle PT_DOUBLE in set_SPropValue() */
+//		set_SPropValue_proptag(&props[i++], proptag_array->aulPropTag[I_TASK_PERCENT], (const void *) &d); 
+		props[i].ulPropTag = proptag_array->aulPropTag[I_TASK_PERCENT];
+		props[i].dwAlignPad = 0x0;
+		memcpy (&(props[i].value.dbl), &d, sizeof(double));
+		i++; 
+
+		set_SPropValue_proptag(&props[i++], proptag_array->aulPropTag[I_TASK_ISCOMPLETE], (const void *) &b);
+
+		/* Date completed */
+		if (b) {
+			struct icaltimetype completed;
+			prop = icalcomponent_get_first_property (ical_comp, ICAL_COMPLETED_PROPERTY);
+			completed = icalproperty_get_completed (prop);
+
+			completed.hour = completed.minute = completed.second = 0; completed.is_date = completed.is_utc = 1;
+			t.tv_sec = icaltime_as_timet (completed);
+			t.tv_usec = 0;
+			set_SPropValue_proptag_date_timeval(&props[i++], proptag_array->aulPropTag[I_TASK_COMPLETED], &t);
+		}
+
+		/* Start */
+		dtstart.hour = dtstart.minute = dtstart.second = 0; dtstart.is_date = dtstart.is_utc = 1;
+		t.tv_sec = icaltime_as_timet (dtstart);
+		t.tv_usec = 0;
+		if (!icaltime_is_null_time (dtstart))
+			set_SPropValue_proptag_date_timeval(&props[i++], proptag_array->aulPropTag[I_TASK_START], &t);
+
+		/* Due */
+		dtend.hour = dtend.minute = dtend.second = 0; dtend.is_date = dtend.is_utc = 1;
+		t.tv_sec = icaltime_as_timet (dtend);
+		t.tv_usec = 0;
+		if (!icaltime_is_null_time (dtend))
+			set_SPropValue_proptag_date_timeval(&props[i++], proptag_array->aulPropTag[I_TASK_DUE], &t);
+
+		/* FIXME: Evolution does not support recurring tasks */
+		b = 0;
+		set_SPropValue_proptag(&props[i++], proptag_array->aulPropTag[I_TASK_ISRECURRING], (const void *) &b);
+
+	} else if (kind == ICAL_VJOURNAL_COMPONENT) {
+		uint32_t color = olYellow; 
+
+		set_SPropValue_proptag(&props[i++], PR_MESSAGE_CLASS, (const void *) IPM_STICKYNOTE);
+
+		/* Context menu flags */
+		flag32 = 0x0110; 
+		set_SPropValue_proptag(&props[i++], proptag_array->aulPropTag[I_COMMON_SIDEEFFECTS], (const void *) &flag32);
+
+		flag32 = 0x0300 + color; 
+		set_SPropValue_proptag(&props[i++], PR_ICON_INDEX, (const void *) &flag32);
+
+		flag32 = color; 
+		set_SPropValue_proptag(&props[i++], proptag_array->aulPropTag[I_NOTE_COLOR], (const void *) &flag32);
+
+		/* some random value */
+		flag32 = 0x00FF; 
+		set_SPropValue_proptag(&props[i++], proptag_array->aulPropTag[I_NOTE_WIDTH], (const void *) &flag32);
+
+		/* some random value */
+		flag32 = 0x00FF; 
+		set_SPropValue_proptag(&props[i++], proptag_array->aulPropTag[I_NOTE_HEIGHT], (const void *) &flag32);
+	}
+
+	*value = props;
+	/* Free this memory at the backends. */
+	cbdata->props = props;
+
+	d(g_debug ("Ended up setting %d props ", i));
+
+	return i;
+}
+
+uint32_t
+exchange_mapi_cal_util_get_new_appt_id (mapi_id_t fid)
+{
+	struct mapi_SRestriction res;
+	struct SPropValue sprop;
+	uint32_t id;
+	gboolean found = FALSE;
+
+	res.rt = RES_PROPERTY;
+	res.res.resProperty.relop = RELOP_EQ;
+	res.res.resProperty.ulPropTag = PR_OWNER_APPT_ID;
+
+	while (!found) {
+		id = g_random_int ();
+		if (id) {
+			GSList *ids = NULL;
+			set_SPropValue_proptag (&sprop, PR_OWNER_APPT_ID, (const void *) &id);
+			cast_mapi_SPropValue (&(res.res.resProperty.lpProp), &sprop);
+			ids = exchange_mapi_util_check_restriction (fid, &res);
+			if (ids) {
+				GSList *l;
+				for (l = ids; l; l = l->next)
+					g_free (l->data);
+			} else 
+				found = TRUE;
+		}
+	};
+
+	return id;
+}
+

Added: trunk/src/libexchangemapi/exchange-mapi-cal-utils.h
==============================================================================
--- (empty file)
+++ trunk/src/libexchangemapi/exchange-mapi-cal-utils.h	Wed Nov 19 04:28:20 2008
@@ -0,0 +1,153 @@
+/* -*- 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/>  
+ *
+ *
+ * Authors:
+ *    Suman Manjunath <msuman novell com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef EXCHANGE_MAPI_CAL_UTILS_H
+#define EXCHANGE_MAPI_CAL_UTILS_H
+
+#include <libecal/e-cal-component.h>
+
+#include "exchange-mapi-connection.h"
+#include "exchange-mapi-defs.h"
+#include "exchange-mapi-utils.h"
+
+#include "exchange-mapi-cal-tz-utils.h"
+#include "exchange-mapi-cal-recur-utils.h"
+
+G_BEGIN_DECLS
+
+typedef enum {
+	NOT_A_MEETING 		= (1 << 0), 
+	MEETING_OBJECT 		= (1 << 1), 
+	MEETING_OBJECT_SENT 	= (1 << 2), 
+	MEETING_OBJECT_RCVD 	= (1 << 3), 
+	MEETING_REQUEST 	= (1 << 4), 
+	MEETING_REQUEST_RCVD 	= (1 << 5), 
+	MEETING_RESPONSE 	= (1 << 6), 
+	MEETING_RESPONSE_RCVD 	= (1 << 7), 
+	MEETING_CANCEL 		= (1 << 8), 
+	MEETING_CANCEL_RCVD 	= (1 << 9) 
+} MAPIMeetingOptions;
+
+struct cbdata { 
+	ECalComponent *comp;
+	struct SPropValue *props;
+	gboolean is_modify;
+
+	/* These are appt specific data */ 
+	MAPIMeetingOptions meeting_type;
+	uint32_t appt_id;
+	uint32_t appt_seq;
+	struct SBinary *globalid;
+	struct SBinary *cleanglobalid;
+
+	uint32_t msgflags;
+	OlResponseStatus resp; 
+	const char *username;
+	const char *useridtype;
+	const char *userid;
+	const char *ownername;
+	const char *owneridtype;
+	const char *ownerid;
+};
+
+void
+exchange_mapi_cal_util_fetch_organizer (ECalComponent *comp, GSList **recip_list);
+void
+exchange_mapi_cal_util_fetch_recipients (ECalComponent *comp, GSList **recip_list);
+void
+exchange_mapi_cal_util_fetch_attachments (ECalComponent *comp, GSList **attach_list, const char *local_store_uri);
+
+ECalComponent *
+exchange_mapi_cal_util_mapi_props_to_comp (icalcomponent_kind kind, const gchar *mid, struct mapi_SPropValue_array *properties, 
+					   GSList *streams, GSList *recipients, GSList *attachments, 
+					   const char *local_store_uri, const icaltimezone *default_zone);
+gboolean
+exchange_mapi_cal_util_build_name_id (struct mapi_nameid *nameid, gpointer data);
+
+int
+exchange_mapi_cal_util_build_props (struct SPropValue **value, struct SPropTagArray *proptag_array, gpointer data);
+
+void
+exchange_mapi_cal_util_generate_globalobjectid (gboolean is_clean, const char *uid, struct SBinary *sb);
+
+char *
+exchange_mapi_cal_util_camel_helper (struct mapi_SPropValue_array *properties, 
+				   GSList *streams, GSList *recipients, GSList *attachments);
+
+uint32_t
+exchange_mapi_cal_util_get_new_appt_id (mapi_id_t fid);
+
+static const uint32_t cal_GetPropsList[] = {
+	PR_FID, 
+	PR_MID, 
+
+	PR_SUBJECT, 
+	PR_SUBJECT_UNICODE, 
+	PR_NORMALIZED_SUBJECT, 
+	PR_NORMALIZED_SUBJECT_UNICODE, 
+	PR_CONVERSATION_TOPIC, 
+	PR_CONVERSATION_TOPIC_UNICODE, 
+	PR_BODY, 
+	PR_BODY_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_MSG_EDITOR_FORMAT, 
+
+	PR_SENT_REPRESENTING_NAME, 
+	PR_SENT_REPRESENTING_NAME_UNICODE, 
+	PR_SENT_REPRESENTING_ADDRTYPE, 
+	PR_SENT_REPRESENTING_ADDRTYPE_UNICODE, 
+	PR_SENT_REPRESENTING_EMAIL_ADDRESS, 
+	PR_SENT_REPRESENTING_EMAIL_ADDRESS_UNICODE, 
+
+	PR_SENDER_NAME, 
+	PR_SENDER_NAME_UNICODE, 
+	PR_SENDER_ADDRTYPE, 
+	PR_SENDER_ADDRTYPE_UNICODE, 
+	PR_SENDER_EMAIL_ADDRESS, 
+	PR_SENDER_EMAIL_ADDRESS_UNICODE, 
+
+	PR_RCVD_REPRESENTING_NAME, 
+	PR_RCVD_REPRESENTING_NAME_UNICODE, 
+	PR_RCVD_REPRESENTING_ADDRTYPE, 
+	PR_RCVD_REPRESENTING_ADDRTYPE_UNICODE, 
+	PR_RCVD_REPRESENTING_EMAIL_ADDRESS, 
+	PR_RCVD_REPRESENTING_EMAIL_ADDRESS_UNICODE
+};
+
+static const uint32_t cal_IDList[] = {
+	PR_FID, 
+	PR_MID
+};
+
+G_END_DECLS
+
+#endif

Added: trunk/src/libexchangemapi/exchange-mapi-connection.c
==============================================================================
--- (empty file)
+++ trunk/src/libexchangemapi/exchange-mapi-connection.c	Wed Nov 19 04:28:20 2008
@@ -0,0 +1,2660 @@
+/* -*- 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/>  
+ *
+ *
+ * Authors:
+ *    Srinivasa Ragavan <sragavan novell com>
+ *    Suman Manjunath <msuman novell com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#include "exchange-mapi-connection.h"
+#include "exchange-mapi-folder.h"
+#include "exchange-mapi-utils.h"
+#include <param.h>
+
+#define DEFAULT_PROF_PATH ".evolution/mapi-profiles.ldb"
+#define d(x) x
+
+static struct mapi_session *global_mapi_session= NULL;
+static GStaticRecMutex connect_lock = G_STATIC_REC_MUTEX_INIT;
+
+
+#define LOCK() 		g_message("%s(%d): %s: lock(connect_lock)", __FILE__, __LINE__, __PRETTY_FUNCTION__);g_static_rec_mutex_lock(&connect_lock);
+#define UNLOCK() 	g_message("%s(%d): %s: unlock(connect_lock)", __FILE__, __LINE__, __PRETTY_FUNCTION__);g_static_rec_mutex_unlock(&connect_lock);
+
+#if 0
+#define LOGALL() 	lp_set_cmdline(global_mapi_ctx->lp_ctx, "log level", "10"); global_mapi_ctx->dumpdata = TRUE;
+#define LOGNONE() 	lp_set_cmdline(global_mapi_ctx->lp_ctx, "log level", "0"); global_mapi_ctx->dumpdata = FALSE;
+
+#define ENABLE_VERBOSE_LOG() 	global_mapi_ctx->dumpdata = TRUE;
+#define DISABLE_VERBOSE_LOG() 	global_mapi_ctx->dumpdata = FALSE;
+#endif
+
+//#if 0
+#define LOGALL()
+#define LOGNONE()
+
+#define ENABLE_VERBOSE_LOG()
+#define DISABLE_VERBOSE_LOG()
+//#endif 
+
+/* Specifies READ/WRITE sizes to be used while handling normal streams */
+#define STREAM_MAX_READ_SIZE    0x1000
+#define STREAM_MAX_WRITE_SIZE   0x1000
+#define STREAM_ACCESS_READ      0x0000
+#define STREAM_ACCESS_WRITE     0x0001
+#define STREAM_ACCESS_READWRITE 0x0002
+
+static struct mapi_session *
+mapi_profile_load (const char *profname, const char *password)
+{
+	enum MAPISTATUS	retval = MAPI_E_SUCCESS;
+	struct mapi_session *session = NULL;
+	gchar *profpath = NULL;
+	const char *profile = NULL;
+
+	d(g_print("\n%s(%d): Entering %s ", __FILE__, __LINE__, __PRETTY_FUNCTION__));
+
+	profpath = g_build_filename (g_get_home_dir(), DEFAULT_PROF_PATH, NULL);
+	if (!g_file_test (profpath, G_FILE_TEST_EXISTS)) {
+		g_warning ("\nMAPI profile database @ %s not found ", profpath);
+		goto cleanup;
+	}
+
+	MAPIUninitialize ();
+
+	retval = MAPIInitialize(profpath);
+	if (retval != MAPI_E_SUCCESS) {
+		mapi_errstr("MAPIInitialize", GetLastError());
+		if (retval == MAPI_E_SESSION_LIMIT)
+			g_print("\n%s(%d): %s: Already connected ", __FILE__, __LINE__, __PRETTY_FUNCTION__);
+		goto cleanup;
+	}
+
+	if (profname)
+		profile = profname;
+	else {
+		retval = GetDefaultProfile(&profile);
+		if (retval != MAPI_E_SUCCESS) {
+			mapi_errstr("GetDefaultProfile", GetLastError());
+			goto cleanup;
+		}
+	}
+
+	g_print("\nLoading profile %s ", profile);
+
+	retval = MapiLogonEx(&session, profile, password);
+	if (retval != MAPI_E_SUCCESS) {
+		mapi_errstr("MapiLogonEx", GetLastError());
+		goto cleanup;
+	}
+
+cleanup:
+	if (retval != MAPI_E_SUCCESS && retval != MAPI_E_SESSION_LIMIT)
+		MAPIUninitialize ();
+	g_free (profpath);
+
+	d(g_print("\n%s(%d): Leaving %s ", __FILE__, __LINE__, __PRETTY_FUNCTION__));
+
+	return session;
+}
+
+gboolean
+exchange_mapi_connection_exists ()
+{
+	return global_mapi_session != NULL;
+}
+
+gboolean 
+exchange_mapi_connection_new (const char *profile, const char *password)
+{
+	LOCK();
+	if (!global_mapi_session)
+		global_mapi_session = mapi_profile_load (profile, password);
+	UNLOCK();
+
+	if (!global_mapi_session)
+		g_warning ("\n%s(%d): %s: Login failed ", __FILE__, __LINE__, __PRETTY_FUNCTION__);
+	else
+		g_message ("\n%s(%d): %s: Connected ", __FILE__, __LINE__, __PRETTY_FUNCTION__);
+
+	return global_mapi_session != NULL;
+}
+
+void
+exchange_mapi_connection_close ()
+{
+	LOCK();
+	global_mapi_session = NULL;
+	MAPIUninitialize ();	
+	UNLOCK();
+	/* TODO :  Return status. get last error ? */
+}
+
+static gboolean 
+exchange_mapi_util_read_generic_stream (mapi_object_t *obj_message, uint32_t proptag, GSList **stream_list)
+{
+	enum MAPISTATUS	retval;
+	TALLOC_CTX 	*mem_ctx;
+	mapi_object_t 	obj_stream;
+	uint16_t 	cn_read = 0;
+	uint32_t 	off_data = 0;
+	uint8_t		*buf_data = NULL;
+	uint32_t 	buf_size = 0;
+	gboolean 	done = FALSE;
+
+	/* sanity */
+	g_return_val_if_fail (obj_message, FALSE);
+	g_return_val_if_fail (((proptag & 0xFFFF) == PT_BINARY), FALSE);
+
+	/* if compressed RTF stream, then return */
+	g_return_val_if_fail (proptag != PR_RTF_COMPRESSED, FALSE);
+
+	d(g_print("\n%s(%d): Entering %s ", __FILE__, __LINE__, __PRETTY_FUNCTION__));
+	d(g_print("\nAttempt to read stream for proptag 0x%08X ", proptag));
+
+	mem_ctx = talloc_init ("ExchangeMAPI_ReadGenericStream");
+	mapi_object_init(&obj_stream);
+
+	/* get a stream on specified proptag */
+	retval = OpenStream(obj_message, proptag, STREAM_ACCESS_READ, &obj_stream);
+	if (retval != MAPI_E_SUCCESS) {
+	/* If OpenStream failed, should we attempt any other call(s) to fetch the blob? */
+		mapi_errstr("OpenStream", GetLastError());
+		goto cleanup;
+	}
+
+	/* NOTE: This may prove unreliable for streams larger than 4GB length */
+	retval = GetStreamSize(&obj_stream, &buf_size);
+	if (retval != MAPI_E_SUCCESS) {
+		mapi_errstr("GetStreamSize", GetLastError());
+		goto cleanup;
+	}
+
+	buf_data = talloc_size (mem_ctx, buf_size);
+	if (!buf_data)
+		goto cleanup; 
+
+	/* Read from the stream */
+	while (!done) {
+		retval = ReadStream(&obj_stream,
+				    (buf_data) + off_data,
+				    STREAM_MAX_READ_SIZE,
+				    &cn_read);
+		if (retval != MAPI_E_SUCCESS) { 
+			mapi_errstr("ReadStream", GetLastError());
+			done = TRUE; 
+		} else if (cn_read == 0) {
+			done = TRUE; 
+		} else {
+			off_data += cn_read;
+			if (off_data >= buf_size)
+				done = TRUE;
+		}
+	};
+
+	if (retval == MAPI_E_SUCCESS) {
+		ExchangeMAPIStream 		*stream = g_new0 (ExchangeMAPIStream, 1);
+		struct mapi_SPropValue_array 	properties_array;
+
+		stream->value = g_byte_array_sized_new (off_data);
+		stream->value = g_byte_array_append (stream->value, buf_data, off_data);
+
+		/* Build a mapi_SPropValue_array structure */
+		properties_array.cValues = 1; 
+		properties_array.lpProps = talloc_array (mem_ctx, struct mapi_SPropValue, properties_array.cValues);
+		properties_array.lpProps[0].ulPropTag = proptag; 
+		/* 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;
+
+		d(g_print("\nAttempt succeeded for proptag 0x%08X (after name conversion) ", stream->proptag));
+
+		*stream_list = g_slist_append (*stream_list, stream);
+	}
+
+cleanup: 
+	mapi_object_release(&obj_stream);
+	talloc_free (mem_ctx);
+
+	d(g_print("\n%s(%d): Leaving %s ", __FILE__, __LINE__, __PRETTY_FUNCTION__));
+
+	return (retval == MAPI_E_SUCCESS);
+}
+
+static gboolean
+exchange_mapi_util_read_body_stream (mapi_object_t *obj_message, GSList **stream_list, gboolean getbestbody)
+{
+	enum MAPISTATUS			retval;
+	TALLOC_CTX 			*mem_ctx;
+	struct SPropTagArray		*SPropTagArray;
+	struct SPropValue		*lpProps;
+	uint32_t			count;
+	DATA_BLOB			body;
+	uint8_t 			editor;
+	const char			*data = NULL;
+	const bool 			*rtf_in_sync;
+	uint32_t 			proptag = 0;
+
+	/* sanity check */
+	g_return_val_if_fail (obj_message, FALSE);
+
+	d(g_print("\n%s(%d): Entering %s ", __FILE__, __LINE__, __PRETTY_FUNCTION__));
+
+	mem_ctx = talloc_init ("ExchangeMAPI_ReadBodyStream");
+
+	/* Build the array of properties we want to fetch */
+	SPropTagArray = set_SPropTagArray(mem_ctx, 0x6,
+					  PR_MSG_EDITOR_FORMAT,
+					  PR_BODY,
+					  PR_BODY_UNICODE,
+					  PR_HTML,
+					  PR_RTF_COMPRESSED,
+					  PR_RTF_IN_SYNC);
+
+	lpProps = talloc_zero(mem_ctx, struct SPropValue);
+	retval = GetProps(obj_message, SPropTagArray, &lpProps, &count);
+	MAPIFreeBuffer(SPropTagArray);
+
+	if (retval != MAPI_E_SUCCESS) {
+		mapi_errstr("GetProps", GetLastError());
+		return FALSE;
+	}
+
+	if (getbestbody) {
+		/* Use BestBody Algo */
+		retval = GetBestBody(obj_message, &editor);
+		if (retval != MAPI_E_SUCCESS) {
+			mapi_errstr("GetBestBody", GetLastError());
+			/* On failure, fallback to Plain Text */
+			editor = olEditorText; 
+		}
+
+		/* HACK : We can't handle RTF. So default to HTML */ 
+		if (editor != olEditorText && editor != olEditorHTML) 
+			editor = olEditorHTML;
+	} else {
+		const uint32_t *ui32 = (const uint32_t *) get_SPropValue(lpProps, PR_MSG_EDITOR_FORMAT);
+		/* if PR_MSG_EDITOR_FORMAT doesn't exist, set it to PLAINTEXT */
+		editor = ui32 ? *ui32 : olEditorText;
+	}
+
+	/* initialize body DATA_BLOB */
+	body.data = NULL;
+	body.length = 0;
+
+	retval = -1;
+	switch (editor) {
+		case olEditorText:
+			if ((data = (const char *) get_SPropValue (lpProps, PR_BODY_UNICODE)) != NULL)
+				proptag = PR_BODY_UNICODE;
+			else if ((data = (const char *) get_SPropValue (lpProps, PR_BODY)) != NULL)
+				proptag = PR_BODY;
+			if (data) {
+				size_t size = strlen(data)+1;
+				body.data = talloc_memdup(mem_ctx, data, size);
+				body.length = size;
+				retval = MAPI_E_SUCCESS;
+			} 
+			break;
+		case olEditorHTML: 
+			/* Fixme : */
+ 			/*if ((data = (const char *) get_SPropValue (lpProps, PR_BODY_HTML_UNICODE)) != NULL) */
+ 			/*	proptag = PR_BODY_HTML_UNICODE; */
+			if ((data = (const char *) get_SPropValue (lpProps, PR_BODY_HTML)) != NULL)
+				proptag = PR_BODY_HTML;
+
+			if (data) {
+				size_t size = strlen(data)+1;
+				body.data = talloc_memdup(mem_ctx, data, size);
+				body.length = size;
+				retval = MAPI_E_SUCCESS;
+			} else if (exchange_mapi_util_read_generic_stream (obj_message, PR_HTML, stream_list)) {
+				retval = MAPI_E_SUCCESS;
+			}
+			break;
+		case olEditorRTF: 
+			rtf_in_sync = (const bool *) get_SPropValue (lpProps, PR_RTF_IN_SYNC);
+//			if (!(rtf_in_sync && *rtf_in_sync))
+			{
+				mapi_object_t obj_stream;
+
+				mapi_object_init(&obj_stream);
+
+				retval = OpenStream(obj_message, PR_RTF_COMPRESSED, STREAM_ACCESS_READ, &obj_stream);
+				if (retval != MAPI_E_SUCCESS) {
+					mapi_errstr("OpenStream", GetLastError());
+					mapi_object_release(&obj_stream);
+					break;
+				}
+
+				retval = WrapCompressedRTFStream(&obj_stream, &body);
+				if (retval != MAPI_E_SUCCESS) {
+					mapi_errstr("WrapCompressedRTFStream", GetLastError());
+					mapi_object_release(&obj_stream);
+					break;
+				}
+
+				proptag = PR_RTF_COMPRESSED;
+
+				mapi_object_release(&obj_stream);
+			}
+			break;
+		default: 
+			break;
+	}
+
+	if (retval == MAPI_E_SUCCESS && proptag) {
+		ExchangeMAPIStream 	*stream = g_new0 (ExchangeMAPIStream, 1);
+
+		stream->value = g_byte_array_sized_new (body.length);
+		stream->value = g_byte_array_append (stream->value, body.data, body.length);
+
+		stream->proptag = proptag;
+
+		*stream_list = g_slist_append (*stream_list, stream);
+	}
+
+	talloc_free (mem_ctx);
+
+	d(g_print("\n%s(%d): Leaving %s ", __FILE__, __LINE__, __PRETTY_FUNCTION__));
+
+	return (retval == MAPI_E_SUCCESS);
+}
+
+/* Returns TRUE if all streams were written succcesfully, else returns FALSE */
+static gboolean
+exchange_mapi_util_write_generic_streams (mapi_object_t *obj_message, GSList *stream_list) 
+{
+
+//	TALLOC_CTX 	*mem_ctx;
+	GSList 		*l;
+	enum MAPISTATUS	retval;
+	gboolean 	status = TRUE;
+
+	d(g_print("\n%s(%d): Entering %s ", __FILE__, __LINE__, __PRETTY_FUNCTION__));
+
+//	mem_ctx = talloc_init ("ExchangeMAPI_WriteGenericStreams");
+
+	for (l = stream_list; l; l = l->next) {
+		ExchangeMAPIStream 	*stream = (ExchangeMAPIStream *) (l->data);
+		uint32_t 		total_written;
+		gboolean 		done = FALSE;
+		mapi_object_t		obj_stream;
+
+		mapi_object_init(&obj_stream);
+
+		/* OpenStream on required proptag */
+		retval = OpenStream(obj_message, stream->proptag, STREAM_ACCESS_READWRITE, &obj_stream);
+		if (retval != MAPI_E_SUCCESS) {
+			mapi_errstr("OpenStream", GetLastError());
+			goto cleanup;
+		}
+
+		/* Set the stream size */
+		retval = SetStreamSize(&obj_stream, stream->value->len);
+		if (retval != MAPI_E_SUCCESS) {
+			mapi_errstr("SetStreamSize", GetLastError());
+			goto cleanup;
+		}
+
+		total_written = 0;
+		/* Write attachment */
+		while (!done) {
+			uint16_t 	cn_written = 0;
+			DATA_BLOB 	blob;
+
+			blob.length = (stream->value->len - total_written) < STREAM_MAX_WRITE_SIZE ? 
+					(stream->value->len - total_written) : STREAM_MAX_WRITE_SIZE;
+			blob.data = (stream->value->data) + total_written;
+
+			retval = WriteStream(&obj_stream,
+					     &blob,
+					     &cn_written);
+
+			if (retval != MAPI_E_SUCCESS) {
+				mapi_errstr("WriteStream", GetLastError());
+				done = TRUE;
+			} else if (cn_written == 0) {
+				done = TRUE; 
+			} else {
+				total_written += cn_written;
+				if (total_written >= stream->value->len)
+					done = TRUE;
+			}
+		}
+
+		/* Commit the stream */
+		retval = CommitStream(&obj_stream);
+		if (retval != MAPI_E_SUCCESS) {
+			mapi_errstr("CommitStream", GetLastError());
+			goto cleanup;
+		}
+
+	cleanup:
+		if (retval != MAPI_E_SUCCESS) 
+			status = FALSE;
+		mapi_object_release(&obj_stream);
+	}
+
+//	talloc_free (mem_ctx);
+
+	d(g_print("\n%s(%d): Leaving %s ", __FILE__, __LINE__, __PRETTY_FUNCTION__));
+
+	return status;
+}
+
+static gboolean
+exchange_mapi_util_delete_attachments (mapi_object_t *obj_message)
+{
+	enum MAPISTATUS		retval;
+	TALLOC_CTX 		*mem_ctx;
+	mapi_object_t 		obj_tb_attach;
+	struct SPropTagArray	*proptags;
+	struct SRowSet		rows_attach;
+	uint32_t		attach_count;
+	uint32_t		i_row_attach;
+	gboolean 		status = TRUE;
+
+	d(g_print("\n%s(%d): Entering %s ", __FILE__, __LINE__, __PRETTY_FUNCTION__));
+
+	mem_ctx = talloc_init ("ExchangeMAPI_DeleteAttachments");
+
+	proptags = set_SPropTagArray(mem_ctx, 0x4, 
+				     PR_ATTACH_NUM, 
+				     PR_INSTANCE_KEY, 
+				     PR_RECORD_KEY, 
+				     PR_RENDERING_POSITION);
+
+	mapi_object_init(&obj_tb_attach);
+
+	/* open attachment table */
+	retval = GetAttachmentTable(obj_message, &obj_tb_attach);
+	if (retval != MAPI_E_SUCCESS) {
+		mapi_errstr("GetAttachmentTable", GetLastError());
+		goto cleanup;
+	}
+
+	retval = SetColumns(&obj_tb_attach, proptags);
+	if (retval != MAPI_E_SUCCESS) {
+		mapi_errstr("SetColumns", GetLastError());
+		goto cleanup;
+	}
+
+	retval = GetRowCount(&obj_tb_attach, &attach_count);
+	if (retval != MAPI_E_SUCCESS) {
+		mapi_errstr("GetRowCount", GetLastError());
+		goto cleanup;
+	}
+
+	retval = QueryRows(&obj_tb_attach, attach_count, TBL_ADVANCE, &rows_attach);
+	if (retval != MAPI_E_SUCCESS) {
+		mapi_errstr("QueryRows", GetLastError());
+		goto cleanup;
+	}
+
+	/* foreach attachment, delete by PR_ATTACH_NUM */
+	for (i_row_attach = 0; i_row_attach < rows_attach.cRows; i_row_attach++) {
+		const uint32_t	*num_attach;
+
+		num_attach = (const uint32_t *) get_SPropValue_SRow_data(&rows_attach.aRow[i_row_attach], PR_ATTACH_NUM);
+
+		retval = DeleteAttach(obj_message, *num_attach);
+		if (retval != MAPI_E_SUCCESS) {
+			mapi_errstr("DeleteAttach", GetLastError());
+			status = FALSE;
+		}
+	}
+
+cleanup:
+	if (retval != MAPI_E_SUCCESS)
+		status = FALSE;
+	mapi_object_release(&obj_tb_attach);
+	talloc_free (mem_ctx);
+
+	d(g_print("\n%s(%d): Leaving %s ", __FILE__, __LINE__, __PRETTY_FUNCTION__));
+
+	return status;
+}
+
+/* Returns TRUE if all attachments were written succcesfully, else returns FALSE */
+static gboolean
+exchange_mapi_util_set_attachments (mapi_object_t *obj_message, GSList *attach_list, gboolean remove_existing)
+{
+//	TALLOC_CTX 	*mem_ctx;
+	GSList 		*l;
+	enum MAPISTATUS	retval;
+	gboolean 	status = TRUE;
+
+	d(g_print("\n%s(%d): Entering %s ", __FILE__, __LINE__, __PRETTY_FUNCTION__));
+
+	if (remove_existing)
+		exchange_mapi_util_delete_attachments (obj_message);
+
+//	mem_ctx = talloc_init ("ExchangeMAPI_SetAttachments");
+
+	for (l = attach_list; l; l = l->next) {
+		ExchangeMAPIAttachment 	*attachment = (ExchangeMAPIAttachment *) (l->data);
+		mapi_object_t		obj_attach;
+
+		mapi_object_init(&obj_attach);
+
+		/* CreateAttach */
+		retval = CreateAttach(obj_message, &obj_attach);
+		if (retval != MAPI_E_SUCCESS) {
+			mapi_errstr("CreateAttach", GetLastError());
+			goto cleanup;
+		}
+
+		/* SetProps */
+		retval = SetProps(&obj_attach, attachment->lpProps, attachment->cValues);
+		if (retval != MAPI_E_SUCCESS) {
+			mapi_errstr("SetProps", GetLastError());
+			goto cleanup;
+		}
+
+		/* If there are any streams to be set, write them. */
+		exchange_mapi_util_write_generic_streams (&obj_attach, attachment->streams);
+
+		/* message->SaveChangesAttachment() */
+		retval = SaveChangesAttachment(obj_message, &obj_attach, KEEP_OPEN_READWRITE);
+		if (retval != MAPI_E_SUCCESS) {
+			mapi_errstr("SaveChangesAttachment", GetLastError());
+			goto cleanup;
+		}
+
+	cleanup:
+		if (retval != MAPI_E_SUCCESS) 
+			status = FALSE;
+		mapi_object_release(&obj_attach);
+	}
+
+//	talloc_free (mem_ctx);
+
+	d(g_print("\n%s(%d): Leaving %s ", __FILE__, __LINE__, __PRETTY_FUNCTION__));
+
+	return status;
+}
+
+/* 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)
+{
+	enum MAPISTATUS		retval;
+	TALLOC_CTX 		*mem_ctx;
+	mapi_object_t 		obj_tb_attach;
+	struct SPropTagArray	*proptags;
+	struct SRowSet		rows_attach;
+	uint32_t		attach_count;
+	uint32_t		i_row_attach;
+	gboolean 		status = TRUE;
+
+	d(g_print("\n%s(%d): Entering %s ", __FILE__, __LINE__, __PRETTY_FUNCTION__));
+
+	mem_ctx = talloc_init ("ExchangeMAPI_GetAttachments");
+
+	proptags = set_SPropTagArray(mem_ctx, 0x5, 
+				     PR_ATTACH_NUM, 
+				     PR_INSTANCE_KEY, 
+				     PR_RECORD_KEY, 
+				     PR_RENDERING_POSITION, 
+				     PR_ATTACH_METHOD);
+
+	mapi_object_init(&obj_tb_attach);
+
+	/* open attachment table */
+	retval = GetAttachmentTable(obj_message, &obj_tb_attach);
+	if (retval != MAPI_E_SUCCESS) {
+		mapi_errstr("GetAttachmentTable", GetLastError());
+		goto cleanup;
+	}
+
+	retval = SetColumns(&obj_tb_attach, proptags);
+	if (retval != MAPI_E_SUCCESS) {
+		mapi_errstr("SetColumns", GetLastError());
+		goto cleanup;
+	}
+
+	retval = GetRowCount(&obj_tb_attach, &attach_count);
+	if (retval != MAPI_E_SUCCESS) {
+		mapi_errstr("GetRowCount", GetLastError());
+		goto cleanup;
+	}
+
+	retval = QueryRows(&obj_tb_attach, attach_count, TBL_ADVANCE, &rows_attach);
+	if (retval != MAPI_E_SUCCESS) {
+		mapi_errstr("QueryRows", GetLastError());
+		goto cleanup;
+	}
+
+	/* foreach attachment, open by PR_ATTACH_NUM */
+	for (i_row_attach = 0; i_row_attach < rows_attach.cRows; i_row_attach++) {
+		ExchangeMAPIAttachment 	*attachment;
+		struct mapi_SPropValue_array properties;
+		const uint32_t	*ui32;
+		mapi_object_t	obj_attach;
+		uint32_t 	z;
+
+		mapi_object_init(&obj_attach);
+
+		ui32 = (const uint32_t *) get_SPropValue_SRow_data(&rows_attach.aRow[i_row_attach], PR_ATTACH_NUM);
+
+		retval = OpenAttach(obj_message, *ui32, &obj_attach);
+		if (retval != MAPI_E_SUCCESS) {
+			mapi_errstr("OpenAttach", GetLastError());
+			goto loop_cleanup;
+		}
+
+		retval = GetPropsAll (&obj_attach, &properties);
+		if (retval != MAPI_E_SUCCESS) {
+			mapi_errstr("GetPropsAll", GetLastError());
+			goto loop_cleanup;
+		}
+
+		attachment = g_new0 (ExchangeMAPIAttachment, 1);
+		attachment->cValues = properties.cValues; 
+		attachment->lpProps = g_new0 (struct SPropValue, attachment->cValues);
+		for (z=0; z < properties.cValues; z++) 
+			cast_SPropValue (&properties.lpProps[z], &(attachment->lpProps[z]));
+
+		/* 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)
+			exchange_mapi_util_read_generic_stream (&obj_attach, PR_ATTACH_DATA_BIN, &(attachment->streams));
+
+		*attach_list = g_slist_append (*attach_list, attachment);
+
+	loop_cleanup:
+		if (retval != MAPI_E_SUCCESS)
+			status = FALSE;
+		mapi_object_release(&obj_attach);
+	}
+
+cleanup:
+	if (retval != MAPI_E_SUCCESS)
+		status = FALSE;
+	mapi_object_release(&obj_tb_attach);
+	talloc_free (mem_ctx);
+
+	d(g_print("\n%s(%d): Leaving %s ", __FILE__, __LINE__, __PRETTY_FUNCTION__));
+
+	return status;
+}
+
+/* Returns TRUE if all recipients were read succcesfully, else returns FALSE */
+static gboolean
+exchange_mapi_util_get_recipients (mapi_object_t *obj_message, GSList **recip_list)
+{
+	enum MAPISTATUS		retval;
+//	TALLOC_CTX 		*mem_ctx;
+	struct SPropTagArray	proptags;
+	struct SRowSet		rows_recip;
+	uint32_t		i_row_recip;
+	gboolean 		status = TRUE;
+
+	d(g_print("\n%s(%d): Entering %s ", __FILE__, __LINE__, __PRETTY_FUNCTION__));
+
+//	mem_ctx = talloc_init ("ExchangeMAPI_GetRecipients");
+
+	/* fetch recipient table */
+	retval = GetRecipientTable(obj_message, &rows_recip, &proptags);
+	if (retval != MAPI_E_SUCCESS) {
+		mapi_errstr("GetRecipientTable", GetLastError());
+		goto cleanup;
+	}
+
+	for (i_row_recip = 0; i_row_recip < rows_recip.cRows; i_row_recip++) {
+		ExchangeMAPIRecipient 	*recipient = g_new0 (ExchangeMAPIRecipient, 1);
+
+		recipient->email_id = (const char *) exchange_mapi_util_find_row_propval (&(rows_recip.aRow[i_row_recip]), PR_SMTP_ADDRESS);
+		/* fallback */
+		if (!recipient->email_id) {
+			const char *addrtype = (const char *) exchange_mapi_util_find_row_propval (&(rows_recip.aRow[i_row_recip]), PR_ADDRTYPE);
+			if (addrtype && !g_ascii_strcasecmp(addrtype, "SMTP"))
+				recipient->email_id = (const char *) exchange_mapi_util_find_row_propval (&(rows_recip.aRow[i_row_recip]), PR_EMAIL_ADDRESS);
+		}
+		/* fail */
+		if (!recipient->email_id) {
+			g_warning ("\n%s:%d %s() - object has a recipient without a PR_SMTP_ADDRESS ", __FILE__, __LINE__, __PRETTY_FUNCTION__);
+			mapidump_SRow (&(rows_recip.aRow[i_row_recip]), " ");
+		}
+
+		recipient->out.all_lpProps = rows_recip.aRow[i_row_recip].lpProps;
+		recipient->out.all_cValues = rows_recip.aRow[i_row_recip].cValues;
+
+		*recip_list = g_slist_append (*recip_list, recipient);
+	}
+
+cleanup:
+	if (retval != MAPI_E_SUCCESS)
+		status = FALSE;
+//	talloc_free (mem_ctx);
+
+	d(g_print("\n%s(%d): Leaving %s ", __FILE__, __LINE__, __PRETTY_FUNCTION__));
+
+	return status;
+}
+
+static void 
+set_recipient_properties (TALLOC_CTX *mem_ctx, struct SRow *aRow, ExchangeMAPIRecipient *recipient, gboolean is_external)
+{
+	uint32_t i;
+
+	if (is_external && recipient->in.ext_lpProps) {
+		struct SBinary *oneoff_eid;
+		struct SPropValue sprop; 
+		const gchar *dn = NULL, *email = NULL; 
+
+		for (i = 0; i < recipient->in.ext_cValues; ++i)
+			SRow_addprop (aRow, recipient->in.ext_lpProps[i]);
+
+		dn = (const gchar *) get_SPropValue (recipient->in.ext_lpProps, PR_DISPLAY_NAME);
+		if (!dn)
+			dn = "";
+		email = (const gchar *) get_SPropValue (recipient->in.ext_lpProps, PR_SMTP_ADDRESS);
+		if (!email)
+			email = "";
+		oneoff_eid = exchange_mapi_util_entryid_generate_oneoff (mem_ctx, dn, email, FALSE);
+		set_SPropValue_proptag (&sprop, PR_ENTRYID, (const void *)(oneoff_eid));
+		SRow_addprop (aRow, sprop);
+	}
+
+	for (i = 0; i < recipient->in.req_cValues; ++i)
+		SRow_addprop (aRow, recipient->in.req_lpProps[i]);
+}
+
+/* DON'T f***ing touch this function. */
+static void
+exchange_mapi_util_modify_recipients (TALLOC_CTX *mem_ctx, mapi_object_t *obj_message , GSList *recipients, gboolean remove_existing)
+{
+	enum MAPISTATUS 	retval;
+	struct SPropTagArray 	*SPropTagArray = NULL;
+	struct SRowSet 		*SRowSet = NULL;
+	struct FlagList 	*FlagList = NULL;
+	GSList 			*l;
+	const char 		**users = NULL;
+	uint32_t 		i, j, count = 0;
+
+	d(g_print("\n%s(%d): Entering %s ", __FILE__, __LINE__, __PRETTY_FUNCTION__));
+
+	SPropTagArray = set_SPropTagArray(mem_ctx, 0x7,
+					  PR_DISPLAY_TYPE,
+					  PR_OBJECT_TYPE, 
+//					  PR_ADDRTYPE,
+//					  PR_EMAIL_ADDRESS,
+					  PR_SMTP_ADDRESS,
+					  PR_DISPLAY_NAME,
+					  PR_GIVEN_NAME,
+					  PR_SURNAME, 
+					  PR_7BIT_DISPLAY_NAME);
+//					  PR_ENTRYID,
+//					  PR_SEARCH_KEY,
+//					  PR_TRANSMITTABLE_DISPLAY_NAME);
+
+	SRowSet = talloc_zero(mem_ctx, struct SRowSet);
+	FlagList = talloc_zero(mem_ctx, struct FlagList);
+	count = g_slist_length (recipients);
+	users = g_new0 (const char *, count + 1);
+
+	for (i = 0, l = recipients; (i < count && l != NULL); ++i, l = l->next) { 
+		ExchangeMAPIRecipient *recipient = (ExchangeMAPIRecipient *)(l->data);
+		users[i] = recipient->email_id;
+	}
+
+	/* Attempt to resolve names from the server */
+	retval = ResolveNames (users, SPropTagArray, &SRowSet, &FlagList, 0);
+	if (retval != MAPI_E_SUCCESS) {
+		mapi_errstr("ResolveNames", GetLastError());
+		goto cleanup;
+	}
+
+	g_assert (count == FlagList->cFlags);
+
+	for (i = 0, l = recipients, j = 0; (i < count && l != NULL); ++i, l = l->next) {
+		ExchangeMAPIRecipient *recipient = (ExchangeMAPIRecipient *)(l->data);
+		uint32_t last;
+
+		switch (FlagList->ulFlags[i]) {
+		case MAPI_AMBIGUOUS:
+		/* We should never get an ambiguous resolution as we use the email-id for resolving. 
+		 * However, if we do still get an ambiguous entry, we can't handle it :-( */
+			g_warning ("\n%s:%d %s() - '%s' is ambiguous ", __FILE__, __LINE__, __PRETTY_FUNCTION__, recipient->email_id);
+			break;
+		case MAPI_UNRESOLVED:
+		/* This is currently a bug in libmapi that unresolved recipients are not added to the SRowSet. 
+		 * Julien knows about it and would fix it. */
+			SRowSet->aRow = talloc_realloc(mem_ctx, SRowSet->aRow, struct SRow, SRowSet->cRows + 1);
+			last = SRowSet->cRows;
+			SRowSet->aRow[last].cValues = 0;
+			SRowSet->aRow[last].lpProps = talloc_zero(mem_ctx, struct SPropValue);
+			set_recipient_properties (mem_ctx, &SRowSet->aRow[last], recipient, TRUE);
+			SRowSet->cRows += 1;
+			break;
+		case MAPI_RESOLVED:
+			set_recipient_properties (mem_ctx, &SRowSet->aRow[j], recipient, FALSE);
+			j += 1;
+			break;
+		}
+	}
+
+	if (remove_existing) {
+		RemoveAllRecipients (obj_message);
+		if (retval != MAPI_E_SUCCESS) {
+			mapi_errstr("RemoveAllRecipients", GetLastError());
+			goto cleanup;
+		}
+	}
+
+	/* Modify the recipient table */
+	retval = ModifyRecipients (obj_message, SRowSet);
+	if (retval != MAPI_E_SUCCESS) {
+		mapi_errstr("ModifyRecpients", GetLastError());
+		goto cleanup;
+	}
+
+cleanup:
+	g_free (users);
+
+	d(g_print("\n%s(%d): Leaving %s ", __FILE__, __LINE__, __PRETTY_FUNCTION__));
+}
+
+GSList *
+exchange_mapi_util_check_restriction (mapi_id_t fid, struct mapi_SRestriction *res)
+{
+	enum MAPISTATUS retval;
+	TALLOC_CTX *mem_ctx;
+	mapi_object_t obj_store;
+	mapi_object_t obj_folder;
+	mapi_object_t obj_table;
+	struct SPropTagArray *SPropTagArray, *GetPropsTagArray;
+	struct SRowSet SRowSet;
+	uint32_t count, i;
+	GSList *mids = NULL;
+
+	d(g_print("\n%s(%d): Entering %s: folder-id %016llX ", __FILE__, __LINE__, __PRETTY_FUNCTION__, fid));
+
+	LOCK();
+	LOGALL();
+	mem_ctx = talloc_init("ExchangeMAPI_CheckRestriction");
+	mapi_object_init(&obj_store);
+	mapi_object_init(&obj_folder);
+	mapi_object_init(&obj_table);
+
+	/* Open the message store */
+	retval = OpenMsgStore(&obj_store);
+	if (retval != MAPI_E_SUCCESS) {
+		mapi_errstr("OpenMsgStore", GetLastError());
+		goto cleanup;
+	}
+
+	/* Attempt to open the folder */
+	retval = OpenFolder(&obj_store, fid, &obj_folder);
+	if (retval != MAPI_E_SUCCESS) {
+		mapi_errstr("OpenFolder", GetLastError());
+		goto cleanup;
+	}
+
+	/* Get a handle on the container */
+	retval = GetContentsTable(&obj_folder, &obj_table, 0, NULL);
+	if (retval != MAPI_E_SUCCESS) {
+		mapi_errstr("GetContentsTable", GetLastError());
+		goto cleanup;
+	}
+
+	GetPropsTagArray = talloc_zero(mem_ctx, struct SPropTagArray);
+	GetPropsTagArray->cValues = 0;
+
+	// FIXME : Why are we fetching all these props ?
+
+	SPropTagArray = set_SPropTagArray(mem_ctx, 0xA,
+					  PR_FID,
+					  PR_MID,
+					  PR_INST_ID,
+					  PR_INSTANCE_NUM,
+					  PR_SUBJECT,
+					  PR_MESSAGE_CLASS,
+					  PR_LAST_MODIFICATION_TIME,
+					  PR_HASATTACH,
+					  PR_RULE_MSG_PROVIDER,
+					  PR_RULE_MSG_NAME);
+
+	/* Set primary columns to be fetched */
+	retval = SetColumns(&obj_table, SPropTagArray);
+	if (retval != MAPI_E_SUCCESS) {
+		mapi_errstr("SetColumns", GetLastError());
+		goto cleanup;
+	}
+
+	if (res) {
+		/* Applying any restriction that are set. */
+		retval = Restrict(&obj_table, res);
+		if (retval != MAPI_E_SUCCESS) {
+			mapi_errstr("Restrict", GetLastError());
+			goto cleanup;
+		}
+	}
+
+	/* Number of items in the container */
+	retval = GetRowCount(&obj_table, &count);
+	if (retval != MAPI_E_SUCCESS) {
+		mapi_errstr("GetRowCount", GetLastError());
+		goto cleanup;
+	}
+
+	/* Fill the table columns with data from the rows */
+	retval = QueryRows(&obj_table, count, TBL_ADVANCE, &SRowSet);
+	if (retval != MAPI_E_SUCCESS) {
+		mapi_errstr("QueryRows", GetLastError());
+		goto cleanup;
+	}
+
+	for (i = 0; i < SRowSet.cRows; i++) {
+		mapi_id_t *pmid = (mapi_id_t *) get_SPropValue_SRow_data(&SRowSet.aRow[i], PR_MID);
+		struct id_list *id_list = g_new0 (struct id_list, 1);
+		id_list->id = *pmid;
+		mids = g_slist_prepend (mids, id_list);
+	}
+
+cleanup:
+	mapi_object_release(&obj_folder);
+	mapi_object_release(&obj_table);
+	mapi_object_release(&obj_store);
+	talloc_free (mem_ctx);
+	LOGNONE();
+	UNLOCK();
+
+	d(g_print("\n%s(%d): Leaving %s ", __FILE__, __LINE__, __PRETTY_FUNCTION__));
+
+	return mids;
+}
+
+gboolean
+exchange_mapi_connection_fetch_items   (mapi_id_t fid, 
+					struct mapi_SRestriction *res,
+					const uint32_t *GetPropsList, const uint16_t cn_props, 
+					BuildNameID build_name_id, gpointer build_name_data, 
+					FetchCallback cb, gpointer data, 
+					guint32 options)
+{
+	enum MAPISTATUS retval;
+	TALLOC_CTX *mem_ctx;
+	mapi_object_t obj_store;
+	mapi_object_t obj_folder;
+	mapi_object_t obj_table;
+	struct SPropTagArray *SPropTagArray, *GetPropsTagArray;
+	struct SRowSet SRowSet;
+	uint32_t count, i;
+	gboolean result = FALSE;
+
+	d(g_print("\n%s(%d): Entering %s: folder-id %016llX ", __FILE__, __LINE__, __PRETTY_FUNCTION__, fid));
+
+	LOCK();
+	LOGALL();
+	mem_ctx = talloc_init("ExchangeMAPI_FetchItems");
+	mapi_object_init(&obj_store);
+	mapi_object_init(&obj_folder);
+	mapi_object_init(&obj_table);
+
+	/* Open the message store */
+	retval = ((options & MAPI_OPTIONS_USE_PFSTORE) ? OpenPublicFolder(&obj_store) : OpenMsgStore(&obj_store));
+	if (retval != MAPI_E_SUCCESS) {
+		mapi_errstr("OpenMsgStore / OpenPublicFolder", GetLastError());
+		goto cleanup;
+	}
+
+	/* Attempt to open the folder */
+	retval = OpenFolder(&obj_store, fid, &obj_folder);
+	if (retval != MAPI_E_SUCCESS) {
+		mapi_errstr("OpenFolder", GetLastError());
+		goto cleanup;
+	}
+
+	/* Get a handle on the container */
+	retval = GetContentsTable(&obj_folder, &obj_table, 0, NULL);
+	if (retval != MAPI_E_SUCCESS) {
+		mapi_errstr("GetContentsTable", GetLastError());
+		goto cleanup;
+	}
+
+	GetPropsTagArray = talloc_zero(mem_ctx, struct SPropTagArray);
+	GetPropsTagArray->cValues = 0;
+
+	SPropTagArray = set_SPropTagArray(mem_ctx, 0x4,
+					  PR_FID,
+					  PR_MID,
+					  PR_LAST_MODIFICATION_TIME,
+					  PR_HASATTACH);
+
+	/* Set primary columns to be fetched */
+	retval = SetColumns(&obj_table, SPropTagArray);
+	if (retval != MAPI_E_SUCCESS) {
+		mapi_errstr("SetColumns", GetLastError());
+		goto cleanup;
+	}
+
+	if (res) {
+		/* Applying any restriction that are set. */
+		retval = Restrict(&obj_table, res);
+		if (retval != MAPI_E_SUCCESS) {
+			mapi_errstr("Restrict", GetLastError());
+			goto cleanup;
+		}
+	}
+
+	/* Number of items in the container */
+	retval = GetRowCount(&obj_table, &count);
+	if (retval != MAPI_E_SUCCESS) {
+		mapi_errstr("GetRowCount", GetLastError());
+		goto cleanup;
+	}
+
+	/* Fill the table columns with data from the rows */
+	retval = QueryRows(&obj_table, count, TBL_ADVANCE, &SRowSet);
+	if (retval != MAPI_E_SUCCESS) {
+		mapi_errstr("QueryRows", GetLastError());
+		goto cleanup;
+	}
+
+	if ((GetPropsList && (cn_props > 0)) || build_name_id) {
+		struct SPropTagArray *NamedPropsTagArray;
+		uint32_t m, n=0;
+		struct mapi_nameid *nameid;
+
+		nameid = mapi_nameid_new(mem_ctx);
+		NamedPropsTagArray = talloc_zero(mem_ctx, struct SPropTagArray);
+
+		NamedPropsTagArray->cValues = 0;
+		/* Add named props using callback */
+		if (build_name_id) {
+			if (!build_name_id (nameid, build_name_data)) {
+				g_warning ("\n%s(%d): (%s): Could not build named props ", __FILE__, __LINE__, __PRETTY_FUNCTION__);
+				goto GetProps_cleanup;
+			}
+
+			retval = mapi_nameid_GetIDsFromNames(nameid, &obj_folder, NamedPropsTagArray);
+			if (retval != MAPI_E_SUCCESS) {
+				mapi_errstr("mapi_nameid_GetIDsFromNames", GetLastError());
+				goto GetProps_cleanup;
+			}
+		}
+
+		GetPropsTagArray->cValues = (cn_props + NamedPropsTagArray->cValues);
+		GetPropsTagArray->aulPropTag = talloc_array(mem_ctx, uint32_t, (cn_props + NamedPropsTagArray->cValues));
+
+		for (m = 0; m < NamedPropsTagArray->cValues; m++, n++)
+			GetPropsTagArray->aulPropTag[n] = NamedPropsTagArray->aulPropTag[m];
+
+		for (m = 0; m < cn_props; m++, n++)
+			GetPropsTagArray->aulPropTag[n] = GetPropsList[m];
+
+	GetProps_cleanup:
+			MAPIFreeBuffer (NamedPropsTagArray);
+			talloc_free (nameid);
+	}
+
+	for (i = 0; i < SRowSet.cRows; i++) {
+		mapi_object_t obj_message;
+		struct mapi_SPropValue_array properties_array;
+		const mapi_id_t *pfid;
+		const mapi_id_t	*pmid;
+		const bool *has_attach = NULL;
+		GSList *attach_list = NULL;
+		GSList *recip_list = NULL;
+		GSList *stream_list = NULL;
+
+		mapi_object_init(&obj_message);
+
+		pfid = (const uint64_t *) get_SPropValue_SRow_data(&SRowSet.aRow[i], PR_FID);
+		pmid = (const uint64_t *) get_SPropValue_SRow_data(&SRowSet.aRow[i], PR_MID);
+
+		has_attach = (const bool *) get_SPropValue_SRow_data(&SRowSet.aRow[i], PR_HASATTACH);
+
+		retval = OpenMessage(&obj_folder, *pfid, *pmid, &obj_message, 0);
+		if (retval != MAPI_E_SUCCESS) {
+			mapi_errstr("OpenMessage", GetLastError());
+			goto loop_cleanup;
+		}
+
+		if (has_attach && *has_attach && (MAPI_OPTIONS_FETCH_ATTACHMENTS & options)) {
+			exchange_mapi_util_get_attachments (&obj_message, &attach_list);
+		}
+
+		if (options & MAPI_OPTIONS_FETCH_RECIPIENTS) 
+			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, 
+				options & MAPI_OPTIONS_GETBESTBODY);
+
+		if (GetPropsTagArray->cValues) {
+			struct SPropValue *lpProps;
+			uint32_t prop_count = 0, k;
+
+			lpProps = talloc_zero(mem_ctx, struct SPropValue);
+			retval = GetProps (&obj_message, GetPropsTagArray, &lpProps, &prop_count);
+
+			/* Conversion from SPropValue to mapi_SPropValue. (no padding here) */
+			properties_array.cValues = prop_count;
+			properties_array.lpProps = talloc_array (mem_ctx, struct mapi_SPropValue, prop_count);
+			for (k=0; k < prop_count; k++)
+				cast_mapi_SPropValue(&properties_array.lpProps[k], &lpProps[k]);
+
+			MAPIFreeBuffer(lpProps);
+		} else
+			retval = GetPropsAll (&obj_message, &properties_array);
+
+		if (retval == MAPI_E_SUCCESS) {
+			uint32_t z;
+
+			/* 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);
+			}
+
+			mapi_SPropValue_array_named(&obj_message, &properties_array);
+
+			/* NOTE: stream_list, recipient_list and attach_list should be freed by the callback */
+			FetchItemsCallbackData *item_data = g_new0 (FetchItemsCallbackData, 1);
+			item_data->fid = *pfid;
+			item_data->mid = *pmid;
+			item_data->properties = &properties_array;
+			item_data->streams = stream_list;
+			item_data->recipients = recip_list;
+			item_data->attachments = attach_list;
+			item_data->total = SRowSet.cRows;
+			item_data->index = i;
+
+			if (!cb (item_data, data)) {
+				g_warning ("\n%s(%d): %s: Callback failed for message-id %016llX ", __FILE__, __LINE__, __PRETTY_FUNCTION__, *pmid);
+			}
+
+			g_free (item_data);
+		}
+
+		if (GetPropsTagArray->cValues) 
+			talloc_free (properties_array.lpProps);
+
+	loop_cleanup:
+		mapi_object_release(&obj_message);
+	}
+
+	result = TRUE;
+
+cleanup:
+	mapi_object_release(&obj_folder);
+	mapi_object_release(&obj_table);
+	mapi_object_release(&obj_store);
+	talloc_free (mem_ctx);
+	LOGNONE();
+	UNLOCK();
+
+	d(g_print("\n%s(%d): Leaving %s: folder-id %016llX ", __FILE__, __LINE__, __PRETTY_FUNCTION__, fid));
+
+	return result;
+}
+
+gboolean
+exchange_mapi_connection_fetch_item (mapi_id_t fid, mapi_id_t mid, 
+				     const uint32_t *GetPropsList, const uint16_t cn_props, 
+				     BuildNameID build_name_id, gpointer build_name_data, 
+				     FetchCallback cb, gpointer data, 
+				     guint32 options)
+{
+	enum MAPISTATUS retval;
+	TALLOC_CTX *mem_ctx;
+	mapi_object_t obj_store;
+	mapi_object_t obj_folder;
+	mapi_object_t obj_message;
+	struct mapi_SPropValue_array properties_array;
+	struct SPropTagArray *GetPropsTagArray;
+	GSList *attach_list = NULL;
+	GSList *recip_list = NULL;
+	GSList *stream_list = NULL;
+	gboolean result = FALSE;
+
+	d(g_print("\n%s(%d): Entering %s: folder-id %016llX message-id %016llX ", __FILE__, __LINE__, __PRETTY_FUNCTION__, fid, mid));
+
+	LOCK();
+	LOGALL();
+	mem_ctx = talloc_init("ExchangeMAPI_FetchItem");
+	mapi_object_init(&obj_store);
+	mapi_object_init(&obj_folder);
+	mapi_object_init(&obj_message);
+
+	/* Open the message store */
+	retval = ((options & MAPI_OPTIONS_USE_PFSTORE) ? OpenPublicFolder(&obj_store) : OpenMsgStore(&obj_store));
+	if (retval != MAPI_E_SUCCESS) {
+		mapi_errstr("OpenMsgStore", GetLastError());
+		goto cleanup;
+	}
+
+	/* Attempt to open the folder */
+	retval = OpenFolder(&obj_store, fid, &obj_folder);
+	if (retval != MAPI_E_SUCCESS) {
+		mapi_errstr("OpenFolder", GetLastError());
+		goto cleanup;
+	}
+
+	GetPropsTagArray = talloc_zero(mem_ctx, struct SPropTagArray);
+	GetPropsTagArray->cValues = 0;
+
+	if ((GetPropsList && (cn_props > 0)) || build_name_id) {
+		struct SPropTagArray *NamedPropsTagArray;
+		uint32_t m, n=0;
+		struct mapi_nameid *nameid;
+
+		nameid = mapi_nameid_new(mem_ctx);
+		NamedPropsTagArray = talloc_zero(mem_ctx, struct SPropTagArray);
+
+		NamedPropsTagArray->cValues = 0;
+		/* Add named props using callback */
+		if (build_name_id) {
+			if (!build_name_id (nameid, build_name_data)) {
+				g_warning ("\n%s(%d): (%s): Could not build named props ", __FILE__, __LINE__, __PRETTY_FUNCTION__);
+				goto GetProps_cleanup;
+			}
+
+			retval = mapi_nameid_GetIDsFromNames(nameid, &obj_folder, NamedPropsTagArray);
+			if (retval != MAPI_E_SUCCESS) {
+				mapi_errstr("mapi_nameid_GetIDsFromNames", GetLastError());
+				goto GetProps_cleanup;
+			}
+		}
+
+		GetPropsTagArray->cValues = (cn_props + NamedPropsTagArray->cValues);
+		GetPropsTagArray->aulPropTag = talloc_array(mem_ctx, uint32_t, (cn_props + NamedPropsTagArray->cValues));
+
+		for (m = 0; m < NamedPropsTagArray->cValues; m++, n++)
+			GetPropsTagArray->aulPropTag[n] = NamedPropsTagArray->aulPropTag[m];
+
+		for (m = 0; m < cn_props; m++, n++)
+			GetPropsTagArray->aulPropTag[n] = GetPropsList[m];
+
+	GetProps_cleanup:
+			MAPIFreeBuffer (NamedPropsTagArray);
+			talloc_free (nameid);
+	}
+
+	/* 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);
+
+	/* Fetch recipients */
+	if (options & MAPI_OPTIONS_FETCH_RECIPIENTS) 
+		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, 
+			options & MAPI_OPTIONS_GETBESTBODY);
+
+	if (GetPropsTagArray->cValues) {
+		struct SPropValue *lpProps;
+		uint32_t prop_count = 0, k;
+
+		lpProps = talloc_zero(mem_ctx, struct SPropValue);
+		retval = GetProps (&obj_message, GetPropsTagArray, &lpProps, &prop_count);
+
+		/* Conversion from SPropValue to mapi_SPropValue. (no padding here) */
+		properties_array.cValues = prop_count;
+		properties_array.lpProps = talloc_array (mem_ctx, struct mapi_SPropValue, prop_count);
+		for (k=0; k < prop_count; k++)
+			cast_mapi_SPropValue(&properties_array.lpProps[k], &lpProps[k]);
+
+		MAPIFreeBuffer(lpProps);
+	} else
+		retval = GetPropsAll (&obj_message, &properties_array);
+
+	if (retval == MAPI_E_SUCCESS) {
+		uint32_t z;
+
+		/* 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);
+
+		mapi_SPropValue_array_named(&obj_message, &properties_array);
+
+		FetchItemsCallbackData *item_data = g_new0 (FetchItemsCallbackData, 1);
+		item_data->fid = fid;
+		item_data->mid = mid;
+		item_data->properties = &properties_array;
+		item_data->streams = stream_list;
+		item_data->recipients = recip_list;
+		item_data->attachments = attach_list;
+
+		/* NOTE: stream_list, recipient_list and attach_list should be freed by the callback */
+		cb (item_data, data);
+
+		g_free (item_data);
+	}
+
+//	if (GetPropsTagArray->cValues) 
+//		talloc_free (properties_array.lpProps);
+
+	result = TRUE;
+
+cleanup:
+	mapi_object_release(&obj_message);
+	mapi_object_release(&obj_folder);
+	mapi_object_release(&obj_store);
+	talloc_free (mem_ctx);
+	LOGNONE();
+	UNLOCK();
+
+	d(g_print("\n%s(%d): Leaving %s ", __FILE__, __LINE__, __PRETTY_FUNCTION__));
+
+	return result;
+}
+
+mapi_id_t 
+exchange_mapi_create_folder (uint32_t olFolder, mapi_id_t pfid, const char *name)
+{
+	enum MAPISTATUS retval;
+	mapi_object_t obj_store;
+	mapi_object_t obj_folder;
+	mapi_object_t obj_top;
+	struct SPropValue vals[1];
+	const char *type;
+	mapi_id_t fid = 0;
+
+	d(g_print("\n%s(%d): Entering %s ", __FILE__, __LINE__, __PRETTY_FUNCTION__));
+
+	LOCK();
+	LOGALL();
+	mapi_object_init(&obj_store);
+	mapi_object_init(&obj_top);
+	mapi_object_init(&obj_folder);
+
+	retval = OpenMsgStore(&obj_store);
+	if (retval != MAPI_E_SUCCESS) {
+		mapi_errstr("OpenMsgStore", GetLastError());
+		goto cleanup;
+	}
+
+	/* We now open the top/parent folder */
+	retval = OpenFolder(&obj_store, pfid, &obj_top);
+	if (retval != MAPI_E_SUCCESS) {
+		mapi_errstr("OpenFolder", GetLastError());
+		goto cleanup;
+	}
+	
+	/* Attempt to create the folder */
+	retval = CreateFolder(&obj_top, FOLDER_GENERIC, name, "Created using Evolution/LibMAPI", OPEN_IF_EXISTS, &obj_folder);
+	if (retval != MAPI_E_SUCCESS) {
+		mapi_errstr("CreateFolder", GetLastError());
+		goto cleanup;
+	}
+
+	switch (olFolder) {
+		case olFolderInbox:
+			type = IPF_NOTE;
+			break;
+		case olFolderCalendar:
+			type = IPF_APPOINTMENT;
+			break;
+		case olFolderContacts:
+			type = IPF_CONTACT;
+			break;
+		case olFolderTasks:
+			type = IPF_TASK;
+			break;
+		case olFolderNotes:
+			type = IPF_STICKYNOTE;
+			break;
+		default:
+			type = IPF_NOTE;
+	}
+
+	vals[0].value.lpszA = type;
+	vals[0].ulPropTag = PR_CONTAINER_CLASS;
+
+	retval = SetProps(&obj_folder, vals, 1);
+	if (retval != MAPI_E_SUCCESS) {
+		mapi_errstr("SetProps", GetLastError());
+		goto cleanup;
+	}
+
+	fid = mapi_object_get_id (&obj_folder);
+	g_print("\nFolder %s created with id %016llX ", name, fid);
+
+cleanup:
+	mapi_object_release(&obj_folder);
+	mapi_object_release(&obj_top);
+	mapi_object_release(&obj_store);
+	LOGNONE();
+	UNLOCK();
+
+	d(g_print("\n%s(%d): Leaving %s ", __FILE__, __LINE__, __PRETTY_FUNCTION__));
+
+	/* Shouldn't we return (ExchangeMAPIFolder *) instead of a plain fid ? */
+	return fid;
+}
+
+gboolean
+exchange_mapi_empty_folder (mapi_id_t fid)
+{
+	enum MAPISTATUS retval;
+	mapi_object_t obj_store;
+	mapi_object_t obj_folder;
+	gboolean result = FALSE;
+
+	d(g_print("\n%s(%d): Entering %s ", __FILE__, __LINE__, __PRETTY_FUNCTION__));
+
+	LOCK();
+	LOGALL();
+	mapi_object_init(&obj_store);
+	mapi_object_init(&obj_folder);
+
+	retval = OpenMsgStore(&obj_store);
+	if (retval != MAPI_E_SUCCESS) {
+		mapi_errstr("OpenMsgStore", GetLastError());
+		goto cleanup;
+	}
+
+	/* Attempt to open the folder to be emptied */
+	retval = OpenFolder(&obj_store, fid, &obj_folder);
+	if (retval != MAPI_E_SUCCESS) {
+		mapi_errstr("OpenFolder", GetLastError());
+		goto cleanup;
+	}
+
+	/* Empty the contents of the folder */
+	retval = EmptyFolder(&obj_folder);
+	if (retval != MAPI_E_SUCCESS) {
+		mapi_errstr("EmptyFolder", GetLastError());
+		goto cleanup;
+	}
+
+	g_print("\nFolder with id %016llX was emptied ", fid);
+
+	result = TRUE;
+
+cleanup:
+	mapi_object_release(&obj_folder);
+	mapi_object_release(&obj_store);
+	LOGNONE();
+	UNLOCK();
+
+	d(g_print("\n%s(%d): Leaving %s ", __FILE__, __LINE__, __PRETTY_FUNCTION__));
+
+	return result;
+}
+
+/* FIXME: param olFolder is never used in the routine. Remove it and cleanup at the backends */
+gboolean
+exchange_mapi_remove_folder (uint32_t olFolder, mapi_id_t fid)
+{
+	enum MAPISTATUS retval;
+	mapi_object_t obj_store;
+	mapi_object_t obj_top;
+	mapi_object_t obj_folder;
+	ExchangeMAPIFolder *folder;
+	gboolean result = FALSE;
+
+	d(g_print("\n%s(%d): Entering %s ", __FILE__, __LINE__, __PRETTY_FUNCTION__));
+
+	folder = exchange_mapi_folder_get_folder (fid);
+	g_return_val_if_fail (folder != NULL, FALSE);
+
+	LOCK();
+	LOGALL();
+	mapi_object_init(&obj_store);
+	mapi_object_init(&obj_top);
+	mapi_object_init(&obj_folder);
+
+	retval = OpenMsgStore(&obj_store);
+	if (retval != MAPI_E_SUCCESS) {
+		mapi_errstr("OpenMsgStore", GetLastError());
+		goto cleanup;
+	}
+
+	/* FIXME: If the folder has sub-folders, open each of them in turn, empty them and delete them.
+	 * Note that this has to be done recursively, for the sub-folders as well. 
+	 */
+
+	/* Attempt to open the folder to be removed */
+	retval = OpenFolder(&obj_store, fid, &obj_folder);
+	if (retval != MAPI_E_SUCCESS) {
+		mapi_errstr("OpenFolder", GetLastError());
+		goto cleanup;
+	}
+
+	/* Empty the contents of the folder */
+	retval = EmptyFolder(&obj_folder);
+	if (retval != MAPI_E_SUCCESS) {
+		mapi_errstr("EmptyFolder", GetLastError());
+		goto cleanup;
+	}
+
+	g_print("\nFolder with id %016llX was emptied ", fid);
+
+	/* Attempt to open the top/parent folder */
+	retval = OpenFolder(&obj_store, folder->parent_folder_id, &obj_top);
+	if (retval != MAPI_E_SUCCESS) {
+		mapi_errstr("OpenFolder", GetLastError());
+		goto cleanup;
+	}
+
+	/* Call DeleteFolder on the folder to be removed */
+	retval = DeleteFolder(&obj_top, fid);
+	if (retval != MAPI_E_SUCCESS) {
+		mapi_errstr("DeleteFolder", GetLastError());
+		goto cleanup;
+	}
+
+	g_print("\nFolder with id %016llX was deleted ", fid);
+
+	result = TRUE;
+
+cleanup:
+	mapi_object_release(&obj_folder);
+	mapi_object_release(&obj_top);
+	mapi_object_release(&obj_store);
+	LOGNONE();
+	UNLOCK();
+
+	d(g_print("\n%s(%d): Leaving %s ", __FILE__, __LINE__, __PRETTY_FUNCTION__));
+
+	return result;
+}
+
+gboolean 
+exchange_mapi_rename_folder (mapi_id_t fid, const char *new_name)
+{
+	enum MAPISTATUS retval;
+	mapi_object_t obj_store;
+	mapi_object_t obj_folder;
+	struct SPropValue *props = NULL;
+	TALLOC_CTX *mem_ctx;
+	gboolean result = FALSE;
+
+	d(g_print("\n%s(%d): Entering %s ", __FILE__, __LINE__, __PRETTY_FUNCTION__));
+
+	LOCK();
+	LOGALL();
+	mem_ctx = talloc_init("ExchangeMAPI_RenameFolder");
+	mapi_object_init(&obj_store);
+	mapi_object_init(&obj_folder);
+
+	retval = OpenMsgStore(&obj_store);
+	if (retval != MAPI_E_SUCCESS) {
+		mapi_errstr("OpenMsgStore", GetLastError());
+		goto cleanup;
+	}
+
+	/* Open the folder to be renamed */
+	retval = OpenFolder(&obj_store, fid, &obj_folder);
+	if (retval != MAPI_E_SUCCESS) {
+		mapi_errstr("OpenFolder", GetLastError());
+		goto cleanup;
+	}
+
+	props = talloc_zero(mem_ctx, struct SPropValue);
+	set_SPropValue_proptag (props, PR_DISPLAY_NAME, new_name);
+
+	retval = SetProps(&obj_folder, props, 1);
+	if (retval != MAPI_E_SUCCESS) {
+		mapi_errstr("SetProps", GetLastError());
+		goto cleanup;
+	}
+
+	result = TRUE;
+
+cleanup:
+	mapi_object_release(&obj_folder);
+	mapi_object_release(&obj_store);
+	talloc_free(mem_ctx);
+	LOGNONE();
+	UNLOCK();
+
+	d(g_print("\n%s(%d): Leaving %s ", __FILE__, __LINE__, __PRETTY_FUNCTION__));
+
+	return result;
+}
+
+struct SPropTagArray *
+exchange_mapi_util_resolve_named_props (uint32_t olFolder, mapi_id_t fid, 
+					BuildNameID build_name_id, gpointer ni_data)
+{
+	enum MAPISTATUS retval;
+	TALLOC_CTX *mem_ctx;
+	mapi_object_t obj_store;
+	mapi_object_t obj_folder;
+	struct mapi_nameid *nameid;
+	struct SPropTagArray *SPropTagArray, *ret_array = NULL;
+	uint32_t i;
+
+	d(g_print("\n%s(%d): Entering %s ", __FILE__, __LINE__, __PRETTY_FUNCTION__));
+
+	LOCK();
+	LOGALL();
+	mem_ctx = talloc_init("ExchangeMAPI_ResolveNamedProps");
+	mapi_object_init(&obj_store);
+	mapi_object_init(&obj_folder);
+
+	nameid = mapi_nameid_new(mem_ctx);
+	SPropTagArray = talloc_zero(mem_ctx, struct SPropTagArray);
+
+	/* Open the message store */
+	retval = OpenMsgStore(&obj_store);
+	if (retval != MAPI_E_SUCCESS) {
+		mapi_errstr("OpenMsgStore", GetLastError());
+		goto cleanup;
+	}
+
+	/* If fid not present then we'll use olFolder. Document this in API doc. */
+	if (fid == 0) {
+		retval = GetDefaultFolder(&obj_store, &fid, olFolder);
+		if (retval != MAPI_E_SUCCESS) {
+			mapi_errstr("GetDefaultFolder", GetLastError());
+			goto cleanup;
+		}
+	}
+
+	/* Attempt to open the folder */
+	retval = OpenFolder(&obj_store, fid, &obj_folder);
+	if (retval != MAPI_E_SUCCESS) {
+		mapi_errstr("OpenFolder", GetLastError());
+		goto cleanup;
+	}
+
+	/* Add named props using callback */
+	if (build_name_id) {
+		if (!build_name_id (nameid, ni_data)) {
+			g_warning ("\n%s(%d): (%s): Could not build named props ", __FILE__, __LINE__, __PRETTY_FUNCTION__);
+			goto cleanup;
+		}
+
+		retval = mapi_nameid_GetIDsFromNames(nameid, &obj_folder, SPropTagArray);
+		if (retval != MAPI_E_SUCCESS) {
+			mapi_errstr("mapi_nameid_GetIDsFromNames", GetLastError());
+			goto cleanup;
+		}
+	}
+
+	ret_array = g_new0 (struct SPropTagArray, 1);
+	ret_array->aulPropTag = g_new0 (enum MAPITAGS, SPropTagArray->cValues);
+	ret_array->cValues = SPropTagArray->cValues;
+	for (i = 0; i < SPropTagArray->cValues; ++i)
+		ret_array->aulPropTag[i] = SPropTagArray->aulPropTag[i];
+
+cleanup:
+	mapi_object_release(&obj_folder);
+	mapi_object_release(&obj_store);
+	talloc_free(mem_ctx);
+	LOGNONE();
+	UNLOCK();
+
+	d(g_print("\n%s(%d): Leaving %s ", __FILE__, __LINE__, __PRETTY_FUNCTION__));
+
+	return ret_array;
+}
+
+struct SPropTagArray *
+exchange_mapi_util_resolve_named_prop (uint32_t olFolder, mapi_id_t fid, uint16_t lid, const char *OLEGUID)
+{
+	enum MAPISTATUS retval;
+	TALLOC_CTX *mem_ctx;
+	mapi_object_t obj_store;
+	mapi_object_t obj_folder;
+	struct mapi_nameid *nameid;
+	struct SPropTagArray *SPropTagArray, *ret_array = NULL;
+	uint32_t i;
+
+	d(g_print("\n%s(%d): Entering %s ", __FILE__, __LINE__, __PRETTY_FUNCTION__));
+
+	LOCK();
+	LOGALL();
+	mem_ctx = talloc_init("ExchangeMAPI_ResolveNamedProp");
+	mapi_object_init(&obj_store);
+	mapi_object_init(&obj_folder);
+
+	nameid = mapi_nameid_new(mem_ctx);
+	SPropTagArray = talloc_zero(mem_ctx, struct SPropTagArray);
+
+	/* Open the message store */
+	retval = OpenMsgStore(&obj_store);
+	if (retval != MAPI_E_SUCCESS) {
+		mapi_errstr("OpenMsgStore", GetLastError());
+		goto cleanup;
+	}
+
+	/* If fid not present then we'll use olFolder. Document this in API doc. */
+	if (fid == 0) {
+		retval = GetDefaultFolder(&obj_store, &fid, olFolder);
+		if (retval != MAPI_E_SUCCESS) {
+			mapi_errstr("GetDefaultFolder", GetLastError());
+			goto cleanup;
+		}
+	}
+
+	/* Attempt to open the folder */
+	retval = OpenFolder(&obj_store, fid, &obj_folder);
+	if (retval != MAPI_E_SUCCESS) {
+		mapi_errstr("OpenFolder", GetLastError());
+		goto cleanup;
+	}
+
+	mapi_nameid_lid_add (nameid, lid, OLEGUID);
+
+	retval = mapi_nameid_GetIDsFromNames(nameid, &obj_folder, SPropTagArray);
+	if (retval != MAPI_E_SUCCESS) {
+		mapi_errstr("mapi_nameid_GetIDsFromNames", GetLastError());
+		goto cleanup;
+	}
+
+	ret_array = g_new0 (struct SPropTagArray, 1);
+	ret_array->aulPropTag = g_new0 (enum MAPITAGS, SPropTagArray->cValues);
+	ret_array->cValues = SPropTagArray->cValues;
+	for (i = 0; i < SPropTagArray->cValues; ++i)
+		ret_array->aulPropTag[i] = SPropTagArray->aulPropTag[i];
+
+cleanup:
+	mapi_object_release(&obj_folder);
+	mapi_object_release(&obj_store);
+	talloc_free(mem_ctx);
+	LOGNONE();
+	UNLOCK();
+
+	d(g_print("\n%s(%d): Leaving %s ", __FILE__, __LINE__, __PRETTY_FUNCTION__));
+
+	return ret_array;
+}
+
+uint32_t
+exchange_mapi_util_create_named_prop (uint32_t olFolder, mapi_id_t fid, 
+				      const char *named_prop_name, uint32_t ptype)
+{
+	enum MAPISTATUS retval;
+	TALLOC_CTX *mem_ctx;
+	mapi_object_t obj_store;
+	mapi_object_t obj_folder;
+	struct GUID guid;
+	struct MAPINAMEID *nameid;
+	struct SPropTagArray *SPropTagArray;
+	uint32_t propID = 0x00000000;
+
+	d(g_print("\n%s(%d): Entering %s ", __FILE__, __LINE__, __PRETTY_FUNCTION__));
+
+	LOCK();
+	LOGALL();
+	mem_ctx = talloc_init("ExchangeMAPI_CreateNamedProp");
+
+	mapi_object_init(&obj_store);
+	mapi_object_init(&obj_folder);
+
+	GUID_from_string(PS_INTERNET_HEADERS, &guid);
+	nameid = talloc_zero(mem_ctx, struct MAPINAMEID);
+	SPropTagArray = talloc_zero(mem_ctx, struct SPropTagArray);
+
+	nameid[0].lpguid = guid;
+	nameid[0].ulKind = MNID_STRING;
+	nameid[0].kind.lpwstr.Name = named_prop_name;
+
+	/* Open the message store */
+	retval = OpenMsgStore(&obj_store);
+	if (retval != MAPI_E_SUCCESS) {
+		mapi_errstr("OpenMsgStore", GetLastError());
+		goto cleanup;
+	}
+
+	/* If fid not present then we'll use olFolder. Document this in API doc. */
+	if (fid == 0) {
+		retval = GetDefaultFolder(&obj_store, &fid, olFolder);
+		if (retval != MAPI_E_SUCCESS) {
+			mapi_errstr("GetDefaultFolder", GetLastError());
+			goto cleanup;
+		}
+	}
+
+	/* Attempt to open the folder */
+	retval = OpenFolder(&obj_store, fid, &obj_folder);
+	if (retval != MAPI_E_SUCCESS) {
+		mapi_errstr("OpenFolder", GetLastError());
+		goto cleanup;
+	}
+
+	/* Fetch an ID from the server */
+	retval = GetIDsFromNames(&obj_folder, 1, &nameid[0], MAPI_CREATE, &SPropTagArray);
+	if (retval != MAPI_E_SUCCESS) {
+		mapi_errstr("GetIDsFromNames", GetLastError());
+		goto cleanup;
+	}
+
+	propID = SPropTagArray->aulPropTag[0] | ptype;
+
+cleanup:
+	mapi_object_release(&obj_folder);
+	mapi_object_release(&obj_store);
+	talloc_free(mem_ctx);
+	LOGNONE();
+	UNLOCK();
+
+	d(g_print("\n%s(%d): Leaving %s ", __FILE__, __LINE__, __PRETTY_FUNCTION__));
+
+	return propID; 
+}
+
+mapi_id_t
+exchange_mapi_get_default_folder_id (uint32_t olFolder)
+{
+	enum MAPISTATUS retval;
+	mapi_object_t obj_store;
+	mapi_id_t fid = 0;
+
+	d(g_print("\n%s(%d): Entering %s ", __FILE__, __LINE__, __PRETTY_FUNCTION__));
+
+	LOCK();
+	LOGALL();
+	mapi_object_init(&obj_store);
+
+	/* Open the message store */
+	retval = OpenMsgStore(&obj_store);
+	if (retval != MAPI_E_SUCCESS) {
+		mapi_errstr("OpenMsgStore", GetLastError());
+		goto cleanup;
+	}
+
+	retval = GetDefaultFolder(&obj_store, &fid, olFolder);
+	if (retval != MAPI_E_SUCCESS) {
+		mapi_errstr("GetDefaultFolder", GetLastError());
+		goto cleanup;
+	}
+
+cleanup:
+	mapi_object_release(&obj_store);
+	LOGNONE();
+	UNLOCK();
+
+	d(g_print("\n%s(%d): Leaving %s ", __FILE__, __LINE__, __PRETTY_FUNCTION__));
+
+	return (retval == MAPI_E_SUCCESS ? fid : 0);
+}
+
+mapi_id_t
+exchange_mapi_create_item (uint32_t olFolder, mapi_id_t fid, 
+			   BuildNameID build_name_id, gpointer ni_data, 
+			   BuildProps build_props, gpointer p_data, 
+			   GSList *recipients, GSList *attachments, GSList *generic_streams, 
+			   uint32_t options)
+{
+	enum MAPISTATUS retval;
+	TALLOC_CTX *mem_ctx;
+	mapi_object_t obj_store;
+	mapi_object_t obj_folder;
+	mapi_object_t obj_message;
+	struct mapi_nameid *nameid;
+	struct SPropTagArray *SPropTagArray;
+	struct SPropValue *props = NULL;
+	gint propslen = 0;
+	mapi_id_t mid = 0;
+
+	d(g_print("\n%s(%d): Entering %s ", __FILE__, __LINE__, __PRETTY_FUNCTION__));
+
+	LOCK();
+	LOGALL();
+	mem_ctx = talloc_init("ExchangeMAPI_CreateItem");
+	mapi_object_init(&obj_store);
+	mapi_object_init(&obj_folder);
+	mapi_object_init(&obj_message);
+
+	nameid = mapi_nameid_new(mem_ctx);
+	SPropTagArray = talloc_zero(mem_ctx, struct SPropTagArray);
+
+	/* Open the message store */
+	retval = OpenMsgStore(&obj_store);
+	if (retval != MAPI_E_SUCCESS) {
+		mapi_errstr("OpenMsgStore", GetLastError());
+		goto cleanup;
+	}
+
+	/* If fid not present then we'll use olFolder. Document this in API doc. */
+	if (fid == 0) {
+		retval = GetDefaultFolder(&obj_store, &fid, olFolder);
+		if (retval != MAPI_E_SUCCESS) {
+			mapi_errstr("GetDefaultFolder", GetLastError());
+			goto cleanup;
+		}
+	}
+
+	/* Attempt to open the folder */
+	retval = OpenFolder(&obj_store, fid, &obj_folder);
+	if (retval != MAPI_E_SUCCESS) {
+		mapi_errstr("OpenFolder", GetLastError());
+		goto cleanup;
+	}
+
+	/* Create the item */
+	retval = CreateMessage(&obj_folder, &obj_message);
+	if (retval != MAPI_E_SUCCESS) {
+		mapi_errstr("CreateMessage", GetLastError());
+		goto cleanup;
+	}
+
+//	d(mapi_object_debug (&obj_message));
+
+	/* Add named props using callback */
+	if (build_name_id) {
+		if (!build_name_id (nameid, ni_data)) {
+			g_warning ("\n%s(%d): (%s): Could not build named props ", __FILE__, __LINE__, __PRETTY_FUNCTION__);
+			goto cleanup;
+		}
+
+		retval = mapi_nameid_GetIDsFromNames(nameid, &obj_folder, SPropTagArray);
+		if (retval != MAPI_E_SUCCESS) {
+			mapi_errstr("mapi_nameid_GetIDsFromNames", GetLastError());
+			goto cleanup;
+		}
+	}
+
+	/* Add regular props using callback */
+	if (build_props) {
+		propslen = build_props (&props, SPropTagArray, p_data);
+		if (propslen < 1) {
+			g_warning ("\n%s(%d): (%s): build_props failed! propslen = %d ", __FILE__, __LINE__, __PRETTY_FUNCTION__, propslen);
+			goto cleanup;
+		}
+	}
+
+	/* set properties for the item */
+	retval = SetProps(&obj_message, props, propslen);
+	if (retval != MAPI_E_SUCCESS) {
+		mapi_errstr("SetProps", GetLastError());
+		goto cleanup;
+	}
+
+	if (generic_streams) {
+		exchange_mapi_util_write_generic_streams (&obj_message, generic_streams);
+	}
+
+	/* Set attachments if any */
+	if (attachments) {
+		exchange_mapi_util_set_attachments (&obj_message, attachments, FALSE);
+	}
+
+	/* Set recipients if any */
+	if (recipients) {
+		exchange_mapi_util_modify_recipients (mem_ctx, &obj_message, recipients, FALSE);
+	}
+
+	/* Finally, save all changes */
+	retval = SaveChangesMessage(&obj_folder, &obj_message);
+	if (retval != MAPI_E_SUCCESS) {
+		mapi_errstr("SaveChangesMessage", GetLastError());
+		goto cleanup;
+	}
+
+	if (recipients && !(options & MAPI_OPTIONS_DONT_SUBMIT)) {
+		/* Mark message as ready to be sent */
+		retval = SubmitMessage(&obj_message);
+		if (retval != MAPI_E_SUCCESS) {
+			mapi_errstr("SubmitMessage", GetLastError());
+			goto cleanup;
+		}
+	}
+
+	mid = mapi_object_get_id (&obj_message);
+
+cleanup:
+	mapi_object_release(&obj_message);
+	mapi_object_release(&obj_folder);
+	mapi_object_release(&obj_store);
+	talloc_free(mem_ctx);
+	LOGNONE();
+	UNLOCK();
+
+	d(g_print("\n%s(%d): Leaving %s ", __FILE__, __LINE__, __PRETTY_FUNCTION__));
+
+	return mid;
+}
+
+gboolean
+exchange_mapi_modify_item (uint32_t olFolder, mapi_id_t fid, mapi_id_t mid, 
+			   BuildNameID build_name_id, gpointer ni_data, 
+			   BuildProps build_props, gpointer p_data, 
+			   GSList *recipients, GSList *attachments, GSList *generic_streams, 
+			   uint32_t options)
+{
+	enum MAPISTATUS retval;
+	TALLOC_CTX *mem_ctx;
+	mapi_object_t obj_store;
+	mapi_object_t obj_folder;
+	mapi_object_t obj_message;
+	struct mapi_nameid *nameid;
+	struct SPropTagArray *SPropTagArray;
+	struct SPropValue *props = NULL;
+	gint propslen = 0;
+	gboolean result = FALSE;
+
+	d(g_print("\n%s(%d): Entering %s ", __FILE__, __LINE__, __PRETTY_FUNCTION__));
+
+	LOCK();
+	LOGALL();
+	mem_ctx = talloc_init("ExchangeMAPI_ModifyItem");
+	mapi_object_init(&obj_store);
+	mapi_object_init(&obj_folder);
+	mapi_object_init(&obj_message);
+
+	nameid = mapi_nameid_new(mem_ctx);
+	SPropTagArray = talloc_zero(mem_ctx, struct SPropTagArray);
+
+	/* Open the message store */
+	retval = OpenMsgStore(&obj_store);
+	if (retval != MAPI_E_SUCCESS) {
+		mapi_errstr("OpenMsgStore", GetLastError());
+		goto cleanup;
+	}
+
+	/* If fid not present then we'll use olFolder. Document this in API doc. */
+	if (fid == 0) {
+		retval = GetDefaultFolder(&obj_store, &fid, olFolder);
+		if (retval != MAPI_E_SUCCESS) {
+			mapi_errstr("GetDefaultFolder", GetLastError());
+			goto cleanup;
+		}
+	}
+
+	/* Attempt to open the folder */
+	retval = OpenFolder(&obj_store, fid, &obj_folder);
+	if (retval != MAPI_E_SUCCESS) {
+		mapi_errstr("OpenFolder", GetLastError());
+		goto cleanup;
+	}
+
+	/* Open the item to be modified */
+	retval = OpenMessage(&obj_folder, fid, mid, &obj_message, MAPI_MODIFY);
+	if (retval != MAPI_E_SUCCESS) {
+		mapi_errstr("OpenMessage", GetLastError());
+		goto cleanup;
+	}
+
+//	d(mapi_object_debug (&obj_message));
+
+	/* Add named props using callback */
+	if (build_name_id) {
+		if (!build_name_id (nameid, ni_data)) {
+			g_warning ("\n%s(%d): (%s): Could not build named props ", __FILE__, __LINE__, __PRETTY_FUNCTION__);
+			goto cleanup;
+		}
+
+		retval = mapi_nameid_GetIDsFromNames(nameid, &obj_folder, SPropTagArray);
+		if (retval != MAPI_E_SUCCESS) {
+			mapi_errstr("mapi_nameid_GetIDsFromNames", GetLastError());
+			goto cleanup;
+		}
+	}
+
+	/* Add regular props using callback */
+	if (build_props) {
+		propslen = build_props (&props, SPropTagArray, p_data);
+		if (propslen < 1) {
+			g_warning ("\n%s(%d): (%s): Could not build props ", __FILE__, __LINE__, __PRETTY_FUNCTION__);
+			goto cleanup;
+		}
+	}
+
+	/* set properties for the item */
+	retval = SetProps(&obj_message, props, propslen);
+	if (retval != MAPI_E_SUCCESS) {
+		mapi_errstr("SetProps", GetLastError());
+		goto cleanup;
+	}
+
+	if (generic_streams) {
+		exchange_mapi_util_write_generic_streams (&obj_message, generic_streams);
+	}
+
+	/* Set attachments if any */
+	if (attachments) {
+		exchange_mapi_util_set_attachments (&obj_message, attachments, TRUE);
+	}
+
+	/* Set recipients if any */
+	if (recipients) {
+		exchange_mapi_util_modify_recipients (mem_ctx, &obj_message, recipients, TRUE);
+	}
+ 
+	/* Finally, save all changes */
+	retval = SaveChangesMessage(&obj_folder, &obj_message);
+	if (retval != MAPI_E_SUCCESS) {
+		mapi_errstr("SaveChangesMessage", GetLastError());
+		goto cleanup;
+	}
+
+	if (recipients && !(options & MAPI_OPTIONS_DONT_SUBMIT)) {
+		/* Mark message as ready to be sent */
+		retval = SubmitMessage(&obj_message);
+		if (retval != MAPI_E_SUCCESS) {
+			mapi_errstr("SubmitMessage", GetLastError());
+			goto cleanup;
+		}
+	}
+
+	result = TRUE;
+
+cleanup:
+	mapi_object_release(&obj_message);
+	mapi_object_release(&obj_folder);
+	mapi_object_release(&obj_store);
+	talloc_free(mem_ctx);
+	LOGNONE();
+	UNLOCK();
+
+	d(g_print("\n%s(%d): Leaving %s ", __FILE__, __LINE__, __PRETTY_FUNCTION__));
+
+	return result;
+}
+
+gboolean
+exchange_mapi_set_flags (uint32_t olFolder, mapi_id_t fid, GSList *mids, uint32_t flag, guint32 options)
+{
+	enum MAPISTATUS retval;
+	TALLOC_CTX *mem_ctx;
+	mapi_object_t obj_store;
+	mapi_object_t obj_folder;
+	uint32_t i;
+	mapi_id_t *id_messages;
+	GSList *tmp = mids;
+	gboolean result = FALSE;
+
+	d(g_print("\n%s(%d): Entering %s ", __FILE__, __LINE__, __PRETTY_FUNCTION__));
+
+	LOCK();
+	LOGALL();
+	mem_ctx = talloc_init("ExchangeMAPI_SetFlags");
+	mapi_object_init(&obj_store);
+	mapi_object_init(&obj_folder);
+
+	id_messages = talloc_array(mem_ctx, mapi_id_t, g_slist_length (mids));
+	for (i=0; tmp; tmp=tmp->next, i++)
+		id_messages[i] = *((mapi_id_t *)tmp->data);
+
+	/* Open the message store */
+	retval = ((options & MAPI_OPTIONS_USE_PFSTORE) ? OpenPublicFolder(&obj_store) : OpenMsgStore(&obj_store)) ;
+	if (retval != MAPI_E_SUCCESS) {
+		mapi_errstr("OpenMsgStore / OpenPublicFolder", GetLastError());
+		goto cleanup;
+	}
+
+	/* Attempt to open the folder */
+	retval = OpenFolder(&obj_store, fid, &obj_folder);
+	if (retval != MAPI_E_SUCCESS) {
+		mapi_errstr("OpenFolder", GetLastError());
+		goto cleanup;
+	}
+
+	retval = SetReadFlags(&obj_folder, flag, i, id_messages);
+	if (retval != MAPI_E_SUCCESS) {
+		mapi_errstr("SetReadFlags", GetLastError());
+		goto cleanup;
+	}
+
+	result = TRUE;
+
+cleanup:
+	mapi_object_release(&obj_folder);
+	mapi_object_release(&obj_store);
+	talloc_free(mem_ctx);
+	LOGNONE();
+	UNLOCK();
+
+	d(g_print("\n%s(%d): Leaving %s ", __FILE__, __LINE__, __PRETTY_FUNCTION__));
+
+	return result;
+}
+
+static gboolean
+mapi_move_items (mapi_id_t src_fid, mapi_id_t dest_fid, GSList *mid_list, gboolean do_copy)
+{
+	enum MAPISTATUS	retval;
+	mapi_object_t obj_store;
+	mapi_object_t obj_folder_src;
+	mapi_object_t obj_folder_dst;
+	mapi_id_array_t msg_id_array;
+	GSList *l;
+	gboolean result = FALSE;
+
+	mapi_object_init(&obj_store);
+	mapi_object_init(&obj_folder_src);
+	mapi_object_init(&obj_folder_dst);
+	mapi_id_array_init(&msg_id_array);
+
+	for (l = mid_list; l != NULL; l = g_slist_next (l))
+		mapi_id_array_add_id (&msg_id_array, *((mapi_id_t *)l->data));
+
+	retval = OpenMsgStore(&obj_store);
+	if (retval != MAPI_E_SUCCESS) {
+		mapi_errstr("OpenMsgStore", GetLastError());
+		goto cleanup;
+	}
+
+	retval = OpenFolder(&obj_store, src_fid, &obj_folder_src);
+	if (retval != MAPI_E_SUCCESS) {
+		mapi_errstr("OpenFolder - source folder", GetLastError());
+		goto cleanup;
+	}
+
+	retval = OpenFolder(&obj_store, dest_fid, &obj_folder_dst);
+	if (retval != MAPI_E_SUCCESS) {
+		mapi_errstr("OpenFolder - destination folder", GetLastError());
+		goto cleanup;
+	}
+
+	retval = MoveCopyMessages(&obj_folder_src, &obj_folder_dst, &msg_id_array, do_copy);
+	if (retval != MAPI_E_SUCCESS) {
+		mapi_errstr("MoveCopyMessages", GetLastError());
+		goto cleanup;
+	}
+
+	result = TRUE;
+
+cleanup:
+	mapi_id_array_release(&msg_id_array);
+	mapi_object_release(&obj_folder_dst);
+	mapi_object_release(&obj_folder_src);
+	mapi_object_release(&obj_store);
+
+	return result;
+}
+
+gboolean
+exchange_mapi_copy_items (mapi_id_t src_fid, mapi_id_t dest_fid, GSList *mids)
+{
+	gboolean result = FALSE; 
+
+	d(g_print("\n%s(%d): Entering %s ", __FILE__, __LINE__, __PRETTY_FUNCTION__));
+
+	LOCK();
+	LOGALL();
+	result = mapi_move_items (src_fid, dest_fid, mids, TRUE);
+	LOGNONE();
+	UNLOCK();
+
+	d(g_print("\n%s(%d): Leaving %s ", __FILE__, __LINE__, __PRETTY_FUNCTION__));
+
+	return result; 
+}
+
+gboolean
+exchange_mapi_move_items (mapi_id_t src_fid, mapi_id_t dest_fid, GSList *mids)
+{
+	gboolean result = FALSE; 
+
+	d(g_print("\n%s(%d): Entering %s ", __FILE__, __LINE__, __PRETTY_FUNCTION__));
+
+	LOCK();
+	LOGALL();
+	result = mapi_move_items (src_fid, dest_fid, mids, FALSE);
+	LOGNONE();
+	UNLOCK();
+
+	d(g_print("\n%s(%d): Leaving %s ", __FILE__, __LINE__, __PRETTY_FUNCTION__));
+
+	return result; 
+}
+
+gboolean
+exchange_mapi_remove_items (uint32_t olFolder, mapi_id_t fid, GSList *mids)
+{
+	enum MAPISTATUS retval;
+	TALLOC_CTX *mem_ctx;
+	mapi_object_t obj_store;
+	mapi_object_t obj_folder;
+	uint32_t i;
+	mapi_id_t *id_messages;
+	GSList *tmp = mids;
+	gboolean result = FALSE;
+
+	d(g_print("\n%s(%d): Entering %s ", __FILE__, __LINE__, __PRETTY_FUNCTION__));
+
+	LOCK();
+	LOGALL();
+	mem_ctx = talloc_init("ExchangeMAPI_RemoveItems");
+	mapi_object_init(&obj_store);
+	mapi_object_init(&obj_folder);
+
+	id_messages = talloc_array(mem_ctx, mapi_id_t, g_slist_length (mids));
+	for (i=0; tmp; tmp=tmp->next, i++) {
+		struct id_list *data = tmp->data;
+		id_messages[i] = data->id;
+	}
+
+	/* Open the message store */
+	retval = OpenMsgStore(&obj_store);
+	if (retval != MAPI_E_SUCCESS) {
+		mapi_errstr("OpenMsgStore", GetLastError());
+		goto cleanup;
+	}
+
+	/* If fid not present then we'll use olFolder. Document this in API doc. */
+	if (fid == 0) {
+		retval = GetDefaultFolder(&obj_store, &fid, olFolder);
+		if (retval != MAPI_E_SUCCESS) {
+			mapi_errstr("GetDefaultFolder", GetLastError());
+			goto cleanup;
+		}
+	}
+
+	/* Attempt to open the folder */
+	retval = OpenFolder(&obj_store, fid, &obj_folder);
+	if (retval != MAPI_E_SUCCESS) {
+		mapi_errstr("OpenFolder", GetLastError());
+		goto cleanup;
+	}
+
+	/* Delete the messages from the folder */
+	retval = DeleteMessage(&obj_folder, id_messages, i);
+	if (retval != MAPI_E_SUCCESS) {
+		mapi_errstr("DeleteMessage", GetLastError());
+		goto cleanup;
+	}
+
+	result = TRUE;
+
+cleanup:
+	mapi_object_release(&obj_folder);
+	mapi_object_release(&obj_store);
+	talloc_free(mem_ctx);
+	LOGNONE();
+	UNLOCK();
+
+	d(g_print("\n%s(%d): Leaving %s ", __FILE__, __LINE__, __PRETTY_FUNCTION__));
+
+	return result;
+}
+
+static gboolean
+get_child_folders(TALLOC_CTX *mem_ctx, ExchangeMAPIFolderCategory folder_hier, mapi_object_t *parent, mapi_id_t folder_id, GSList **mapi_folders)
+{
+	enum MAPISTATUS		retval;
+	mapi_object_t		obj_folder;
+	mapi_object_t		obj_table;
+	struct SPropTagArray	*SPropTagArray = NULL;
+	struct SRowSet		rowset;
+	uint32_t		i, row_count = 0;
+	gboolean 		result = TRUE;
+
+	/* sanity check */
+	g_return_val_if_fail (mem_ctx != NULL, FALSE);
+	g_return_val_if_fail (parent != NULL, FALSE);
+
+	mapi_object_init(&obj_folder);
+	mapi_object_init(&obj_table);
+
+	/* Attempt to open the folder */
+	retval = OpenFolder(parent, folder_id, &obj_folder);
+	if (retval != MAPI_E_SUCCESS) {
+		mapi_errstr("OpenFolder", GetLastError());
+		goto cleanup;
+	}
+
+	/* Get the hierarchy table */
+	retval = GetHierarchyTable(&obj_folder, &obj_table, 0, &row_count);
+	if (retval != MAPI_E_SUCCESS) {
+		mapi_errstr("GetHierarchyTable", GetLastError());
+		goto cleanup;
+	}
+
+	SPropTagArray = set_SPropTagArray(mem_ctx, 0x6,
+					  PR_FID,
+					  PR_CONTAINER_CLASS,
+					  PR_DISPLAY_NAME,
+					  PR_CONTENT_UNREAD,
+					  PR_CONTENT_COUNT,
+					  PR_FOLDER_CHILD_COUNT);
+
+	retval = SetColumns(&obj_table, SPropTagArray);
+	if (retval != MAPI_E_SUCCESS) {
+		mapi_errstr("SetColumns", GetLastError());
+		goto cleanup;
+	}
+
+	/* Fill the table columns with data from the rows */
+	retval = QueryRows(&obj_table, row_count, TBL_ADVANCE, &rowset);
+	if (retval != MAPI_E_SUCCESS) {
+		mapi_errstr("QueryRows", GetLastError());
+		goto cleanup;
+	}
+
+	for (i = 0; i < rowset.cRows; i++) {
+		ExchangeMAPIFolder *folder = NULL;
+		gchar *newname = NULL;
+
+		const mapi_id_t *fid = (const mapi_id_t *)find_SPropValue_data(&rowset.aRow[i], PR_FID);
+		const char *class = (const char *)find_SPropValue_data(&rowset.aRow[i], PR_CONTAINER_CLASS);
+		const char *name = (const char *)find_SPropValue_data(&rowset.aRow[i], PR_DISPLAY_NAME);
+		const uint32_t *unread = (const uint32_t *)find_SPropValue_data(&rowset.aRow[i], PR_CONTENT_UNREAD);
+		const uint32_t *total = (const uint32_t *)find_SPropValue_data(&rowset.aRow[i], PR_CONTENT_COUNT);
+		const uint32_t *child = (const uint32_t *)find_SPropValue_data(&rowset.aRow[i], PR_FOLDER_CHILD_COUNT);
+
+		if (!class)
+			class = IPF_NOTE;
+
+		newname = utf8tolinux (name);
+		g_print("\n|---+ %-15s : (Container class: %s %016llX) UnRead : %d Total : %d ", newname, class, *fid, unread ? *unread : 0, total ? *total : 0);
+
+		folder = exchange_mapi_folder_new (newname, class, folder_hier, *fid, folder_id, child ? *child : 0, unread ? *unread : 0, total ? *total : 0);
+		*mapi_folders = g_slist_prepend (*mapi_folders, folder);
+
+		if (child && *child)
+			result = (result && get_child_folders(mem_ctx, folder_hier, &obj_folder, *fid, mapi_folders));
+
+		g_free (newname);
+	}
+
+cleanup:
+	MAPIFreeBuffer (SPropTagArray);
+	mapi_object_release (&obj_folder);
+	mapi_object_release (&obj_table);
+
+	return result;
+}
+
+static void 
+set_default_folders (mapi_object_t *obj_store, GSList **mapi_folders)
+{
+	GSList *folder_list = *mapi_folders;
+	
+	while (folder_list = g_slist_next (folder_list)) {
+		ExchangeMAPIFolder *folder = NULL;
+		guint32 default_type = 0;
+		folder = folder_list->data;
+		if (IsMailboxFolder (obj_store,folder->folder_id, &default_type )) {
+			folder->is_default = true; /* TODO : Clean up. Redundant.*/
+			folder->default_type = default_type;
+		}
+	}
+}
+
+static void 
+set_owner_name (gpointer data, gpointer user_data)
+{
+	ExchangeMAPIFolder *folder = (ExchangeMAPIFolder *)(data);
+	folder->owner_name = (const gchar *)(user_data);
+}
+
+static void 
+set_user_name (gpointer data, gpointer user_data)
+{
+	ExchangeMAPIFolder *folder = (ExchangeMAPIFolder *)(data);
+	folder->user_name = (const gchar *)(user_data);
+}
+
+gboolean 
+exchange_mapi_get_folders_list (GSList **mapi_folders)
+{
+	enum MAPISTATUS 	retval;
+	TALLOC_CTX 		*mem_ctx;
+	mapi_object_t 		obj_store;
+	struct SPropTagArray 	*SPropTagArray;
+	struct SPropValue 	*lpProps;
+	struct SRow		aRow;
+	gboolean 		result = FALSE;
+	mapi_id_t		mailbox_id;
+	ExchangeMAPIFolder 	*folder;
+	uint32_t 		count = 0;
+	const char 		*mailbox_name = NULL;
+	char 			*utf8_mailbox_name = NULL;
+	const char 		*mailbox_owner_name = NULL;
+	const char 		*mailbox_user_name = NULL;
+
+	d(g_print("\n%s(%d): Entering %s ", __FILE__, __LINE__, __PRETTY_FUNCTION__));
+
+	LOCK();
+	LOGALL();
+	mem_ctx = talloc_init("ExchangeMAPI_GetFoldersList");
+	mapi_object_init(&obj_store);
+
+	/* Open the message store */
+	retval = OpenMsgStore(&obj_store);
+	if (retval != MAPI_E_SUCCESS) {
+		mapi_errstr("OpenMsgStore", GetLastError());
+		goto cleanup;
+	}
+
+	/* Build the array of Mailbox properties we want to fetch */
+	SPropTagArray = set_SPropTagArray(mem_ctx, 0x3,
+					  PR_DISPLAY_NAME,
+					  PR_MAILBOX_OWNER_NAME,
+					  PR_USER_NAME);
+
+	lpProps = talloc_zero(mem_ctx, struct SPropValue);
+	retval = GetProps (&obj_store, SPropTagArray, &lpProps, &count);
+	MAPIFreeBuffer(SPropTagArray);
+
+	if (retval != MAPI_E_SUCCESS) {
+		mapi_errstr("GetProps", GetLastError());
+		goto cleanup;
+	}
+
+	/* Build a SRow structure */
+	aRow.ulAdrEntryPad = 0;
+	aRow.cValues = count;
+	aRow.lpProps = lpProps;
+
+	/* betting that these will never fail */
+	mailbox_name = (const char *) find_SPropValue_data(&aRow, PR_DISPLAY_NAME);
+	mailbox_owner_name = (const char *) find_SPropValue_data(&aRow, PR_MAILBOX_OWNER_NAME);
+	mailbox_user_name = (const char *) find_SPropValue_data(&aRow, PR_USER_NAME);
+
+	/* Prepare the directory listing */
+	retval = GetDefaultFolder(&obj_store, &mailbox_id, olFolderTopInformationStore);
+	if (retval != MAPI_E_SUCCESS) {
+		mapi_errstr("GetDefaultFolder", GetLastError());
+		goto cleanup;
+	}
+
+	utf8_mailbox_name = utf8tolinux (mailbox_name);
+
+	/* FIXME: May have to get the child folders count? Do we need/use it? */
+	folder = exchange_mapi_folder_new (utf8_mailbox_name, IPF_NOTE, MAPI_PERSONAL_FOLDER, mailbox_id, 0, 0, 0 ,0); 
+	*mapi_folders = g_slist_prepend (*mapi_folders, folder);
+
+	/* FIXME: check status of get_child_folders */
+	get_child_folders (mem_ctx, MAPI_PERSONAL_FOLDER, &obj_store, mailbox_id, mapi_folders);
+
+	g_free(utf8_mailbox_name);
+
+	*mapi_folders = g_slist_reverse (*mapi_folders);
+
+	set_default_folders (&obj_store, mapi_folders);
+	g_slist_foreach (*mapi_folders, (GFunc) set_owner_name, (gpointer) mailbox_owner_name);
+	g_slist_foreach (*mapi_folders, (GFunc) set_user_name, (gpointer) mailbox_user_name);
+
+	result = TRUE;
+
+cleanup:
+	mapi_object_release(&obj_store);
+	talloc_free (mem_ctx);
+	LOGNONE();
+	UNLOCK();
+
+	d(g_print("\n%s(%d): Leaving %s ", __FILE__, __LINE__, __PRETTY_FUNCTION__));
+
+	return result;
+}
+
+gboolean 
+exchange_mapi_get_pf_folders_list (GSList **mapi_folders)
+{
+	enum MAPISTATUS 	retval;
+	TALLOC_CTX 		*mem_ctx;
+	mapi_object_t 		obj_store;
+	gboolean 		result = FALSE;
+	mapi_id_t		mailbox_id;
+	ExchangeMAPIFolder 	*folder;
+
+	d(g_print("\n%s(%d): Entering %s ", __FILE__, __LINE__, __PRETTY_FUNCTION__));
+
+	LOCK();
+	LOGALL();
+	mem_ctx = talloc_init("ExchangeMAPI_PF_GetFoldersList");
+	mapi_object_init(&obj_store);
+
+	/* Open the PF message store */
+	retval = OpenPublicFolder(&obj_store);
+	if (retval != MAPI_E_SUCCESS) {
+		mapi_errstr("OpenPublicFolder", GetLastError());
+		goto cleanup;
+	}
+
+	/* Prepare the directory listing */
+	retval = GetDefaultPublicFolder(&obj_store, &mailbox_id, olFolderPublicIPMSubtree);
+	if (retval != MAPI_E_SUCCESS) {
+		mapi_errstr("GetDefaultPublicFolder", GetLastError());
+		goto cleanup;
+	}
+
+	/*  TODO : Localized string */
+	folder = exchange_mapi_folder_new ("All Public Folders", IPF_NOTE, 0, mailbox_id, 0, 0, 0 ,0);
+
+	*mapi_folders = g_slist_prepend (*mapi_folders, folder);
+
+	/* FIXME: check status of get_child_folders */
+	get_child_folders (mem_ctx, MAPI_FAVOURITE_FOLDER, &obj_store, mailbox_id, mapi_folders);
+
+	result = TRUE;
+
+cleanup:
+	mapi_object_release(&obj_store);
+	talloc_free (mem_ctx);
+	LOGNONE();
+	UNLOCK();
+
+	d(g_print("\n%s(%d): Leaving %s ", __FILE__, __LINE__, __PRETTY_FUNCTION__));
+
+	return result;
+}
+

Added: trunk/src/libexchangemapi/exchange-mapi-connection.h
==============================================================================
--- (empty file)
+++ trunk/src/libexchangemapi/exchange-mapi-connection.h	Wed Nov 19 04:28:20 2008
@@ -0,0 +1,190 @@
+/* -*- 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/>  
+ *
+ *
+ * Authors:
+ *    Srinivasa Ragavan <sragavan novell com>
+ *    Suman Manjunath <msuman novell com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef EXCHANGE_MAPI_CONNECTION_H
+#define EXCHANGE_MAPI_CONNECTION_H 
+
+#include <glib.h>
+
+#include <libmapi/libmapi.h>
+
+typedef enum {
+	MAPI_OPTIONS_FETCH_ATTACHMENTS = 1<<0,
+	MAPI_OPTIONS_FETCH_RECIPIENTS = 1<<1,
+	MAPI_OPTIONS_FETCH_BODY_STREAM = 1<<2,
+	MAPI_OPTIONS_FETCH_GENERIC_STREAMS = 1<<3, 
+	MAPI_OPTIONS_DONT_SUBMIT = 1<<4, 
+	MAPI_OPTIONS_GETBESTBODY = 1<<5,
+	MAPI_OPTIONS_USE_PFSTORE = 1<<6
+} ExchangeMAPIOptions;
+
+#define MAPI_OPTIONS_FETCH_ALL MAPI_OPTIONS_FETCH_ATTACHMENTS | \
+	                       MAPI_OPTIONS_FETCH_RECIPIENTS | \
+	                       MAPI_OPTIONS_FETCH_BODY_STREAM | \
+	                       MAPI_OPTIONS_FETCH_GENERIC_STREAMS
+
+typedef struct {
+	GByteArray *value;
+	uint32_t proptag;
+} ExchangeMAPIStream;
+
+typedef struct {
+	GByteArray *value;
+	uint32_t proptag;
+	uint32_t editor_format;
+} ExchangeMAPIBodyStream;
+
+typedef struct {
+	/* MANDATORY */
+	const char *email_id;
+
+	/* It is ideal to set all these properties on all recipients 
+	 * as we never know if a recipient would be resolved or not. */ 
+	struct {
+		/* These are properties which would be set on the 
+		 * recipients regardless if the recipient is resolved or not */
+		uint32_t req_cValues; 
+		struct SPropValue *req_lpProps;
+
+		/* These are properties which would be set on the 
+		 * recipients only if the recipient is MAPI_UNRESOLVED */
+		uint32_t ext_cValues; 
+		struct SPropValue *ext_lpProps;
+	} in; 
+
+	struct {
+		/* These are properties which would be set on the 
+		 * recipients after GetRecipientTable() */
+		uint32_t all_cValues; 
+		struct SPropValue *all_lpProps;
+	} out; 
+} ExchangeMAPIRecipient;
+
+typedef struct {
+	uint32_t cValues; 
+	struct SPropValue *lpProps; 
+	GSList *streams; 
+	GSList *objects; 
+} ExchangeMAPIAttachment;
+
+typedef struct {
+	struct mapi_SPropValue_array *properties;
+	mapi_id_t fid;
+	mapi_id_t mid;
+	GSList *attachments;
+	GSList *recipients;
+	GSList *streams;
+	guint total; /*Total number of results*/
+	guint index; /*Index of this Item*/
+} FetchItemsCallbackData;
+
+struct id_list {
+	mapi_id_t id;
+};
+
+typedef gboolean (*FetchCallback) 	(FetchItemsCallbackData *item_data, gpointer data);
+typedef gboolean (*BuildNameID) 	(struct mapi_nameid *nameid, gpointer data);
+typedef int 	 (*BuildProps) 		(struct SPropValue **, struct SPropTagArray *, gpointer data);
+
+gboolean 
+exchange_mapi_connection_new (const char *profile, const char *password);
+
+void
+exchange_mapi_connection_close (void);
+
+gboolean
+exchange_mapi_connection_exists (void);
+
+gboolean
+exchange_mapi_connection_fetch_item (mapi_id_t fid, mapi_id_t mid, 
+				     const uint32_t *GetPropsList, const uint16_t cn_props, 
+				     BuildNameID build_name_id, gpointer build_name_data, 
+				     FetchCallback cb, gpointer data, 
+				     guint32 options);
+gboolean
+exchange_mapi_connection_fetch_items   (mapi_id_t fid, 
+					struct mapi_SRestriction *res,
+					const uint32_t *GetPropsList, const uint16_t cn_props, 
+					BuildNameID build_name_id, gpointer build_name_data, 
+					FetchCallback cb, gpointer data, 
+					guint32 options);
+
+mapi_id_t 
+exchange_mapi_create_folder (uint32_t olFolder, mapi_id_t pfid, const char *name);
+
+gboolean 
+exchange_mapi_remove_folder (uint32_t olFolder, mapi_id_t fid);
+
+gboolean
+exchange_mapi_empty_folder (mapi_id_t fid);
+
+gboolean 
+exchange_mapi_rename_folder (mapi_id_t fid, const char *new_name);
+
+GSList *
+exchange_mapi_util_check_restriction (mapi_id_t fid, struct mapi_SRestriction *res);
+
+mapi_id_t
+exchange_mapi_get_default_folder_id (uint32_t olFolder);
+
+mapi_id_t
+exchange_mapi_create_item (uint32_t olFolder, mapi_id_t fid, 
+			   BuildNameID build_name_id, gpointer ni_data, 
+			   BuildProps build_props, gpointer p_data, 
+			   GSList *recipients, GSList *attachments, GSList *generic_streams,
+			   uint32_t options);
+gboolean
+exchange_mapi_modify_item (uint32_t olFolder, mapi_id_t fid, mapi_id_t mid, 
+			   BuildNameID build_name_id, gpointer ni_data, 
+			   BuildProps build_props, gpointer p_data,
+			   GSList *recipients, GSList *attachments, GSList *generic_streams,
+			   uint32_t options);
+
+gboolean
+exchange_mapi_set_flags (uint32_t olFolder, mapi_id_t fid, GSList *mid_list, uint32_t flag, guint32 options);
+
+gboolean
+exchange_mapi_remove_items (uint32_t olFolder, mapi_id_t fid, GSList *mids);
+
+gboolean
+exchange_mapi_copy_items ( mapi_id_t src_fid, mapi_id_t dest_fid, GSList *mids);
+
+gboolean
+exchange_mapi_move_items ( mapi_id_t src_fid, mapi_id_t dest_fid, GSList *mids);
+
+
+gboolean exchange_mapi_get_folders_list (GSList **mapi_folders); 
+gboolean exchange_mapi_get_pf_folders_list (GSList **mapi_folders); 
+
+struct SPropTagArray *
+exchange_mapi_util_resolve_named_props (uint32_t olFolder, mapi_id_t fid, 
+				   BuildNameID build_name_id, gpointer ni_data);
+struct SPropTagArray *
+exchange_mapi_util_resolve_named_prop (uint32_t olFolder, mapi_id_t fid, 
+				       uint16_t lid, const char *OLEGUID);
+uint32_t
+exchange_mapi_util_create_named_prop (uint32_t olFolder, mapi_id_t fid, 
+				      const char *named_prop_name, uint32_t ptype);
+
+#endif

Added: trunk/src/libexchangemapi/exchange-mapi-defs.h
==============================================================================
--- (empty file)
+++ trunk/src/libexchangemapi/exchange-mapi-defs.h	Wed Nov 19 04:28:20 2008
@@ -0,0 +1,266 @@
+/* -*- 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/>  
+ *
+ *
+ * Authors:
+ *    Suman Manjunath <msuman novell com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+/* Someday, all these definitions should be pushed in libmapi/mapidefs.h */
+/* NOTE: Some of the enumerations are commented out since they conflict with libmapi/mapidefs.h */
+
+#ifndef EXCHANGE_MAPI_DEFS_H
+#define EXCHANGE_MAPI_DEFS_H
+
+G_BEGIN_DECLS
+
+/* GENERAL */
+typedef enum {
+    olSunday = 1,
+    olMonday = 2,
+    olTuesday = 4,
+    olWednesday = 8,
+    olThursday = 16,
+    olFriday = 32,
+    olSaturday = 64
+} OlDaysOfWeek;
+
+typedef enum {
+    olNormal = 0,
+    olPersonal = 1,
+    olPrivate = 2,
+    olConfidential = 3
+} OlSensitivity;
+
+typedef enum {
+    olImportanceLow = 0,
+    olImportanceNormal = 1,
+    olImportanceHigh = 2
+} OlImportance;
+
+typedef enum {
+    olOriginator = 0,
+    olTo = 1,
+    olCC = 2,
+    olBCC = 3
+} OlMailRecipientType;
+
+typedef enum {
+    SingleAppt = 0x0400 ,
+    RecurAppt = 0x0401 ,
+    SingleMeet = 0x0402 , 
+    RecurMeet = 0x0403 ,
+    MeetReq = 0x0404 ,
+    RespAccept = 0x0405 ,
+    RespDecline = 0x0406 ,
+    RespTentAccept = 0x0407 ,
+    MeetCancel = 0x0408 ,
+    MeetInfoUpdate = 0x0409 
+} IconIndex;
+
+#if 0
+typedef enum {
+    olEditorText = 1,
+    olEditorHTML = 2,
+    olEditorRTF = 3,
+    olEditorWord = 4
+} OlEditorType; /* PR_MESSAGE_EDITOR_FORMAT type */
+
+typedef enum {
+    olFolderDeletedItems = 3,
+    olFolderOutbox = 4,
+    olFolderSentMail = 5,
+    olFolderInbox = 6,
+    olFolderCalendar = 9,
+    olFolderContacts = 10,
+    olFolderJournal = 11,
+    olFolderNotes = 12,
+    olFolderTasks = 13,
+    olFolderDrafts = 16,
+    olPublicFoldersAllPublicFolders = 18,
+    olFolderConflicts = 19,
+    olFolderSyncIssues = 20,
+    olFolderLocalFailures = 21,
+    olFolderServerFailures = 22,
+    olFolderJunk = 23,
+    olFolderRssFeeds = 25,
+    olFolderToDo = 28,
+    olFolderManagedEmail = 29
+} OlDefaultFolders;
+
+#define	olFolderTopInformationStore	1
+#define	olFolderCommonView		8
+#define	olFolderFinder			24
+#define	olFolderPublicRoot		25
+#define	olFolderPublicIPMSubtree	26
+#endif
+
+
+/* APPOINTMENTS */
+typedef enum {
+    olFree = 0,
+    olTentative = 1,
+    olBusy = 2,
+    olOutOfOffice = 3
+} OlBusyStatus; /* Appointment flags with PR_APPOINTMENT_BUSY_STATUS */
+
+typedef enum {
+    olOrganizer = 0,
+    olRequired = 1,
+    olOptional = 2,
+    olResource = 3
+} OlMeetingRecipientType;
+
+typedef enum {
+    olMeetingTentative = 2,
+    olMeetingAccepted = 3,
+    olMeetingDeclined = 4
+} OlMeetingResponse;
+
+typedef enum {
+    olResponseNone = 0,
+    olResponseOrganized = 1,
+    olResponseTentative = 2,
+    olResponseAccepted = 3,
+    olResponseDeclined = 4,
+    olResponseNotResponded = 5
+} OlResponseStatus;
+
+typedef enum {
+    mtgEmpty = 		0x00000000,
+    mtgRequest = 	0x00000001,
+    mtgFull = 		0x00010000,
+    mtgInfo = 		0x00020000,
+    mtgOutOfDate = 	0x00080000,
+    mtgDelegatorCopy = 	0x00100000
+} MeetingType;
+
+typedef enum {
+    olNonMeeting = 0,
+    olMeeting = 1,
+    olMeetingReceived = 3,
+    olMeetingCanceled = 5
+} OlMeetingStatus;
+
+typedef enum {
+    asfNone = 0,
+    asfMeeting = 1,
+    asfReceived = 2,
+    asfCanceled = 4
+} AppointmentStateFlags;
+
+typedef enum {
+    olNetMeeting = 0,
+    olNetShow = 1,
+    olChat = 2
+} OlNetMeetingType;
+
+
+/* TASKS */
+typedef enum {
+    olTaskNotDelegated = 0,
+    olTaskDelegationUnknown = 1,
+    olTaskDelegationAccepted = 2,
+    olTaskDelegationDeclined = 3
+} OlTaskDelegationState;
+
+typedef enum {
+    olUpdate = 2,
+    olFinalStatus = 3
+} OlTaskRecipientType;
+
+typedef enum {
+    olTaskSimple = 0,
+    olTaskAssign = 1,
+    olTaskAccept = 2,
+    olTaskDecline = 3
+} OlTaskResponse;
+
+#if 0
+typedef enum {
+    olNewTask = 0,
+    olDelegatedTask = 1,
+    olOwnTask = 2
+} OlTaskOwnership;
+
+typedef enum {
+    olTaskNotStarted = 0,
+    olTaskInProgress = 1,
+    olTaskComplete = 2,
+    olTaskWaiting = 3,
+    olTaskDeferred = 4
+} OlTaskStatus;
+#endif
+
+
+/* NOTES */
+#if 0
+typedef enum {
+    olBlue = 0,
+    olGreen = 1,
+    olPink = 2,
+    olYellow = 3,
+    olWhite = 4
+} OlNoteColor;
+#endif
+
+
+/* RECURRENCE (APPOINTMENTS/MEETINGS/TASKS) */
+typedef enum { 
+    rectypeNone = 0,
+    rectypeDaily = 1,
+    rectypeWeekly = 2,
+    rectypeMonthly = 3,
+    rectypeYearly = 4
+} OlRecurrenceType;
+
+typedef enum {
+    olApptNotRecurring = 0,
+    olApptMaster = 1,
+    olApptOccurrence = 2,
+    olApptException = 3
+} OlRecurrenceState;
+
+#if 0
+typedef enum {
+    olRecursDaily = 0,
+    olRecursWeekly = 1,
+    olRecursMonthly = 2,
+    olRecursMonthNth = 3,
+    olRecursYearly = 5,
+    olRecursYearNth = 6
+} OlRecurrencePatternType;
+#endif 
+
+
+#define IPM_CONTACT 				"IPM.Contact"
+#define IPM_APPOINTMENT 			"IPM.Appointment"
+#define IPM_SCHEDULE_MEETING_PREFIX 		"IPM.Schedule.Meeting."
+#define IPM_SCHEDULE_MEETING_REQUEST 		"IPM.Schedule.Meeting.Request"
+#define IPM_SCHEDULE_MEETING_CANCELED 		"IPM.Schedule.Meeting.Canceled"
+#define IPM_SCHEDULE_MEETING_RESP_PREFIX 	"IPM.Schedule.Meeting.Resp."
+#define IPM_SCHEDULE_MEETING_RESP_POS 		"IPM.Schedule.Meeting.Resp.Pos"
+#define IPM_SCHEDULE_MEETING_RESP_TENT 		"IPM.Schedule.Meeting.Resp.Tent"
+#define IPM_SCHEDULE_MEETING_RESP_NEG 		"IPM.Schedule.Meeting.Resp.Neg"
+#define IPM_TASK 				"IPM.Task"
+#define IPM_STICKYNOTE 				"IPM.StickyNote"
+
+
+G_END_DECLS
+
+#endif

Added: trunk/src/libexchangemapi/exchange-mapi-folder.c
==============================================================================
--- (empty file)
+++ trunk/src/libexchangemapi/exchange-mapi-folder.c	Wed Nov 19 04:28:20 2008
@@ -0,0 +1,200 @@
+/* -*- 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/>  
+ *
+ *
+ * Authors:
+ *    Srinivasa Ragavan <sragavan novell com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#include "exchange-mapi-connection.h"
+#include "exchange-mapi-folder.h"
+
+static GSList *folder_list = NULL;
+
+/* we use a static mutex - even the same thread *may not* use the static vars concurrently */
+static GStaticMutex folder_lock = G_STATIC_MUTEX_INIT;
+
+#define LOCK() 		g_message("%s(%d): %s: lock(folder_lock)", __FILE__, __LINE__, __PRETTY_FUNCTION__);g_static_mutex_lock(&folder_lock)
+#define UNLOCK() 	g_message("%s(%d): %s: unlock(folder_lock)", __FILE__, __LINE__, __PRETTY_FUNCTION__);g_static_mutex_unlock(&folder_lock)
+#define d(x) x
+
+static ExchangeMAPIFolderType
+container_class_to_type (const char *type)
+{
+	ExchangeMAPIFolderType folder_type = MAPI_FOLDER_TYPE_UNKNOWN;;
+
+	if (!strcmp (type, IPF_APPOINTMENT)) 
+		folder_type = MAPI_FOLDER_TYPE_APPOINTMENT;
+	else if (!strcmp (type, IPF_CONTACT))
+		folder_type = MAPI_FOLDER_TYPE_CONTACT;
+	else if (!strcmp (type, IPF_STICKYNOTE))
+		folder_type = MAPI_FOLDER_TYPE_MEMO;
+	else if (!strcmp (type, IPF_TASK))
+		folder_type = MAPI_FOLDER_TYPE_TASK;
+	else if (!strcmp (type, IPF_NOTE))
+		folder_type = MAPI_FOLDER_TYPE_MAIL;
+	/* Fixme : no definition for this is available in mapidef.h */
+	else if (!strcmp (type, "IPF.Note.HomePage"))
+		folder_type = MAPI_FOLDER_TYPE_NOTE_HOMEPAGE;
+	else if (!strcmp (type, IPF_JOURNAL))
+		folder_type = MAPI_FOLDER_TYPE_JOURNAL;
+
+	return folder_type;
+}
+
+ExchangeMAPIFolder *
+exchange_mapi_folder_new (const char *folder_name, const char *container_class, ExchangeMAPIFolderCategory category, mapi_id_t folder_id, mapi_id_t parent_folder_id, uint32_t child_count, uint32_t unread_count, uint32_t total)
+{
+	ExchangeMAPIFolder *folder;
+
+	folder = g_new0 (ExchangeMAPIFolder, 1);
+	folder->is_default = FALSE;
+	folder->folder_name = g_strdup (folder_name);
+	folder->container_class = container_class_to_type (container_class);
+	folder->folder_id = folder_id;
+	folder->parent_folder_id = parent_folder_id;
+	folder->child_count = child_count;
+	folder->unread_count = unread_count;
+	folder->total = total;
+	folder->category = category;
+
+	return folder;
+}
+
+ExchangeMAPIFolderType
+exchange_mapi_container_class (char *type)
+{
+	return container_class_to_type (type);
+}
+
+const gchar*
+exchange_mapi_folder_get_name (ExchangeMAPIFolder *folder)
+{
+	return folder->folder_name;
+}
+
+guint64
+exchange_mapi_folder_get_fid (ExchangeMAPIFolder *folder)
+{
+	return folder->folder_id;
+}
+
+guint64
+exchange_mapi_folder_get_parent_id (ExchangeMAPIFolder *folder)
+{
+	return folder->parent_folder_id;
+}
+
+gboolean
+exchange_mapi_folder_is_root (ExchangeMAPIFolder *folder)
+{
+	return (folder->parent_folder_id == 0);
+}
+
+ExchangeMAPIFolderType
+exchange_mapi_folder_get_type (ExchangeMAPIFolder *folder)
+{
+	return folder->container_class;
+}
+
+guint32
+exchange_mapi_folder_get_unread_count (ExchangeMAPIFolder *folder)
+{
+	return folder->unread_count;
+}
+
+guint32
+exchange_mapi_folder_get_total_count (ExchangeMAPIFolder *folder)
+{
+	return folder->total;
+}
+
+GSList *
+exchange_mapi_peek_folder_list ()
+{
+	LOCK ();
+	if (!folder_list)
+		exchange_mapi_get_folders_list (&folder_list); 
+	if (!folder_list)
+		g_warning ("Get folders list call failed \n");
+	UNLOCK ();
+
+	return folder_list;
+}
+
+ExchangeMAPIFolder *
+exchange_mapi_folder_get_folder (mapi_id_t fid)
+{
+	GSList *tmp = folder_list;
+
+	if (!folder_list)
+		exchange_mapi_peek_folder_list ();
+	
+	tmp = folder_list;
+	while (tmp) {
+		ExchangeMAPIFolder * folder = tmp->data;
+		g_print ("%016llX %016llX\n", folder->folder_id, fid);
+		if (folder->folder_id == fid)
+			return folder;
+		tmp=tmp->next;
+	}
+
+	return NULL;
+}
+
+void
+exchange_mapi_folder_list_free ()
+{
+	GSList *tmp = folder_list;
+	LOCK ();
+	while (tmp) {
+		ExchangeMAPIFolder *data = tmp->data;
+		g_free (data);
+		data = NULL;
+		tmp = tmp->next;
+	}
+	g_slist_free (folder_list);
+	folder_list = NULL;
+	UNLOCK ();
+
+	d(g_print("Folder list freed\n"));
+	return;
+}
+
+void
+exchange_mapi_folder_list_add (ExchangeMAPIFolder *folder)
+{
+	GSList *tmp = folder_list;
+	LOCK ();
+	while (tmp) {
+		ExchangeMAPIFolder *data = tmp->data;
+		if (data->folder_id == folder->parent_folder_id) {
+			/* Insert it here */
+			d(g_print ("Inserted below the parent\n"));
+			folder_list = g_slist_insert_before (folder_list, tmp->next, folder);
+			UNLOCK ();
+			return;
+		}
+		tmp = tmp->next;
+	}
+
+	/* Append at the end */
+	folder_list = g_slist_append (folder_list, folder);
+	UNLOCK ();
+	d(g_print("Appended folder at the end\n"));
+}

Added: trunk/src/libexchangemapi/exchange-mapi-folder.h
==============================================================================
--- (empty file)
+++ trunk/src/libexchangemapi/exchange-mapi-folder.h	Wed Nov 19 04:28:20 2008
@@ -0,0 +1,95 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/* -*- 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/>  
+ *
+ *
+ * Authors:
+ *    Srinivasa Ragavan <sragavan novell com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef EXCHANGE_MAPI_FOLDER_H
+#define EXCHANGE_MAPI_FOLDER_H
+
+#include <glib.h>
+
+#include <libmapi/libmapi.h>
+
+typedef enum  {
+	MAPI_FOLDER_TYPE_MAIL=1,
+	MAPI_FOLDER_TYPE_APPOINTMENT,
+	MAPI_FOLDER_TYPE_CONTACT,
+	MAPI_FOLDER_TYPE_MEMO,
+	MAPI_FOLDER_TYPE_JOURNAL,
+	MAPI_FOLDER_TYPE_TASK,
+	MAPI_FOLDER_TYPE_NOTE_HOMEPAGE,
+	MAPI_FOLDER_TYPE_UNKNOWN
+} ExchangeMAPIFolderType;
+
+typedef enum {
+	MAPI_PERSONAL_FOLDER,
+	MAPI_FAVOURITE_FOLDER,
+	MAPI_FOREIGN_FOLDER
+} ExchangeMAPIFolderCategory;
+
+typedef struct _ExchangeMAPIFolder {
+	/* We'll need this separation of 'owner' and 'user' when we do delegation */
+	gchar *owner_name;
+	gchar *owner_email;
+	gchar *user_name;
+	gchar *user_email;
+
+	/* Need this info - default calendars/address books/notes folders can't be deleted */
+	gboolean is_default;
+	guint32 default_type;
+
+	gchar *folder_name;
+	ExchangeMAPIFolderType container_class;
+	ExchangeMAPIFolderCategory category;
+	mapi_id_t folder_id;
+	mapi_id_t parent_folder_id;
+	guint32 child_count;
+	guint32 unread_count;
+	guint32 total;
+
+	/* reserved */
+	gpointer reserved1;
+	gpointer reserved2;
+	gpointer reserved3;
+} ExchangeMAPIFolder;
+
+ExchangeMAPIFolder *
+exchange_mapi_folder_new (const char *folder_name, const char *container_class, 
+			  ExchangeMAPIFolderCategory catgory, 
+			  mapi_id_t folder_id, mapi_id_t parent_folder_id, 
+			  uint32_t child_count, uint32_t unread_count, uint32_t total);
+ExchangeMAPIFolderType exchange_mapi_container_class (char *type);
+
+const gchar* exchange_mapi_folder_get_name (ExchangeMAPIFolder *folder);
+guint64 exchange_mapi_folder_get_fid (ExchangeMAPIFolder *folder);
+guint64 exchange_mapi_folder_get_parent_id (ExchangeMAPIFolder *folder);
+ExchangeMAPIFolderType exchange_mapi_folder_get_type (ExchangeMAPIFolder *folder);
+guint32 exchange_mapi_folder_get_unread_count (ExchangeMAPIFolder *folder);
+guint32 exchange_mapi_folder_get_total_count (ExchangeMAPIFolder *folder);
+
+gboolean exchange_mapi_folder_is_root (ExchangeMAPIFolder *folder);
+GSList * exchange_mapi_peek_folder_list (void);
+void exchange_mapi_folder_list_free (void);
+ExchangeMAPIFolder * exchange_mapi_folder_get_folder (mapi_id_t fid);
+void exchange_mapi_folder_list_add (ExchangeMAPIFolder *folder);
+
+#endif

Added: trunk/src/libexchangemapi/exchange-mapi-utils.c
==============================================================================
--- (empty file)
+++ trunk/src/libexchangemapi/exchange-mapi-utils.c	Wed Nov 19 04:28:20 2008
@@ -0,0 +1,606 @@
+/* -*- 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/>  
+ *
+ *
+ * Authors:
+ *    Suman Manjunath <msuman novell com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#include "exchange-mapi-utils.h"
+
+#ifdef G_OS_WIN32
+/* Undef the similar macro from pthread.h, it doesn't check if
+ * gmtime() returns NULL.
+ */
+#undef gmtime_r
+
+/* The gmtime() in Microsoft's C library is MT-safe */
+#define gmtime_r(tp,tmp) (gmtime(tp)?(*(tmp)=*gmtime(tp),(tmp)):0)
+#endif
+
+/* Converts a string from Windows-UTF8 to classic-UTF8.
+ * NOTE: If the returned value is non-NULL, the caller has to free the newly
+ * allocated string using g_free()
+ */
+gchar *
+utf8tolinux (const char *wstring)
+{
+	TALLOC_CTX 	*mem_ctx;
+	gchar		*newstr, *retval = NULL;
+
+	g_return_val_if_fail (wstring != NULL, NULL);
+
+	mem_ctx = talloc_init ("ExchangeMAPI_utf8tolinux");
+
+	newstr = windows_to_utf8(mem_ctx, wstring);
+
+	if (g_utf8_validate (newstr, -1, NULL)) 
+		retval = g_strdup (newstr);
+
+	talloc_free (mem_ctx);
+
+	return retval;
+}
+
+inline gchar *
+exchange_mapi_util_mapi_id_to_string (mapi_id_t id)
+{
+	return g_strdup_printf ("%016llX", id);
+}
+
+inline gboolean 
+exchange_mapi_util_mapi_id_from_string (const char *str, mapi_id_t *id)
+{
+	gint n = 0;
+
+	if (str && *str)
+		n = sscanf (str, "%016llX", id);
+
+	return (n == 1);
+}
+
+/* NOTE: We use the UID as a combination of the folder-id and the message-id. 
+ * Specifically, it is in this format: ("%016llX%016llX", fid, mid).
+ */
+inline gchar *
+exchange_mapi_util_mapi_ids_to_uid (mapi_id_t fid, mapi_id_t mid)
+{
+	return g_strdup_printf ("%016llX%016llX", fid, mid);
+}
+
+inline gboolean 
+exchange_mapi_util_mapi_ids_from_uid (const char *str, mapi_id_t *fid, mapi_id_t *mid)
+{
+	gint n = 0;
+
+	if (str && *str)
+		n = sscanf (str, "%016llX%016llX", fid, mid);
+
+	return (n == 2);
+}
+
+/*
+ * Retrieve the property value for a given SPropValue and property tag.  
+ *
+ * If the property type is a string: fetch PT_STRING8 then PT_UNICODE
+ * in case the desired property is not available in first choice.
+ *
+ * Fetch property normally for any others properties
+ */
+/* NOTE: For now, since this function has special significance only for
+ * 'string' type properties, callers should (preferably) use it for fetching 
+ * such properties alone. If callers are sure that proptag would, for instance, 
+ * return an 'int' or a 'systime', they should prefer get_SPropValue.
+ */
+const void *
+exchange_mapi_util_find_SPropVal_array_propval (struct SPropValue *values, uint32_t proptag)
+{
+	if (((proptag & 0xFFFF) == PT_STRING8) ||
+	    ((proptag & 0xFFFF) == PT_UNICODE)) {
+		const void	*str = NULL;
+
+		proptag = (proptag & 0xFFFF0000) | PT_UNICODE;
+		str = get_SPropValue(values, proptag);
+		if (str)
+			return str;
+
+		proptag = (proptag & 0xFFFF0000) | PT_STRING8;
+		str = get_SPropValue(values, proptag);
+		if (str)
+			return str;
+
+		return NULL;
+	} 
+
+	/* NOTE: Similar generalizations (if any) for other property types 
+	 * can be made here. 
+	 */
+
+	return (get_SPropValue(values, proptag));
+}
+
+/*
+ * Retrieve the property value for a given SRow and property tag.  
+ *
+ * If the property type is a string: fetch PT_STRING8 then PT_UNICODE
+ * in case the desired property is not available in first choice.
+ *
+ * Fetch property normally for any others properties
+ */
+/* NOTE: For now, since this function has special significance only for
+ * 'string' type properties, callers should (preferably) use it for fetching 
+ * such properties alone. If callers are sure that proptag would, for instance, 
+ * return an 'int' or a 'systime', they should prefer find_SPropValue_data.
+ */
+const void *
+exchange_mapi_util_find_row_propval (struct SRow *aRow, uint32_t proptag)
+{
+	if (((proptag & 0xFFFF) == PT_STRING8) ||
+	    ((proptag & 0xFFFF) == PT_UNICODE)) {
+		const void	*str = NULL;
+
+		proptag = (proptag & 0xFFFF0000) | PT_UNICODE;
+		str = find_SPropValue_data(aRow, proptag);
+		if (str)
+			return str;
+
+		proptag = (proptag & 0xFFFF0000) | PT_STRING8;
+		str = find_SPropValue_data(aRow, proptag);
+		if (str)
+			return str;
+
+		return NULL;
+	} 
+
+	/* NOTE: Similar generalizations (if any) for other property types 
+	 * can be made here. 
+	 */
+
+	return (find_SPropValue_data(aRow, proptag));
+}
+
+/*
+ * Retrieve the property value for a given mapi_SPropValue_array and property tag.  
+ *
+ * If the property type is a string: fetch PT_STRING8 then PT_UNICODE
+ * in case the desired property is not available in first choice.
+ *
+ * Fetch property normally for any others properties
+ */
+/* NOTE: For now, since this function has special significance only for
+ * 'string' type properties, callers should (preferably) use it for fetching 
+ * such properties alone. If callers are sure that proptag would, for instance, 
+ * return an 'int' or a 'systime', they should prefer find_mapi_SPropValue_data.
+ */
+const void *
+exchange_mapi_util_find_array_propval (struct mapi_SPropValue_array *properties, uint32_t proptag)
+{
+	if (((proptag & 0xFFFF) == PT_STRING8) ||
+	    ((proptag & 0xFFFF) == PT_UNICODE)) {
+		const void	*str = NULL;
+
+		proptag = (proptag & 0xFFFF0000) | PT_UNICODE;
+		str = find_mapi_SPropValue_data(properties, proptag);
+		if (str)
+			return str;
+
+		proptag = (proptag & 0xFFFF0000) | PT_STRING8;
+		str = find_mapi_SPropValue_data(properties, proptag);
+		if (str)
+			return str;
+
+		return NULL;
+	} 
+
+	/* NOTE: Similar generalizations (if any) for other property types 
+	 * can be made here. 
+	 */
+
+	return (find_mapi_SPropValue_data(properties, proptag));
+}
+
+ExchangeMAPIStream *
+exchange_mapi_util_find_stream (GSList *stream_list, uint32_t proptag)
+{
+	GSList *l = stream_list;
+
+	for (; l != NULL; l = l->next) {
+		ExchangeMAPIStream *stream = (ExchangeMAPIStream *) (l->data);
+		if (stream->proptag == proptag)
+			return stream;
+	}
+
+	return NULL;
+}
+
+void 
+exchange_mapi_util_free_attachment_list (GSList **attach_list)
+{
+	GSList *l = *attach_list;
+
+	if(!l)
+		return;
+
+	for (; l != NULL; l = l->next) {
+		ExchangeMAPIAttachment *attachment = (ExchangeMAPIAttachment *) (l->data);
+		/* FIXME: more stuff here */
+		g_free (attachment->lpProps);
+		exchange_mapi_util_free_stream_list (&(attachment->streams)); 
+		g_free (attachment);
+		attachment = NULL;
+	}
+	g_slist_free (l);
+	l = NULL;
+}
+
+void 
+exchange_mapi_util_free_recipient_list (GSList **recip_list)
+{
+	GSList *l = *recip_list;
+
+	if(!l)
+		return;
+
+	for (; l != NULL; l = l->next) {
+		ExchangeMAPIRecipient *recipient = (ExchangeMAPIRecipient *) (l->data);
+		if (recipient->in.ext_cValues)
+			g_free (recipient->in.ext_lpProps);
+		if (recipient->in.req_cValues)
+			g_free (recipient->in.req_lpProps);
+/*		if (recipient->out.all_cValues)
+			g_free (recipient->out.all_lpProps);
+*/		g_free (recipient);
+	}
+	g_slist_free (l);
+	l = NULL;
+}
+
+void 
+exchange_mapi_util_free_stream_list (GSList **stream_list)
+{
+	GSList *l = *stream_list;
+
+	if(!l)
+		return;
+
+	for (; l != NULL; l = l->next) {
+		ExchangeMAPIStream *stream = (ExchangeMAPIStream *) (l->data);
+		g_byte_array_free (stream->value, TRUE);
+		stream->value = NULL;
+		g_free (stream);
+		stream = NULL;
+	}
+	g_slist_free (l);
+	l = NULL;
+}
+
+const gchar *
+exchange_mapi_util_ex_to_smtp (const gchar *ex_address)
+{
+	enum MAPISTATUS 	retval;
+	TALLOC_CTX 		*mem_ctx;
+	struct SPropTagArray	*SPropTagArray;
+	struct SRowSet 		*SRowSet = NULL;
+	struct FlagList		*flaglist = NULL;
+	const gchar 		*str_array[2];
+	const gchar 		*smtp_addr = NULL;
+
+	g_return_val_if_fail (ex_address != NULL, NULL);
+
+	str_array[0] = ex_address;
+	str_array[1] = NULL;
+
+	mem_ctx = talloc_init("ExchangeMAPI_EXtoSMTP");
+
+	SPropTagArray = set_SPropTagArray(mem_ctx, 0x2,
+					  PR_SMTP_ADDRESS,
+					  PR_SMTP_ADDRESS_UNICODE);
+
+	retval = ResolveNames((const char **)str_array, SPropTagArray, &SRowSet, &flaglist, 0);
+	if (retval != MAPI_E_SUCCESS)
+		retval = ResolveNames((const char **)str_array, SPropTagArray, &SRowSet, &flaglist, MAPI_UNICODE);
+
+	if (retval == MAPI_E_SUCCESS && SRowSet && SRowSet->cRows == 1) {
+		smtp_addr = (const char *) find_SPropValue_data(SRowSet->aRow, PR_SMTP_ADDRESS);
+		if (!smtp_addr)
+			smtp_addr = (const char *) find_SPropValue_data(SRowSet->aRow, PR_SMTP_ADDRESS_UNICODE);
+	}
+
+	talloc_free (mem_ctx);
+
+	return smtp_addr;
+}
+
+void
+exchange_mapi_debug_property_dump (struct mapi_SPropValue_array *properties)
+{
+	gint i = 0;
+
+	for (i = 0; i < properties->cValues; i++) { 
+		for (i = 0; i < properties->cValues; i++) {
+			struct mapi_SPropValue *lpProp = &properties->lpProps[i];
+			const char *tmp =  get_proptag_name (lpProp->ulPropTag);
+			char t_str[26];
+			gint j = 0;
+			if (tmp && *tmp)
+				g_print("\n%s \t",tmp);
+			else
+				g_print("\n0x%08X \t", lpProp->ulPropTag);
+			switch(lpProp->ulPropTag & 0xFFFF) {
+			case PT_BOOLEAN:
+				g_print(" (bool) - %d", (bool) lpProp->value.b);
+				break;
+			case PT_I2:
+				g_print(" (uint16_t) - %d", lpProp->value.i);
+				break;
+			case PT_LONG:
+				g_print(" (long) - %u", lpProp->value.l);
+				break;
+			case PT_DOUBLE:
+				g_print (" (double) -  %lf", (double)lpProp->value.dbl);
+				break;
+			case PT_I8:
+				g_print (" (int) - 0x%016lX", lpProp->value.d);
+				break;
+			case PT_SYSTIME: {
+					struct timeval t;
+					struct tm tm;
+					if (get_mapi_SPropValue_array_date_timeval (&t, properties, lpProp->ulPropTag) == MAPI_E_SUCCESS) {
+						gmtime_r (&(t.tv_sec), &tm);
+						strftime (t_str, 26, "%Y-%m-%dT%H:%M:%SZ", &tm);
+						g_print (" (struct FILETIME *) - %p\t (struct timeval) %s\t", &lpProp->value.ft, t_str);
+					}
+				}
+				break;
+			case PT_ERROR:
+				g_print (" (error) - "/* , lpProp->value.err */);
+				break;
+			case PT_STRING8:
+				g_print(" (string) - %s", lpProp->value.lpszA ? lpProp->value.lpszA : "null" );
+				break;
+			case PT_UNICODE:
+				if (lpProp)
+					g_print(" (unicodestring) - %s", lpProp->value.lpszW ? lpProp->value.lpszW : lpProp->value.lpszA ? lpProp->value.lpszA : "null");
+				break;
+			case PT_BINARY:
+				g_print(" (struct SBinary_short *) - %p Binary data follows: \n", &lpProp->value.bin);
+				for (j = 0; j < lpProp->value.bin.cb; j++)
+					g_print("0x%02X ", lpProp->value.bin.lpb[j]);
+				break;
+			case PT_MV_STRING8:
+ 				g_print(" (struct mapi_SLPSTRArray *) - %p", &lpProp->value.MVszA);
+				break;
+			default:
+				g_print(" - NONE NULL");
+			}
+		}
+	}
+}
+
+
+/* Attention: Devs at work ;-) */
+
+static void 
+exchange_mapi_util_bin_append_uint16 (TALLOC_CTX *mem_ctx, struct SBinary *bin, const uint16_t val)
+{
+	uint8_t *ptr = NULL;
+
+	bin->lpb = talloc_realloc (mem_ctx, bin->lpb, uint8_t, bin->cb + 2);
+	bin->cb += 2;
+
+	ptr = bin->lpb + bin->cb - 2;
+
+	*ptr++ = ( val        & 0xFF);
+	*ptr++ = ((val >>  8) & 0xFF);
+}
+
+static void 
+exchange_mapi_util_bin_append_uint32 (TALLOC_CTX *mem_ctx, struct SBinary *bin, const uint32_t val)
+{
+	uint8_t *ptr = NULL;
+
+	bin->lpb = talloc_realloc (mem_ctx, bin->lpb, uint8_t, bin->cb + 4);
+	bin->cb += 4;
+
+	ptr = bin->lpb + bin->cb - 4;
+
+	*ptr++ = ( val        & 0xFF);
+	*ptr++ = ((val >>  8) & 0xFF);
+	*ptr++ = ((val >> 16) & 0xFF);
+	*ptr++ = ((val >> 24) & 0xFF);
+}
+
+static void 
+exchange_mapi_util_bin_append_string (TALLOC_CTX *mem_ctx, struct SBinary *bin, const char *val)
+{
+	size_t len = strlen (val);
+	char *ptr = NULL;
+
+	bin->lpb = talloc_realloc (mem_ctx, bin->lpb, uint8_t, bin->cb + (len + 1));
+	bin->cb += (len + 1);
+
+	ptr = (char *) bin->lpb + bin->cb - (len + 1);
+
+	strcpy (ptr, val);
+}
+
+static void 
+exchange_mapi_util_bin_append_unicode (TALLOC_CTX *mem_ctx, struct SBinary *bin, const char *val)
+{
+	/* WRITE ME */
+}
+
+static void 
+exchange_mapi_util_bin_append_val (TALLOC_CTX *mem_ctx, struct SBinary *bin, const uint8_t *val, size_t len)
+{
+	uint8_t *ptr = NULL;
+
+	bin->lpb = talloc_realloc (mem_ctx, bin->lpb, uint8_t, bin->cb + len);
+	bin->cb += len;
+
+	ptr = bin->lpb + bin->cb - len;
+
+	memcpy (ptr, val, len);
+}
+
+static const uint8_t MAPI_ONE_OFF_UID[] = {
+	0x81, 0x2b, 0x1f, 0xa4, 0xbe, 0xa3, 0x10, 0x19,
+	0x9d, 0x6e, 0x00, 0xdd, 0x01, 0x0f, 0x54, 0x02
+};
+
+#define MAPI_ONE_OFF_UNICODE	  0x8000
+#define MAPI_ONE_OFF_NO_RICH_INFO 0x0001
+#define MAPI_ONE_OFF_MYSTERY_FLAG 0x1000
+
+/**
+ * e2k_entryid_generate_oneoff:
+ * @display_name: the display name of the user
+ * @email: the email address
+ * @unicode: %TRUE to generate a Unicode ENTRYID (in which case
+ * @display_name should be UTF-8), %FALSE for an ASCII ENTRYID.
+ *
+ * Constructs a "one-off" ENTRYID value that can be used as a MAPI
+ * recipient (eg, for a message forwarding server-side rule),
+ * corresponding to @display_name and @email.
+ *
+ * Return value: the recipient ENTRYID
+ **/
+struct SBinary *
+exchange_mapi_util_entryid_generate_oneoff (TALLOC_CTX *mem_ctx, const char *display_name, const char *email, gboolean unicode)
+{
+	struct SBinary *entryid;
+
+	entryid = talloc_zero (mem_ctx, struct SBinary);
+
+	exchange_mapi_util_bin_append_uint32 (mem_ctx, entryid, 0);
+	exchange_mapi_util_bin_append_val (mem_ctx, entryid, MAPI_ONE_OFF_UID, sizeof(MAPI_ONE_OFF_UID));
+	exchange_mapi_util_bin_append_uint16 (mem_ctx, entryid, 0);
+	exchange_mapi_util_bin_append_uint16 (mem_ctx, entryid,
+		MAPI_ONE_OFF_NO_RICH_INFO |
+		MAPI_ONE_OFF_MYSTERY_FLAG |
+		(unicode ? MAPI_ONE_OFF_UNICODE : 0));
+
+	if (unicode) {
+		exchange_mapi_util_bin_append_unicode (mem_ctx, entryid, display_name);
+		exchange_mapi_util_bin_append_unicode (mem_ctx, entryid, "SMTP");
+		exchange_mapi_util_bin_append_unicode (mem_ctx, entryid, email);
+	} else {
+		exchange_mapi_util_bin_append_string (mem_ctx, entryid, display_name);
+		exchange_mapi_util_bin_append_string (mem_ctx, entryid, "SMTP");
+		exchange_mapi_util_bin_append_string (mem_ctx, entryid, email);
+	}
+
+	return entryid;
+}
+
+static const uint8_t MAPI_LOCAL_UID[] = {
+	0xdc, 0xa7, 0x40, 0xc8, 0xc0, 0x42, 0x10, 0x1a,
+	0xb4, 0xb9, 0x08, 0x00, 0x2b, 0x2f, 0xe1, 0x82
+};
+
+/**
+ * e2k_entryid_generate_local:
+ * @exchange_dn: the Exchange 5.5-style DN of the local user
+ *
+ * Constructs an ENTRYID value that can be used as a MAPI
+ * recipient (eg, for a message forwarding server-side rule),
+ * corresponding to the local user identified by @exchange_dn.
+ *
+ * Return value: the recipient ENTRYID
+ **/
+struct SBinary *
+exchange_mapi_util_entryid_generate_local (TALLOC_CTX *mem_ctx, const char *exchange_dn)
+{
+	struct SBinary *entryid;
+
+	entryid = talloc_zero (mem_ctx, struct SBinary);
+
+	exchange_mapi_util_bin_append_uint32 (mem_ctx, entryid, 0);
+	exchange_mapi_util_bin_append_val (mem_ctx, entryid, MAPI_LOCAL_UID, sizeof(MAPI_LOCAL_UID));
+	exchange_mapi_util_bin_append_uint16 (mem_ctx, entryid, 1);
+	exchange_mapi_util_bin_append_uint16 (mem_ctx, entryid, 0);
+	exchange_mapi_util_bin_append_string (mem_ctx, entryid, exchange_dn);
+
+	return entryid;
+}
+
+/**
+ * exchange_lf_to_crlf:
+ * @in: input text in UNIX ("\n") format
+ *
+ * Creates a copy of @in with all LFs converted to CRLFs.
+ *
+ * Return value: the converted text, which the caller must free.
+ **/
+char *
+exchange_lf_to_crlf (const char *in)
+{
+	int len;
+	const char *s;
+	char *out, *d;
+
+	g_return_val_if_fail (in != NULL, NULL);
+
+	len = strlen (in);
+	for (s = strchr (in, '\n'); s; s = strchr (s + 1, '\n'))
+		len++;
+
+	out = g_malloc (len + 1);
+	for (s = in, d = out; *s; s++) {
+		if (*s == '\n')
+			*d++ = '\r';
+		*d++ = *s;
+	}
+	*d = '\0';
+
+	return out;
+}
+
+/**
+ * exchange_crlf_to_lf:
+ * @in: input text in network ("\r\n") format
+ *
+ * Creates a copy of @in with all CRLFs converted to LFs. (Actually,
+ * it just strips CRs, so any raw CRs will be removed.)
+ *
+ * Return value: the converted text, which the caller must free.
+ **/
+char *
+exchange_crlf_to_lf (const char *in)
+{
+	int len;
+	const char *s;
+	char *out;
+	GString *str;
+
+	g_return_val_if_fail (in != NULL, NULL);
+
+	str = g_string_new ("");
+
+	len = strlen (in);
+	for (s = in; *s; s++) {
+		if (*s != '\r')
+			str = g_string_append_c (str, *s);
+	}
+
+	out = str->str;
+	g_string_free (str, FALSE);
+
+	return out;
+}
+

Added: trunk/src/libexchangemapi/exchange-mapi-utils.h
==============================================================================
--- (empty file)
+++ trunk/src/libexchangemapi/exchange-mapi-utils.h	Wed Nov 19 04:28:20 2008
@@ -0,0 +1,76 @@
+/* -*- 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/>  
+ *
+ *
+ * Authors:
+ *    Suman Manjunath <msuman novell com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef EXCHANGE_MAPI_UTILS_H
+#define EXCHANGE_MAPI_UTILS_H 
+
+#include "exchange-mapi-connection.h"
+
+gchar *
+utf8tolinux (const char *wstring);
+
+gchar *
+exchange_mapi_util_mapi_id_to_string (mapi_id_t id);
+gboolean 
+exchange_mapi_util_mapi_id_from_string (const char *str, mapi_id_t *id);
+
+gchar *
+exchange_mapi_util_mapi_ids_to_uid (mapi_id_t fid, mapi_id_t mid);
+gboolean 
+exchange_mapi_util_mapi_ids_from_uid (const char *str, mapi_id_t *fid, mapi_id_t *mid);
+
+const void *
+exchange_mapi_util_find_SPropVal_array_propval (struct SPropValue *values, uint32_t proptag);
+const void *
+exchange_mapi_util_find_row_propval (struct SRow *aRow, uint32_t proptag);
+const void *
+exchange_mapi_util_find_array_propval (struct mapi_SPropValue_array *properties, uint32_t proptag);
+
+ExchangeMAPIStream *
+exchange_mapi_util_find_stream (GSList *stream_list, uint32_t proptag);
+
+void 
+exchange_mapi_util_free_attachment_list (GSList **attach_list);
+void 
+exchange_mapi_util_free_recipient_list (GSList **recip_list);
+void 
+exchange_mapi_util_free_stream_list (GSList **stream_list);
+
+const gchar *
+exchange_mapi_util_ex_to_smtp (const gchar *ex_address);
+
+void
+exchange_mapi_debug_property_dump (struct mapi_SPropValue_array *properties);
+
+struct SBinary *
+exchange_mapi_util_entryid_generate_oneoff (TALLOC_CTX *mem_ctx, const char *display_name, const char *email, gboolean unicode);
+struct SBinary *
+exchange_mapi_util_entryid_generate_local (TALLOC_CTX *mem_ctx, const char *exchange_dn);
+
+char *
+exchange_lf_to_crlf (const char *in);
+char *
+exchange_crlf_to_lf (const char *in);
+
+#endif
+

Added: trunk/src/libexchangemapi/libexchangemapi.pc.in
==============================================================================
--- (empty file)
+++ trunk/src/libexchangemapi/libexchangemapi.pc.in	Wed Nov 19 04:28:20 2008
@@ -0,0 +1,18 @@
+prefix= prefix@
+exec_prefix= exec_prefix@
+libdir= libdir@
+includedir= includedir@
+datarootdir= datarootdir@
+datadir= datadir@
+
+idldir= idldir@
+IDL_INCLUDES=-I${idldir} @IDL_INCLUDES@
+
+privincludedir= privincludedir@
+
+Name: libexchangemapi
+Description: Client library for accessing Exchange with libmapi
+Version: @VERSION@
+Requires: @LIBMAPI@
+Libs: -L${libdir} -lexchangemapi-1.0 -lmapi
+Cflags: -I${privincludedir}/mapi

Added: trunk/src/libexchangemapi/tz-ical-to-mapi
==============================================================================
--- (empty file)
+++ trunk/src/libexchangemapi/tz-ical-to-mapi	Wed Nov 19 04:28:20 2008
@@ -0,0 +1,399 @@
+UTC~~~GMT Standard Time
+/softwarestudio.org/Tzfile/Africa/Abidjan~~~Greenwich Standard Time
+/softwarestudio.org/Tzfile/Africa/Accra~~~Greenwich Standard Time
+/softwarestudio.org/Tzfile/Africa/Addis_Ababa~~~E. Africa Standard Time
+/softwarestudio.org/Tzfile/Africa/Algiers~~~W. Central Africa Standard Time
+/softwarestudio.org/Tzfile/Africa/Asmara~~~E. Africa Standard Time
+/softwarestudio.org/Tzfile/Africa/Bamako~~~Greenwich Standard Time
+/softwarestudio.org/Tzfile/Africa/Bangui~~~W. Central Africa Standard Time
+/softwarestudio.org/Tzfile/Africa/Banjul~~~Greenwich Standard Time
+/softwarestudio.org/Tzfile/Africa/Bissau~~~Greenwich Standard Time
+/softwarestudio.org/Tzfile/Africa/Blantyre~~~South Africa Standard Time
+/softwarestudio.org/Tzfile/Africa/Brazzaville~~~W. Central Africa Standard Time
+/softwarestudio.org/Tzfile/Africa/Bujumbura~~~South Africa Standard Time
+/softwarestudio.org/Tzfile/Africa/Cairo~~~Egypt Standard Time
+/softwarestudio.org/Tzfile/Africa/Casablanca~~~Greenwich Standard Time
+/softwarestudio.org/Tzfile/Africa/Ceuta~~~W. Central Africa Standard Time
+/softwarestudio.org/Tzfile/Africa/Conakry~~~Greenwich Standard Time
+/softwarestudio.org/Tzfile/Africa/Dakar~~~Greenwich Standard Time
+/softwarestudio.org/Tzfile/Africa/Dar_es_Salaam~~~E. Africa Standard Time
+/softwarestudio.org/Tzfile/Africa/Djibouti~~~E. Africa Standard Time
+/softwarestudio.org/Tzfile/Africa/Douala~~~W. Central Africa Standard Time
+/softwarestudio.org/Tzfile/Africa/El_Aaiun~~~Greenwich Standard Time
+/softwarestudio.org/Tzfile/Africa/Freetown~~~Greenwich Standard Time
+/softwarestudio.org/Tzfile/Africa/Gaborone~~~South Africa Standard Time
+/softwarestudio.org/Tzfile/Africa/Harare~~~South Africa Standard Time
+/softwarestudio.org/Tzfile/Africa/Johannesburg~~~South Africa Standard Time
+/softwarestudio.org/Tzfile/Africa/Kampala~~~E. Africa Standard Time
+/softwarestudio.org/Tzfile/Africa/Khartoum~~~E. Africa Standard Time
+/softwarestudio.org/Tzfile/Africa/Kigali~~~Egypt Standard Time
+/softwarestudio.org/Tzfile/Africa/Kinshasa~~~W. Central Africa Standard Time
+/softwarestudio.org/Tzfile/Africa/Lagos~~~Greenwich Standard Time
+/softwarestudio.org/Tzfile/Africa/Libreville~~~W. Central Africa Standard Time
+/softwarestudio.org/Tzfile/Africa/Lome~~~Greenwich Standard Time
+/softwarestudio.org/Tzfile/Africa/Luanda~~~W. Central Africa Standard Time
+/softwarestudio.org/Tzfile/Africa/Lubumbashi~~~South Africa Standard Time
+/softwarestudio.org/Tzfile/Africa/Lusaka~~~South Africa Standard Time
+/softwarestudio.org/Tzfile/Africa/Malabo~~~W. Central Africa Standard Time
+/softwarestudio.org/Tzfile/Africa/Maputo~~~South Africa Standard Time
+/softwarestudio.org/Tzfile/Africa/Maseru~~~South Africa Standard Time
+/softwarestudio.org/Tzfile/Africa/Mbabane~~~South Africa Standard Time
+/softwarestudio.org/Tzfile/Africa/Mogadishu~~~E. Africa Standard Time
+/softwarestudio.org/Tzfile/Africa/Monrovia~~~Greenwich Standard Time
+/softwarestudio.org/Tzfile/Africa/Nairobi~~~E. Africa Standard Time
+/softwarestudio.org/Tzfile/Africa/Ndjamena~~~W. Central Africa Standard Time
+/softwarestudio.org/Tzfile/Africa/Niamey~~~W. Central Africa Standard Time
+/softwarestudio.org/Tzfile/Africa/Nouakchott~~~Greenwich Standard Time
+/softwarestudio.org/Tzfile/Africa/Ouagadougou~~~Greenwich Standard Time
+/softwarestudio.org/Tzfile/Africa/Porto-Novo~~~W. Central Africa Standard Time
+/softwarestudio.org/Tzfile/Africa/Sao_Tome~~~Cape Verde Standard Time
+/softwarestudio.org/Tzfile/Africa/Tripoli~~~Egypt Standard Time
+/softwarestudio.org/Tzfile/Africa/Tunis~~~W. Central Africa Standard Time
+/softwarestudio.org/Tzfile/Africa/Windhoek~~~Namibia Standard Time
+/softwarestudio.org/Tzfile/America/Adak~~~Hawaiian Standard Time
+/softwarestudio.org/Tzfile/America/Anchorage~~~Alaskan Standard Time
+/softwarestudio.org/Tzfile/America/Anguilla~~~SA Western Standard Time
+/softwarestudio.org/Tzfile/America/Antigua~~~SA Western Standard Time
+/softwarestudio.org/Tzfile/America/Araguaina~~~E. South America Standard Time
+/softwarestudio.org/Tzfile/America/Argentina/Buenos_Aires~~~SA Eastern Standard Time
+/softwarestudio.org/Tzfile/America/Argentina/Catamarca~~~SA Eastern Standard Time
+/softwarestudio.org/Tzfile/America/Argentina/Cordoba~~~SA Eastern Standard Time
+/softwarestudio.org/Tzfile/America/Argentina/Jujuy~~~SA Eastern Standard Time
+/softwarestudio.org/Tzfile/America/Argentina/La_Rioja~~~SA Eastern Standard Time
+/softwarestudio.org/Tzfile/America/Argentina/Mendoza~~~SA Eastern Standard Time
+/softwarestudio.org/Tzfile/America/Argentina/Rio_Gallegos~~~SA Eastern Standard Time
+/softwarestudio.org/Tzfile/America/Argentina/San_Juan~~~SA Eastern Standard Time
+/softwarestudio.org/Tzfile/America/Argentina/Tucuman~~~SA Eastern Standard Time
+/softwarestudio.org/Tzfile/America/Argentina/Ushuaia~~~SA Eastern Standard Time
+/softwarestudio.org/Tzfile/America/Aruba~~~Venezuela Standard Time
+/softwarestudio.org/Tzfile/America/Asuncion~~~SA Eastern Standard Time
+/softwarestudio.org/Tzfile/America/Atikokan~~~US Eastern Standard Time
+/softwarestudio.org/Tzfile/America/Bahia~~~E. South America Standard Time
+/softwarestudio.org/Tzfile/America/Barbados~~~SA Western Standard Time
+/softwarestudio.org/Tzfile/America/Belem~~~E. South America Standard Time
+/softwarestudio.org/Tzfile/America/Belize~~~Mexico Standard Time
+/softwarestudio.org/Tzfile/America/Blanc-Sablon~~~Atlantic Standard Time
+/softwarestudio.org/Tzfile/America/Boa_Vista~~~SA Western Standard Time
+/softwarestudio.org/Tzfile/America/Bogota~~~SA Pacific Standard Time
+/softwarestudio.org/Tzfile/America/Boise~~~US Mountain Standard Time
+/softwarestudio.org/Tzfile/America/Cambridge_Bay~~~Mountain Standard Time
+/softwarestudio.org/Tzfile/America/Campo_Grande~~~E. South America Standard Time
+/softwarestudio.org/Tzfile/America/Cancun~~~Central America Standard Time
+/softwarestudio.org/Tzfile/America/Caracas~~~Venezuela Standard Time
+/softwarestudio.org/Tzfile/America/Cayenne~~~E. South America Standard Time
+/softwarestudio.org/Tzfile/America/Cayman~~~SA Pacific Standard Time
+/softwarestudio.org/Tzfile/America/Chicago~~~Central Standard Time
+/softwarestudio.org/Tzfile/America/Chihuahua~~~Mexico Standard Time 2
+/softwarestudio.org/Tzfile/America/Costa_Rica~~~Central America Standard Time
+/softwarestudio.org/Tzfile/America/Cuiaba~~~E. South America Standard Time
+/softwarestudio.org/Tzfile/America/Curacao~~~Venezuela Standard Time
+/softwarestudio.org/Tzfile/America/Danmarkshavn~~~GMT Standard Time
+/softwarestudio.org/Tzfile/America/Dawson~~~Pacific Standard Time
+/softwarestudio.org/Tzfile/America/Dawson_Creek~~~Mountain Standard Time
+/softwarestudio.org/Tzfile/America/Denver~~~Mountain Standard Time
+/softwarestudio.org/Tzfile/America/Detroit~~~Eastern Standard Time
+/softwarestudio.org/Tzfile/America/Dominica~~~SA Western Standard Time
+/softwarestudio.org/Tzfile/America/Edmonton~~~Mountain Standard Time
+/softwarestudio.org/Tzfile/America/Eirunepe~~~SA Pacific Standard Time
+/softwarestudio.org/Tzfile/America/El_Salvador~~~Central America Standard Time
+/softwarestudio.org/Tzfile/America/Fortaleza~~~E. South America Standard Time
+/softwarestudio.org/Tzfile/America/Glace_Bay~~~Atlantic Standard Time
+/softwarestudio.org/Tzfile/America/Godthab~~~Greenland Standard Time
+/softwarestudio.org/Tzfile/America/Goose_Bay~~~Atlantic Standard Time
+/softwarestudio.org/Tzfile/America/Grand_Turk~~~SA Pacific Standard Time
+/softwarestudio.org/Tzfile/America/Grenada~~~SA Western Standard Time
+/softwarestudio.org/Tzfile/America/Guadeloupe~~~SA Western Standard Time
+/softwarestudio.org/Tzfile/America/Guatemala~~~Central America Standard Time
+/softwarestudio.org/Tzfile/America/Guayaquil~~~SA Pacific Standard Time
+/softwarestudio.org/Tzfile/America/Guyana~~~Venezuela Standard Time
+/softwarestudio.org/Tzfile/America/Halifax~~~Atlantic Standard Time
+/softwarestudio.org/Tzfile/America/Havana~~~SA Pacific Standard Time
+/softwarestudio.org/Tzfile/America/Hermosillo~~~Mexico Standard Time 2
+/softwarestudio.org/Tzfile/America/Indiana/Indianapolis~~~US Eastern Standard Time
+/softwarestudio.org/Tzfile/America/Indiana/Knox~~~Canada Central Standard Time
+/softwarestudio.org/Tzfile/America/Indiana/Marengo~~~US Eastern Standard Time
+/softwarestudio.org/Tzfile/America/Indiana/Petersburg~~~US Eastern Standard Time
+/softwarestudio.org/Tzfile/America/Indiana/Tell_City~~~Canada Central Standard Time
+/softwarestudio.org/Tzfile/America/Indiana/Vevay~~~US Eastern Standard Time
+/softwarestudio.org/Tzfile/America/Indiana/Vincennes~~~US Eastern Standard Time
+/softwarestudio.org/Tzfile/America/Indiana/Winamac~~~US Eastern Standard Time
+/softwarestudio.org/Tzfile/America/Inuvik~~~Mountain Standard Time
+/softwarestudio.org/Tzfile/America/Iqaluit~~~Eastern Standard Time
+/softwarestudio.org/Tzfile/America/Jamaica~~~SA Pacific Standard Time
+/softwarestudio.org/Tzfile/America/Juneau~~~Alaskan Standard Time
+/softwarestudio.org/Tzfile/America/Kentucky/Louisville~~~US Eastern Standard Time
+/softwarestudio.org/Tzfile/America/Kentucky/Monticello~~~US Eastern Standard Time
+/softwarestudio.org/Tzfile/America/La_Paz~~~SA Western Standard Time
+/softwarestudio.org/Tzfile/America/Lima~~~SA Pacific Standard Time
+/softwarestudio.org/Tzfile/America/Los_Angeles~~~Pacific Standard Time
+/softwarestudio.org/Tzfile/America/Maceio~~~E. South America Standard Time
+/softwarestudio.org/Tzfile/America/Managua~~~Central America Standard Time
+/softwarestudio.org/Tzfile/America/Manaus~~~Central Brazilian Standard Time
+/softwarestudio.org/Tzfile/America/Martinique~~~SA Western Standard Time
+/softwarestudio.org/Tzfile/America/Mazatlan~~~Mountain Standard Time (Mexico)
+/softwarestudio.org/Tzfile/America/Menominee~~~Central Standard Time
+/softwarestudio.org/Tzfile/America/Merida~~~Central America Standard Time
+/softwarestudio.org/Tzfile/America/Mexico_City~~~Mexico Standard Time
+/softwarestudio.org/Tzfile/America/Miquelon~~~Greenland Standard Time
+/softwarestudio.org/Tzfile/America/Moncton~~~Atlantic Standard Time
+/softwarestudio.org/Tzfile/America/Monterrey~~~Central Standard Time (Mexico)
+/softwarestudio.org/Tzfile/America/Montevideo~~~Montevideo Standard Time
+/softwarestudio.org/Tzfile/America/Montreal~~~Eastern Standard Time
+/softwarestudio.org/Tzfile/America/Montserrat~~~SA Western Standard Time
+/softwarestudio.org/Tzfile/America/Nassau~~~Eastern Standard Time
+/softwarestudio.org/Tzfile/America/New_York~~~Eastern Standard Time
+/softwarestudio.org/Tzfile/America/Nipigon~~~Eastern Standard Time
+/softwarestudio.org/Tzfile/America/Nome~~~Alaskan Standard Time
+/softwarestudio.org/Tzfile/America/Noronha~~~Mid-Atlantic Standard Time
+/softwarestudio.org/Tzfile/America/North_Dakota/Center~~~Central Standard Time
+/softwarestudio.org/Tzfile/America/North_Dakota/New_Salem~~~Central Standard Time
+/softwarestudio.org/Tzfile/America/Panama~~~SA Pacific Standard Time
+/softwarestudio.org/Tzfile/America/Pangnirtung~~~Eastern Standard Time
+/softwarestudio.org/Tzfile/America/Paramaribo~~~Venezuela Standard Time
+/softwarestudio.org/Tzfile/America/Phoenix~~~US Mountain Standard Time
+/softwarestudio.org/Tzfile/America/Port-au-Prince~~~SA Western Standard Time
+/softwarestudio.org/Tzfile/America/Port_of_Spain~~~SA Western Standard Time
+/softwarestudio.org/Tzfile/America/Porto_Velho~~~SA Western Standard Time
+/softwarestudio.org/Tzfile/America/Puerto_Rico~~~SA Western Standard Time
+/softwarestudio.org/Tzfile/America/Rainy_River~~~Canada Central Standard Time
+/softwarestudio.org/Tzfile/America/Rankin_Inlet~~~Canada Central Standard Time
+/softwarestudio.org/Tzfile/America/Recife~~~E. South America Standard Time
+/softwarestudio.org/Tzfile/America/Regina~~~Central America Standard Time
+/softwarestudio.org/Tzfile/America/Resolute~~~Eastern Standard Time
+/softwarestudio.org/Tzfile/America/Rio_Branco~~~SA Pacific Standard Time
+/softwarestudio.org/Tzfile/America/Santiago~~~Pacific SA Standard Time
+/softwarestudio.org/Tzfile/America/Santo_Domingo~~~SA Western Standard Time
+/softwarestudio.org/Tzfile/America/Sao_Paulo~~~Mid-Atlantic Standard Time
+/softwarestudio.org/Tzfile/America/Scoresbysund~~~Azores Standard Time
+/softwarestudio.org/Tzfile/America/Shiprock~~~US Mountain Standard Time
+/softwarestudio.org/Tzfile/America/St_Johns~~~Newfoundland Standard Time
+/softwarestudio.org/Tzfile/America/St_Kitts~~~SA Western Standard Time
+/softwarestudio.org/Tzfile/America/St_Lucia~~~SA Western Standard Time
+/softwarestudio.org/Tzfile/America/St_Thomas~~~SA Western Standard Time
+/softwarestudio.org/Tzfile/America/St_Vincent~~~SA Western Standard Time
+/softwarestudio.org/Tzfile/America/Swift_Current~~~Central Standard Time
+/softwarestudio.org/Tzfile/America/Tegucigalpa~~~Central America Standard Time
+/softwarestudio.org/Tzfile/America/Thule~~~Atlantic Standard Time
+/softwarestudio.org/Tzfile/America/Thunder_Bay~~~Eastern Standard Time
+/softwarestudio.org/Tzfile/America/Tijuana~~~Pacific Standard Time (Mexico)
+/softwarestudio.org/Tzfile/America/Toronto~~~Eastern Standard Time
+/softwarestudio.org/Tzfile/America/Tortola~~~SA Western Standard Time
+/softwarestudio.org/Tzfile/America/Vancouver~~~Pacific Standard Time
+/softwarestudio.org/Tzfile/America/Whitehorse~~~Pacific Standard Time
+/softwarestudio.org/Tzfile/America/Winnipeg~~~Canada Central Standard Time
+/softwarestudio.org/Tzfile/America/Yakutat~~~Alaskan Standard Time
+/softwarestudio.org/Tzfile/America/Yellowknife~~~Mountain Standard Time
+/softwarestudio.org/Tzfile/Antarctica/Casey~~~GMT Standard Time
+/softwarestudio.org/Tzfile/Antarctica/Davis~~~SE Asia Standard Time
+/softwarestudio.org/Tzfile/Antarctica/DumontDUrville~~~West Pacific Standard Time
+/softwarestudio.org/Tzfile/Antarctica/Mawson~~~GMT Standard Time
+/softwarestudio.org/Tzfile/Antarctica/McMurdo~~~Tonga Standard Time
+/softwarestudio.org/Tzfile/Antarctica/Palmer~~~Greenland Standard Time
+/softwarestudio.org/Tzfile/Antarctica/Rothera~~~GMT Standard Time
+/softwarestudio.org/Tzfile/Antarctica/South_Pole~~~GMT Standard Time
+/softwarestudio.org/Tzfile/Antarctica/Syowa~~~GMT Standard Time
+/softwarestudio.org/Tzfile/Antarctica/Vostok~~~GMT Standard Time
+/softwarestudio.org/Tzfile/Arctic/Longyearbyen~~~Central Europe Standard Time
+/softwarestudio.org/Tzfile/Asia/Aden~~~Arab Standard Time
+/softwarestudio.org/Tzfile/Asia/Almaty~~~N. Central Asia Standard Time
+/softwarestudio.org/Tzfile/Asia/Amman~~~Jordan Standard Time
+/softwarestudio.org/Tzfile/Asia/Anadyr~~~Fiji Standard Time
+/softwarestudio.org/Tzfile/Asia/Aqtau~~~Ekaterinburg Standard Time
+/softwarestudio.org/Tzfile/Asia/Aqtobe~~~Ekaterinburg Standard Time
+/softwarestudio.org/Tzfile/Asia/Ashgabat~~~Ekaterinburg Standard Time
+/softwarestudio.org/Tzfile/Asia/Baghdad~~~Arabic Standard Time
+/softwarestudio.org/Tzfile/Asia/Bahrain~~~Arab Standard Time
+/softwarestudio.org/Tzfile/Asia/Baku~~~Azerbaijan Standard Time
+/softwarestudio.org/Tzfile/Asia/Bangkok~~~SE Asia Standard Time
+/softwarestudio.org/Tzfile/Asia/Beijing~~~China Standard Time
+/softwarestudio.org/Tzfile/Asia/Beirut~~~Middle East Standard Time
+/softwarestudio.org/Tzfile/Asia/Bishkek~~~Central Asia Standard Time
+/softwarestudio.org/Tzfile/Asia/Brunei~~~Taipei Standard Time
+/softwarestudio.org/Tzfile/Asia/Kolkata~~~India Standard Time
+/softwarestudio.org/Tzfile/Asia/Choibalsan~~~Yakutsk Standard Time
+/softwarestudio.org/Tzfile/Asia/Chongqing~~~China Standard Time
+/softwarestudio.org/Tzfile/Asia/Colombo~~~India Standard Time
+/softwarestudio.org/Tzfile/Asia/Damascus~~~Israel Standard Time
+/softwarestudio.org/Tzfile/Asia/Dhaka~~~Central Asia Standard Time
+/softwarestudio.org/Tzfile/Asia/Dili~~~Yakutsk Standard Time
+/softwarestudio.org/Tzfile/Asia/Dubai~~~Iran Standard Time
+/softwarestudio.org/Tzfile/Asia/Dushanbe~~~West Asia Standard Time
+/softwarestudio.org/Tzfile/Asia/Gaza~~~Israel Standard Time
+/softwarestudio.org/Tzfile/Asia/Harbin~~~China Standard Time
+/softwarestudio.org/Tzfile/Asia/Hong_Kong~~~China Standard Time
+/softwarestudio.org/Tzfile/Asia/Hovd~~~North Asia Standard Time
+/softwarestudio.org/Tzfile/Asia/Irkutsk~~~North Asia East Standard Time
+/softwarestudio.org/Tzfile/Asia/Jakarta~~~SE Asia Standard Time
+/softwarestudio.org/Tzfile/Asia/Jayapura~~~Yakutsk Standard Time
+/softwarestudio.org/Tzfile/Asia/Jerusalem~~~Israel Standard Time
+/softwarestudio.org/Tzfile/Asia/Kabul~~~Afghanistan Standard Time
+/softwarestudio.org/Tzfile/Asia/Kamchatka~~~Fiji Standard Time
+/softwarestudio.org/Tzfile/Asia/Karachi~~~West Asia Standard Time
+/softwarestudio.org/Tzfile/Asia/Kashgar~~~China Standard Time
+/softwarestudio.org/Tzfile/Asia/Katmandu~~~Nepal Standard Time
+/softwarestudio.org/Tzfile/Asia/Krasnoyarsk~~~North Asia Standard Time
+/softwarestudio.org/Tzfile/Asia/Kuala_Lumpur~~~Singapore Standard Time
+/softwarestudio.org/Tzfile/Asia/Kuching~~~Taipei Standard Time
+/softwarestudio.org/Tzfile/Asia/Kuwait~~~Arab Standard Time
+/softwarestudio.org/Tzfile/Asia/Macau~~~China Standard Time
+/softwarestudio.org/Tzfile/Asia/Magadan~~~Central Pacific Standard Time
+/softwarestudio.org/Tzfile/Asia/Makassar~~~Taipei Standard Time
+/softwarestudio.org/Tzfile/Asia/Manila~~~Taipei Standard Time
+/softwarestudio.org/Tzfile/Asia/Muscat~~~Arabian Standard Time
+/softwarestudio.org/Tzfile/Asia/Nicosia~~~Israel Standard Time
+/softwarestudio.org/Tzfile/Asia/Novosibirsk~~~N. Central Asia Standard Time
+/softwarestudio.org/Tzfile/Asia/Omsk~~~N. Central Asia Standard Time
+/softwarestudio.org/Tzfile/Asia/Oral~~~Ekaterinburg Standard Time
+/softwarestudio.org/Tzfile/Asia/Phnom_Penh~~~SE Asia Standard Time
+/softwarestudio.org/Tzfile/Asia/Pontianak~~~SE Asia Standard Time
+/softwarestudio.org/Tzfile/Asia/Pyongyang~~~Korea Standard Time
+/softwarestudio.org/Tzfile/Asia/Qatar~~~Arab Standard Time
+/softwarestudio.org/Tzfile/Asia/Qyzylorda~~~Central Asia Standard Time
+/softwarestudio.org/Tzfile/Asia/Rangoon~~~Myanmar Standard Time
+/softwarestudio.org/Tzfile/Asia/Riyadh~~~Arab Standard Time
+/softwarestudio.org/Tzfile/Asia/Saigon~~~SE Asia Standard Time
+/softwarestudio.org/Tzfile/Asia/Sakhalin~~~Vladivostok Standard Time
+/softwarestudio.org/Tzfile/Asia/Samarkand~~~West Asia Standard Time
+/softwarestudio.org/Tzfile/Asia/Seoul~~~Korea Standard Time
+/softwarestudio.org/Tzfile/Asia/Shanghai~~~China Standard Time
+/softwarestudio.org/Tzfile/Asia/Singapore~~~Singapore Standard Time
+/softwarestudio.org/Tzfile/Asia/Taipei~~~Taipei Standard Time
+/softwarestudio.org/Tzfile/Asia/Tashkent~~~West Asia Standard Time
+/softwarestudio.org/Tzfile/Asia/Tbilisi~~~Georgian Standard Time
+/softwarestudio.org/Tzfile/Asia/Tehran~~~Iran Standard Time
+/softwarestudio.org/Tzfile/Asia/Thimphu~~~Central Asia Standard Time
+/softwarestudio.org/Tzfile/Asia/Tokyo~~~Tokyo Standard Time
+/softwarestudio.org/Tzfile/Asia/Ulaanbaatar~~~North Asia East Standard Time
+/softwarestudio.org/Tzfile/Asia/Urumqi~~~China Standard Time
+/softwarestudio.org/Tzfile/Asia/Vientiane~~~SE Asia Standard Time
+/softwarestudio.org/Tzfile/Asia/Vladivostok~~~Vladivostok Standard Time
+/softwarestudio.org/Tzfile/Asia/Yakutsk~~~Yakutsk Standard Time
+/softwarestudio.org/Tzfile/Asia/Yekaterinburg~~~Ekaterinburg Standard Time
+/softwarestudio.org/Tzfile/Asia/Yerevan~~~Armenian Standard Time
+/softwarestudio.org/Tzfile/Atlantic/Azores~~~Azores Standard Time
+/softwarestudio.org/Tzfile/Atlantic/Bermuda~~~Atlantic Standard Time
+/softwarestudio.org/Tzfile/Atlantic/Canary~~~GMT Standard Time
+/softwarestudio.org/Tzfile/Atlantic/Cape_Verde~~~Cape Verde Standard Time
+/softwarestudio.org/Tzfile/Atlantic/Faroe~~~GMT Standard Time
+/softwarestudio.org/Tzfile/Atlantic/Jan_Mayen~~~W. Europe Standard Time
+/softwarestudio.org/Tzfile/Atlantic/Madeira~~~GMT Standard Time
+/softwarestudio.org/Tzfile/Atlantic/Reykjavik~~~GMT Standard Time
+/softwarestudio.org/Tzfile/Atlantic/South_Georgia~~~Mid-Atlantic Standard Time
+/softwarestudio.org/Tzfile/Atlantic/Stanley~~~SA Eastern Standard Time
+/softwarestudio.org/Tzfile/Atlantic/St_Helena~~~Greenwich Standard Time
+/softwarestudio.org/Tzfile/Australia/Adelaide~~~Cen. Australia Standard Time
+/softwarestudio.org/Tzfile/Australia/Brisbane~~~E. Australia Standard Time
+/softwarestudio.org/Tzfile/Australia/Broken_Hill~~~Cen. Australia Standard Time
+/softwarestudio.org/Tzfile/Australia/Currie~~~AUS Eastern Standard Time
+/softwarestudio.org/Tzfile/Australia/Darwin~~~AUS Central Standard Time
+/softwarestudio.org/Tzfile/Australia/Eucla~~~AUS Central Standard Time
+/softwarestudio.org/Tzfile/Australia/Hobart~~~Tasmania Standard Time
+/softwarestudio.org/Tzfile/Australia/Lindeman~~~E. Australia Standard Time
+/softwarestudio.org/Tzfile/Australia/Lord_Howe~~~AUS Eastern Standard Time
+/softwarestudio.org/Tzfile/Australia/Melbourne~~~AUS Eastern Standard Time
+/softwarestudio.org/Tzfile/Australia/Perth~~~W. Australia Standard Time
+/softwarestudio.org/Tzfile/Australia/Sydney~~~AUS Eastern Standard Time
+/softwarestudio.org/Tzfile/Europe/Amsterdam~~~W. Europe Standard Time
+/softwarestudio.org/Tzfile/Europe/Andorra~~~W. Europe Standard Time
+/softwarestudio.org/Tzfile/Europe/Athens~~~GTB Standard Time
+/softwarestudio.org/Tzfile/Europe/Belgrade~~~Central European Standard Time
+/softwarestudio.org/Tzfile/Europe/Berlin~~~W. Europe Standard Time
+/softwarestudio.org/Tzfile/Europe/Bratislava~~~Central Europe Standard Time
+/softwarestudio.org/Tzfile/Europe/Brussels~~~Romance Standard Time
+/softwarestudio.org/Tzfile/Europe/Bucharest~~~E. Europe Standard Time
+/softwarestudio.org/Tzfile/Europe/Budapest~~~Central Europe Standard Time
+/softwarestudio.org/Tzfile/Europe/Chisinau~~~FLE Standard Time
+/softwarestudio.org/Tzfile/Europe/Copenhagen~~~Romance Standard Time
+/softwarestudio.org/Tzfile/Europe/Dublin~~~GMT Standard Time
+/softwarestudio.org/Tzfile/Europe/Gibraltar~~~Romance Standard Time
+/softwarestudio.org/Tzfile/Europe/Guernsey~~~GMT Standard Time
+/softwarestudio.org/Tzfile/Europe/Helsinki~~~FLE Standard Time
+/softwarestudio.org/Tzfile/Europe/Isle_of_Man~~~GMT Standard Time
+/softwarestudio.org/Tzfile/Europe/Istanbul~~~GTB Standard Time
+/softwarestudio.org/Tzfile/Europe/Jersey~~~GMT Standard Time
+/softwarestudio.org/Tzfile/Europe/Kaliningrad~~~FLE Standard Time
+/softwarestudio.org/Tzfile/Europe/Kiev~~~FLE Standard Time
+/softwarestudio.org/Tzfile/Europe/Lisbon~~~GMT Standard Time
+/softwarestudio.org/Tzfile/Europe/Ljubljana~~~Central Europe Standard Time
+/softwarestudio.org/Tzfile/Europe/London~~~GMT Standard Time
+/softwarestudio.org/Tzfile/Europe/Luxembourg~~~Romance Standard Time
+/softwarestudio.org/Tzfile/Europe/Madrid~~~Romance Standard Time
+/softwarestudio.org/Tzfile/Europe/Malta~~~W. Europe Standard Time
+/softwarestudio.org/Tzfile/Europe/Mariehamn~~~FLE Standard Time
+/softwarestudio.org/Tzfile/Europe/Minsk~~~E. Europe Standard Time
+/softwarestudio.org/Tzfile/Europe/Monaco~~~W. Europe Standard Time
+/softwarestudio.org/Tzfile/Europe/Moscow~~~Russian Standard Time
+/softwarestudio.org/Tzfile/Europe/Oslo~~~W. Europe Standard Time
+/softwarestudio.org/Tzfile/Europe/Paris~~~Romance Standard Time
+/softwarestudio.org/Tzfile/Europe/Podgorica~~~Central European Standard Time
+/softwarestudio.org/Tzfile/Europe/Prague~~~Central Europe Standard Time
+/softwarestudio.org/Tzfile/Europe/Riga~~~FLE Standard Time
+/softwarestudio.org/Tzfile/Europe/Rome~~~W. Europe Standard Time
+/softwarestudio.org/Tzfile/Europe/Samara~~~Caucasus Standard Time
+/softwarestudio.org/Tzfile/Europe/San_Marino~~~W. Europe Standard Time
+/softwarestudio.org/Tzfile/Europe/Sarajevo~~~Central European Standard Time
+/softwarestudio.org/Tzfile/Europe/Simferopol~~~FLE Standard Time
+/softwarestudio.org/Tzfile/Europe/Skopje~~~Central European Standard Time
+/softwarestudio.org/Tzfile/Europe/Sofia~~~FLE Standard Time
+/softwarestudio.org/Tzfile/Europe/Stockholm~~~W. Europe Standard Time
+/softwarestudio.org/Tzfile/Europe/Tallinn~~~FLE Standard Time
+/softwarestudio.org/Tzfile/Europe/Tirane~~~Central European Standard Time
+/softwarestudio.org/Tzfile/Europe/Uzhgorod~~~FLE Standard Time
+/softwarestudio.org/Tzfile/Europe/Vaduz~~~W. Europe Standard Time
+/softwarestudio.org/Tzfile/Europe/Vatican~~~W. Europe Standard Time
+/softwarestudio.org/Tzfile/Europe/Vienna~~~W. Europe Standard Time
+/softwarestudio.org/Tzfile/Europe/Vilnius~~~FLE Standard Time
+/softwarestudio.org/Tzfile/Europe/Volgograd~~~Russian Standard Time
+/softwarestudio.org/Tzfile/Europe/Warsaw~~~Central European Standard Time
+/softwarestudio.org/Tzfile/Europe/Zagreb~~~Central European Standard Time
+/softwarestudio.org/Tzfile/Europe/Zaporozhye~~~FLE Standard Time
+/softwarestudio.org/Tzfile/Europe/Zurich~~~W. Europe Standard Time
+/softwarestudio.org/Tzfile/Indian/Antananarivo~~~E. Africa Standard Time
+/softwarestudio.org/Tzfile/Indian/Chagos~~~Sri Lanka Standard Time
+/softwarestudio.org/Tzfile/Indian/Christmas~~~SE Asia Standard Time
+/softwarestudio.org/Tzfile/Indian/Cocos~~~Myanmar Standard Time
+/softwarestudio.org/Tzfile/Indian/Comoro~~~E. Africa Standard Time
+/softwarestudio.org/Tzfile/Indian/Kerguelen~~~GMT Standard Time
+/softwarestudio.org/Tzfile/Indian/Mahe~~~Iran Standard Time
+/softwarestudio.org/Tzfile/Indian/Maldives~~~West Asia Standard Time
+/softwarestudio.org/Tzfile/Indian/Mauritius~~~Arabian Standard Time
+/softwarestudio.org/Tzfile/Indian/Mayotte~~~E. Africa Standard Time
+/softwarestudio.org/Tzfile/Indian/Reunion~~~Iran Standard Time
+/softwarestudio.org/Tzfile/Pacific/Apia~~~Dateline Standard Time
+/softwarestudio.org/Tzfile/Pacific/Auckland~~~New Zealand Standard Time
+/softwarestudio.org/Tzfile/Pacific/Chatham~~~Tonga Standard Time
+/softwarestudio.org/Tzfile/Pacific/Easter~~~SA Pacific Standard Time
+/softwarestudio.org/Tzfile/Pacific/Efate~~~Central Pacific Standard Time
+/softwarestudio.org/Tzfile/Pacific/Enderbury~~~Tonga Standard Time
+/softwarestudio.org/Tzfile/Pacific/Fakaofo~~~Hawaiian Standard Time
+/softwarestudio.org/Tzfile/Pacific/Fiji~~~Fiji Standard Time
+/softwarestudio.org/Tzfile/Pacific/Funafuti~~~Fiji Standard Time
+/softwarestudio.org/Tzfile/Pacific/Galapagos~~~Mexico Standard Time
+/softwarestudio.org/Tzfile/Pacific/Gambier~~~Alaskan Standard Time
+/softwarestudio.org/Tzfile/Pacific/Guadalcanal~~~Central Pacific Standard Time
+/softwarestudio.org/Tzfile/Pacific/Guam~~~West Pacific Standard Time
+/softwarestudio.org/Tzfile/Pacific/Honolulu~~~Hawaiian Standard Time
+/softwarestudio.org/Tzfile/Pacific/Johnston~~~Hawaiian Standard Time
+/softwarestudio.org/Tzfile/Pacific/Kiritimati~~~Tonga Standard Time
+/softwarestudio.org/Tzfile/Pacific/Kosrae~~~Central Pacific Standard Time
+/softwarestudio.org/Tzfile/Pacific/Kwajalein~~~Fiji Standard Time
+/softwarestudio.org/Tzfile/Pacific/Majuro~~~Central Pacific Standard Time
+/softwarestudio.org/Tzfile/Pacific/Marquesas~~~Alaskan Standard Time
+/softwarestudio.org/Tzfile/Pacific/Midway~~~Samoa Standard Time
+/softwarestudio.org/Tzfile/Pacific/Nauru~~~Fiji Standard Time
+/softwarestudio.org/Tzfile/Pacific/Niue~~~Samoa Standard Time
+/softwarestudio.org/Tzfile/Pacific/Norfolk~~~Central Pacific Standard Time
+/softwarestudio.org/Tzfile/Pacific/Noumea~~~Central Pacific Standard Time
+/softwarestudio.org/Tzfile/Pacific/Pago_Pago~~~Samoa Standard Time
+/softwarestudio.org/Tzfile/Pacific/Palau~~~Yakutsk Standard Time
+/softwarestudio.org/Tzfile/Pacific/Pitcairn~~~Pacific Standard Time
+/softwarestudio.org/Tzfile/Pacific/Ponape~~~Central Pacific Standard Time
+/softwarestudio.org/Tzfile/Pacific/Port_Moresby~~~West Pacific Standard Time
+/softwarestudio.org/Tzfile/Pacific/Rarotonga~~~Hawaiian Standard Time
+/softwarestudio.org/Tzfile/Pacific/Saipan~~~West Pacific Standard Time
+/softwarestudio.org/Tzfile/Pacific/Tahiti~~~Hawaiian Standard Time
+/softwarestudio.org/Tzfile/Pacific/Tarawa~~~Fiji Standard Time
+/softwarestudio.org/Tzfile/Pacific/Tongatapu~~~Tonga Standard Time
+/softwarestudio.org/Tzfile/Pacific/Truk~~~West Pacific Standard Time
+/softwarestudio.org/Tzfile/Pacific/Wake~~~Fiji Standard Time
+/softwarestudio.org/Tzfile/Pacific/Wallis~~~Fiji Standard Time

Added: trunk/src/libexchangemapi/tz-mapi-to-ical
==============================================================================
--- (empty file)
+++ trunk/src/libexchangemapi/tz-mapi-to-ical	Wed Nov 19 04:28:20 2008
@@ -0,0 +1,87 @@
+Dateline Standard Time~~~/softwarestudio.org/Tzfile/Pacific/Apia
+Samoa Standard Time~~~/softwarestudio.org/Tzfile/Pacific/Midway
+Hawaiian Standard Time~~~/softwarestudio.org/Tzfile/Pacific/Honolulu
+Alaskan Standard Time~~~/softwarestudio.org/Tzfile/America/Anchorage
+Pacific Standard Time~~~/softwarestudio.org/Tzfile/America/Los_Angeles
+Pacific Standard Time (Mexico)~~~/softwarestudio.org/Tzfile/America/Tijuana
+US Mountain Standard Time~~~/softwarestudio.org/Tzfile/America/Phoenix
+Mountain Standard Time (Mexico)~~~/softwarestudio.org/Tzfile/America/Mazatlan
+Mexico Standard Time 2~~~/softwarestudio.org/Tzfile/America/Chihuahua
+Mountain Standard Time~~~/softwarestudio.org/Tzfile/America/Denver
+Central America Standard Time~~~/softwarestudio.org/Tzfile/America/Costa_Rica
+Central Standard Time~~~/softwarestudio.org/Tzfile/America/Chicago
+Central Standard Time (Mexico)~~~/softwarestudio.org/Tzfile/America/Monterrey
+Mexico Standard Time~~~/softwarestudio.org/Tzfile/America/Mexico_City
+Canada Central Standard Time~~~/softwarestudio.org/Tzfile/America/Winnipeg
+SA Pacific Standard Time~~~/softwarestudio.org/Tzfile/America/Bogota
+Eastern Standard Time~~~/softwarestudio.org/Tzfile/America/New_York
+US Eastern Standard Time~~~/softwarestudio.org/Tzfile/America/Indiana/Indianapolis
+Venezuela Standard Time~~~/softwarestudio.org/Tzfile/America/Caracas
+Atlantic Standard Time~~~/softwarestudio.org/Tzfile/America/Halifax
+SA Western Standard Time~~~/softwarestudio.org/Tzfile/America/La_Paz
+Central Brazilian Standard Time~~~/softwarestudio.org/Tzfile/America/Manaus
+Pacific SA Standard Time~~~/softwarestudio.org/Tzfile/America/La_Paz
+Newfoundland Standard Time~~~/softwarestudio.org/Tzfile/America/St_Johns
+E. South America Standard Time~~~/softwarestudio.org/Tzfile/America/Bahia
+SA Eastern Standard Time~~~/softwarestudio.org/Tzfile/America/Argentina/Buenos_Aires
+Greenland Standard Time~~~/softwarestudio.org/Tzfile/America/Godthab
+Montevideo Standard Time~~~/softwarestudio.org/Tzfile/America/Montevideo
+Mid-Atlantic Standard Time~~~/softwarestudio.org/Tzfile/Atlantic/South_Georgia
+Azores Standard Time~~~/softwarestudio.org/Tzfile/Atlantic/Azores
+Cape Verde Standard Time~~~/softwarestudio.org/Tzfile/Atlantic/Cape_Verde
+Greenwich Standard Time~~~/softwarestudio.org/Tzfile/Africa/Casablanca
+GMT Standard Time~~~UTC
+W. Europe Standard Time~~~/softwarestudio.org/Tzfile/Europe/Berlin
+Central Europe Standard Time~~~/softwarestudio.org/Tzfile/Europe/Prague
+Romance Standard Time~~~/softwarestudio.org/Tzfile/Europe/Paris
+Central European Standard Time~~~/softwarestudio.org/Tzfile/Europe/Belgrade
+W. Central Africa Standard Time~~~/softwarestudio.org/Tzfile/Africa/Luanda
+Jordan Standard Time~~~/softwarestudio.org/Tzfile/Asia/Amman
+GTB Standard Time~~~/softwarestudio.org/Tzfile/Europe/Athens
+Middle East Standard Time~~~/softwarestudio.org/Tzfile/Asia/Beirut
+Egypt Standard Time~~~/softwarestudio.org/Tzfile/Africa/Cairo
+South Africa Standard Time~~~/softwarestudio.org/Tzfile/Africa/Harare
+FLE Standard Time~~~/softwarestudio.org/Tzfile/Europe/Helsinki
+Israel Standard Time~~~/softwarestudio.org/Tzfile/Asia/Jerusalem
+E. Europe Standard Time~~~/softwarestudio.org/Tzfile/Europe/Minsk
+Namibia Standard Time~~~/softwarestudio.org/Tzfile/Africa/Windhoek
+Arabic Standard Time~~~/softwarestudio.org/Tzfile/Asia/Baghdad
+Arab Standard Time~~~/softwarestudio.org/Tzfile/Asia/Qatar
+Russian Standard Time~~~/softwarestudio.org/Tzfile/Europe/Moscow
+E. Africa Standard Time~~~/softwarestudio.org/Tzfile/Africa/Nairobi
+Georgian Standard Time~~~/softwarestudio.org/Tzfile/Asia/Tbilisi
+Iran Standard Time~~~/softwarestudio.org/Tzfile/Asia/Tehran
+Arabian Standard Time~~~/softwarestudio.org/Tzfile/Asia/Muscat
+Azerbaijan Standard Time~~~/softwarestudio.org/Tzfile/Asia/Baku
+Caucasus Standard Time~~~/softwarestudio.org/Tzfile/Asia/Yerevan
+Armenian Standard Time~~~/softwarestudio.org/Tzfile/Asia/Yerevan
+Afghanistan Standard Time~~~/softwarestudio.org/Tzfile/Asia/Kabul
+Ekaterinburg Standard Time~~~/softwarestudio.org/Tzfile/Asia/Yekaterinburg
+West Asia Standard Time~~~/softwarestudio.org/Tzfile/Asia/Karachi
+India Standard Time~~~/softwarestudio.org/Tzfile/Asia/Kolkata
+Sri Lanka Standard Time~~~/softwarestudio.org/Tzfile/Asia/Colombo
+Nepal Standard Time~~~/softwarestudio.org/Tzfile/Asia/Katmandu
+N. Central Asia Standard Time~~~/softwarestudio.org/Tzfile/Asia/Novosibirsk
+Central Asia Standard Time~~~/softwarestudio.org/Tzfile/Asia/Dhaka
+Myanmar Standard Time~~~/softwarestudio.org/Tzfile/Asia/Rangoon
+SE Asia Standard Time~~~/softwarestudio.org/Tzfile/Asia/Bangkok
+North Asia Standard Time~~~/softwarestudio.org/Tzfile/Asia/Krasnoyarsk
+China Standard Time~~~/softwarestudio.org/Tzfile/Asia/Shanghai
+North Asia East Standard Time~~~/softwarestudio.org/Tzfile/Asia/Ulaanbaatar
+Singapore Standard Time~~~/softwarestudio.org/Tzfile/Asia/Singapore
+W. Australia Standard Time~~~/softwarestudio.org/Tzfile/Australia/Perth
+Taipei Standard Time~~~/softwarestudio.org/Tzfile/Asia/Taipei
+Tokyo Standard Time~~~/softwarestudio.org/Tzfile/Asia/Tokyo
+Korea Standard Time~~~/softwarestudio.org/Tzfile/Asia/Seoul
+Yakutsk Standard Time~~~/softwarestudio.org/Tzfile/Asia/Yakutsk
+Cen. Australia Standard Time~~~/softwarestudio.org/Tzfile/Australia/Adelaide
+AUS Central Standard Time~~~/softwarestudio.org/Tzfile/Australia/Darwin
+E. Australia Standard Time~~~/softwarestudio.org/Tzfile/Australia/Brisbane
+AUS Eastern Standard Time~~~/softwarestudio.org/Tzfile/Australia/Sydney
+West Pacific Standard Time~~~/softwarestudio.org/Tzfile/Pacific/Guam
+Tasmania Standard Time~~~/softwarestudio.org/Tzfile/Australia/Hobart
+Vladivostok Standard Time~~~/softwarestudio.org/Tzfile/Asia/Vladivostok
+Central Pacific Standard Time~~~/softwarestudio.org/Tzfile/Asia/Magadan
+New Zealand Standard Time~~~/softwarestudio.org/Tzfile/Pacific/Auckland
+Fiji Standard Time~~~/softwarestudio.org/Tzfile/Pacific/Fiji
+Tonga Standard Time~~~/softwarestudio.org/Tzfile/Pacific/Tongatapu



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]