rev 8942 - in kde-extras/strigi/trunk/debian: . patches

Fathi Boudra fabo at alioth.debian.org
Sun Jan 13 11:15:45 UTC 2008


Author: fabo
Date: 2008-01-13 11:15:45 +0000 (Sun, 13 Jan 2008)
New Revision: 8942

Added:
   kde-extras/strigi/trunk/debian/patches/01_strigi_branch_r760102.diff
Removed:
   kde-extras/strigi/trunk/debian/cmake.mk
   kde-extras/strigi/trunk/debian/patches/01_strigi_branch_r729946.diff
Modified:
   kde-extras/strigi/trunk/debian/changelog
   kde-extras/strigi/trunk/debian/control
   kde-extras/strigi/trunk/debian/libstreamanalyzer0.install
   kde-extras/strigi/trunk/debian/patches/series
   kde-extras/strigi/trunk/debian/rules
Log:
  * Update branch pull patch to r760102.
  * Remove our cmake.mk. Merged in CDBS package.
  * Clean up build dependencies.
  * Update my e-mail address.
  * Bump Standard-Version to 3.7.3.
  * Use Homepage field.
  * Update installed files.
  * Build with --no-undefined and --as-needed linker flags.
  * Remove libstreams-dev dependency on libstdc++-dev. (Closes: #454995)
  * Add strict versioned shlibs. (Closes: #460296)
  * Add CMAKE_CXX_COMPILER:FILEPATH=g++ to workaround g++ path not properly
    set.


Modified: kde-extras/strigi/trunk/debian/changelog
===================================================================
--- kde-extras/strigi/trunk/debian/changelog	2008-01-13 01:38:36 UTC (rev 8941)
+++ kde-extras/strigi/trunk/debian/changelog	2008-01-13 11:15:45 UTC (rev 8942)
@@ -1,3 +1,20 @@
+strigi (0.5.7-2) unstable; urgency=low
+
+  * Update branch pull patch to r760102.
+  * Remove our cmake.mk. Merged in CDBS package.
+  * Clean up build dependencies.
+  * Update my e-mail address.
+  * Bump Standard-Version to 3.7.3.
+  * Use Homepage field.
+  * Update installed files.
+  * Build with --no-undefined and --as-needed linker flags.
+  * Remove libstreams-dev dependency on libstdc++-dev. (Closes: #454995)
+  * Add strict versioned shlibs. (Closes: #460296)
+  * Add CMAKE_CXX_COMPILER:FILEPATH=g++ to workaround g++ path not properly
+    set.
+
+ -- Fathi Boudra <fabo at debian.org>  Sat, 12 Jan 2008 22:57:56 +0100
+
 strigi (0.5.7-1) unstable; urgency=low
 
   * New upstream release.

Deleted: kde-extras/strigi/trunk/debian/cmake.mk

Modified: kde-extras/strigi/trunk/debian/control
===================================================================
--- kde-extras/strigi/trunk/debian/control	2008-01-13 01:38:36 UTC (rev 8941)
+++ kde-extras/strigi/trunk/debian/control	2008-01-13 11:15:45 UTC (rev 8942)
@@ -3,11 +3,11 @@
 Priority: optional
 Maintainer: Debian KDE Extras Team <pkg-kde-extras at lists.alioth.debian.org>
 Uploaders: Fathi Boudra <fabo at debian.org>, Mark Purcell <msp at debian.org>
-Build-Depends: cdbs, debhelper (>= 5), cmake, quilt, bison,
- libattr1-dev, libbz2-dev, libclucene-dev, libcppunit-dev, libdbus-1-dev,
- libexiv2-dev, libqt4-dev, libxml2-dev, zlib1g-dev, libxml2-utils,
- python-support, python
-Standards-Version: 3.7.2
+Build-Depends: cdbs, debhelper (>= 5), cmake, quilt, libbz2-dev,
+ libclucene-dev, libdbus-1-dev, libexiv2-dev, libqt4-dev, libxml2-dev,
+ zlib1g-dev, libxml2-utils, python-support, python
+Standards-Version: 3.7.3
+Homepage: http://strigi.sourceforge.net
 
 Package: strigi-daemon
 Architecture: any
@@ -37,8 +37,6 @@
     duplicates)
  .
  This package contains the Strigi daemon
- .
-  Homepage: http://strigi.sourceforge.net
 
 Package: strigi-client
 Architecture: any
@@ -50,8 +48,6 @@
  This package is part of Strigi Desktop Search, it contains the Qt4 client.
  .
  See the 'strigi-daemon' package for more informations.
- .
-  Homepage: http://strigi.sourceforge.net
 
 Package: strigi-utils
 Architecture: any
@@ -75,8 +71,6 @@
     parsing the output.
  .
  See the 'strigi-daemon' package for more informations.
- .
-  Homepage: http://strigi.sourceforge.net
 
 Package: libstreams0
 Architecture: any
@@ -88,20 +82,16 @@
  writing clients using libstreams.
  .
  See the 'strigi-daemon' package for more informations.
- .
-  Homepage: http://strigi.sourceforge.net
 
 Package: libstreams-dev
 Architecture: any
 Section: libdevel
-Depends: libstreams0 (= ${binary:Version}), libstdc++-dev
+Depends: libstreams0 (= ${binary:Version})
 Description: development files for libstreams
  This package is part of Strigi Desktop Search, it contains the Strigi
  development files for libstreams.
  .
  See the 'strigi-daemon' package for more informations.
- .
-  Homepage: http://strigi.sourceforge.net
 
 Package: libstreamanalyzer0
 Architecture: any
@@ -115,8 +105,6 @@
  writing clients using libstreamanalyzer.
  .
  See the 'strigi-daemon' package for more informations.
- .
-  Homepage: http://strigi.sourceforge.net
 
 Package: libstreamanalyzer-dev
 Architecture: any
@@ -129,8 +117,6 @@
  development files for libstreamanalyzer.
  .
  See the 'strigi-daemon' package for more informations.
- .
-  Homepage: http://strigi.sourceforge.net
 
 Package: libsearchclient0
 Architecture: any
@@ -142,8 +128,6 @@
  writing clients.
  .
  See the 'strigi-daemon' package for more informations.
- .
-  Homepage: http://strigi.sourceforge.net
 
 Package: libsearchclient-dev
 Architecture: any
@@ -154,8 +138,6 @@
  development files for libsearchclient.
  .
  See the 'strigi-daemon' package for more informations.
- .
-  Homepage: http://strigi.sourceforge.net
 
 Package: libstrigihtmlgui0
 Architecture: any
@@ -166,8 +148,6 @@
  writing html clients.
  .
  See the 'strigi-daemon' package for more informations.
- .
-  Homepage: http://strigi.sourceforge.net
 
 Package: libstrigihtmlgui-dev
 Architecture: any
@@ -178,8 +158,6 @@
  development files for libstrigihtmlgui.
  .
  See the 'strigi-daemon' package for more informations.
- .
-  Homepage: http://strigi.sourceforge.net
 
 Package: libstrigiqtdbusclient0
 Architecture: any
@@ -190,8 +168,6 @@
  writing Qt D-Bus clients for strigi.
  .
  See the 'strigi-daemon' package for more informations.
- .
-  Homepage: http://strigi.sourceforge.net
 
 Package: libstrigiqtdbusclient-dev
 Architecture: any
@@ -202,8 +178,6 @@
  development files for libstrigiqtdbusclient.
  .
  See the 'strigi-daemon' package for more informations.
- .
-  Homepage: http://strigi.sourceforge.net
 
 Package: deskbar-plugins-strigi
 Architecture: any
@@ -211,8 +185,6 @@
 Depends: ${python:Depends}, strigi-daemon, deskbar-applet
 Description: Deskbar plugin to search files with strigi
  This package is part of Strigi Desktop Search, it contains a plugin
- for the Gnome Deskbar applet to search for files using Strigi.
+ for the GNOME Deskbar applet to search for files using Strigi.
  .
  See the 'strigi-daemon' package for more informations.
- .
-  Homepage: http://strigi.sourceforge.net

Modified: kde-extras/strigi/trunk/debian/libstreamanalyzer0.install
===================================================================
--- kde-extras/strigi/trunk/debian/libstreamanalyzer0.install	2008-01-13 01:38:36 UTC (rev 8941)
+++ kde-extras/strigi/trunk/debian/libstreamanalyzer0.install	2008-01-13 11:15:45 UTC (rev 8942)
@@ -1,6 +1,7 @@
 usr/lib/libstreamanalyzer.so.*
 usr/lib/strigi/strigiindex_*
-usr/lib/strigi/strigiea_*
 usr/lib/strigi/strigila_*
 usr/lib/strigi/strigita_*
+usr/share/strigi/fieldproperties/strigi.rdfs
+usr/share/strigi/fieldproperties/xesam-convenience.rdfs
 usr/share/strigi/fieldproperties/xesam.rdfs

Deleted: kde-extras/strigi/trunk/debian/patches/01_strigi_branch_r729946.diff

Added: kde-extras/strigi/trunk/debian/patches/01_strigi_branch_r760102.diff
===================================================================
--- kde-extras/strigi/trunk/debian/patches/01_strigi_branch_r760102.diff	                        (rev 0)
+++ kde-extras/strigi/trunk/debian/patches/01_strigi_branch_r760102.diff	2008-01-13 11:15:45 UTC (rev 8942)
@@ -0,0 +1,10197 @@
+--- /dev/null
++++ b/cmake/FindFAM.cmake
+@@ -0,0 +1,36 @@
++# - Try to find the fam libraries
++# Once done this will define
++#
++# FAM_FOUND - system supports fam
++# FAM_INCLUDE_DIR - the fam include directory
++# FAM_LIBRARIES - libfam library
++
++FIND_PATH(FAM_INCLUDE_DIR fam.h PATHS /usr/include /usr/local/include )
++FIND_LIBRARY(FAM_LIBRARIES NAMES fam )
++
++FIND_LIBRARY(GAMIN_LIBRARIES NAMES gamin gamin-1 PATH /usr/lib /usr/local/lib)
++ 
++IF (NOT GAMIN_LIBRARIES AND FAM_LIBRARIES)
++  message (STATUS "Please use Gamin instead of FAM if possible") 
++ENDIF (NOT GAMIN_LIBRARIES AND FAM_LIBRARIES)
++
++if (GAMIN_LIBRARIES)
++  message(STATUS "Found Gamin: good choice, it's better then FAM")
++endif (GAMIN_LIBRARIES)
++
++IF(FAM_INCLUDE_DIR AND FAM_LIBRARIES)
++  SET(FAM_FOUND 1)
++  if(NOT FAM_FIND_QUIETLY)
++    if (GAMIN_LIBRARIES)
++      message(STATUS "Found FAM (provided by Gamin): ${FAM_LIBRARIES}")
++    else (GAMIN_LIBRARIES)
++      message(STATUS "Found FAM: ${FAM_LIBRARIES}")
++    endif (GAMIN_LIBRARIES)
++  endif(NOT FAM_FIND_QUIETLY)
++ELSE(FAM_INCLUDE_DIR AND FAM_LIBRARIES)
++  SET(FAM_FOUND 0 CACHE BOOL "Not found FAM")
++  message(STATUS "NOT Found FAM, disabling it")
++ENDIF(FAM_INCLUDE_DIR AND FAM_LIBRARIES)
++
++MARK_AS_ADVANCED(FAM_INCLUDE_DIR FAM_LIBRARIES)
++
+--- a/cmake/MacroCheckGccVisibility.cmake
++++ b/cmake/MacroCheckGccVisibility.cmake
+@@ -32,7 +32,7 @@
+ 
+    if (${GccVisibility} AND GCC_IS_NEWER_THAN_4_1 AND NOT _GCC_COMPILED_WITH_BAD_ALLOCATOR)
+       set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fvisibility=hidden")
+-      set (KDE4_C_FLAGS "-fvisibility=hidden")
++      set (KDE4_C_FLAGS "${KDE4_C_FLAGS}" "-fvisibility=hidden")
+ 
+       if (GCC_IS_NEWER_THAN_4_2)
+           set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fvisibility-inlines-hidden")
+--- /dev/null
++++ b/cmake/MacroFindOptionalDep.cmake
+@@ -0,0 +1,59 @@
++# FIND_OPTIONAL_DEP macro implements two typical optional dependency handling approaches:
++#
++# Best-effort approach(FORCE_DEPS=OFF):
++#	Link to all enabled optional dependencies if found. Turn off not found ones, and keep compiling.
++# This greatly benefits hand-compiling from source if all suggested dependencies are turned on by default.
++# Newly installed software conveniently integrates with whatever environment it's compiled in.
++#
++# Strict dependencies approach(FORCE_DEPS=ON):
++#	All enabled optional dependencies must be found, or compilation aborts.
++# This approach lets request and ensure specific functionality. The compilation is deterministic
++# in the sense that everything that's requested is provided or the process fails.
++# This is the preferred behaviour for automated building by package managers/distro maintainers.
++#
++# Parameters:
++# _package:	the package to load
++# _found:	the name of *_FOUND variable which is set by find_package() if ${_package} is found.
++# _enabled:	option/variable name which along with FORCE_DEPS options controls macro behaviour:
++#	${_enabled}	FORCE_DEPS	Behaviour
++#		OFF	any		${_package} is not loaded
++#		ON	ON		Try loading ${_package}. If package is not found, abort(fatal error).
++#		ON	OFF		Try loading ${_package}. If package is not found, continue.
++# _description:	a short description of features provided by ${_package}.
++#		Used to display human-readable diagnostic messages
++
++# macro name changed from FIND_OPTIONAL_PACKAGE to FIND_OPTIONAL_DEP due to clash with a macro from KDE4
++
++# if ON, requested optional deps become required
++# if OFF, requested optional deps are linked to if found
++
++OPTION(FORCE_DEPS "Enforce strict dependencies" OFF)
++
++macro(FIND_OPTIONAL_DEP _package _enabled _found _description)
++
++    if(${_enabled})
++        if(FORCE_DEPS)
++            find_package(${_package} REQUIRED)
++        else(FORCE_DEPS)
++            find_package(${_package})
++        endif(FORCE_DEPS)
++    endif(${_enabled})
++
++    REPORT_OPTIONAL_PACKAGE_STATUS(${_package} ${_enabled} ${_found} ${_description})
++
++endmacro(FIND_OPTIONAL_DEP)
++
++
++macro(REPORT_OPTIONAL_PACKAGE_STATUS _package _enabled _found _description)
++
++    if(${_enabled})
++        if(${_found})
++            MESSAGE("** ${_package} is found. Support for ${_description} is enabled")
++        else(${_found})
++            MESSAGE("** ${_package} not found. Support for ${_description} is disabled")
++        endif(${_found})
++    else(${_enabled})
++        MESSAGE("** ${_package} is disabled. No support for ${_description}")
++    endif(${_enabled})
++
++endmacro(REPORT_OPTIONAL_PACKAGE_STATUS)
+\ No newline at end of file
+--- a/CMakeLists.txt
++++ b/CMakeLists.txt
+@@ -16,6 +16,7 @@
+ # include general modules
+ include(UsePkgConfig)
+ include(MacroCheckGccVisibility)
++include(MacroFindOptionalDep)
+ 
+ # compile in debug mode
+ IF(NOT CMAKE_BUILD_TYPE)
+@@ -67,23 +68,26 @@
+     REMOVE_DEFINITIONS(-fPIC)
+ ENDIF(CMAKE_SYSTEM MATCHES "SunOS-5*.")
+ 
+-OPTION(ENABLE_INOTIFY
+-  "enable inotify support (unstable)"
+-  OFF)
+-
+-OPTION(ENABLE_DBUS
+-  "enable dbus support"
+-  ON)
+-
+-OPTION(ENABLE_NEWXESAM
+-  "enable new xesam support"
+-  OFF)
+-
+-OPTION(ENABLE_SQLITE "enable sqlite support" OFF)
+-
+-OPTION(ENABLE_LOG4CXX
+-  "enable log4cxx support for advanced logging"
+-  OFF)
++OPTION(ENABLE_INOTIFY "enable inotify support (unstable)" OFF)
++IF(NOT WIN32)
++    OPTION(ENABLE_FAM "enable FAM support (testing)" OFF)
++ENDIF(NOT WIN32)
++OPTION(ENABLE_DBUS "enable dbus support" ON)
++OPTION(ENABLE_NEWXESAM "enable new xesam support" OFF)
++OPTION(ENABLE_LOG4CXX "enable log4cxx support for advanced logging" OFF)
++OPTION(ENABLE_CPPUNIT "enable CppUnit for unit tests" ON)
++OPTION(ENABLE_QT4 "enable Qt4 GUI" ON)
++OPTION(ENABLE_EXIV2
++	"enable exiv2 support. This allows you to index EXIF/IPTC metadata." ON)
++
++# backends
++OPTION(ENABLE_CLUCENE "enable CLucene support (recommended)" ON)
++OPTION(ENABLE_HYPERESTRAIER "enable Hyper Estraier support(unreliable)" OFF)
++OPTION(ENABLE_SQLITE "enable SQLite support(unreliable)" OFF)
++
++#OPTION(ENABLE_LIBXML2 "enable libxml2 support" ON)
++OPTION(ENABLE_EXPAT "enable expat support" OFF)
++
+ 
+ find_package(ZLIB REQUIRED)
+ find_package(BZip2 REQUIRED)
+@@ -91,28 +95,24 @@
+ find_package(Iconv REQUIRED)
+ 
+ # use either expat or libxml2
+-find_package(Expat)
++FIND_OPTIONAL_DEP(Expat ENABLE_EXPAT Expat_FOUND "XML via Expat")
++# libxml seems to be required regardless of what because it's used by streamanalyzer
++#FIND_OPTIONAL_DEP(LibXml2 ENABLE_LIBXML2 LIBXML2_FOUND "XML via LibXml2")
+ find_package(LibXml2 REQUIRED)
++
+ if (NOT LIBXML2_FOUND AND NOT Expat_FOUND)
+-  MESSAGE(FATAL "You need libxml2 or libexpat")
++  MESSAGE(FATAL_ERROR "You need libxml2 or libexpat")
+ endif (NOT LIBXML2_FOUND AND NOT Expat_FOUND)
+ 
+-find_package(CLucene)
+-if(NOT CLucene_FOUND)
+-  MESSAGE("Could not find CLucene. Please install CLucene = 0.9.16a (http://clucene.sf.net)")
+-endif(NOT CLucene_FOUND)
+-
+-find_package(HyperEstraier)
+-find_package(Exiv2)
+-if(ENABLE_SQLITE)
+-  find_package(SQLite)
+-endif(ENABLE_SQLITE)
++FIND_OPTIONAL_DEP(CLucene ENABLE_CLUCENE CLucene_FOUND "CLucene backend")
++FIND_OPTIONAL_DEP(HyperEstraier ENABLE_HYPERESTRAIER HyperEstraier_FOUND "HyperEstraier backend")
++FIND_OPTIONAL_DEP(SQLite ENABLE_SQLITE SQLite_FOUND "SQLite backend")
++
++FIND_OPTIONAL_DEP(Exiv2 ENABLE_EXIV2 EXIV2_FOUND "indexing of EXIF/IPTC metadata")
++
+ #find_package(XAttr)
+-set(QT_MIN_VERSION "4.2.0")
+-find_package(Qt4)
+-if (NOT QT4_FOUND)
+-    MESSAGE("** Qt4 was not found. No GUI will be built.")
+-endif (NOT QT4_FOUND)
++set(QT_MIN_VERSION "4.3.0")
++FIND_OPTIONAL_DEP(Qt4 ENABLE_QT4 QT4_FOUND "QT4 GUI client")
+ 
+ check_include_files(strings.h     HAVE_STRINGS_H)                      # various
+ 
+@@ -129,35 +129,43 @@
+   ELSE(WIN32)
+     include(UsePkgConfig)
+     PKGCONFIG(dbus-1 DBUS_INCLUDE_DIR DBUS_LIBRARY_DIR DBUS_LDFLAGS DBUS_CFLAGS)
+-    if (NOT DBUS_INCLUDE_DIR)
+-      MESSAGE(FATAL_ERROR "Could not find DBus")
+-    endif (NOT DBUS_INCLUDE_DIR)
+     
+-    EXEC_PROGRAM(${PKGCONFIG_EXECUTABLE} ARGS --atleast-version=1.0 dbus-1 RETURN_VALUE _return_VALUE OUTPUT_VARIABLE _pkgconfigDevNull )
+-    if(_return_VALUE STREQUAL "0")
+-         message(STATUS "Found dbus-1 release >= 1.0")
+-    else(_return_VALUE STREQUAL "0")
+-         message(STATUS "Found dbus-1 release < 1.0 support for dbus client will be disable")
+-         set(ENABLE_DBUS "OFF")
+-    endif(_return_VALUE STREQUAL "0")
++    if (DBUS_INCLUDE_DIR)
++      EXEC_PROGRAM(${PKGCONFIG_EXECUTABLE} ARGS --atleast-version=1.0 dbus-1 RETURN_VALUE _return_VALUE OUTPUT_VARIABLE _pkgconfigDevNull )
++      if(_return_VALUE STREQUAL "0")
++        message(STATUS "Found dbus-1 release >= 1.0")
++        set(DBUS_FOUND "ON") 
++      else(_return_VALUE STREQUAL "0")
++         message(STATUS "Found dbus-1 release < 1.0. Release >=1.0 is needed")
++      endif(_return_VALUE STREQUAL "0")
++    endif (DBUS_INCLUDE_DIR)
++
++    REPORT_OPTIONAL_PACKAGE_STATUS(DBus-1 ENABLE_DBUS DBUS_FOUND "DBus interface in Strigi daemon")
++    if(NOT DBUS_FOUND)
++      set(ENABLE_DBUS "OFF")
++      if(FORCE_DEPS)
++        MESSAGE(FATAL_ERROR "Aborting")
++      endif(FORCE_DEPS)
++    endif(NOT DBUS_FOUND)
+ 
+   ENDIF(WIN32)
+ ENDIF(ENABLE_DBUS)
+ 
+-find_program (BISON
+-              bison
+-              DOC "Path to bison command, used for xesam userlanguage parser generation"
+-)
+-
+-if (BISON)
+-  MESSAGE (STATUS "Found bison: ${BISON}")
+-else (BISON)
+-  MESSAGE ("** GNU bison not found. This affects the xesam parser.")
+-endif (BISON)
+-
+-if (ENABLE_LOG4CXX)
+-    find_package (Log4cxx)
+-endif (ENABLE_LOG4CXX)
++# Don't delete bison section, but only micron seems to need this
++#find_program (BISON
++#              bison
++#              DOC "Path to bison command, used for xesam userlanguage parser generation")
++
++#if (BISON)
++#  MESSAGE (STATUS "Found bison: ${BISON}")
++#else (BISON)
++#  MESSAGE ("** GNU bison not found. This affects the xesam parser.")
++#endif (BISON)
++
++FIND_OPTIONAL_DEP(Log4cxx ENABLE_LOG4CXX LOG4CXX_FOUND "advanced logging")
++IF(NOT WIN32)
++    FIND_OPTIONAL_DEP(FAM ENABLE_FAM FAM_FOUND "efficient file change monitoring system")
++ENDIF(NOT WIN32)
+ 
+ #
+ # AC_CHECK_LIB(dl, dlopen, DL_LIBRARY="-ldl", DL_LIBRARY="") for cmake by
+@@ -189,13 +197,10 @@
+ 
+ SET (DIRS ${DIRS} src)
+ 
+-find_package(CppUnit)
+-if (NOT CppUnit_FOUND)
+-    MESSAGE("** CppUnit was not found. Strigi unit tests will not be built.")
+-else (NOT CppUnit_FOUND)
+-    MESSAGE(STATUS "CppUnit found. Strigi unit tests will be built.")
++FIND_OPTIONAL_DEP(CppUnit ENABLE_CPPUNIT CppUnit_FOUND "Strigi unit tests")
++if (CppUnit_FOUND)
+     SET (DIRS ${DIRS} tests)
+-endif (NOT CppUnit_FOUND)
++endif (CppUnit_FOUND)
+ 
+ ENABLE_TESTING()
+ SUBDIRS (${DIRS})
+--- a/config.h.cmake
++++ b/config.h.cmake
+@@ -139,6 +139,8 @@
+ 	#ifndef strigi_nanosleep
+ 	    #define strigi_nanosleep(nanoseconds) Sleep(nanoseconds/1000000)
+ 	#endif
++    
++    #define snprintf _snprintf
+ #endif
+ 
+ #include <strigi/strigiconfig.h>
+@@ -147,9 +149,9 @@
+ 
+ #define LIBINSTALLDIR "${LIBINSTALLDIR}"
+ 
+-#define SOURCEDIR "${CMAKE_SOURCE_DIR}"
++#define SOURCEDIR "${CMAKE_CURRENT_SOURCE_DIR}"
+ 
+-#define BINARYDIR "${CMAKE_BINARY_DIR}"
++#define BINARYDIR "${CMAKE_CURRENT_BINARY_DIR}"
+ 
+ #define INSTALLDIR "${CMAKE_INSTALL_PREFIX}"
+ 
+--- a/README
++++ b/README
+@@ -32,6 +32,7 @@
+ - Qt4 >= 4.2 (for a graphical interface)
+ - D-Bus (http://www.freedesktop.org/wiki/Software/dbus): it is optional but is tuned on by default
+ - linux kernel >= 2.6.13 (for inotify support)
++- FAM or Gamin for FAM file system monitoring support (Gamin is recommended)
+ - log4cxx >= 0.9.7 (http://logging.apache.org/log4cxx/) for advanced logging features
+ 
+ Upgrading:
+@@ -60,6 +61,8 @@
+    include a custom library directory
+  -DENABLE_INOTIFY:BOOL=ON
+    enable inotify support, requires kernel >= 2.6.13 with inotify support enabled 
++ -DENABLE_FAM:BOOL=OFF
++   enable FAM support, requires FAM or Gamin (which is better) installed
+  -DENABLE_LOG4CXX:BOOL=ON
+    enable log4cxx support, provides advanced logging features using log4cxx lib
+  -DENABLE_DBUS:BOOL=ON
+--- a/src/CMakeLists.txt
++++ b/src/CMakeLists.txt
+@@ -32,7 +32,7 @@
+ 
+ if (NOT CLucene_FOUND)
+   message("** No CLucene libraries were found, so Strigi cannot use indexes.")
+-  message("** It is recommended to install CLucene >= 0.9.16.")
++  message("** It is recommended to install CLucene >= 0.9.16a.")
+   message("** You will still be able to use deepfind, deepgrep and xmlindexer.")
+ endif (NOT CLucene_FOUND)
+ 
+--- a/src/daemon/CMakeLists.txt
++++ b/src/daemon/CMakeLists.txt
+@@ -14,6 +14,15 @@
+   MESSAGE(STATUS "inotify support enabled")
+ ENDIF(ENABLE_INOTIFY)
+ 
++IF(FAM_FOUND AND ENABLE_FAM)
++  add_definitions(-DHAVE_FAM)
++  IF (GAMIN_LIBRARIES)
++    MESSAGE(STATUS "FAM support enabled (using Gamin)")
++  ELSE (GAMIN_LIBRARIES)
++    MESSAGE(STATUS "FAM support enabled")
++  ENDIF (GAMIN_LIBRARIES)
++ENDIF(FAM_FOUND AND ENABLE_FAM)
++
+ IF(ENABLE_POLLING)
+   add_definitions(-DHAVE_POLLING)
+   MESSAGE(STATUS "polling support enabled")
+--- a/src/daemon/daemon.cpp
++++ b/src/daemon/daemon.cpp
+@@ -28,7 +28,9 @@
+ #include "xesamlivesearch.h"
+ #include "queue/jobqueue.h"
+ 
+-#if defined (HAVE_INOTIFY)
++#if defined (HAVE_FAM)
++#include "famlistener.h"
++#elif defined (HAVE_INOTIFY)
+ #include "inotifylistener.h"
+ #else
+ #include "pollinglistener.h"
+@@ -293,8 +295,9 @@
+     XesamLiveSearch xesam(index, queue);
+ 
+     EventListener* listener = NULL;
+-
+-#if defined (HAVE_INOTIFY)
++#if defined (HAVE_FAM)
++    listener = new FamListener (dirs);
++#elif defined (HAVE_INOTIFY)
+     // listen for requests
+     listener = new InotifyListener(dirs);
+ #else
+--- a/src/daemon/dbus/dbuscpp/makecode.pl
++++ b/src/daemon/dbus/dbuscpp/makecode.pl
+@@ -23,7 +23,7 @@
+ my $classname;
+ my $constructorargs = "";
+ 
+-my @lines = `cat $interfaceheader`;
++my @lines = `cat "$interfaceheader"`;
+ 
+ my %typemapping = (
+ 	"void" => "ignore",
+--- a/src/daemon/eventlistener/CMakeLists.txt
++++ b/src/daemon/eventlistener/CMakeLists.txt
+@@ -3,12 +3,22 @@
+     set (inotify_SRC inotifylistener.cpp)
+ ENDIF(ENABLE_INOTIFY)
+ 
+-INCLUDE_DIRECTORIES ( ${inotify_INCLUDE} ../../streams/strigi .. 
+-	${strigi_BINARY_DIR}/src/streams/strigi
+-	${strigi_SOURCE_DIR}/src/streams/strigi)
++IF(FAM_FOUND AND ENABLE_FAM)
++    set (fam_INCLUDE inotify)
++    set (fam_SRC famlistener.cpp)
++    set (eventlistener_LIBS ${eventlistener_LIBS} ${FAM_LIBRARIES})
++ENDIF(FAM_FOUND AND ENABLE_FAM)
++
++INCLUDE_DIRECTORIES ( ${inotify_INCLUDE} ../../streams/strigi ..
++    ${strigi_BINARY_DIR}/src/streams/strigi
++    ${strigi_SOURCE_DIR}/src/streams/strigi)
+ 
+ ADD_LIBRARY(eventlistener
+-	event.cpp
+-	eventlistenerqueue.cpp
+-	pollinglistener.cpp
+-	${inotify_SRC})
++    event.cpp
++    eventlistenerqueue.cpp
++    pollinglistener.cpp
++    fslistener.cpp	
++    ${inotify_SRC}
++    ${fam_SRC})
++
++TARGET_LINK_LIBRARIES (eventlistener ${eventlistener_LIBS})
+\ No newline at end of file
+--- a/src/daemon/eventlistener/eventlistener.h
++++ b/src/daemon/eventlistener/eventlistener.h
+@@ -41,7 +41,7 @@
+ public:
+     explicit EventListener(const char* name) :StrigiThread(name) {
+         m_pEventQueue = NULL;
+-        m_pindexerconfiguration = NULL;
++        m_pAnalyzerConfiguration = NULL;
+         m_pManager = NULL;
+         m_pollingInterval = 180;
+     }
+@@ -50,14 +50,13 @@
+ 
+     virtual bool init() { return true; }
+     virtual bool addWatch (const std::string& path) = 0;
+-    virtual void addWatches (const std::set<std::string>& watches,
+-                             bool enableInterrupt = false) = 0;
++    virtual void addWatches (const std::set<std::string>& watches) = 0;
+     virtual void setIndexedDirectories (const std::set<std::string>& dirs) = 0;
+     void setEventListenerQueue (EventListenerQueue* eventQueue) {
+         m_pEventQueue = eventQueue;
+     }
+     void setIndexerConfiguration(Strigi::AnalyzerConfiguration* ic) {
+-        m_pindexerconfiguration = ic;
++        m_pAnalyzerConfiguration = ic;
+     }
+     void setCombinedIndexManager (CombinedIndexManager* m) {
+         m_pManager = m;
+@@ -76,7 +75,7 @@
+ 
+ protected:
+     EventListenerQueue* m_pEventQueue;
+-    Strigi::AnalyzerConfiguration* m_pindexerconfiguration;
++    Strigi::AnalyzerConfiguration* m_pAnalyzerConfiguration;
+     CombinedIndexManager* m_pManager;
+     unsigned int m_pollingInterval;//!< pause time between each polling operation
+ };
+--- a/src/daemon/eventlistener/eventlistenerqueue.cpp
++++ b/src/daemon/eventlistener/eventlistenerqueue.cpp
+@@ -292,6 +292,11 @@
+     //     D     |     U     | IMPOSSIBLE
+     //     D     |     C     |     U
+     
++    /*STRIGI_LOG_DEBUG ("strigi.EventListener.Queue.updateEventType",
++                      "old event: " + oldEvent->toString())
++    STRIGI_LOG_DEBUG ("strigi.EventListener.Queue.updateEventType",
++                      "new event: " + newEvent->toString())*/
++    
+     switch (oldEvent->getType())
+     {
+         case Event::CREATED:
+@@ -300,8 +305,8 @@
+             {
+                 case Event::CREATED:
+                     STRIGI_LOG_INFO("strigi.EventListenerQueue.updateEventType",
++                                    "CREATED --> CREATED - "
+                                     "Maybe we've lost some filesystem event");
+-                    
+                     // put in update state, it's the safer solution because with
+                     // update event we make a delete and a create
+                     oldEvent->setType( Event::UPDATED);
+@@ -328,6 +333,7 @@
+             {
+                 case Event::CREATED:
+                     STRIGI_LOG_INFO("strigi.EventListenerQueue.updateEventType",
++                                    "UPDATED --> CREATED - "
+                                     "Maybe we've lost some filesystem event");
+                     // leave UPDATED state, it's the safer solution because with
+                     // update event we make a delete and a create
+@@ -357,6 +363,7 @@
+                     break;
+                 case Event::UPDATED:
+                     STRIGI_LOG_INFO("strigi.EventListenerQueue.updateEventType",
++                                     "DELETED --> UPDATED - "
+                                      "Maybe we've lost some filesystem event");
+                     
+                     // put in update state, it's the safer solution because with
+@@ -365,6 +372,7 @@
+                     break;
+                 case Event::DELETED:
+                     STRIGI_LOG_INFO("strigi.EventListenerQueue.updateEventType",
++                                    "DELETED -> DELETED - "
+                                     "Maybe we've lost some filesystem event");
+                     //leave DELETED state
+                     break;
+--- /dev/null
++++ b/src/daemon/eventlistener/famlistener.cpp
+@@ -0,0 +1,492 @@
++/* This file is part of Strigi Desktop Search
++ *
++ * Copyright (C) 2007 Flavio Castelli <flavio.castelli at gmail.com>
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Library General Public
++ * License as published by the Free Software Foundation; either
++ * version 2 of the License, or (at your option) any later version.
++ *
++ * This library 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
++ * Library General Public License for more details.
++ *
++ * You should have received a copy of the GNU Library General Public License
++ * along with this library; see the file COPYING.LIB.  If not, write to
++ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
++ * Boston, MA 02110-1301, USA.
++ */
++#include "famlistener.h"
++
++#include "analyzerconfiguration.h"
++#include "combinedindexmanager.h"
++#include "event.h"
++#include "eventlistenerqueue.h"
++#include "filelister.h"
++#include "indexreader.h"
++#include "../strigilogging.h"
++
++#include <cerrno>
++#include <sys/resource.h>
++#include <sys/select.h>
++#include <sys/types.h>
++#include <vector>
++
++using namespace std;
++using namespace Strigi;
++
++class MatchString {
++    string m_fixed_val;
++
++    public:
++        MatchString (string fixed_val) {m_fixed_val = fixed_val;}
++        bool operator() (pair<FAMRequest,string> val) {
++            return (m_fixed_val.compare(val.second) == 0 ? true : false);
++        }
++};
++
++bool operator< (const FAMRequest& f1, const FAMRequest& f2)
++{
++    return f1.reqnum < f2.reqnum;
++}
++
++FamEvent::FamEvent (const string& watchName, FAMEvent event)
++    : FsEvent (watchName, event.filename),
++      m_event(event),
++      m_watchName (watchName)
++{
++    bool doStat = true;
++    
++    switch (event.code)
++    {
++        case FAMChanged:
++            m_type = UPDATE;
++            break;
++        case FAMMoved:
++        case FAMDeleted:
++            m_type = DELETE;
++            break;
++        case FAMCreated:
++            m_type = CREATE;
++            break;
++        default:
++            STRIGI_LOG_DEBUG ("strigi.FamEvent.FamEvent",
++                              "unuseful event");
++            doStat = false;
++            break;
++    }
++
++    if (!doStat)
++        return;
++    
++    struct stat status;
++
++    string path = m_watchName;
++    if (path[path.length() - 1] != '/')
++        path += "/";
++    path += event.filename;
++
++    if ( stat( path.c_str(), &status) == 0) {
++        if (S_ISDIR(status.st_mode))
++            m_regardsDir = true;
++        else
++            m_regardsDir = false;
++    }
++    else {
++        string msg;
++        msg = "unable to execute stat() on FAMEvent.filename because of: ";
++        msg += strerror (errno);
++        STRIGI_LOG_ERROR ("strigi.FamEvent", msg)
++    }
++}
++
++char* FamEvent::name()
++{
++    return m_event.filename;
++}
++
++const string FamEvent::description()
++{
++    string message;
++
++    switch (m_event.code)
++    {
++        case FAMChanged:
++            message += "FAMChanged";
++            break;
++        case FAMMoved:
++            message += "FAMMoved";
++            break;
++        case FAMDeleted:
++            message += "FAMDeleted";
++            break;
++        case FAMCreated:
++            message += "FAMCreated";
++            break;
++        case FAMExists:
++            message += "FAMExists";
++            break;
++        case FAMEndExist:
++            message += "FAMEndExist";
++            break;
++        case FAMAcknowledge:
++            message += "FAMAcknowledge";
++            break;
++        case FAMStartExecuting:
++            message += "FAMStartExecuting";
++            break;
++        case FAMStopExecuting:
++            message += "FAMStopExecuting";
++            break;
++    }
++    
++    message += " event regarding ";
++    message += (m_regardsDir) ? "dir " : "file ";
++    message += m_event.filename;
++    message += " ; associated watch description: " + m_watchName;
++    
++    return message;
++}
++
++bool FamEvent::regardsDir()
++{
++    return m_regardsDir;
++}
++
++class FamListener::Private
++{
++    public:
++        Private();
++
++        virtual ~Private();
++
++        bool init();
++        void stopMonitoring();
++
++        bool isEventInteresting (FsEvent * event);
++        bool isEventValid(FsEvent* event);
++
++        // event methods
++        void pendingEvent(vector<FsEvent*>& events, unsigned int& counter);
++
++        // dir methods
++        void dirRemoved (string dir);
++        
++        // watches methods
++        bool addWatch (const std::string& path);
++        void addWatches (const std::set<std::string>& watches);
++        void rmWatch(FAMRequest& famRequest, std::string path);
++        void rmWatches(std::map<FAMRequest, std::string>& watchesToRemove);
++        void rmWatches(std::set<std::string>& watchesToRemove);
++        void clearWatches();
++
++    private:
++        FAMConnection m_famConnection;
++        std::map<FAMRequest, std::string> m_watches; //!< map containing all inotify watches added by FamListener. Key is watch descriptor, value is dir path
++};
++
++bool FamListener::Private::init()
++{
++    if (FAMOpen(&m_famConnection) == -1)
++        return false;
++    
++    return true;
++}
++
++FamListener::Private::Private()
++{
++}
++
++FamListener::Private::~Private()
++{
++    clearWatches();
++    
++    if (FAMClose (&m_famConnection) == -1)
++        STRIGI_LOG_ERROR ("strigi.FamListener",
++                          "Error during FAM close procedure");
++}
++
++void FamListener::Private::pendingEvent(vector<FsEvent*>& events,
++                                        unsigned int& counter)
++{
++    sleep (1);
++    
++    if (FAMPending(&m_famConnection)) {
++        FAMEvent event;
++        if (FAMNextEvent (&m_famConnection, &event) == -1) {
++            STRIGI_LOG_ERROR ("strigi.FamListener.pendingEvent",
++                              "Fam event retrieval failed");
++            return;
++        }
++
++        if ((event.code == FAMChanged) || (event.code == FAMMoved) ||
++             (event.code == FAMDeleted) || (event.code == FAMCreated))
++        {
++            map<FAMRequest, string>::iterator match;
++            match = m_watches.find (event.fr);
++            if (match != m_watches.end()) {
++                events.push_back (new FamEvent (match->second, event));
++                counter++;
++            }
++        }
++    }
++}
++
++bool FamListener::Private::isEventValid(FsEvent* event)
++{
++    FamEvent* famEvent = dynamic_cast<FamEvent*> (event);
++
++    if (famEvent == 0)
++        return false;
++
++    map<FAMRequest, string>::iterator match = m_watches.find(famEvent->fr());
++
++    return (match != m_watches.end());
++}
++
++bool FamListener::Private::addWatch (const string& path)
++{
++    map<FAMRequest, string>::iterator iter;
++    for (iter = m_watches.begin(); iter != m_watches.end(); iter++) {
++        if ((iter->second).compare (path) == 0) // dir is already watched
++            return true;
++    }
++
++    FAMRequest famRequest;
++    if (FAMMonitorDirectory (&m_famConnection, path.c_str(), &famRequest, 0) == 0) {
++        m_watches.insert(make_pair(famRequest, path));
++        return true;
++    }
++    else
++        return false;
++}
++
++void FamListener::Private::rmWatch(FAMRequest& famRequest, string path)
++{
++    if (FAMCancelMonitor (&m_famConnection, &famRequest) == -1)
++        STRIGI_LOG_ERROR ("strigi.FamListener.Private.rmWatch",
++                    string("Error removing watch associated to path: ") + path)
++    else
++        STRIGI_LOG_DEBUG ("strigi.FamListener.Private.rmWatch",
++                    string("Removed watch associated to path: ") + path)
++    
++    map<FAMRequest, string>::iterator match = m_watches.find(famRequest);
++    
++    if (match != m_watches.end() && (path.compare(match->second) == 0))
++        m_watches.erase (match);
++    else
++        STRIGI_LOG_ERROR ("strigi.FamListener.Private.rmWatch",
++                          "unable to remove internal watch reference for " + path)
++}
++
++void FamListener::Private::rmWatches(map<FAMRequest, string>& watchesToRemove)
++{
++    for (map<FAMRequest,string>::iterator it = watchesToRemove.begin();
++         it != watchesToRemove.end(); it++)
++    {
++        map<FAMRequest,string>::iterator match = m_watches.find (it->first);
++        if (match != m_watches.end()) {
++            FAMRequest famRequest = it->first;
++            rmWatch ( famRequest, it->second);
++        }
++        else
++            STRIGI_LOG_WARNING ("strigi.FamListener.Private.rmWatches",
++                        "unable to remove watch associated to " + it->second);
++    }
++}
++
++void FamListener::Private::rmWatches(set<string>& watchesToRemove)
++{
++    map<FAMRequest, string> removedWatches;
++    
++    // find all pairs <watch-id, watch-name> that have to be removed
++    for (set<string>::iterator it = watchesToRemove.begin();
++         it != watchesToRemove.end(); it++)
++    {
++        MatchString finder (*it);
++        map<FAMRequest, string>::iterator match;
++        match = find_if (m_watches.begin(), m_watches.end(), finder);
++        
++        if (match != m_watches.end())
++            removedWatches.insert (make_pair (match->first, match->second));
++        else
++            STRIGI_LOG_WARNING ("strigi.FamListener.Private.rmWatches",
++                                "unable to find the watch associated to " + *it)
++    }
++    
++    rmWatches (removedWatches);
++}
++
++void FamListener::Private::clearWatches ()
++{
++    map<FAMRequest, string>::iterator iter;
++    for (iter = m_watches.begin(); iter != m_watches.end(); iter++) {
++        FAMRequest famRequest = iter->first;
++        if (FAMCancelMonitor (&m_famConnection, &famRequest) == -1)
++            STRIGI_LOG_ERROR ("strigi.FamListener.rmWatch",
++             string("Error removing watch associated to path: ") + iter->second)
++        else
++            STRIGI_LOG_DEBUG ("strigi.FamListener.rmWatch",
++                   string("Removed watch associated to path: ") + iter->second)
++    }
++
++    m_watches.clear();
++}
++
++void FamListener::Private::dirRemoved (string dir)
++{
++    map<FAMRequest, string> watchesToRemove;
++
++    // remove inotify watches over no more indexed dirs
++    for (map<FAMRequest, string>::iterator mi = m_watches.begin();
++         mi != m_watches.end(); mi++)
++    {
++        if ((mi->second).find (dir,0) == 0)
++            watchesToRemove.insert (make_pair (mi->first, mi->second));
++    }
++    
++    rmWatches (watchesToRemove);
++}
++
++// END FamListener::Private
++
++FamListener::FamListener(set<string>& indexedDirs)
++    :FsListener("FamListener", indexedDirs)
++{
++    p = new Private();
++}
++
++FamListener::~FamListener()
++{
++    delete p;
++}
++
++bool FamListener::init()
++{
++    if (!p->init()) {
++        STRIGI_LOG_ERROR ("strigi.FamListener.init",
++                          "Error during FAM initialization");
++        return false;
++    }
++
++    m_bInitialized = true;
++
++    STRIGI_LOG_DEBUG ("strigi.FamListener.init", "successfully initialized");
++
++    return true;
++}
++
++FsEvent* FamListener:: retrieveEvent()
++{
++    if (m_events.empty())
++        return 0;
++
++    vector<FsEvent*>::iterator iter = m_events.begin();
++    
++    FsEvent* event = *iter;
++    m_events.erase(iter);
++    return event;
++}
++
++bool FamListener::pendingEvent()
++{
++    unsigned int counter = 0;
++    p->pendingEvent (m_events, counter);
++
++    if (counter > 0) {
++        char buff [20];
++        snprintf(buff, 20 * sizeof (char), "%i", counter);
++        string message = "Caught ";
++        message += buff;
++        message += " FAM event(s)";
++    
++        STRIGI_LOG_DEBUG ("strigi.FamListener.pendingEvent", message)
++    }
++    
++    return !m_events.empty();
++}
++
++bool FamListener::isEventInteresting (FsEvent* event)
++{
++    FamEvent* famEvent = dynamic_cast<FamEvent*> (event);
++
++    if (famEvent == 0)
++        return false;
++    
++    // ignore directories starting with '.'
++    if ((famEvent->regardsDir()) &&
++        (strlen (famEvent->name()) > 0) && (famEvent->name())[0] == '.')
++        return false;
++
++    if (m_pAnalyzerConfiguration == NULL) {
++        STRIGI_LOG_WARNING ("strigi.FamListener.isEventInteresting",
++                            "AnalyzerConfiguration == NULL")
++        return true;
++    }
++
++    string path = famEvent->watchName();
++    if (path[path.length() - 1] != '/')
++        path += "/";
++    path += famEvent->name();
++    
++    if (famEvent->regardsDir())
++        return m_pAnalyzerConfiguration->indexDir( path.c_str(),
++                                                   famEvent->name());
++    else
++        return m_pAnalyzerConfiguration->indexFile( path.c_str(),
++                                                    famEvent->name());
++}
++
++bool FamListener::isEventValid(FsEvent* event)
++{
++    return p->isEventValid ( event);
++}
++
++bool FamListener::addWatch (const string& path)
++{
++    if (p->addWatch (path)) {
++        STRIGI_LOG_INFO ("strigi.FamListener.addWatch",
++                         "added watch for " + path);
++        return true;
++    }
++    else {
++        STRIGI_LOG_ERROR ("strigi.FamListener.addWatch",
++                          "Failed to watch " + path)
++        return false;
++    }
++}
++
++void FamListener::clearWatches ()
++{
++    p->clearWatches();
++}
++
++void FamListener::dirRemoved (string dir, vector<Event*>& events)
++{
++    map<FAMRequest, string> watchesToRemove;
++
++    STRIGI_LOG_DEBUG ("strigi.FamListener.dirRemoved", dir +
++            " is no longer watched, removing all indexed files contained")
++
++    // we've to de-index all files contained into the deleted/moved directory
++    if (m_pManager)
++    {
++        // all indexed files contained into directory
++        map<string, time_t> indexedFiles;
++        m_pManager->indexReader()->getChildren(dir, indexedFiles);
++
++        // remove all entries that were contained into the removed directory
++        for (map<string, time_t>::iterator it = indexedFiles.begin();
++             it != indexedFiles.end(); it++)
++        {
++            Event* event = new Event (Event::DELETED, it->first);
++            events.push_back (event);
++        }
++    }
++    else
++        STRIGI_LOG_WARNING ("strigi.FamListener.dirRemoved",
++                            "m_pManager == NULL!");
++
++    p->dirRemoved (dir);
++}
+--- /dev/null
++++ b/src/daemon/eventlistener/famlistener.h
+@@ -0,0 +1,84 @@
++/* This file is part of Strigi Desktop Search
++ *
++ * Copyright (C) 2007 Flavio Castelli <flavio.castelli at gmail.com>
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Library General Public
++ * License as published by the Free Software Foundation; either
++ * version 2 of the License, or (at your option) any later version.
++ *
++ * This library 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
++ * Library General Public License for more details.
++ *
++ * You should have received a copy of the GNU Library General Public License
++ * along with this library; see the file COPYING.LIB.  If not, write to
++ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
++ * Boston, MA 02110-1301, USA.
++ */
++#ifndef FAMLISTENER_H
++#define FAMLISTENER_H
++
++#include "fslistener.h"
++#include "strigi_thread.h"
++
++#include <fam.h>
++#include <map>
++#include <vector>
++
++class Event;
++
++class FamEvent : public FsEvent
++{
++    public:
++        FamEvent(const std::string& watchName, FAMEvent event);
++
++        const std::string description();
++        bool regardsDir();
++
++        FAMEvent event() { return m_event;}
++        FAMRequest fr() { return m_event.fr; }
++        std::string watchName() { return m_watchName;}
++        char* name();
++        
++    private:
++        struct FAMEvent m_event;
++        std::string m_watchName;
++        bool m_regardsDir;
++};
++
++/*!
++ * @class FamListener
++ * @brief Uses FAM to keep strigi's index updated.
++ */
++class FamListener : public FsListener
++{
++    private:
++        class Private;
++        Private* p;
++    
++    public:
++        explicit FamListener(std::set<std::string>& indexedDirs);
++
++        virtual ~FamListener();
++
++        bool init();
++
++    protected:
++        void stopMonitoring();
++
++        // event methods
++        bool pendingEvent();
++        FsEvent* retrieveEvent();
++        bool isEventValid(FsEvent* event);
++        bool isEventInteresting (FsEvent * event);
++
++        void dirRemoved (std::string dir, std::vector<Event*>& events);
++
++        // watches methods
++        bool addWatch (const std::string& path);
++        void clearWatches();
++};
++
++#endif
+--- /dev/null
++++ b/src/daemon/eventlistener/fslistener.cpp
+@@ -0,0 +1,632 @@
++/* This file is part of Strigi Desktop Search
++ *
++ * Copyright (C) 2007 Flavio Castelli <flavio.castelli at gmail.com>
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Library General Public
++ * License as published by the Free Software Foundation; either
++ * version 2 of the License, or (at your option) any later version.
++ *
++ * This library 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
++ * Library General Public License for more details.
++ *
++ * You should have received a copy of the GNU Library General Public License
++ * along with this library; see the file COPYING.LIB.  If not, write to
++ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
++ * Boston, MA 02110-1301, USA.
++ */
++#include "fslistener.h"
++
++#include "combinedindexmanager.h"
++#include "event.h"
++#include "eventlistenerqueue.h"
++#include "filelister.h"
++#include "indexreader.h"
++#include "pollinglistener.h"
++#include "../strigilogging.h"
++
++#include <cerrno>
++#include <sys/resource.h>
++#include <sys/select.h>
++#include <sys/types.h>
++#include <sstream>
++#include <vector>
++#include <algorithm>
++
++using namespace std;
++using namespace Strigi;
++
++namespace {
++    /*!
++    * @param path string containing path to check
++    * Removes the terminating char to path.
++    * Under Windows that char is '\', '/' under *nix
++    */
++    string fixPath (string path)
++    {
++        if ( path.c_str() == NULL || path.length() == 0 )
++            return "";
++
++        string temp(path);
++
++    #ifdef HAVE_WINDOWS_H
++        size_t l= temp.length();
++        char* t = (char*)temp.c_str();
++        for (size_t i=0;i<l;i++){
++            if ( t[i] == '\\' )
++                t[i] = '/';
++        }
++        temp[0] = tolower(temp.at(0));
++    #endif
++
++        char separator = '/';
++
++        if (temp[temp.length() - 1 ] == separator)
++            return temp.substr(0, temp.size() - 1);
++
++        return temp;
++    }
++}
++
++void calculateDiff(set<string> actualDirs, set<string> reindexDirs,
++                   set<string>& dirsDeleted,set<string>& dirsCreated)
++{
++    set<string>::iterator iter;
++    stringstream strDirsDeleted;
++    stringstream strDirsCreated;
++    stringstream strDirsActual;
++    stringstream strDirsReindex;
++
++    strDirsDeleted << "Dirs deleted:";
++    strDirsCreated << "Dirs created:";
++    strDirsActual << "Actual dirs:";
++    strDirsReindex << "Reindex dirs:";
++
++    dirsCreated.clear();
++    dirsDeleted.clear();
++
++    for (iter = actualDirs.begin(); iter != actualDirs.end(); iter++)
++        strDirsActual << "\n\t-" << *iter;
++    
++    for (iter = reindexDirs.begin(); iter != reindexDirs.end(); iter++)
++        strDirsReindex << "\n\t-" << *iter;
++
++    STRIGI_LOG_DEBUG ("strigi.calculateDiff", strDirsActual.str())
++    STRIGI_LOG_DEBUG ("strigi.calculateDiff", strDirsReindex.str())
++
++    for (iter = actualDirs.begin(); iter != actualDirs.end(); iter++) {
++        set<string>::iterator match = reindexDirs.find (*iter);
++        if (match == reindexDirs.end()) {
++            dirsDeleted.insert (*iter);
++            strDirsDeleted << "\n\t-" << *iter;
++        }
++        else
++            reindexDirs.erase (match);
++    }
++
++    for (iter = reindexDirs.begin(); iter != reindexDirs.end(); iter++) {
++        dirsCreated.insert (*iter);
++        strDirsCreated << "\n\t-" << *iter;
++    }
++
++    STRIGI_LOG_DEBUG ("strigi.calculateDiff", strDirsCreated.str())
++    STRIGI_LOG_DEBUG ("strigi.calculateDiff", strDirsDeleted.str())
++}
++
++class File
++{
++    public:
++        File(string name, time_t mtime)
++            : m_name (name),
++              m_mtime (mtime)
++            {};
++
++        string m_name;
++        time_t m_mtime;
++};
++
++bool operator< (const File& f1, const File& f2)
++{
++    if (f1.m_name.compare(f2.m_name) < 0)
++        return true;
++    else
++        return false;
++}
++
++class MatchFile
++{
++    string m_name;
++    public:
++        MatchFile( string name)
++            : m_name (name) {};
++
++        bool operator ()(const File& f)
++            { return (m_name == f.m_name); }
++};
++
++FsEvent::FsEvent (const string path, const string name)
++{
++    m_file = fixPath(path);
++    if (!name.empty()) {
++        m_file += '/';
++        m_file += name;
++    }
++}
++
++// improved multimap, stl multimap class doesn't provide a method that returns
++// all the available keys
++typedef map< string, set<File> > iMultimap;
++
++
++FsListener::FsListener(const char* name, set<string>& indexedDirs)
++    : EventListener(name)
++{
++    m_bMonitor = true;
++    setState(Idling);
++    m_bInitialized = false;
++    m_bBootstrapped = false;
++    m_bReindexReq = false;
++    m_counter = 0;
++    m_pollingListener = 0;
++
++    for (set<string>::iterator iter = indexedDirs.begin();
++         iter != indexedDirs.end(); iter++)
++        m_indexedDirs.insert (fixPath (*iter));
++    
++    STRIGI_MUTEX_INIT (&m_reindexLock);
++}
++
++FsListener::~FsListener()
++{
++    if (m_pollingListener) {
++        m_pollingListener->stop();
++        delete m_pollingListener;
++        m_pollingListener = 0;
++    }
++    STRIGI_MUTEX_DESTROY (&m_reindexLock);
++}
++
++void* FsListener::run(void*)
++{
++    while (getState() != Stopping) {
++        if (!m_bBootstrapped)
++            bootstrap();
++        else if (reindexReq())
++            reindex();
++        else
++            watch();
++
++        if (getState() == Working)
++            setState(Idling);
++    }
++
++    STRIGI_LOG_DEBUG ("strigi.FsListener.run",
++                      string("exit state: ") + getStringState());
++    return 0;
++}
++
++bool FsListener::reindexReq()
++{
++    bool ret;
++    
++    STRIGI_MUTEX_LOCK (&m_reindexLock);
++    ret = m_bReindexReq;
++    STRIGI_MUTEX_UNLOCK (&m_reindexLock);
++
++    return ret;
++}
++
++void FsListener::getReindexDirs(set<string>& reindexDirs)
++{
++    STRIGI_MUTEX_LOCK (&m_reindexLock);
++    m_bReindexReq = false;
++    reindexDirs = m_reindexDirs;
++    m_reindexDirs.clear();
++    STRIGI_MUTEX_UNLOCK (&m_reindexLock);
++}
++
++void FsListener::bootstrap()
++{
++    STRIGI_LOG_DEBUG ("strigi.FsListener.bootstrap","BOOTSTRAP INIT");
++    
++    set<string> toWatch;
++    vector<Event*> events;
++    iMultimap files;
++    set<string> bootstrapDirs;
++
++    if (reindexReq())
++        getReindexDirs ( bootstrapDirs);
++    else
++        bootstrapDirs = m_indexedDirs;
++    
++    for (set<string>::iterator iter = bootstrapDirs.begin();
++         iter != bootstrapDirs.end(); iter++)
++    {
++        toWatch.insert (*iter);
++        
++        DirLister lister(m_pAnalyzerConfiguration);
++        string path;
++        vector<pair<string, struct stat> > dirs;
++
++        lister.startListing (*iter);
++        int ret = lister.nextDir(path, dirs);
++
++        while (ret != -1) {
++            if (reindexReq())
++                break;
++            
++            vector<pair<string, struct stat> >::iterator iter;
++            
++            for (iter = dirs.begin(); iter != dirs.end(); iter++) {
++                struct stat stats = iter->second;
++
++                if (S_ISDIR(stats.st_mode)) { //dir
++                    toWatch.insert (iter->first);
++                }
++                else if (S_ISREG(stats.st_mode)) { //file
++                    iMultimap::iterator mIter = files.find (path);
++                    File file (iter->first, stats.st_mtime);
++                    if (mIter != files.end())
++                        (mIter->second).insert (file);
++                    else {
++                        set<File> temp;
++                        temp.insert (file);
++                        files.insert(make_pair(path, temp));
++                    }
++                }
++            }
++            
++            ret = lister.nextDir(path, dirs);
++        }
++    }
++
++    stringstream msg;
++    msg << "there're " << files.size();
++    msg << " keys inside iMultimap";
++    STRIGI_LOG_DEBUG ("strigi.FsListener.bootstrap", msg.str())
++    
++    for (iMultimap::iterator iter = files.begin(); iter != files.end(); iter++)
++    {
++        map <string, time_t> indexedFiles;
++        stringstream msg;
++        string path = iter->first;
++
++        // retrieve all indexed files contained by path
++        m_pManager->indexReader()->getChildren (path, indexedFiles);
++        msg << "there're " << indexedFiles.size();
++        msg << " indexed files associated to dir " << path;
++
++        STRIGI_LOG_DEBUG ("strigi.FsListener.bootstrap", msg.str())
++
++        if (indexedFiles.empty()) {
++            string temp = path + "/";
++            msg.str("");
++            m_pManager->indexReader()->getChildren (temp, indexedFiles);
++            msg << "there're " << indexedFiles.size();
++            msg << " indexed files associated to dir " << temp;
++
++            STRIGI_LOG_DEBUG ("strigi.FsListener.bootstrap", msg.str())
++        }
++
++        if (!indexedFiles.empty()) {
++            // find differences between fs files and indexed ones
++            map<string, time_t>::iterator it = indexedFiles.begin();
++            for ( ; it != indexedFiles.end(); it++) {
++                MatchFile finder (it->first);
++                set<File>::iterator match;
++                match = find_if( (iter->second).begin(),
++                                 (iter->second).end(), finder);
++
++                if (match == (iter->second).end()) {
++                    // indexed file has been deleted from filesystem
++                    events.push_back (new Event (Event::DELETED, iter->first));
++                }
++                else if ((*match).m_mtime > it->second) {
++                    // file has been updated
++                    events.push_back (new Event (Event::UPDATED, iter->first));
++                }
++                else {
++                    // file has not been modified since index time
++                    (iter->second).erase( match);
++                }
++
++                if (reindexReq())
++                    break;
++            }
++        }
++
++        for (set<File>::iterator it = (iter->second).begin();
++             it != (iter->second).end(); it++)
++        {
++            File file = *it;
++            events.push_back (new Event (Event::CREATED, file.m_name));
++        }
++    }
++
++    //TODO: check
++    if (reindexReq()) {
++        for (vector<Event*>::iterator iter = events.begin();
++             iter != events.end(); iter++) {
++            delete *iter;
++        }
++
++        events.clear();
++    }
++    else {
++        if (events.size() > 0)
++            m_pEventQueue->addEvents (events);
++
++        addWatches (toWatch);
++
++        m_bBootstrapped = true;
++        m_indexedDirs = bootstrapDirs;
++    }
++}
++
++void FsListener::reindex()
++{
++    STRIGI_LOG_DEBUG ("strigi.FsListener.reindex","REINDEX INIT");
++    
++    if (m_pEventQueue == NULL) {
++        STRIGI_LOG_ERROR ("strigi.FsListener.reindex",
++                          "m_pEventQueue == NULL!");
++        return;
++    }
++    
++    set<string> reindexDirs;
++    set<string> dirsDeleted;
++    set<string> dirsCreated;
++    set<string> dirsMonitored;
++    vector<Event*> events;
++    
++    if (!reindexReq ())
++        return;
++
++    getReindexDirs(reindexDirs);
++    
++    calculateDiff(m_indexedDirs, reindexDirs, dirsDeleted, dirsCreated);
++
++    for (set<string>::iterator iter = dirsCreated.begin();
++         iter != dirsCreated.end() && !reindexReq(); iter++)
++    {
++        DirLister lister(m_pAnalyzerConfiguration);
++        string path;
++        vector<pair<string, struct stat> > dirs;
++
++        lister.startListing (*iter);
++        int ret = lister.nextDir(path, dirs);
++
++        while (ret != -1) {
++            vector<pair<string, struct stat> >::iterator iter;
++            for (iter = dirs.begin(); iter != dirs.end(); iter++) {
++                struct stat stats = iter->second;
++                if (S_ISDIR(stats.st_mode)) {//dir
++                    set<string> toWatch;
++                    recursivelyMonitor (iter->first, toWatch, events);
++                    // add new watches
++                    addWatches (toWatch);
++                    dirsMonitored.insert (iter->first);
++                }
++                else if (S_ISREG(stats.st_mode)) {
++                    //file
++                    events.push_back (new Event (Event::CREATED, iter->first));
++                }
++            }
++            ret = lister.nextDir(path, dirs);
++        }
++    }
++
++    if (reindexReq()) {
++        // another reindex request arrived, undo last actions
++        for (vector<Event*>::iterator iter = events.begin();
++             iter != events.end(); iter++)
++            delete *iter;
++        events.clear();
++        //TODO check!!!
++        dirsRemoved (dirsMonitored, events);
++    }
++    else {
++        // finish reindex operation
++        dirsRemoved (dirsDeleted, events);
++
++        if (events.size() > 0)
++            m_pEventQueue->addEvents (events);
++        
++        //update indexedDirs
++        m_indexedDirs = reindexDirs;
++    }
++}
++
++void FsListener::watch ()
++{
++    if (m_pEventQueue == NULL) {
++        STRIGI_LOG_ERROR ("strigi.FsListener.watch",
++                          "m_pEventQueue == NULL!");
++        return;
++    }
++
++    vector <Event*> events;
++
++    while (pendingEvent()) {
++        FsEvent* fsevent  = retrieveEvent();
++
++        if (!isEventValid(fsevent)) {
++            STRIGI_LOG_WARNING ("strigi.FsListener.watch",
++                                "discarded invalid event");
++            continue;
++        }
++
++        if (isEventInteresting(fsevent)) {
++            STRIGI_LOG_DEBUG ("strigi.FsListener.watch",
++                              fsevent->description());
++
++            switch (fsevent->type()) {
++                case FsEvent::UPDATE:
++                {
++                    Event* event = new Event (Event::UPDATED, fsevent->file());
++                    events.push_back (event);
++                    break;
++                }
++                case FsEvent::DELETE:
++                {
++                    if (fsevent->regardsDir())
++                        dirRemoved (fsevent->file(), events);
++                    else {
++                        Event* event = new Event (Event::DELETED,
++                                                  fsevent->file());
++                        events.push_back (event);
++                    }
++                    break;
++                }
++                case FsEvent::CREATE:
++                {
++                    if (fsevent->regardsDir()) {
++                        set<string> toWatch;
++                        recursivelyMonitor (fsevent->file(), toWatch, events);
++                        addWatches( toWatch);
++                    }
++                    else {
++                        Event* event = new Event (Event::CREATED,
++                                                  fsevent->file());
++                        events.push_back (event);
++                    }
++                    break;
++                }
++                default:
++                    STRIGI_LOG_DEBUG ("strigi.FsListener.watch",
++                                      "unknown event type")
++                    break;
++            }
++
++            delete fsevent;
++        }
++    }
++
++    if (events.size() > 0) {
++        STRIGI_LOG_DEBUG ("strigi.FsListener.watch",
++                          "adding events to processing queue")
++        m_pEventQueue->addEvents (events);
++    }
++}
++
++void FsListener::recursivelyMonitor (string dir, set<string>& toWatch,
++                                     vector<Event*>& events)
++{
++    STRIGI_LOG_DEBUG ("FsListener.recursivelyMonitor","going to monitor " + dir)
++    DirLister lister(m_pAnalyzerConfiguration);
++    string path;
++    vector<pair<string, struct stat> > fsitems;
++
++    toWatch.insert (dir);
++    
++    lister.startListing (dir);
++    int ret = lister.nextDir(path, fsitems);
++
++    while (ret != -1) {
++        for (vector<pair<string,struct stat> >::iterator iter = fsitems.begin();
++             iter != fsitems.end(); iter++)
++        {
++            struct stat stats = iter->second;
++            
++            if (S_ISDIR(stats.st_mode)) //dir
++                recursivelyMonitor(iter->first, toWatch, events);
++            else if (S_ISREG(stats.st_mode)) {
++                //file
++                Event* event = new Event (Event::CREATED, iter->first);
++                events.push_back (event);
++            }
++        }
++        ret = lister.nextDir(path, fsitems);
++    }
++}
++
++void FsListener::addWatches(const set<string> &watches)
++{
++	set<string>::iterator iter;
++    set<string> toPool;
++    set<string> watched;
++	
++    if (!m_bInitialized) {
++        STRIGI_LOG_ERROR ("strigi.FsListener.addWatches",
++                          "Listener has not been initialized, unable"
++                          "to add watches!")
++        toPool = watches;
++    }
++    else {
++	    for (iter = watches.begin(); iter != watches.end(); iter++) {
++	        if (!addWatch (*iter)) {
++	            // adding watch failed, we've to use polling in order to watch it
++	            toPool.insert(*iter);
++	        }
++	        else
++	            watched.insert (*iter);
++	    }
++    }
++
++    if (!toPool.empty())
++    {
++        if (m_pollingListener == NULL)
++        {
++            m_pollingListener = new PollingListener();
++            m_pollingListener->setEventListenerQueue( m_pEventQueue);
++            m_pollingListener->setCombinedIndexManager( m_pManager);
++            m_pollingListener->setIndexerConfiguration(m_pAnalyzerConfiguration);
++            //TODO: start with a low priority?
++            m_pollingListener->start( );
++        }
++        
++        m_pollingListener->addWatches( toPool);
++        m_pollingDirs.insert (toPool.begin(), toPool.end());
++    }
++}
++
++void FsListener::dirsRemoved (set<string> dirs, vector<Event*>& events)
++{
++    for (set<string>::iterator iter = dirs.begin();
++         iter != dirs.end(); iter++)
++    {
++        string path = fixPath(*iter);
++        set<string>::iterator match = m_pollingDirs.find (path);
++        if (match == m_pollingDirs.end())
++            dirRemoved (path, events);
++        else
++            m_pollingListener->rmWatch (*match);
++    }
++}
++
++void FsListener::setIndexedDirectories (const set<string> &dirs)
++{
++    stringstream msg;
++    set<string> fixedDirs;
++
++    // fix path, all dir must end with a '/'
++    for (set<string>::iterator iter = dirs.begin(); iter != dirs.end(); iter++)
++        fixedDirs.insert (fixPath (*iter));
++
++    STRIGI_MUTEX_LOCK (&m_reindexLock);
++    m_reindexDirs = fixedDirs;
++    m_bReindexReq = true;
++    STRIGI_MUTEX_UNLOCK (&m_reindexLock);
++
++
++    msg << fixedDirs.size() << " dirs specified";
++    STRIGI_LOG_DEBUG ("FsListener.setIndexedDirectories", msg.str())
++}
++
++void FsListener::dumpEvents()
++{
++    unsigned int counter = 1;
++    for (vector<FsEvent*>::iterator iter = m_events.begin();
++         iter != m_events.end(); iter++)
++    {
++        FsEvent* event = *iter;
++        stringstream msg;
++        
++        msg << "Event " << counter << "/" << m_events.size() << ": ";
++        msg << event->description();
++        STRIGI_LOG_DEBUG("strigi.FsListener.dumpEvents", msg.str())
++        counter++;
++    }
++}
+--- /dev/null
++++ b/src/daemon/eventlistener/fslistener.h
+@@ -0,0 +1,153 @@
++/* This file is part of Strigi Desktop Search
++ *
++ * Copyright (C) 2007 Flavio Castelli <flavio.castelli at gmail.com>
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Library General Public
++ * License as published by the Free Software Foundation; either
++ * version 2 of the License, or (at your option) any later version.
++ *
++ * This library 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
++ * Library General Public License for more details.
++ *
++ * You should have received a copy of the GNU Library General Public License
++ * along with this library; see the file COPYING.LIB.  If not, write to
++ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
++ * Boston, MA 02110-1301, USA.
++ */
++#ifndef FSLISTENER_H
++#define FSLISTENER_H
++
++#include "eventlistener.h"
++#include "strigi_thread.h"
++#include <map>
++#include <vector>
++
++class Event;
++class PollingListener;
++
++
++class FsEvent
++{
++    public:
++        FsEvent (const std::string path, const std::string name);
++        virtual ~FsEvent() {};
++
++        enum TYPE {CREATE, UPDATE, DELETE};
++
++        virtual const std::string description() = 0;
++        TYPE type() { return m_type; }
++        const std::string file() { return m_file;}
++        virtual bool regardsDir() = 0;
++
++    protected:
++        std::string m_file;
++        TYPE m_type;
++};
++
++
++/*!
++ * @class FsListener
++ * @brief Interacts generic class for low level monitoring facilities
++ */
++
++class FsListener : public EventListener
++{
++    public:
++        explicit FsListener(const char* name,
++                            std::set<std::string>& indexedDirs);
++
++        virtual ~FsListener();
++
++        virtual bool init() = 0;
++
++        void setIndexedDirectories (const std::set<std::string>& dirs);
++
++        void* run(void*);
++
++    protected:
++        void setInitialized () { m_bInitialized = true; }
++
++        /*!
++         * @param event the filesystem event to analyze
++         * returns true if event is to process (ergo is interesting), false otherwise
++         */
++        virtual bool isEventInteresting (FsEvent * event) = 0;
++
++        /*!
++         * main FsListener thread
++         */
++        void watch ();
++
++        void bootstrap();
++        void reindex();
++        bool reindexReq();
++        void getReindexDirs(std::set<std::string>&);
++
++        // event methods
++        virtual bool pendingEvent() = 0;
++        virtual FsEvent* retrieveEvent() = 0;
++        virtual bool isEventValid(FsEvent* event) = 0;
++        void dumpEvents();
++
++        // dir methods
++        
++        /*!
++         * @param dir removed dir
++         * Removes all db entries of files contained into the removed dir.
++         * Removes also all watches related to removed dir (including watches over subdirs)
++         */
++        virtual void dirRemoved (std::string dir,
++                                 std::vector<Event*>& events) = 0;
++
++        /*!
++         * @param dirs removed dirs
++         * @param events all generated events 
++         * Removes all db entries of files contained into the removed dirs.
++         */
++        void dirsRemoved (std::set<std::string> dirs,
++                          std::vector<Event*>& events);
++
++        /*!
++         * @param dir dir to monitor
++         * @param toWatch directories to be watched
++         * @param events all generated events
++         * Index all files contained inside the directory dir, and all its subdirs
++         */
++        void recursivelyMonitor (const std::string dir,
++                                 std::set<std::string>& toWatch,
++                                 std::vector<Event*>& events);
++ 
++        // watches methods
++        
++        /*!
++         * @param watches directories to be watched
++         * Add a watch for each directory specified
++         */
++        void addWatches (const std::set<std::string>& watches);
++        virtual bool addWatch (const std::string& path) = 0;
++        
++        /*!
++         * removes and release all watches
++         */
++        virtual void clearWatches() {};
++
++        bool m_bMonitor;
++        bool m_bInitialized;
++        bool m_bBootstrapped;
++        unsigned int m_counter;
++
++        std::set<std::string> m_indexedDirs;
++        std::set<std::string> m_pollingDirs;
++        
++        bool m_bReindexReq;
++        std::set<std::string> m_reindexDirs;
++        pthread_mutex_t m_reindexLock;
++        std::vector<FsEvent*> m_events;
++
++        PollingListener* m_pollingListener;
++};
++
++#endif
+--- a/src/daemon/eventlistener/inotifylistener.cpp
++++ b/src/daemon/eventlistener/inotifylistener.cpp
+@@ -18,8 +18,8 @@
+  * Boston, MA 02110-1301, USA.
+  */
+ #include "inotifylistener.h"
+-#include "pollinglistener.h"
+ 
++#include "analyzerconfiguration.h"
+ #include "combinedindexmanager.h"
+ #include "event.h"
+ #include "eventlistenerqueue.h"
+@@ -28,10 +28,12 @@
+ #include "../strigilogging.h"
+ 
+ #include <cerrno>
++#include <cstring>
+ #include <sys/resource.h>
+ #include <sys/select.h>
+ #include <sys/types.h>
+ #include <vector>
++#include <algorithm>
+ 
+ #include "local_inotify.h"
+ #include "local_inotify-syscalls.h"
+@@ -39,38 +41,6 @@
+ using namespace std;
+ using namespace Strigi;
+ 
+-namespace {
+-    /*!
+-    * @param path string containing path to check
+-    * Appends the terminating char to path.
+-    * Under Windows that char is '\', '/' under *nix
+-    */
+-    string fixPath (string path)
+-    {
+-        if ( path.c_str() == NULL || path.length() == 0 )
+-            return "";
+-
+-        string temp(path);
+-
+-    #ifdef HAVE_WINDOWS_H
+-        size_t l= temp.length();
+-        char* t = (char*)temp.c_str();
+-        for (size_t i=0;i<l;i++){
+-            if ( t[i] == '\\' )
+-                t[i] = '/';
+-        }
+-        temp[0] = tolower(temp.at(0));
+-    #endif
+-
+-        char separator = '/';
+-
+-        if (temp[temp.length() - 1 ] != separator)
+-            temp += separator;
+-
+-        return temp;
+-    }
+-}
+-
+ class MatchString {
+     string m_fixed_val;
+ 
+@@ -81,597 +51,147 @@
+         }
+ };
+ 
+-////////////////////////////////////////////
+-// ReindexDirsThread class implementation //
+-///////////////////////////////////////////
+-
+-/*!
+- * @class ReindexDirsThread
+- * @brief Simple thread called when user changes indexed dirs
+- *
+- * It's a separate thread that takes care of updating inotify watches and indexed files according to the new directories specified by the user
+-*/
+-class InotifyListener::ReindexDirsThread : public StrigiThread
+-{
+-    //friend class InotifyListener;
+-
+-    public:
+-        explicit ReindexDirsThread (const char* name,
+-                                    const std::set<std::string> &olddirs);
+-
+-        explicit ReindexDirsThread (const char* name);
+-
+-        ~ReindexDirsThread();
+-
+-        void* run(void*);
+-
+-        void setIndexerConfiguration(Strigi::AnalyzerConfiguration* ic) {
+-            m_pindexerconfiguration = ic;
+-        }
+-
+-        void setIndexedDirs (const std::set<std::string>& dirs,
+-                            const std::map<int, std::string>& watchedDirs);
+-
+-        void setCombinedIndexManager (CombinedIndexManager* m) {
+-            m_pManager = m;
+-        }
+-
+-        void getData(std::set<std::string>& noMoreIndexed,
+-                    std::set<std::string>& toWatch,
+-                    std::set<std::string>& newDirs,
+-                    std::vector<Event*>& events);
+-
+-        bool working();
+-
+-    protected:
+-        void cleanup();
+-        void reindex();
+-
+-        void interrupt ();
+-        bool testInterrupt();
+-        void setWorking (bool value);
+-
+-        CombinedIndexManager* m_pManager;
+-        Strigi::AnalyzerConfiguration* m_pindexerconfiguration;
+-        std::map<std::string, time_t> m_toIndex; //!< new files to index
+-        std::set<std::string> m_toWatch; //!< new directories to watch
+-        std::vector<Event*> m_events;
+-        std::set<std::string> m_newDirs; //!< new indexed dirs specified by the user
+-        std::set<std::string> m_oldDirs; //!< old indexed dirs
+-        std::set<std::string> m_nextJobDirs; //!< new dirs to index, user changed indexed dirs more than one time
+-        std::map<int, std::string> m_nextJobWatchedDirs;
+-        std::set<std::string> m_nomoreIndexedDirs; //!< dirs no more indexed
+-        pthread_mutex_t m_nextJobLock;//!< mutex lock over m_nextJobDirs
+-        pthread_mutex_t m_resourcesLock; //!< mutex lock over all variables (excluding m_nextJobDirs)
+-        pthread_mutex_t m_interruptLock;
+-        pthread_mutex_t m_workingLock;
+-        bool m_bWorking;
+-        bool m_bInterrupt;
+-        bool m_bInterrupted;
+-        bool m_bDataTaken;
+-        bool m_bHasWorkTodo;
+-};
+-
+-InotifyListener::ReindexDirsThread::ReindexDirsThread (const char* name,
+-                                        const std::set<std::string> &olddirs)
+-: StrigiThread (name) {
+-    m_pManager = NULL;
+-    m_pindexerconfiguration = NULL;
+-    m_oldDirs = olddirs;
+-    m_bInterrupt = false;
+-    m_bInterrupted = false;
+-    m_bDataTaken = true;
+-    m_bHasWorkTodo = false;
+-    m_bWorking = false;
+-    STRIGI_MUTEX_INIT (&m_nextJobLock);
+-    STRIGI_MUTEX_INIT (&m_resourcesLock);
+-    STRIGI_MUTEX_INIT (&m_interruptLock);
+-    STRIGI_MUTEX_INIT (&m_workingLock);
+-}
+-
+-InotifyListener::ReindexDirsThread::ReindexDirsThread (const char* name)
+-: StrigiThread (name) {
+-    m_pManager = NULL;
+-    m_pindexerconfiguration = NULL;
+-    m_newDirs.clear();
+-    m_oldDirs.clear();
+-    m_bInterrupt = false;
+-    m_bInterrupted = false;
+-    m_bDataTaken = true;
+-    m_bHasWorkTodo = false;
+-    m_bWorking = false;
+-    STRIGI_MUTEX_INIT (&m_nextJobLock);
+-    STRIGI_MUTEX_INIT (&m_resourcesLock);
+-    STRIGI_MUTEX_INIT (&m_interruptLock);
+-    STRIGI_MUTEX_INIT (&m_workingLock);
+-}
+-
+-void InotifyListener::ReindexDirsThread::cleanup() {
+-    STRIGI_LOG_DEBUG( "strigi.ReindexDirsThread.cleanup",
+-                      "reindexing cancelled");
+-
+-    //clean-up everything
+-    m_newDirs.clear();
+-    m_toWatch.clear();
+-    m_toIndex.clear();
+-    
+-    // free some memory
+-    for (vector<Event*>::iterator iter = m_events.begin();
+-         iter != m_events.end(); iter++)
+-    {
+-        if (*iter != NULL) {
+-            delete *iter;
+-            *iter = NULL;
+-        }
+-    }
+-    m_events.clear();
+-    
+-    m_bDataTaken = true;
+-    m_bInterrupt = false;
+-    m_bInterrupted = true;
+-    setWorking (false);
+-    
+-    STRIGI_MUTEX_UNLOCK (&m_resourcesLock);
++InotifyEvent::InotifyEvent (int watchID, const string& watchName,
++                            struct inotify_event* event)
++    : FsEvent (watchName, event->name),
++      m_event(event),
++      m_watchName (watchName),
++      m_watchID (watchID)
++{
++    if ( ((IN_MODIFY & m_event->mask) != 0) ||
++           ((IN_CLOSE_WRITE & m_event->mask) != 0) )
++        m_type = UPDATE;
++    else if (  ((IN_DELETE & m_event->mask) != 0) ||
++               ((IN_MOVED_FROM & m_event->mask) != 0 ) ||
++               ((IN_DELETE_SELF & m_event->mask) != 0 ) ||
++               ((IN_MOVE_SELF & m_event->mask) != 0 ))
++        m_type = DELETE;
++    else if ( ((IN_CREATE & m_event->mask) != 0) ||
++              ((IN_MOVED_TO & m_event->mask) != 0 ) )
++        m_type = CREATE;
++    else
++        STRIGI_LOG_DEBUG ("strigi.InotifyEvent.InotifyEvent",
++                          "inotify's unknown event");
+ }
+ 
+-InotifyListener::ReindexDirsThread::~ReindexDirsThread()
++char* InotifyEvent::name()
+ {
+-    for (unsigned int i = 0; i < m_events.size(); i++)
+-        delete m_events[i];
+-
+-    m_events.clear();
+-
+-    STRIGI_MUTEX_DESTROY(&m_nextJobLock);
+-    STRIGI_MUTEX_DESTROY(&m_resourcesLock);
+-    STRIGI_MUTEX_DESTROY(&m_interruptLock);
+-    STRIGI_MUTEX_DESTROY(&m_workingLock);
++    return m_event->name;
+ }
+ 
+-void InotifyListener::ReindexDirsThread::interrupt () {
+-    STRIGI_MUTEX_LOCK(&m_interruptLock);
+-    m_bInterrupt = true;
+-    STRIGI_MUTEX_UNLOCK(&m_interruptLock);
+-}
++const string InotifyEvent::description()
++{
++    string message;
+ 
+-bool InotifyListener::ReindexDirsThread::testInterrupt() {
+-    bool value;
+-    STRIGI_MUTEX_LOCK(&m_interruptLock);
+-    value = m_bInterrupt;
+-    STRIGI_MUTEX_UNLOCK(&m_interruptLock);
+-    
+-    if (value)
+-        STRIGI_LOG_DEBUG ("strigi.ReindexDirsThread.testInterrupt",
+-                          "Caught interrupt event");
+-    
+-    return value;
+-}
++    if ( (IN_ACCESS & m_event->mask) != 0 )
++        message += "ACCESS";
++    else if ( (IN_MODIFY & m_event->mask) != 0 )
++        message += "MODIFY";
++    else if ( (IN_ATTRIB & m_event->mask) != 0 )
++        message += "ATTRIB";
++    else if ( (IN_CLOSE_WRITE & m_event->mask) != 0 )
++        message += "CLOSE_WRITE";
++    else if ( (IN_CLOSE_NOWRITE & m_event->mask) != 0 )
++        message += "CLOSE_NOWRITE";
++    else if ( (IN_OPEN & m_event->mask) != 0 )
++        message += "OPEN";
++    else if ( (IN_MOVED_FROM & m_event->mask) != 0 )
++        message += "MOVED_FROM";
++    else if ( (IN_MOVED_TO & m_event->mask) != 0 )
++        message += "MOVED_TO";
++    else if ( (IN_CREATE & m_event->mask) != 0 )
++        message += "CREATE";
++    else if ( (IN_DELETE & m_event->mask) != 0 )
++        message += "DELETE";
++    else if ( (IN_DELETE_SELF & m_event->mask) != 0 )
++        message += "DELETE_SELF";
++    else if ( (IN_UNMOUNT & m_event->mask) != 0 )
++        message += "UNMOUNT";
++    else if ( (IN_Q_OVERFLOW & m_event->mask) != 0 )
++        message += " Q_OVERFLOW";
++    else if ( (IN_IGNORED & m_event->mask) != 0 )
++        message += " IGNORED";
++    else if ( (IN_CLOSE & m_event->mask) != 0 )
++        message += "CLOSE";
++    else if ( (IN_MOVE & m_event->mask) != 0 )
++        message += "MOVE";
++    else if ( (IN_ISDIR & m_event->mask) != 0 )
++        message += " ISDIR";
++    else if ( (IN_ONESHOT & m_event->mask) != 0 )
++        message += " ONESHOT";
++    else
++        message = "UNKNOWN";
+ 
+-void InotifyListener::ReindexDirsThread::getData(set<string>& noMoreIndexed,
+-        set<string>& toWatch,
+-        set<string>& newDirs,
+-        vector<Event*>& events)
+-{
+-    // assure all arrays are empty
+-    noMoreIndexed.clear();
+-    toWatch.clear();
+-    newDirs.clear();
+-    events.clear();
+-    
+-    if (STRIGI_MUTEX_TRY_LOCK (&m_resourcesLock) != 0)
+-        return;
++    message += " event regarding ";
++    message += string(m_event->name, m_event->len);
++    message += " ; associated watch description: " + m_watchName;
+     
+-    if (m_bDataTaken) {
+-        STRIGI_MUTEX_UNLOCK (&m_resourcesLock);
+-        return;
+-    }
+-    
+-    noMoreIndexed = m_nomoreIndexedDirs;
+-    toWatch = m_toWatch;
+-    events = m_events;
+-    newDirs = m_newDirs;
+-    
+-    m_toWatch.clear();
+-    m_nomoreIndexedDirs.clear();
+-    m_events.clear();
+-    
+-    m_bDataTaken = true;
+-    
+-    STRIGI_MUTEX_UNLOCK (&m_resourcesLock);
+-    
+-    char buffer [50];
+-    snprintf (buffer, 50 * sizeof (char), "%i", noMoreIndexed.size());
+-    STRIGI_LOG_DEBUG ("strigi.ReindexDirsThread.getData",
+-                      string("dirs no more indexed: ") + buffer);
+-    snprintf (buffer, 50 * sizeof (char), "%i", toWatch.size());
+-    STRIGI_LOG_DEBUG ("strigi.ReindexDirsThread.getData",
+-                      string("dirs to watch: ") + buffer);
+-    snprintf (buffer, 50 * sizeof (char), "%i", newDirs.size());
+-    STRIGI_LOG_DEBUG ("strigi.ReindexDirsThread.getData",
+-                      string("dirs selected by the user: ") + buffer);
+-    snprintf (buffer, 50 * sizeof (char), "%i", events.size());
+-    STRIGI_LOG_DEBUG ("strigi.ReindexDirsThread.getData",
+-                      string("events to process: ") + buffer);
++    return message;
+ }
+ 
+-void* InotifyListener::ReindexDirsThread::run(void*)
++bool InotifyEvent::regardsDir()
+ {
+-    STRIGI_LOG_DEBUG ("strigi.ReindexDirsThread.run","starting");
+-    
+-    while (getState() != Stopping)
+-    {
+-        //TODO: increase value
+-        sleep (1);
+-        
+-        if (STRIGI_MUTEX_TRY_LOCK (&m_nextJobLock) == 0) {
+-            if ((m_bHasWorkTodo)
+-                    && STRIGI_MUTEX_TRY_LOCK (&m_resourcesLock) == 0) {
+-                // there's work to do, we've acquired locks over m_nextJobLock
+-                // and m_resourcesLock
+-            
+-                if (!m_bDataTaken) {
+-                    // previous reindex() run data has to be taken
+-                    STRIGI_MUTEX_UNLOCK (&m_nextJobLock);
+-                    STRIGI_MUTEX_UNLOCK (&m_resourcesLock);
+-                    continue;
+-                }
+-
+-                setWorking (true);
+-
+-                if (!m_bInterrupted)
+-                    m_oldDirs = m_newDirs;
+-                
+-                m_newDirs = m_nextJobDirs;
+-                m_nextJobDirs.clear();
+-                m_bHasWorkTodo = false;
+-                STRIGI_MUTEX_UNLOCK (&m_nextJobLock);
+-                
+-                // clear old structures
+-                m_toWatch.clear();
+-                m_toIndex.clear();
+-                m_events.clear();
+-                m_nomoreIndexedDirs.clear();
+-                
+-                if (m_newDirs == m_oldDirs) {
+-                    STRIGI_MUTEX_UNLOCK (&m_resourcesLock);
+-                    setWorking (false);
+-                    continue;
+-                }
+-                
+-                m_bDataTaken = false;
+-                
+-                reindex();
+-                
+-                setWorking (false);
+-
+-                STRIGI_MUTEX_UNLOCK (&m_resourcesLock);
+-            }
+-            else
+-                STRIGI_MUTEX_UNLOCK (&m_nextJobLock);
+-        }
+-        
+-        if (getState() == Working)
+-            setState(Idling);
+-    }
+-
+-    STRIGI_LOG_DEBUG ("strigi.ReindexDirsThread.run",
+-                      string("exit state: ") + getStringState());
+-    return 0;
++    return ((IN_ISDIR & m_event->mask) != 0);
+ }
+ 
+-void InotifyListener::ReindexDirsThread::reindex () {
+-    if (!m_pManager) {
+-        STRIGI_LOG_ERROR ("strigi.ReindexDirsThread.reindex",
+-                          "m_pManager == NULL!");
+-        return;
+-    }
+-    
+-    m_bInterrupted = false;
+-    
+-    map<int, string> watchedDirs = m_nextJobWatchedDirs;
+-    
+-    if (testInterrupt()) {
+-        cleanup();
+-        return;
+-    }
+-    
+-    m_toWatch.clear();
+-    m_toIndex.clear();
+-    
+-    for (set<string>::iterator iter = m_newDirs.begin();
+-         iter != m_newDirs.end(); iter++)
+-    {
+-        DirLister lister(m_pindexerconfiguration);
+-        string path;
+-        vector<pair<string, struct stat> > dirs;
+-
+-        lister.startListing (*iter);
+-        int ret = lister.nextDir(path, dirs);
+-
+-        while (ret != -1) {
+-            for (vector<pair<string, struct stat> >::iterator iter = dirs.begin();
+-                 iter != dirs.end(); iter++)
+-            {
+-                struct stat stats = iter->second;
+-
+-                if (S_ISDIR(stats.st_mode)) {
+-                    //dir
+-                    m_toWatch.insert (iter->first);
+-                }
+-                else if (S_ISREG(stats.st_mode)) {
+-                    //file
+-                    m_events.push_back (new Event (Event::CREATED, iter->first));
+-                }
+-            }
+-            ret = lister.nextDir(path, dirs);
+-        }
+-    }
+-
+-    m_nomoreIndexedDirs.clear();
+-    set<string> alreadyWatched;
+-    
+-    for (map<int, string>::iterator it = watchedDirs.begin();
+-         it != watchedDirs.end(); it++)
+-    {
+-        set<string>::iterator match = m_toWatch.find(it->second);
+-        if (match == m_toWatch.end()) // dir is no longer watched
+-            m_nomoreIndexedDirs.insert(it->second);
+-        else // dir is already watched
+-            alreadyWatched.insert (*match);
+-    }
+-
+-    // look for updated dirs
+-    m_toIndex.clear();
+-    for (set<string>::iterator iter = alreadyWatched.begin();
+-         iter != alreadyWatched.end(); iter++)
+-    {
+-        // retrieve files contained into the already watched dirs
+-
+-        Strigi::DirLister lister (m_pindexerconfiguration);
++class InotifyListener::Private
++{
++    public:
++        Private();
+ 
+-        lister.startListing (*iter);
++        virtual ~Private();
+ 
+-        string path;
+-        vector<pair<string, struct stat> > dirs;
+-        int ret = lister.nextDir(path, dirs);
+-
+-        while (ret != -1) {
+-            cout << "path = " << path << endl;
+-
+-            for (vector<pair<string, struct stat> >::iterator iter = dirs.begin();
+-                 iter != dirs.end(); iter++)
+-            {
+-                struct stat stats = iter->second;
+-                if (S_ISREG(stats.st_mode))
+-                    m_toIndex.insert (make_pair (iter->first, stats.st_mtime));
+-            }
+-            ret = lister.nextDir(path, dirs);
+-        }
++        bool init();
+ 
+-        map <string, time_t> indexedFiles;
+-        m_pManager->indexReader()->getChildren (*iter, indexedFiles);
+-        for (map<string, time_t>::iterator iter = m_toIndex.begin();
+-             iter != m_toIndex.end(); iter++)
+-        {
+-            map<string, time_t>::iterator match;
+-            match = indexedFiles.find(iter->first);
+-            if (match == indexedFiles.end()) {
+-                // new file created
+-                m_events.push_back (new Event (Event::CREATED, iter->first));
+-            }
+-            else if (match->second < iter->second) {
+-                // file has been updated
+-                m_events.push_back (new Event (Event::UPDATED, iter->first));
+-            }
+-        }
+-        m_toIndex.clear();
+-    }
++        bool isEventInteresting (FsEvent * event);
++        bool isEventValid(FsEvent* event);
+ 
+-    // remove no more indexed items
+-    for (set<string>::iterator iter = m_nomoreIndexedDirs.begin();
+-         iter != m_nomoreIndexedDirs.end(); iter++)
+-    {
+-        map <string, time_t> indexedFiles;
+-        m_pManager->indexReader()->getChildren (*iter, indexedFiles);
++        void stopMonitoring();
+ 
+-        for (map<string,time_t>::iterator mi = indexedFiles.begin();
+-             mi != indexedFiles.end(); mi++)
+-        {
+-            m_events.push_back (new Event (Event::DELETED, mi->first));
+-        }
+-    }
+-    
+-    if (testInterrupt()) {
+-        cleanup();
+-        return;
+-    }
+-}
++        // event methods
++        void pendingEvent(vector<FsEvent*>& events, unsigned int& counter);
+ 
+-bool InotifyListener::ReindexDirsThread::working()
+-{
+-    bool value;
+-    
+-    STRIGI_MUTEX_LOCK (&m_workingLock);
+-    value = m_bWorking;
+-    STRIGI_MUTEX_UNLOCK (&m_workingLock);
+-    
+-    return value;
+-}
++        // watches methods
++        bool addWatch (const std::string& path);
++        void addWatches (const std::set<std::string>& watches);
++        void rmWatch(int wd, std::string path);
++        void rmWatches(std::map<int, std::string>& watchesToRemove);
++        void rmWatches(std::set<std::string>& watchesToRemove);
++        void clearWatches();
+ 
+-void InotifyListener::ReindexDirsThread::setWorking(bool value)
+-{
+-    STRIGI_MUTEX_LOCK (&m_workingLock);
+-    m_bWorking = value;
+-    STRIGI_MUTEX_UNLOCK (&m_workingLock);
+-}
++        void dirRemoved (string dir);
+ 
+-void InotifyListener::ReindexDirsThread::setIndexedDirs (
+-        const set<string>& dirs,
+-        const map<int,string>& watchedDirs)
+-{
+-    if (working()) {
+-        STRIGI_LOG_DEBUG ("strigi.ReindexDirsThread.setIndexedDirectories",
+-                          "going to interrupt previous reindexing operation");
+-        interrupt();
+-    }
+-    
+-    STRIGI_MUTEX_LOCK (&m_nextJobLock);
+-    m_nextJobDirs = dirs;
+-    m_nextJobWatchedDirs = watchedDirs;
+-    m_bHasWorkTodo = true;
+-    STRIGI_MUTEX_UNLOCK (&m_nextJobLock);
+-}
++    private:
++        int m_iInotifyFD;
++        int m_iEvents;
++        std::map<int, std::string> m_watches; //!< map containing all inotify watches added by InotifyListener. Key is watch descriptor, value is dir path
++};
+ 
+-/* ----------- End ReindexDirsThread -------------------- */
+ 
+-InotifyListener::InotifyListener(set<string>& indexedDirs)
+-    :EventListener("InotifyListener")
++InotifyListener::Private::Private()
+ {
+     // listen only to interesting events
+     m_iEvents = IN_CLOSE_WRITE | IN_MODIFY | IN_MOVED_FROM | IN_MOVED_TO
+-        | IN_CREATE | IN_DELETE | IN_DELETE_SELF | IN_MOVE_SELF;
+-
+-    m_bMonitor = true;
+-    setState(Idling);
+-    m_bInitialized = false;
+-    m_pollingListener = NULL;
+-    m_pReindexDirThread = NULL;
+-    STRIGI_MUTEX_INIT (&m_watchesLock);
+-
+-    // fix path, all dir must end with a '/'
+-    for (set<string>::iterator iter = indexedDirs.begin();
+-         iter != indexedDirs.end(); iter++)
+-        m_indexedDirs.insert (fixPath(*iter));
++                | IN_CREATE | IN_DELETE | IN_DELETE_SELF | IN_MOVE_SELF;
+ }
+ 
+-InotifyListener::~InotifyListener()
++InotifyListener::Private::~Private()
+ {
+-    clearWatches();
+-
+-    if (m_pollingListener != NULL) {
+-        m_pollingListener->stop();
+-        delete m_pollingListener;
+-        m_pollingListener = NULL;
+-    }
+-
+-    if (m_pReindexDirThread != NULL) {
+-        m_pReindexDirThread->stop();
+-        delete m_pReindexDirThread;
+-        m_pReindexDirThread = NULL;
+-    }
+-
+-    STRIGI_MUTEX_DESTROY (&m_watchesLock);
+ }
+ 
+-bool InotifyListener::init()
++bool InotifyListener::Private::init()
+ {
+     m_iInotifyFD = inotify_init();
+-    if (m_iInotifyFD < 0) {
+-        STRIGI_LOG_ERROR ("strigi.InotifyListener",
+-                        "inotify_init() failed.  Are you running Linux 2.6.13\
+-                        or later? If so, something mysterious has gone wrong.");
++    if (m_iInotifyFD < 0)
+         return false;
+-    }
+-
+-    m_bInitialized = true;
+-
+-    STRIGI_LOG_DEBUG ("strigi.InotifyListener", "successfully initialized");
+ 
+     return true;
+ }
+ 
+-void* InotifyListener::run(void*)
+-{
+-    if (m_pReindexDirThread == NULL) {
+-        m_pReindexDirThread = new ReindexDirsThread ("ReindexDirThread");
+-        m_pReindexDirThread->setIndexerConfiguration(m_pindexerconfiguration);
+-        m_pReindexDirThread->setCombinedIndexManager( m_pManager);
+-
+-        m_pReindexDirThread->start();
+-        
+-        m_pReindexDirThread->setIndexedDirs (m_indexedDirs, m_watches);
+-        // clear m_indexedDirs, ReindexDirsThread will set it by few seconds
+-        m_indexedDirs.clear();
+-    }
+-    
+-    while (getState() != Stopping) {
+-        watch();
+-
+-        processReindexDirThreadData();
+-
+-        if (getState() == Working)
+-            setState(Idling);
+-    }
+-
+-    STRIGI_LOG_DEBUG ("strigi.InotifyListener.run",
+-                      string("exit state: ") + getStringState());
+-    return 0;
+-}
+-
+-void InotifyListener::processReindexDirThreadData()
+-{
+-    if (m_pReindexDirThread == NULL) {
+-        STRIGI_LOG_WARNING("strigi.InotifyListener.processReindexDirThreadData",
+-                           "m_pReindexDirThread == NULL");
+-        return;
+-    }
+-    
+-    set<string> noMoreIndexed, toWatch, newDirs;
+-    vector<Event*> events;
+-    char buffer [50];
+-
+-    m_pReindexDirThread->getData(noMoreIndexed, toWatch, newDirs, events);
+-    
+-    if (events.size() > 0) {
+-        snprintf (buffer, 50 * sizeof (char), "%i", events.size());
+-        STRIGI_LOG_DEBUG ("strigi.InotifyListener.processReindexDirThreadData",
+-                          string("events to process (without delete events: ")
+-                                  + buffer + ")");
+-    }
+-    
+-    if (toWatch.size() > 0) {
+-        snprintf (buffer, 50 * sizeof (char), "%i", toWatch.size());
+-        STRIGI_LOG_DEBUG ("strigi.InotifyListener.processReindexDirThreadData",
+-                          string("dirs to watch: ") + buffer);
+-        addWatches (toWatch, true);
+-    }
+-    
+-    if (newDirs.size() > 0) {
+-        snprintf (buffer, 50 * sizeof (char), "%i", newDirs.size());
+-        STRIGI_LOG_DEBUG ("strigi.InotifyListener.processReindexDirThreadData",
+-                          string("dirs selected by the user: ") + buffer);
+-    }
+-    
+-    if (noMoreIndexed.size() > 0) {
+-        snprintf (buffer, 50 * sizeof (char), "%i", noMoreIndexed.size());
+-        STRIGI_LOG_DEBUG ("strigi.InotifyListener.processReindexDirThreadData",
+-                          string("dirs no more indexed: ") + buffer);
+-        // remove old indexed files from db (interrupt enabled)
+-        rmWatches (noMoreIndexed, true);
+-    }
+-
+-    if (!testInterrupt() && (events.size() > 0))
+-        m_pEventQueue->addEvents (events);
+-
+-    // restore interrupt state
+-    setInterrupt (false);
+-    
+-    // TODO: lock?
+-    if (noMoreIndexed.size() != 0 || toWatch.size() != 0)
+-        m_indexedDirs = newDirs;
+-}
+-
+-void InotifyListener::watch ()
++void InotifyListener::Private::pendingEvent(vector<FsEvent*>& events,
++                                            unsigned int& counter)
+ {
+-    if (m_pEventQueue == NULL) {
+-        STRIGI_LOG_ERROR ("strigi.InotifyListener.watch",
+-                          "m_pEventQueue == NULL!");
+-        return;
+-    }
+-
+-    // some code taken from inotify-tools (http://inotify-tools.sourceforge.net/)
+-
+-    vector <Event*> events;
+-
++    counter = 0;
+     struct timeval read_timeout;
+     read_timeout.tv_sec = 1;
+     read_timeout.tv_usec = 0;
+@@ -695,7 +215,7 @@
+         int rc = select(m_iInotifyFD + 1, &read_fds, NULL, NULL, &read_timeout);
+ 
+         if ( rc < 0 ) {
+-            STRIGI_LOG_ERROR ("strigi.InotifyListener.watch",
++            STRIGI_LOG_ERROR ("strigi.InotifyListener.Private.pendingEvent",
+                               "Select on inotify failed");
+             return;
+         }
+@@ -703,19 +223,20 @@
+             //Inotify select timeout
+             return;
+         }
+-
+-        int thisBytes = read(m_iInotifyFD, &event + bytes, sizeof(struct inotify_event)*MAX_EVENTS - bytes);
++        
++        int thisBytes = read(m_iInotifyFD, &event + bytes,
++                             sizeof(struct inotify_event)*MAX_EVENTS - bytes);
+ 
+         if ( thisBytes < 0 ) {
+-            STRIGI_LOG_ERROR ("strigi.InotifyListener.watch",
++            STRIGI_LOG_ERROR ("strigi.InotifyListener.Private.pendingEvent",
+                               "Read from inotify failed");
+             return;
+         }
+ 
+         if ( thisBytes == 0 ) {
+-            STRIGI_LOG_WARNING ("strigi.InotifyListener.watch",
+-                                "Inotify reported end-of-file.\
+-                                Possibly too many events occurred at once.");
++            STRIGI_LOG_WARNING ("strigi.InotifyListener.Private.pendingEvent",
++                                "Inotify reported end-of-file."
++                                "Possibly too many events occurred at once.");
+             return;
+         }
+ 
+@@ -732,129 +253,22 @@
+ 
+     do
+     {
+-        string message;
+-        string watchName;
+-        int watchID;
+-
++        string watchName = "";
++        int watchID = -1;
++        
+         this_event = (struct inotify_event *)this_event_char;
+ 
+-        STRIGI_MUTEX_LOCK (&m_watchesLock);
+-
+         map <int, string>::iterator watchIter = m_watches.find (this_event->wd);
+ 
+-        if (watchIter == m_watches.end()) {
+-            if ((this_event->wd && IN_IGNORED) == 0) {
+-                // event wasn't marked with IGNORE flag, print some message
+-
+-                char buff [20];
+-                snprintf(buff, 20 * sizeof (char), "%i",this_event->wd);
+-
+-                STRIGI_LOG_WARNING ("strigi.InotifyListener.watch",
+-                    string("returned an unknown watch descriptor: ") + buff);
+-
+-                string eventtype = eventToString (this_event->mask);
+-
+-                STRIGI_LOG_WARNING ("strigi.InotifyListener.watch",
+-                                    "missed event type: " + eventtype);
+-            }
+-            // jump to next event
+-            this_event_char += sizeof(struct inotify_event) + this_event->len;
+-            remaining_bytes -= sizeof(struct inotify_event) + this_event->len;
+-
+-            STRIGI_MUTEX_UNLOCK (&m_watchesLock);
+-
+-            continue;
+-        }
+-
+-        watchName = watchIter->second;
+-        watchID   = watchIter->first;
+-
+-        STRIGI_MUTEX_UNLOCK (&m_watchesLock);
+-
+-        if (isEventInteresting (this_event)) {
+-            STRIGI_LOG_DEBUG ("strigi.InotifyListener.watch",
+-                              watchName + " changed");
+-            STRIGI_LOG_DEBUG ("strigi.InotifyListener.watch",
+-                               string("caught inotify event: ") +
+-                               eventToString( this_event->mask));
+-
+-            if ((this_event->len > 0))
+-                STRIGI_LOG_DEBUG ("strigi.InotifyListener.watch",
+-                                  "event regards " +
+-                                  string(this_event->name, this_event->len));
+-
+-            string file (watchName + string(this_event->name));
+-
+-            if ( ((IN_MODIFY & this_event->mask) != 0) ||
+-                 ((IN_CLOSE_WRITE & this_event->mask) != 0) )
+-            {
+-                Event* event = new Event (Event::UPDATED, file);
+-                events.push_back (event);
+-            }
+-            else if (((IN_DELETE & this_event->mask) != 0) ||
+-                     ((IN_MOVED_FROM & this_event->mask) != 0 ) ||
+-                     ((IN_DELETE_SELF & this_event->mask) != 0 ) ||
+-                     ((IN_MOVE_SELF & this_event->mask) != 0 ))
+-            {
+-                if ((IN_ISDIR & this_event->mask) != 0)
+-                    dirRemoved (file, events);
+-                else {
+-                    Event* event = new Event (Event::DELETED, file);
+-                    events.push_back (event);
+-                }
+-            }
+-            else if (( (IN_CREATE & this_event->mask) != 0) ||
+-                       ((IN_MOVED_TO & this_event->mask) != 0 ) )
+-            {
+-                if ( (IN_ISDIR & this_event->mask) != 0 ) {
+-                    // a new directory has been created or an already watched
+-                    // directory has been moved into a watched place
+-                    
+-                    m_toWatch.clear();
+-
+-                    DirLister lister(m_pindexerconfiguration);
+-                    string path;
+-                    vector<pair<string, struct stat> > dirs;
+-
+-                    lister.startListing (file);
+-                    int ret = lister.nextDir(path, dirs);
+-
+-                    while (ret != -1) {
+-                        for (vector<pair<string, struct stat> >::iterator iter = dirs.begin();
+-                             iter != dirs.end(); iter++)
+-                        {
+-                            struct stat stats = iter->second;
+-                            
+-                            if (S_ISDIR(stats.st_mode)) {
+-                                //dir
+-                                m_toWatch.insert (iter->first);
+-                            }
+-                            else if (S_ISREG(stats.st_mode)) {
+-                                //file
+-                                Event* event = new Event (Event::CREATED,
+-                                                          iter->first);
+-                                events.push_back (event);
+-                            }
+-                        }
+-                        ret = lister.nextDir(path, dirs);
+-                    }
+-                    
+-                    // add new watches
+-                    addWatches (m_toWatch);
+-
+-                    m_toWatch.clear();
+-                    m_toIndex.clear();
+-                }
+-                else {
+-                    Event* event = new Event (Event::CREATED, file);
+-                    events.push_back (event);
+-                }
+-            }
+-            else
+-                STRIGI_LOG_DEBUG ("strigi.InotifyListener.watch",
+-                                  "inotify's unknown event");
++        if (watchIter != m_watches.end()) {
++            watchName = watchIter->second;
++            watchID   = watchIter->first;
+         }
+ 
++        events.push_back (new InotifyEvent ( watchID, watchName, this_event));
++        counter++;
++        
++        // next event
+         this_event_char += sizeof(struct inotify_event) + this_event->len;
+         remaining_bytes -= sizeof(struct inotify_event) + this_event->len;
+     }
+@@ -868,50 +282,19 @@
+         snprintf(buff, 20 * sizeof (char), "%f", (((float)remaining_bytes)/((float)sizeof(struct inotify_event))));
+         message = buff;
+         message += "event(s) may have been lost!";
+-        STRIGI_LOG_ERROR ("strigi.InotifyListener.watch", message);
++        STRIGI_LOG_ERROR ("strigi.InotifyListener.Private.pendingEvent", message);
+     }
+ 
+-    if (events.size() > 0)
+-        m_pEventQueue->addEvents (events);
+-
+     fflush( NULL );
+ }
+ 
+-bool
+-InotifyListener::isEventInteresting (struct inotify_event * event)
+-{
+-    // ignore files starting with '.'
+-    if (((IN_ISDIR & event->mask) == 0) && (event->len > 0)
+-          && ((event->name)[0] == '.'))
+-        return false;
+-
+-    //TODO: FIX with AnalyzerConfiguration
+-//     if (m_pFilterManager != NULL)
+-//     {
+-//         if ((event->len > 0) && m_pFilterManager->findMatch(event->name, event->len))
+-//             return false;
+-//     }
+-//     else
+-//         STRIGI_LOG_WARNING ("strigi.InotifyListener.isEventInteresting", "unable to use filters, m_pFilterManager == NULL!")
+-
+-    return true;
+-}
+-
+-bool InotifyListener::addWatch (const string& path)
++bool InotifyListener::Private::addWatch (const string& path)
+ {
+-    if (!m_bInitialized)
+-        return false;
+-
+-    STRIGI_MUTEX_LOCK (&m_watchesLock);
+-
+     map<int, string>::iterator iter;
+     for (iter = m_watches.begin(); iter != m_watches.end(); iter++)
+     {
+         if ((iter->second).compare (path) == 0) // dir is already watched
+-        {
+-            STRIGI_MUTEX_UNLOCK (&m_watchesLock);
+             return true;
+-        }
+     }
+ 
+     static int wd;
+@@ -919,30 +302,28 @@
+ 
+     if (wd < 0)
+     {
+-        STRIGI_MUTEX_UNLOCK (&m_watchesLock);
+-
+         if ((wd == -1) && ( errno == ENOSPC))
+         {
+-            STRIGI_LOG_ERROR ("strigi.InotifyListener.addWatch",
++            STRIGI_LOG_ERROR ("strigi.InotifyListener.Private.addWatch",
+                               "Failed to watch, maximum watch number reached");
+-            STRIGI_LOG_ERROR ("strigi.InotifyListener.addWatch",
++            STRIGI_LOG_ERROR ("strigi.InotifyListener.Private.addWatch",
+                               "You've to increase the value stored into\
+                                /proc/sys/fs/inotify/max_user_watches");
+         }
+         else if ( wd == -1 )
+         {
+-            STRIGI_LOG_ERROR ("strigi.InotifyListener.addWatch",
++            STRIGI_LOG_ERROR ("strigi.InotifyListener.Private.addWatch",
+                               "Failed to watch " + path + " because of: " +
+-                               strerror(-wd));
++                                      strerror(-wd));
+         }
+         else
+         {
+             char buff [20];
+             snprintf(buff, 20* sizeof (char), "%i", wd);
+ 
+-            STRIGI_LOG_ERROR ("strigi.InotifyListener.addWatch",
++            STRIGI_LOG_ERROR ("strigi.InotifyListener.Private.addWatch",
+                               "Failed to watch " + path + ": returned wd was " +
+-                               buff + " (expected -1 or >0 )");
++                                      buff + " (expected -1 or >0 )");
+         }
+ 
+         return false;
+@@ -951,412 +332,270 @@
+     {
+         m_watches.insert(make_pair(wd, path));
+ 
+-        STRIGI_MUTEX_UNLOCK (&m_watchesLock);
+-
+-        STRIGI_LOG_INFO ("strigi.InotifyListener.addWatch",
++        STRIGI_LOG_INFO ("strigi.InotifyListener.Private.addWatch",
+                          "added watch for " + path);
+ 
+         return true;
+     }
+ }
+ 
+-void InotifyListener::addWatches (const set<string> &watches,
+-                                  bool enableInterrupt)
+-{
+-    set<string>::iterator iter;
+-    set<string> toPool;
+-    set<string> watched;
+-
+-    for (iter = watches.begin(); iter != watches.end(); iter++)
+-    {
+-        if (enableInterrupt && testInterrupt())
+-            break;
+-        
+-        if (!addWatch (*iter))
+-        {
+-
+-            if (errno == ENOSPC)
+-                 // user can't add no more watches, it's useless to go on
+-                break;
+-
+-            // adding watch failed for other reason, keep trying with others
+-            toPool.insert(*iter);
+-        }
+-        else
+-            watched.insert (*iter);
+-    }
+-
+-    if (iter != watches.end())
+-    {
+-        // probably we reached the max_user_watches limit
+-        for ( ; iter != watches.end(); iter++)
+-            toPool.insert (*iter);
+-    }
+-
+-    
+-    if (enableInterrupt && testInterrupt())
+-    {
+-        //TODO: check
+-        
+-        vector <Event*> events;
+-        // recover from interrupt
+-        for (set<string>::iterator iter = watched.begin();
+-             iter != watched.end(); iter++)
+-        {
+-            dirRemoved (*iter, events);
+-        }
+-        
+-        m_pEventQueue->addEvents(events);
+-        
+-        setInterrupt (false);
+-    }
+-    else if (!toPool.empty())
+-    {
+-        if (m_pollingListener == NULL)
+-        {
+-            m_pollingListener = new PollingListener();
+-            m_pollingListener->setEventListenerQueue( m_pEventQueue);
+-            m_pollingListener->setCombinedIndexManager( m_pManager);
+-            m_pollingListener->setIndexerConfiguration(m_pindexerconfiguration);
+-            //TODO: start with a low priority?
+-            m_pollingListener->start( );
+-        }
+-        
+-        m_pollingListener->addWatches( toPool);
+-    }
+-}
+-
+-void InotifyListener::rmWatch(int wd, string path)
++void InotifyListener::Private::rmWatch(int wd, string path)
+ {
+     char buff [20];
+     snprintf(buff, 20 * sizeof (char), "%i",wd);
+ 
+     if (inotify_rm_watch (m_iInotifyFD, wd) == -1)
+     {
+-        STRIGI_LOG_ERROR ("strigi.InotifyListener.rmWatch",
+-                           string("Error removing watch ") + buff +
+-                           " associated to path: " + path);
+-        STRIGI_LOG_ERROR ("strigi.InotifyListener.rmWatch",
+-                           string("error: ") + strerror(errno));
++        STRIGI_LOG_ERROR ("strigi.InotifyListener.Private.rmWatch",
++                          string("Error removing watch ") + buff +
++                                  " associated to path: " + path);
++        STRIGI_LOG_ERROR ("strigi.InotifyListener.Private.rmWatch",
++                          string("error: ") + strerror(errno));
+     }
+     else
+-        STRIGI_LOG_DEBUG ("strigi.InotifyListener.rmWatch",
+-                           string("Removed watch ") + buff + 
+-                           " associated to path: " + path);
++        STRIGI_LOG_DEBUG ("strigi.InotifyListener.Private.rmWatch",
++                          string("Removed watch ") + buff +
++                                  " associated to path: " + path);
+     
+-    STRIGI_MUTEX_LOCK (&m_watchesLock);
+     map<int, string>::iterator match = m_watches.find(wd);
+     
+     if (match != m_watches.end() && (path.compare(match->second) == 0))
+         m_watches.erase (match);
+     else
+-        STRIGI_LOG_ERROR ("strigi.InotifyListener.rmWatch",
++        STRIGI_LOG_ERROR ("strigi.InotifyListener.Private.rmWatch",
+                        "unable to remove internal watch reference for " + path);
+-    
+-    STRIGI_MUTEX_UNLOCK (&m_watchesLock);
+ }
+ 
+-void InotifyListener::rmWatches(map<int, string>& watchesToRemove,
+-                                bool enableInterrupt)
++void InotifyListener::Private::rmWatches(map<int, string>& watchesToRemove)
+ {
+-    set<string> removedWatches;
+-    map<int,string> watches;
+-    
+-    STRIGI_MUTEX_LOCK (&m_watchesLock);
+-    watches = m_watches;
+-    STRIGI_MUTEX_UNLOCK (&m_watchesLock);
+-    
+     for (map<int,string>::iterator it = watchesToRemove.begin();
+          it != watchesToRemove.end(); it++)
+     {
+-        if (enableInterrupt && testInterrupt())
+-            break;
+-        
+-        map<int,string>::iterator match = watches.find (it->first);
+-        if (match != watches.end())
+-        {
++        map<int,string>::iterator match = m_watches.find (it->first);
++        if (match != m_watches.end())
+             rmWatch (it->first, it->second);
+-            removedWatches.insert (it->second);
+-        }
+         else
+-            STRIGI_LOG_WARNING ("strigi.InotifyListener.rmWatches", 
+-                        "unable to remove watch associated to " + it->second);
+-    }
+-    
+-    if (enableInterrupt && testInterrupt())
+-    {
+-        // undo the delete operation
+-        for (set<string>::iterator it = removedWatches.begin();
+-             it != removedWatches.end(); it++)
+-        {
+-            addWatch (*it);
+-        }
++            STRIGI_LOG_WARNING ("strigi.InotifyListener.Private.rmWatches",
++                          "unable to remove watch associated to " + it->second);
+     }
+ }
+ 
+-void InotifyListener::rmWatches(set<string>& watchesToRemove,
+-                                bool enableInterrupt)
++void InotifyListener::Private::rmWatches(set<string>& watchesToRemove)
+ {
+     map<int, string> removedWatches;
+     
+-    STRIGI_MUTEX_LOCK (&m_watchesLock);
+     // find all pairs <watch-id, watch-name> that have to be removed
+     for (set<string>::iterator it = watchesToRemove.begin();
+          it != watchesToRemove.end(); it++)
+     {
+         MatchString finder (*it);
+-        map<int, string>::iterator match = find_if (m_watches.begin(), m_watches.end(),
+-                                         finder);
++        map<int, string>::iterator match = find_if (m_watches.begin(),
++                m_watches.end(), finder);
+         if (match != m_watches.end())
+             removedWatches.insert (make_pair (match->first, match->second));
+         else
+-            STRIGI_LOG_WARNING ("strigi.InotifyListener.rmWatches",
+-                "unable to find the watch associated to " + *it);
++            STRIGI_LOG_WARNING ("strigi.InotifyListener.Private.rmWatches",
++                                "unable to find the watch associated to " + *it);
+     }
+-    STRIGI_MUTEX_UNLOCK (&m_watchesLock);
+-
+-    if (!enableInterrupt || !testInterrupt())
+-        rmWatches (removedWatches, enableInterrupt);
++    
++    rmWatches (removedWatches);
+ }
+ 
+-void InotifyListener::clearWatches ()
++void InotifyListener::Private::clearWatches ()
+ {
+-    STRIGI_MUTEX_LOCK (&m_watchesLock);
++    map<int, string>::iterator iter;
++    for (iter = m_watches.begin(); iter != m_watches.end(); iter++) {
++        char buff [20];
++        snprintf(buff, 20 * sizeof (char), "%i", iter->first);
+ 
+-    for (map<int, string>::iterator iter = m_watches.begin();
+-         iter != m_watches.end(); iter++) 
+-    {
+-        rmWatch (iter->first, iter->second);
++        if (inotify_rm_watch (m_iInotifyFD, iter->first) == -1)
++        {
++            STRIGI_LOG_ERROR ("strigi.InotifyListener.Private.clearWatches",
++                              string("Error removing watch ") + buff +
++                                      " associated to path: " + iter->second);
++            STRIGI_LOG_ERROR ("strigi.InotifyListener.Private.clearWatches",
++                              string("error: ") + strerror(errno));
++        }
++        else
++            STRIGI_LOG_DEBUG ("strigi.InotifyListener.Private.clearWatches",
++                              string("Removed watch ") + buff +
++                                      " associated to path: " + iter->second);
+     }
+ 
+     m_watches.clear();
+-
+-    STRIGI_MUTEX_UNLOCK (&m_watchesLock);
+ }
+ 
+-void InotifyListener::dirRemoved (string dir, vector<Event*>& events,
+-                                  bool enableInterrupt)
++bool InotifyListener::Private::isEventValid(FsEvent* event)
+ {
+-    dir = fixPath (dir);
+-    vector<Event*> newEvents;
+-    map<int, string> watches;
+-    map<int, string> watchesToRemove;
++    InotifyEvent* inotifyEvent = dynamic_cast<InotifyEvent*> (event);
+ 
+-    STRIGI_LOG_DEBUG ("strigi.InotifyListener.dirRemoved", dir +
+-            " is no longer watched, removing all indexed files contained");
++    if (inotifyEvent == 0)
++        return false;
+ 
+-    // we've to de-index all files contained into the deleted/moved directory
+-    if (m_pManager)
+-    {
+-        // all indexed files contained into dir
+-        map<string, time_t> indexedFiles;
+-        m_pManager->indexReader()->getChildren(dir, indexedFiles);
++    map<int, string>::iterator match = m_watches.find(inotifyEvent->watchID());
+ 
+-        // remove all entries that were contained into the removed dir
+-        for (map<string, time_t>::iterator it = indexedFiles.begin();
+-             it != indexedFiles.end(); it++)
+-        {
+-            if (enableInterrupt && testInterrupt())
+-                break;
+-            
+-            Event* event = new Event (Event::DELETED, it->first);
+-            newEvents.push_back (event);
+-        }
+-    }
+-    else
+-        STRIGI_LOG_WARNING ("strigi.InotifyListener.dirRemoved",
+-                            "m_pManager == NULL!");
++    return (match != m_watches.end());
++}
+ 
+-    // remove inotify watches over no more indexed dirs
+-    STRIGI_MUTEX_LOCK (&m_watchesLock);
+-    watches = m_watches;
+-    STRIGI_MUTEX_UNLOCK (&m_watchesLock);
++void InotifyListener::Private::dirRemoved (string dir)
++{
++    map <int, string> watchesToRemove;
+     
+-    for (map<int, string>::iterator mi = watches.begin();
+-         mi != watches.end(); mi++)
++    // remove inotify watches over no more indexed directories
++    for (map<int, string>::iterator mi = m_watches.begin();
++         mi != m_watches.end(); mi++)
+     {
+         if ((mi->second).find (dir,0) == 0)
+             watchesToRemove.insert (make_pair (mi->first, mi->second));
+-        
+-        if (enableInterrupt && testInterrupt())
+-            break;
+-    }
+-    
+-    if (enableInterrupt && testInterrupt())
+-    {
+-        for (vector<Event*>::iterator iter = newEvents.begin();
+-             iter != newEvents.end(); iter++)
+-        {
+-            delete *iter;
+-        }
+-        newEvents.clear();
+-    }
+-    else
+-    {
+-        rmWatches (watchesToRemove);
+-        
+-        for (vector<Event*>::iterator iter = newEvents.begin();
+-             iter != newEvents.end(); iter++)
+-        {
+-            events.push_back(*iter);
+-        }
+-        newEvents.clear();
+     }
+     
+-    // remove also dir watched by pollinglistener
+-    //FIXME: to fix, call right method
+-    if (m_pollingListener != NULL)
+-        m_pollingListener->rmWatch( dir);
++    rmWatches (watchesToRemove);
+ }
+ 
+-void InotifyListener::dirsRemoved (set<string> dirs, vector<Event*>& events,
+-                                   bool enableInterrupt)
++// END InotifyListener::Private
++
++
++InotifyListener::InotifyListener(set<string>& indexedDirs)
++    :FsListener("InotifyListener", indexedDirs)
+ {
+-    vector<Event*> newEvents;
+-    
+-    for (set<string>::iterator iter = dirs.begin();
+-         iter != dirs.end(); iter++)
+-    {
+-        if (enableInterrupt && testInterrupt())
+-            break;
+-        
+-        dirRemoved (*iter, newEvents, enableInterrupt);
+-    }
+-    
+-    if (enableInterrupt && testInterrupt())
+-    {
+-        STRIGI_LOG_DEBUG ("strigi.InotifyListener.dirsRemoved",
+-                          "recovering from interrupt signal");
+-        
+-        for (vector<Event*>::iterator iter = newEvents.begin();
+-             iter != newEvents.end(); iter++)
+-        {
+-            delete *iter;
+-        }
+-        newEvents.clear();
+-    }
+-    else
+-    {
+-        printf ("newEvents.size() == %i\n",events.size());
+-        for (vector<Event*>::iterator iter = newEvents.begin();
+-             iter != newEvents.end(); iter++)
+-        {
+-            events.push_back(*iter);
+-        }
+-        newEvents.clear();
+-    }
++    p = new Private();
+ }
+ 
+-void InotifyListener::setInterrupt (bool value)
++InotifyListener::~InotifyListener()
+ {
+-    STRIGI_MUTEX_LOCK(&m_interruptLock);
+-    m_bInterrupt = value;
+-    STRIGI_MUTEX_UNLOCK(&m_interruptLock);
++    clearWatches();
++    delete p;
++
+ }
+ 
+-bool InotifyListener::testInterrupt()
++void InotifyListener::clearWatches ()
+ {
+-    bool value;
+-    STRIGI_MUTEX_LOCK(&m_interruptLock);
+-    value = m_bInterrupt;
+-    STRIGI_MUTEX_UNLOCK(&m_interruptLock);
+-    
+-    if (value)
+-        STRIGI_LOG_DEBUG ("strigi.ReindexDirsThread.testInterrupt",
+-                          "Caught interrupt event");
+-    
+-    return value;
++    p->clearWatches();
+ }
+ 
+-void InotifyListener::setIndexedDirectories (const set<string> &dirs) {
+-    if (!m_pManager) {
+-        STRIGI_LOG_ERROR ("strigi.InotifyListener.setIndexedDirectories",
+-                          "m_pManager == NULL!");
+-        return;
+-    }
+-    if (m_pEventQueue == NULL)
+-    {
+-        STRIGI_LOG_ERROR ("strigi.InotifyListener.setIndexedDirectories",
+-                          "m_pEventQueue == NULL!");
+-        return;
++bool InotifyListener::init()
++{
++    if (!p->init()) {
++        STRIGI_LOG_ERROR ("strigi.InotifyListener.init",
++                        "inotify_init() failed.  Are you running Linux 2.6.13\
++                        or later? If so, something mysterious has gone wrong.");
++        return false;
+     }
+ 
+-    set<string> fixedDirs;
++    m_bInitialized = true;
+ 
+-    // fix path, all dir must end with a '/'
+-    for (set<string>::iterator iter = dirs.begin(); iter != dirs.end(); iter++)
+-        fixedDirs.insert (fixPath (*iter));
++    STRIGI_LOG_DEBUG ("strigi.InotifyListener.init","successfully initialized");
+ 
+-    if (m_pReindexDirThread == NULL)
+-    {
+-        m_pReindexDirThread = new ReindexDirsThread ("ReindexDirThread",
+-                                                     m_indexedDirs);
+-        m_pReindexDirThread->setIndexerConfiguration(m_pindexerconfiguration);
+-        m_pReindexDirThread->setCombinedIndexManager ( m_pManager);
++    return true;
++}
++
++FsEvent* InotifyListener:: retrieveEvent()
++{
++    if (m_events.empty())
++        return 0;
++
++    vector<FsEvent*>::iterator iter = m_events.begin();
++    
++    FsEvent* event = *iter;
++    m_events.erase(iter);
++    
++    STRIGI_LOG_DEBUG("strigi.InotifyListener.retrieveEvent",
++                     "returning " + event->description())
++    
++    return event;
++}
+ 
+-        m_pReindexDirThread->start();
++bool InotifyListener::pendingEvent()
++{
++    unsigned int counter = 0;
++    p->pendingEvent(m_events, counter);
++    
++    if (counter > 0) {
++        char buff [20];
++        snprintf(buff, 20 * sizeof (char), "%i", counter);
++        string message = "Caught ";
++        message += buff;
++        message += " inotify's pending event(s)";
++        
++        STRIGI_LOG_DEBUG ("strigi.InotifyListener.pendingEvent", message)
+     }
+     
+-    if (m_pReindexDirThread->working())
+-        setInterrupt (true);
++    dumpEvents();
+     
+-    STRIGI_MUTEX_LOCK (&m_watchesLock);
+-    map <int, string> watches = m_watches;
+-    STRIGI_MUTEX_UNLOCK (&m_watchesLock);
++    return !m_events.empty();
++}
++
++bool InotifyListener::isEventInteresting (FsEvent* event)
++{
++    InotifyEvent* inotifyEvent = dynamic_cast<InotifyEvent*> (event);
++
++    if (inotifyEvent == 0)
++        return false;
+     
+-    m_pReindexDirThread->setIndexedDirs( fixedDirs, watches);
++    struct inotify_event* structInotify = inotifyEvent->event();
++
++    if ((structInotify->wd && IN_IGNORED) == 0)
++        return false;
++
++    // ignore files starting with '.'
++    if (((IN_ISDIR & structInotify->mask) == 0) && (structInotify->len > 0)
++          && ((structInotify->name)[0] == '.'))
++        return false;
++
+ 
+-    string newdirs;
++    if (m_pAnalyzerConfiguration == NULL) {
++        STRIGI_LOG_WARNING ("strigi.InotifyListener.isEventInteresting",
++                            "AnalyzerConfiguration == NULL")
++        return true;
++    }
+ 
+-    for (set<string>::iterator iter = fixedDirs.begin(); iter != fixedDirs.end(); iter++)
+-        newdirs += ('|' + *iter);
++    string path = inotifyEvent->watchName();
++    if (path[path.length() - 1] != '/')
++        path += "/";
++    path += inotifyEvent->name();
++    
++    if (inotifyEvent->regardsDir())
++        return m_pAnalyzerConfiguration->indexDir( path.c_str(),
++                                                   inotifyEvent->name());
++    else
++        return m_pAnalyzerConfiguration->indexFile( path.c_str(),
++                                                    inotifyEvent->name());
++}
+ 
+-    STRIGI_LOG_DEBUG ("strigi.InotifyListener.setIndexedDirectories",
+-                      "new indexed dirs: " + newdirs);
++bool InotifyListener::isEventValid(FsEvent* event)
++{
++    return p->isEventValid (event);
+ }
+ 
+-string InotifyListener::eventToString(int events)
++bool InotifyListener::addWatch (const string& path)
+ {
+-    string message;
++    return p->addWatch (path);
++}
+ 
+-    if ( (IN_ACCESS & events) != 0 )
+-        message += "ACCESS";
+-    else if ( (IN_MODIFY & events) != 0 )
+-        message += "MODIFY";
+-    else if ( (IN_ATTRIB & events) != 0 )
+-        message += "ATTRIB";
+-    else if ( (IN_CLOSE_WRITE & events) != 0 )
+-        message += "CLOSE_WRITE";
+-    else if ( (IN_CLOSE_NOWRITE & events) != 0 )
+-        message += "CLOSE_NOWRITE";
+-    else if ( (IN_OPEN & events) != 0 )
+-        message += "OPEN";
+-    else if ( (IN_MOVED_FROM & events) != 0 )
+-        message += "MOVED_FROM";
+-    else if ( (IN_MOVED_TO & events) != 0 )
+-        message += "MOVED_TO";
+-    else if ( (IN_CREATE & events) != 0 )
+-        message += "CREATE";
+-    else if ( (IN_DELETE & events) != 0 )
+-        message += "DELETE";
+-    else if ( (IN_DELETE_SELF & events) != 0 )
+-        message += "DELETE_SELF";
+-    else if ( (IN_UNMOUNT & events) != 0 )
+-        message += "UNMOUNT";
+-    else if ( (IN_Q_OVERFLOW & events) != 0 )
+-        message += " Q_OVERFLOW";
+-    else if ( (IN_IGNORED & events) != 0 )
+-        message += " IGNORED";
+-    else if ( (IN_CLOSE & events) != 0 )
+-        message += "CLOSE";
+-    else if ( (IN_MOVE & events) != 0 )
+-        message += "MOVE";
+-    else if ( (IN_ISDIR & events) != 0 )
+-        message += " ISDIR";
+-    else if ( (IN_ONESHOT & events) != 0 )
+-        message += " ONESHOT";
+-    else
+-        message = "UNKNOWN";
++void InotifyListener::dirRemoved (string dir, vector<Event*>& events)
++{
++    map<int, string> watchesToRemove;
++    
++    STRIGI_LOG_DEBUG ("strigi.InotifyListener.dirRemoved", dir +
++            " is no longer watched, removing all indexed files contained");
++    
++    // we've to de-index all files contained into the deleted/moved directory
++    if (m_pManager)
++    {
++        // all indexed files contained into directory
++        map<string, time_t> indexedFiles;
++        m_pManager->indexReader()->getChildren(dir, indexedFiles);
+ 
+-    return message;
++        // remove all entries that were contained into the removed directory
++        for (map<string, time_t>::iterator it = indexedFiles.begin();
++             it != indexedFiles.end(); it++)
++        {
++            Event* event = new Event (Event::DELETED, it->first);
++            events.push_back (event);
++        }
++    }
++    else
++        STRIGI_LOG_WARNING ("strigi.InotifyListener.Private.dirRemoved",
++                            "m_pManager == NULL!");
++    p->dirRemoved (dir);
+ }
+--- a/src/daemon/eventlistener/inotifylistener.h
++++ b/src/daemon/eventlistener/inotifylistener.h
+@@ -20,7 +20,7 @@
+ #ifndef INOTIFYLISTENER_H
+ #define INOTIFYLISTENER_H
+ 
+-#include "eventlistener.h"
++#include "fslistener.h"
+ #include "strigi_thread.h"
+ #include <map>
+ #include <vector>
+@@ -28,105 +28,59 @@
+ class Event;
+ class PollingListener;
+ 
+-/*!
+-* @class InotifyListener
+-* @brief Interacts with kernel inotify monitoring recursively all changes over indexed directories
+-*/
++class InotifyEvent : public FsEvent
++{
++    public:
++        InotifyEvent(int watchID, const std::string& watchName,
++                     struct inotify_event* event);
++
++        const std::string description();
++        bool regardsDir();
++
++        struct inotify_event* event() { return m_event;}
++        char* name();
++        int watchID() { return m_watchID;}
++        std::string watchName() { return m_watchName;}
++        
++    private:
++        struct inotify_event* m_event;
++        std::string m_watchName;
++        int m_watchID;
++
++};
+ 
+-class InotifyListener : public EventListener
++/*!
++ * @class InotifyListener
++ * @brief Uses linux kernel inotify facility in order to keep strigi's index updated. 
++ */
++class InotifyListener : public FsListener
+ {
++    private:
++        class Private;
++        Private* p; 
++    
+     public:
+         explicit InotifyListener(std::set<std::string>& indexedDirs);
+ 
+-        ~InotifyListener();
++        virtual ~InotifyListener();
+ 
+         bool init();
+ 
+-        bool addWatch (const std::string& path);
+-        void addWatches (const std::set<std::string>& watches,
+-                         bool enableInterrupt = false);
+-        void setIndexedDirectories (const std::set<std::string>& dirs);
+-
+-        void* run(void*);
+-
+     protected:
+-        /*!
+-        * @param event inotify's event mask
+-        * returns a string containing the event description
+-        */
+-        std::string eventToString(int events);
+-
+-        /*!
+-        * @param event the inotify event to analyze
+-        * returns true if event is to process (ergo is interesting), false otherwise
+-        */
+-        bool isEventInteresting (struct inotify_event * event);
+-
+-        /*!
+-        * main InotifyListener thread
+-        */
+-        void watch ();
++        void stopMonitoring();
+ 
+-        
+-        void processReindexDirThreadData();
+-        /*!
+-        * @param dir removed dir
+-        * Removes all db entries of files contained into the removed dir.
+-        * Removes also all inotify watches related to removed dir (including watches over subdirs), there's <b>no need</b> to call rmWatch after invoking that method
+-        * Updates also m_watches
+-        */
+-        void dirRemoved (std::string dir,
+-                         std::vector<Event*>& events,
+-                         bool enableInterrupt = false);
+-
+-        /*!
+-        * @param dirs removed dirs
+-        * Removes all db entries of files contained into the removed dirs.
+-        * Removes also all inotify watches related to removed dirs (including watches over subdirs), there's <b>no need</b> to call rmWatch after invoking that method
+-        * Optimized for large removal
+-        * Updates also m_watches
+-        */
+-        void dirsRemoved (std::set<std::string> dirs,
+-                          std::vector<Event*>& events,
+-                          bool enableInterrupt = false);
+-
+-        /*!
+-        * @param wd inotify watch descriptor
+-        * @param path path associated to inotify watch
+-        * removes and release an inotify watch. Usually there's no need to use this method.
+-        * @sa dirRemoved
+-        */
+-        void rmWatch(int wd, std::string path);
++        // event methods
++        bool pendingEvent();
++        FsEvent* retrieveEvent();
++        bool isEventValid(FsEvent* event);
++        bool isEventInteresting (FsEvent * event);
+ 
+-        void rmWatches(std::map<int, std::string>& watchesToRemove,
+-                       bool enableInterrupt = false);
+-        
+-        void rmWatches(std::set<std::string>& watchesToRemove,
+-                       bool enableInterrupt = false);
+-        
+-        /*!
+-        * removes and release all inotify watches
+-        */
+-        void clearWatches();
+-        
+-        void setInterrupt (bool value);
+-        bool testInterrupt();
++        void dirRemoved (std::string dir, std::vector<Event*>& events);
+ 
+-        PollingListener* m_pollingListener;
+-        int m_iInotifyFD;
+-        int m_iEvents;
+-        std::map<int, std::string> m_watches; //!< map containing all inotify watches added by InotifyListener. Key is watch descriptor, value is dir path
+-        bool m_bMonitor;
+-        bool m_bInterrupt;
+-        bool m_bInitialized;
+-        std::map<std::string, time_t> m_toIndex;
+-        std::set<std::string> m_toWatch;
+-        std::set<std::string> m_indexedDirs;
+-        pthread_mutex_t m_watchesLock;
+-        pthread_mutex_t m_interruptLock;
++        // watches methods
++        bool addWatch (const std::string& path);
+ 
+-        class ReindexDirsThread;
+-        ReindexDirsThread* m_pReindexDirThread;
++        void clearWatches();
+ };
+ 
+ #endif
+--- a/src/daemon/eventlistener/pollinglistener.cpp
++++ b/src/daemon/eventlistener/pollinglistener.cpp
+@@ -106,14 +106,14 @@
+ }
+ void PollingListener::poll () {
+     assert(m_pManager);
+-    assert(m_pindexerconfiguration);
++    assert(m_pAnalyzerConfiguration);
+ 
+     // get a shadow copy of m_watches
+     STRIGI_MUTEX_LOCK (&m_mutex);
+     vector<string> watches = m_watches;
+     STRIGI_MUTEX_UNLOCK (&m_mutex);
+ 
+-    DirAnalyzer diranalyzer(*m_pManager, *m_pindexerconfiguration);
++    DirAnalyzer diranalyzer(*m_pManager, *m_pAnalyzerConfiguration);
+     STRIGI_LOG_DEBUG ("strigi.PollingListener.poll", "going across filesystem");
+     diranalyzer.updateDirs(watches, 1, this);
+     STRIGI_LOG_DEBUG ("strigi.PollingListener.poll",
+@@ -157,7 +157,7 @@
+ }
+ 
+ void
+-PollingListener::addWatches(const set<string>& watches, bool enableInterrupt) {
++PollingListener::addWatches(const set<string>& watches) {
+     for (set<string>::iterator iter = watches.begin();
+             iter != watches.end(); iter++) {
+         string temp = fixPath(*iter);
+--- a/src/daemon/eventlistener/pollinglistener.h
++++ b/src/daemon/eventlistener/pollinglistener.h
+@@ -53,8 +53,7 @@
+ 
+     bool addWatch (const std::string& path);
+     void rmWatch (const std::string& path);
+-    void addWatches (const std::set<std::string>& watches,
+-                     bool enableInterrupt = false);
++    void addWatches (const std::set<std::string>& watches);
+     void setIndexedDirectories (const std::set<std::string>& dirs);
+ 
+     void* run(void*);
+--- a/src/luceneindexer/luceneindexer.cpp
++++ b/src/luceneindexer/luceneindexer.cpp
+@@ -25,6 +25,7 @@
+ #include <sys/types.h>
+ #include <stgdirent.h>
+ #include <string.h>
++#include <stdlib.h>
+ 
+ using namespace std;
+ 
+@@ -36,19 +37,20 @@
+     }
+     return false;
+ }
+-void
++bool
+ checkIndexdirIsEmpty(const char* dir) {
+     DIR* d = opendir(dir);
+-    if (!d) return;
++    if (!d) return false;
+     struct dirent* de = readdir(d);
+     while (de) {
+         if (strcmp(de->d_name, "..") && strcmp(de->d_name, ".")) {
+             fprintf(stderr, "Directory %s is not empty.\n", dir);
+-            exit(1);
++            return false;
+         }
+         de = readdir(d);
+     }
+     closedir(d);
++    return true;
+ }
+ int
+ main(int argc, char **argv) {
+@@ -57,7 +59,9 @@
+         return -1;
+     }
+ 
+-    checkIndexdirIsEmpty(argv[1]);
++    if (!checkIndexdirIsEmpty(argv[1])) {
++        return 1;
++    }
+ 
+     vector<pair<bool,string> >filters;
+     filters.push_back(make_pair<bool,string>(false,".*/"));
+--- a/src/streamanalyzer/CMakeLists.txt
++++ b/src/streamanalyzer/CMakeLists.txt
+@@ -67,7 +67,8 @@
+ #	set(streamindex_LIBS ${streamindex_LIBS} ntquery)
+ #ELSE(WIN32)
+ 	add_library(streamanalyzer SHARED ${streamanalyzer_SRCS})
+-	install(TARGETS streamanalyzer LIBRARY DESTINATION ${LIB_DESTINATION})
++	install(TARGETS streamanalyzer LIBRARY DESTINATION ${LIB_DESTINATION}
++                                   RUNTIME DESTINATION ${LIB_DESTINATION})
+ #ENDIF(WIN32)
+ 
+ set_target_properties(streamanalyzer PROPERTIES
+--- a/src/streamanalyzer/endanalyzers/arendanalyzer.cpp
++++ b/src/streamanalyzer/endanalyzers/arendanalyzer.cpp
+@@ -21,11 +21,13 @@
+ #include <strigi/strigiconfig.h>
+ #include "arinputstream.h"
+ #include "analysisresult.h"
++#include "fieldtypes.h"
+ #include "subinputstream.h"
+ using namespace Strigi;
+ 
+ void
+ ArEndAnalyzerFactory::registerFields(FieldRegister& reg) {
++    typeField = reg.typeField;
+ }
+ 
+ bool
+@@ -34,7 +36,9 @@
+ }
+ char
+ ArEndAnalyzer::analyze(AnalysisResult& idx, InputStream* in) {
+-    return staticAnalyze(idx, in);
++    char result = staticAnalyze(idx, in);
++    idx.addValue(factory->typeField, "http://freedesktop.org/standards/xesam/1.0/core#Archive");
++    return  result;
+ }
+ char
+ ArEndAnalyzer::staticAnalyze(AnalysisResult& idx,
+--- a/src/streamanalyzer/endanalyzers/arendanalyzer.h
++++ b/src/streamanalyzer/endanalyzers/arendanalyzer.h
+@@ -23,8 +23,14 @@
+ #include "streamendanalyzer.h"
+ #include "streambase.h"
+ 
++class ArEndAnalyzerFactory;
+ class ArEndAnalyzer : public Strigi::StreamEndAnalyzer {
++private:
++    const ArEndAnalyzerFactory* factory;
+ public:
++    ArEndAnalyzer(const ArEndAnalyzerFactory* f)
++        :factory(f) {}
++
+     bool checkHeader(const char* header, int32_t headersize) const;
+     char analyze(Strigi::AnalysisResult& idx, Strigi::InputStream* in);
+     static char staticAnalyze(Strigi::AnalysisResult& idx,
+@@ -33,12 +39,15 @@
+ };
+ 
+ class ArEndAnalyzerFactory : public Strigi::StreamEndAnalyzerFactory {
++friend class ArEndAnalyzer;
++private:
++    const Strigi::RegisteredField* typeField;
+ public:
+     const char* name() const {
+         return "ArEndAnalyzer";
+     }
+     Strigi::StreamEndAnalyzer* newInstance() const {
+-        return new ArEndAnalyzer();
++        return new ArEndAnalyzer(this);
+     }
+     bool analyzesSubStreams() const { return true; }
+     void registerFields(Strigi::FieldRegister&);
+--- a/src/streamanalyzer/endanalyzers/bmpendanalyzer.cpp
++++ b/src/streamanalyzer/endanalyzers/bmpendanalyzer.cpp
+@@ -40,6 +40,8 @@
+     widthField = reg.registerField(widthFieldName);
+     heightField = reg.registerField(heightFieldName);
+     colorDepthField = reg.registerField(colorDepthFieldName);
++
++    rdftypeField = reg.typeField;
+ }
+ 
+ bool
+@@ -115,6 +117,8 @@
+         rs.addValue(factory->compressionField, "Unknown");
+     }
+ 
++    rs.addValue(factory->rdftypeField, "http://freedesktop.org/standards/xesam/1.0/core#Image");
++
+     return 0;
+ }
+ 
+--- a/src/streamanalyzer/endanalyzers/bmpendanalyzer.h
++++ b/src/streamanalyzer/endanalyzers/bmpendanalyzer.h
+@@ -47,6 +47,9 @@
+     const Strigi::RegisteredField* heightField;
+     const Strigi::RegisteredField* colorDepthField;
+     const Strigi::RegisteredField* compressionField;
++
++    const Strigi::RegisteredField* rdftypeField;
++
+     const char* name() const {
+         return "BmpEndAnalyzer";
+     }
+--- a/src/streamanalyzer/endanalyzers/bz2endanalyzer.cpp
++++ b/src/streamanalyzer/endanalyzers/bz2endanalyzer.cpp
+@@ -24,11 +24,14 @@
+ #include "tarinputstream.h"
+ #include "streamanalyzer.h"
+ #include "analysisresult.h"
++#include "fieldtypes.h"
++
+ using namespace std;
+ using namespace Strigi;
+ 
+ void
+ Bz2EndAnalyzerFactory::registerFields(FieldRegister& reg) {
++    typeField = reg.typeField;
+ }
+ 
+ bool
+@@ -53,6 +56,7 @@
+         fprintf(stderr, "Error reading bz2: %s\n", stream.error());
+         return -2;
+     }
++    idx.addValue(factory->typeField, "http://freedesktop.org/standards/xesam/1.0/core#Archive");
+     stream.reset(0);
+     if (TarInputStream::checkHeader(start, nread)) {
+         return TarEndAnalyzer::staticAnalyze(idx, &stream);
+--- a/src/streamanalyzer/endanalyzers/bz2endanalyzer.h
++++ b/src/streamanalyzer/endanalyzers/bz2endanalyzer.h
+@@ -23,20 +23,29 @@
+ #include "streamendanalyzer.h"
+ #include "streambase.h"
+ 
++class Bz2EndAnalyzerFactory;
+ class Bz2EndAnalyzer : public Strigi::StreamEndAnalyzer {
++private:
++    const Bz2EndAnalyzerFactory* factory;
+ public:
++    Bz2EndAnalyzer(const Bz2EndAnalyzerFactory* f)
++        :factory(f) {}
++
+     bool checkHeader(const char* header, int32_t headersize) const;
+     char analyze(Strigi::AnalysisResult& idx, Strigi::InputStream* in);
+     const char* name() const { return "Bz2EndAnalyzer"; }
+ };
+ 
+ class Bz2EndAnalyzerFactory : public Strigi::StreamEndAnalyzerFactory {
++friend class Bz2EndAnalyzer;
++private:
++    const Strigi::RegisteredField* typeField;
+ public:
+     const char* name() const {
+         return "Bz2EndAnalyzer";
+     }
+     Strigi::StreamEndAnalyzer* newInstance() const {
+-        return new Bz2EndAnalyzer();
++        return new Bz2EndAnalyzer(this);
+     }
+     bool analyzesSubStreams() const { return true; }
+     void registerFields(Strigi::FieldRegister&);
+--- a/src/streamanalyzer/endanalyzers/gzipendanalyzer.cpp
++++ b/src/streamanalyzer/endanalyzers/gzipendanalyzer.cpp
+@@ -23,11 +23,14 @@
+ #include "tarendanalyzer.h"
+ #include "tarinputstream.h"
+ #include "analysisresult.h"
++#include "fieldtypes.h"
++
+ using namespace Strigi;
+ using namespace std;
+ 
+ void
+ GZipEndAnalyzerFactory::registerFields(FieldRegister& reg) {
++    typeField = reg.typeField;
+ }
+ 
+ bool
+@@ -48,6 +51,9 @@
+         printf("Error reading gzip: %s\n", stream.error());
+         return -2;
+     }
++
++    idx.addValue(factory->typeField, "http://freedesktop.org/standards/xesam/1.0/core#Archive");
++
+     stream.reset(0);
+     if (TarInputStream::checkHeader(start, nread)) {
+         return TarEndAnalyzer::staticAnalyze(idx, &stream);
+--- a/src/streamanalyzer/endanalyzers/gzipendanalyzer.h
++++ b/src/streamanalyzer/endanalyzers/gzipendanalyzer.h
+@@ -23,20 +23,29 @@
+ #include "streamendanalyzer.h"
+ #include "streambase.h"
+ 
++class GZipEndAnalyzerFactory;
+ class GZipEndAnalyzer : public Strigi::StreamEndAnalyzer {
++private:
++    const GZipEndAnalyzerFactory* factory;
+ public:
++    GZipEndAnalyzer(const GZipEndAnalyzerFactory* f)
++        :factory(f) {}
++
+     bool checkHeader(const char* header, int32_t headersize) const;
+     char analyze(Strigi::AnalysisResult& idx, Strigi::InputStream* in);
+     const char* name() const { return "GZipEndAnalyzer"; }
+ };
+ 
+ class GZipEndAnalyzerFactory : public Strigi::StreamEndAnalyzerFactory {
++friend class GZipEndAnalyzer;
++private:
++    const Strigi::RegisteredField* typeField;
+ public:
+     const char* name() const {
+         return "GZipEndAnalyzer";
+     }
+     Strigi::StreamEndAnalyzer* newInstance() const {
+-        return new GZipEndAnalyzer();
++        return new GZipEndAnalyzer(this);
+     }
+     bool analyzesSubStreams() const { return true; }
+     void registerFields(Strigi::FieldRegister&);
+--- a/src/streamanalyzer/endanalyzers/mailendanalyzer.cpp
++++ b/src/streamanalyzer/endanalyzers/mailendanalyzer.cpp
+@@ -30,7 +30,7 @@
+ 
+ const string MailEndAnalyzerFactory::titleFieldName = "http://freedesktop.org/standards/xesam/1.0/core#subject";
+ const string MailEndAnalyzerFactory::contenttypeFieldName = "http://freedesktop.org/standards/xesam/1.0/core#contentType";
+-const string MailEndAnalyzerFactory::fromFieldName = "TODO.from";
++const string MailEndAnalyzerFactory::fromFieldName = "http://freedesktop.org/standards/xesam/1.0/core#author";
+ const string MailEndAnalyzerFactory::toFieldName = "http://freedesktop.org/standards/xesam/1.0/core#to";
+ const string MailEndAnalyzerFactory::ccFieldName = "http://freedesktop.org/standards/xesam/1.0/core#cc";
+ const string MailEndAnalyzerFactory::bccFieldName = "http://freedesktop.org/standards/xesam/1.0/core#bcc";
+@@ -51,6 +51,8 @@
+     contentidField = r.registerField(contentidFieldName);
+     contentlinkField = r.registerField(contentlinkFieldName);
+     emailInReplyToField = r.registerField(emailInReplyToFieldName);
++
++    typeField = r.typeField;
+ }
+ 
+ bool
+@@ -87,6 +89,7 @@
+     if (enc.length()) {
+         idx.setEncoding(enc.c_str());
+     }
++    idx.addValue(factory->typeField, "http://freedesktop.org/standards/xesam/1.0/core#Email");
+     idx.addValue(factory->titleField, mail.subject());
+     idx.addValue(factory->contenttypeField, mail.contentType());
+     idx.addValue(factory->fromField, mail.from());
+--- a/src/streamanalyzer/endanalyzers/mailendanalyzer.h
++++ b/src/streamanalyzer/endanalyzers/mailendanalyzer.h
+@@ -57,6 +57,8 @@
+     const Strigi::RegisteredField* contentlinkField;
+     const Strigi::RegisteredField* emailInReplyToField;
+ 
++    const Strigi::RegisteredField* typeField;
++
+ public:
+     const char* name() const {
+         return "MailEndAnalyzer";
+--- a/src/streamanalyzer/endanalyzers/mpegendanalyzer.cpp
++++ b/src/streamanalyzer/endanalyzers/mpegendanalyzer.cpp
+@@ -38,6 +38,8 @@
+     fields["video codec"] = r.registerField("http://freedesktop.org/standards/xesam/1.0/core#videoCodec");
+     fields["audio codec"] = r.registerField("http://freedesktop.org/standards/xesam/1.0/core#audioCodec");
+     fields["aspect ratio"] = r.registerField("http://freedesktop.org/standards/xesam/1.0/core#aspectRatio");
++
++    fields["type"] = r.typeField;
+ }
+ 
+ bool MpegEndAnalyzer::checkHeader(const char* header, int32_t headersize) const
+@@ -132,6 +134,7 @@
+                 break;
+         }
+     }
++    idx.addValue(tempfields["type"], "http://freedesktop.org/standards/xesam/1.0/core#Video");
+     return 0;
+ }
+ 
+--- a/src/streamanalyzer/endanalyzers/oleendanalyzer.cpp
++++ b/src/streamanalyzer/endanalyzers/oleendanalyzer.cpp
+@@ -163,6 +163,8 @@
+     if (r) (*m)[14] = r;
+     r = reg.registerField("ole.company", FieldRegister::stringType, 1, 0);
+     if (r) (*m)[15] = r;
++
++    typeField = reg.typeField;
+ }
+ const map<int, const RegisteredField*>*
+ OleEndAnalyzerFactory::getFieldMap(const string& key) const {
+@@ -392,6 +394,7 @@
+         m_error = ole.error();
+         return -1;
+     } else {
++        ar.addValue(factory->typeField, "http://freedesktop.org/standards/xesam/1.0/core#Document");
+         m_error.resize(0);
+     }
+     return 0;
+--- a/src/streamanalyzer/endanalyzers/oleendanalyzer.h
++++ b/src/streamanalyzer/endanalyzers/oleendanalyzer.h
+@@ -72,9 +72,11 @@
+ };
+ 
+ class OleEndAnalyzerFactory : public Strigi::StreamEndAnalyzerFactory {
++friend class OleEndAnalyzer;
+ private:
+     std::map<std::string,
+         std::map<int,const Strigi::RegisteredField*> > fieldsMaps;
++    const Strigi::RegisteredField* typeField;
+ public:
+     const char* name() const {
+         return "OleEndAnalyzer";
+--- a/src/streamanalyzer/endanalyzers/pdfendanalyzer.cpp
++++ b/src/streamanalyzer/endanalyzers/pdfendanalyzer.cpp
+@@ -21,6 +21,7 @@
+ #include "pdfendanalyzer.h"
+ #include <strigi/strigiconfig.h>
+ #include "analysisresult.h"
++#include "fieldtypes.h"
+ #include "textutils.h"
+ #include <sstream>
+ #include <cstring>
+@@ -29,7 +30,9 @@
+ 
+ void
+ PdfEndAnalyzerFactory::registerFields(FieldRegister& reg) {
++    typeField = reg.typeField;
+ }
++
+ PdfEndAnalyzer::PdfEndAnalyzer(const PdfEndAnalyzerFactory* f) :factory(f) {
+     parser.setStreamHandler(this);
+     parser.setTextHandler(this);
+@@ -57,5 +60,6 @@
+     n = 0;
+     StreamStatus r = parser.parse(in);
+     if (r != Eof) m_error.assign(parser.error());
++    analysisresult->addValue(factory->typeField, "http://freedesktop.org/standards/xesam/1.0/core#TextDocument");
+     return (r == Eof) ?0 :-1;
+ }
+--- a/src/streamanalyzer/endanalyzers/pdfendanalyzer.h
++++ b/src/streamanalyzer/endanalyzers/pdfendanalyzer.h
+@@ -46,6 +46,8 @@
+ class PdfEndAnalyzerFactory : public Strigi::StreamEndAnalyzerFactory {
+ friend class PdfEndAnalyzer;
+ private:
++    const Strigi::RegisteredField* typeField;
++public:
+     const char* name() const {
+         return "PdfEndAnalyzer";
+     }
+--- a/src/streamanalyzer/endanalyzers/pngendanalyzer.cpp
++++ b/src/streamanalyzer/endanalyzers/pngendanalyzer.cpp
+@@ -46,9 +46,10 @@
+ const string PngEndAnalyzerFactory::creationTimeFieldName("http://freedesktop.org/standards/xesam/1.0/core#contentCreated");
+ const string PngEndAnalyzerFactory::softwareFieldName("http://freedesktop.org/standards/xesam/1.0/core#generator");
+ const string PngEndAnalyzerFactory::disclaimerFieldName("http://freedesktop.org/standards/xesam/1.0/core#disclaimer");
+-const string PngEndAnalyzerFactory::warningFieldName("content.warning");
++ // putting warning into comment field since it's the closest equivalent
++const string PngEndAnalyzerFactory::warningFieldName("http://freedesktop.org/standards/xesam/1.0/core#contentComment");
+  // PNG spec says Source is Device used to create the image
+-const string PngEndAnalyzerFactory::sourceFieldName("photo.camera_model");
++const string PngEndAnalyzerFactory::sourceFieldName("http://freedesktop.org/standards/xesam/1.0/core#cameraModel");
+ const string PngEndAnalyzerFactory::commentFieldName("http://freedesktop.org/standards/xesam/1.0/core#contentComment");
+ 
+ // and for the colors
+@@ -86,6 +87,8 @@
+     warningField = reg.registerField(warningFieldName);
+     sourceField = reg.registerField(sourceFieldName);
+     commentField = reg.registerField(commentFieldName);
++
++    typeField = reg.typeField;
+ }
+ 
+ PngEndAnalyzer::PngEndAnalyzer(const PngEndAnalyzerFactory* f) :factory(f) {
+@@ -128,6 +131,8 @@
+         return -1;
+     }
+ 
++    as.addValue(factory->typeField, "http://freedesktop.org/standards/xesam/1.0/core#Image");
++
+     // read the png dimensions
+     uint32_t width = readBigEndianUInt32(c+4);
+     uint32_t height = readBigEndianUInt32(c+8);
+--- a/src/streamanalyzer/endanalyzers/pngendanalyzer.h
++++ b/src/streamanalyzer/endanalyzers/pngendanalyzer.h
+@@ -82,6 +82,9 @@
+     const Strigi::RegisteredField* warningField;
+     const Strigi::RegisteredField* sourceField;
+     const Strigi::RegisteredField* commentField;
++
++    const Strigi::RegisteredField* typeField;
++
+     const char* name() const {
+         return "PngEndAnalyzer";
+     }
+--- a/src/streamanalyzer/endanalyzers/rpmendanalyzer.cpp
++++ b/src/streamanalyzer/endanalyzers/rpmendanalyzer.cpp
+@@ -22,10 +22,13 @@
+ #include "rpminputstream.h"
+ #include "subinputstream.h"
+ #include "analysisresult.h"
++#include "fieldtypes.h"
++
+ using namespace Strigi;
+ 
+ void
+ RpmEndAnalyzerFactory::registerFields(FieldRegister& reg) {
++    typeField = reg.typeField;
+ }
+ 
+ bool
+@@ -40,6 +43,7 @@
+         fprintf(stderr, "error: %s\n", rpm.error());
+ //        exit(1);
+     }
++    idx.addValue(factory->typeField, "http://freedesktop.org/standards/xesam/1.0/core#SoftwarePackage");
+     while (s) {
+         idx.indexChild(rpm.entryInfo().filename, rpm.entryInfo().mtime,
+             s);
+--- a/src/streamanalyzer/endanalyzers/rpmendanalyzer.h
++++ b/src/streamanalyzer/endanalyzers/rpmendanalyzer.h
+@@ -23,20 +23,29 @@
+ #include "streamendanalyzer.h"
+ #include "streambase.h"
+ 
++class RpmEndAnalyzerFactory;
+ class RpmEndAnalyzer : public Strigi::StreamEndAnalyzer {
++private:
++    const RpmEndAnalyzerFactory* factory;
+ public:
++    RpmEndAnalyzer(const RpmEndAnalyzerFactory* f)
++        :factory(f) {}
++
+     bool checkHeader(const char* header, int32_t headersize) const;
+     char analyze(Strigi::AnalysisResult& idx, Strigi::InputStream* in);
+     const char* name() const { return "RpmEndAnalyzer"; }
+ };
+ 
+ class RpmEndAnalyzerFactory : public Strigi::StreamEndAnalyzerFactory {
++friend class RpmEndAnalyzer;
++private:
++    const Strigi::RegisteredField* typeField;
+ public:
+     const char* name() const {
+         return "RpmEndAnalyzer";
+     }
+     Strigi::StreamEndAnalyzer* newInstance() const {
+-        return new RpmEndAnalyzer();
++        return new RpmEndAnalyzer(this);
+     }
+     bool analyzesSubStreams() const { return true; }
+     void registerFields(Strigi::FieldRegister&);
+--- a/src/streamanalyzer/endanalyzers/sdfendanalyzer.cpp
++++ b/src/streamanalyzer/endanalyzers/sdfendanalyzer.cpp
+@@ -24,11 +24,9 @@
+ using namespace Strigi;
+ using namespace std;
+ 
+-const string SdfEndAnalyzerFactory::moleculeCountFieldName = "chemistry.molecule_count";
+-
+ void
+ SdfEndAnalyzerFactory::registerFields(FieldRegister& r) {
+-    moleculeCountField = r.registerField(moleculeCountFieldName);
++    moleculeCountField = r.registerField("http://rdf.openmolecules.net/0.9#moleculeCount");
+ }
+ 
+ bool
+--- a/src/streamanalyzer/endanalyzers/tarendanalyzer.cpp
++++ b/src/streamanalyzer/endanalyzers/tarendanalyzer.cpp
+@@ -22,10 +22,12 @@
+ #include "tarinputstream.h"
+ #include "subinputstream.h"
+ #include "analysisresult.h"
++#include "fieldtypes.h"
+ using namespace Strigi;
+ 
+ void
+ TarEndAnalyzerFactory::registerFields(FieldRegister& reg) {
++    typeField = reg.typeField;
+ }
+ 
+ bool
+@@ -34,7 +36,9 @@
+ }
+ char
+ TarEndAnalyzer::analyze(AnalysisResult& idx, InputStream* in) {
+-    return staticAnalyze(idx, in);
++    char result = staticAnalyze(idx, in);
++    idx.addValue(factory->typeField, "http://freedesktop.org/standards/xesam/1.0/core#Archive");
++    return result;
+ }
+ char
+ TarEndAnalyzer::staticAnalyze(AnalysisResult& idx,
+--- a/src/streamanalyzer/endanalyzers/tarendanalyzer.h
++++ b/src/streamanalyzer/endanalyzers/tarendanalyzer.h
+@@ -23,8 +23,14 @@
+ #include "streamendanalyzer.h"
+ #include "streambase.h"
+ 
++class TarEndAnalyzerFactory;
+ class TarEndAnalyzer : public Strigi::StreamEndAnalyzer {
++private:
++    const TarEndAnalyzerFactory* factory;
+ public:
++    TarEndAnalyzer(const TarEndAnalyzerFactory* f)
++        :factory(f) {}
++
+     bool checkHeader(const char* header, int32_t headersize) const;
+     char analyze(Strigi::AnalysisResult& idx, Strigi::InputStream* in);
+     static char staticAnalyze(Strigi::AnalysisResult& idx,
+@@ -33,12 +39,15 @@
+ };
+ 
+ class TarEndAnalyzerFactory : public Strigi::StreamEndAnalyzerFactory {
++friend class TarEndAnalyzer;
++private:
++    const Strigi::RegisteredField* typeField;
+ public:
+     const char* name() const {
+         return "TarEndAnalyzer";
+     }
+     Strigi::StreamEndAnalyzer* newInstance() const {
+-        return new TarEndAnalyzer();
++        return new TarEndAnalyzer(this);
+     }
+     bool analyzesSubStreams() const { return true; }
+     void registerFields(Strigi::FieldRegister&);
+--- a/src/streamanalyzer/endanalyzers/zipendanalyzer.cpp
++++ b/src/streamanalyzer/endanalyzers/zipendanalyzer.cpp
+@@ -28,6 +28,7 @@
+ void
+ ZipEndAnalyzerFactory::registerFields(FieldRegister& reg) {
+     mimetypefield = reg.mimetypeField;
++    typeField = reg.typeField;
+ }
+ 
+ bool
+@@ -45,6 +46,7 @@
+         fprintf(stderr, "error: %s\n", zip.error());
+ //        exit(1);
+     }
++
+     while (s) {
+ //        fprintf(stderr, "zip: %s\n", zip.entryInfo().filename.c_str());
+         idx.indexChild(zip.entryInfo().filename, zip.entryInfo().mtime,
+@@ -56,6 +58,7 @@
+         return -1;
+     } else {
+         idx.addValue(factory->mimetypefield, "application/zip");
++        idx.addValue(factory->typeField, "http://freedesktop.org/standards/xesam/1.0/core#Archive");
+         m_error.resize(0);
+     }
+     return 0;
+--- a/src/streamanalyzer/endanalyzers/zipendanalyzer.h
++++ b/src/streamanalyzer/endanalyzers/zipendanalyzer.h
+@@ -40,6 +40,8 @@
+         return "ZipEndAnalyzer";
+     }
+     const Strigi::RegisteredField* mimetypefield;
++    const Strigi::RegisteredField* typeField;
++
+     Strigi::StreamEndAnalyzer* newInstance() const {
+         return new ZipEndAnalyzer(this);
+     }
+--- a/src/streamanalyzer/endplugins/CMakeLists.txt
++++ b/src/streamanalyzer/endplugins/CMakeLists.txt
+@@ -22,9 +22,11 @@
+   install(TARGETS ${libname} LIBRARY DESTINATION ${LIB_DESTINATION}/strigi)
+ ENDMACRO(ADD_STRIGIEA)
+ 
+-if(EXIV2_FOUND)
+-  set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fexceptions")
++if(Exiv2_FOUND)
++  IF (CMAKE_COMPILER_IS_GNUCXX)
++    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fexceptions")
++  ENDIF(CMAKE_COMPILER_IS_GNUCXX)
+   include_directories(${EXIV2_INCLUDE_DIR})
+   ADD_STRIGIEA(jpeg jpegendanalyzer.cpp)
+   target_link_libraries(jpeg ${EXIV2_LIBRARIES})
+-endif(EXIV2_FOUND)
++endif(Exiv2_FOUND)
+--- a/src/streamanalyzer/endplugins/jpegendanalyzer.cpp
++++ b/src/streamanalyzer/endplugins/jpegendanalyzer.cpp
+@@ -128,31 +128,34 @@
+     const RegisteredField* userCommentField;
+     const RegisteredField* jpegProcessField;
+     const RegisteredField* thumbnailField;
++
++    const RegisteredField* typeField;
++
+ };
+ 
+-const string JpegEndAnalyzerFactory::commentFieldName("content.comment");
+-const string JpegEndAnalyzerFactory::manufacturerFieldName("photo.camera_manufacturer");
+-const string JpegEndAnalyzerFactory::modelFieldName("photo.camera_model");
+-const string JpegEndAnalyzerFactory::creationDateFieldName("content.creation_time");
+-const string JpegEndAnalyzerFactory::widthFieldName("image.width");
+-const string JpegEndAnalyzerFactory::heightFieldName("image.height");
+-const string JpegEndAnalyzerFactory::orientationFieldName("photo.orientation");
+-const string JpegEndAnalyzerFactory::colorModeFieldName("image.color_space");
+-const string JpegEndAnalyzerFactory::flashUsedFieldName("photo.flash_used");
+-const string JpegEndAnalyzerFactory::focalLengthFieldName("photo.focal_length");
+-const string JpegEndAnalyzerFactory::_35mmEquivalentFieldName("photo.35mm_equivalent");
+-const string JpegEndAnalyzerFactory::ccdWidthFieldName("photo.cdd_width");
+-const string JpegEndAnalyzerFactory::exposureTimeFieldName("photo.exposure_time");
+-const string JpegEndAnalyzerFactory::apertureFieldName("photo.aperture");
+-const string JpegEndAnalyzerFactory::focusDistFieldName("photo.focus_distance");
+-const string JpegEndAnalyzerFactory::exposureBiasFieldName("photo.exposure_bias");
+-const string JpegEndAnalyzerFactory::whiteBalanceFieldName("photo.white_balance");
+-const string JpegEndAnalyzerFactory::meteringModeFieldName("photo.metering_mode");
+-const string JpegEndAnalyzerFactory::exposureFieldName("photo.exposure_program");
+-const string JpegEndAnalyzerFactory::isoEquivFieldName("photo.iso_equivalent");
+-const string JpegEndAnalyzerFactory::jpegQualityFieldName("compressed.target_quality");
+-const string JpegEndAnalyzerFactory::userCommentFieldName("content.comment");
+-const string JpegEndAnalyzerFactory::jpegProcessFieldName("compressed.compression_algorithm");
++const string JpegEndAnalyzerFactory::commentFieldName("http://freedesktop.org/standards/xesam/1.0/core#contentComment");
++const string JpegEndAnalyzerFactory::manufacturerFieldName("http://freedesktop.org/standards/xesam/1.0/core#cameraManufacturer");
++const string JpegEndAnalyzerFactory::modelFieldName("http://freedesktop.org/standards/xesam/1.0/core#cameraModel");
++const string JpegEndAnalyzerFactory::creationDateFieldName("http://freedesktop.org/standards/xesam/1.0/core#contentCreated");
++const string JpegEndAnalyzerFactory::widthFieldName("http://freedesktop.org/standards/xesam/1.0/core#width");
++const string JpegEndAnalyzerFactory::heightFieldName("http://freedesktop.org/standards/xesam/1.0/core#height");
++const string JpegEndAnalyzerFactory::orientationFieldName("http://freedesktop.org/standards/xesam/1.0/core#orientation");
++const string JpegEndAnalyzerFactory::colorModeFieldName("http://freedesktop.org/standards/xesam/1.0/core#colorSpace");
++const string JpegEndAnalyzerFactory::flashUsedFieldName("http://freedesktop.org/standards/xesam/1.0/core#flashUsed");
++const string JpegEndAnalyzerFactory::focalLengthFieldName("http://freedesktop.org/standards/xesam/1.0/core#focalLength");
++const string JpegEndAnalyzerFactory::_35mmEquivalentFieldName("http://freedesktop.org/standards/xesam/1.0/core#35mmEquivalent");
++const string JpegEndAnalyzerFactory::ccdWidthFieldName("http://freedesktop.org/standards/xesam/1.0/core#ccdWidth");
++const string JpegEndAnalyzerFactory::exposureTimeFieldName("http://freedesktop.org/standards/xesam/1.0/core#exposureTime");
++const string JpegEndAnalyzerFactory::apertureFieldName("http://freedesktop.org/standards/xesam/1.0/core#aperture");
++const string JpegEndAnalyzerFactory::focusDistFieldName("http://freedesktop.org/standards/xesam/1.0/core#focusDistance");
++const string JpegEndAnalyzerFactory::exposureBiasFieldName("http://freedesktop.org/standards/xesam/1.0/core#exposureBias");
++const string JpegEndAnalyzerFactory::whiteBalanceFieldName("http://freedesktop.org/standards/xesam/1.0/core#whiteBalance");
++const string JpegEndAnalyzerFactory::meteringModeFieldName("http://freedesktop.org/standards/xesam/1.0/core#meteringMode");
++const string JpegEndAnalyzerFactory::exposureFieldName("http://freedesktop.org/standards/xesam/1.0/core#exposureProgram");
++const string JpegEndAnalyzerFactory::isoEquivFieldName("http://freedesktop.org/standards/xesam/1.0/core#isoEquivalent");
++const string JpegEndAnalyzerFactory::jpegQualityFieldName("http://freedesktop.org/standards/xesam/1.0/core#targetQuality");
++const string JpegEndAnalyzerFactory::userCommentFieldName("http://freedesktop.org/standards/xesam/1.0/core#userComment");
++const string JpegEndAnalyzerFactory::jpegProcessFieldName("http://freedesktop.org/standards/xesam/1.0/core#compressionAlgorithm");
+ const string JpegEndAnalyzerFactory::thumbnailFieldName("content.thumbnail");
+ 
+ /*
+@@ -164,22 +167,16 @@
+     commentField = r.registerField(commentFieldName, FieldRegister::stringType,
+         -1, 0);
+ 
+-    exifFields["Exif.Image.DateTime"] = r.registerField(creationDateFieldName,
+-        FieldRegister::stringType, -1, 0);
+-    exifFields["Exif.Image.Make"] = r.registerField(manufacturerFieldName,
+-        FieldRegister::stringType, -1, 0);
+-    exifFields["Exif.Image.Model"] = r.registerField(modelFieldName,
+-        FieldRegister::stringType, -1, 0);
+-    exifFields["Exif.Photo.PixelXDimension"] = r.registerField(widthFieldName,
+-        FieldRegister::integerType, -1, 0);
+-    exifFields["Exif.Photo.PixelYDimension"] = r.registerField(heightFieldName,
+-        FieldRegister::integerType, -1, 0);
++    exifFields["Exif.Image.DateTime"] = r.registerField(creationDateFieldName);
++    exifFields["Exif.Image.Make"] = r.registerField(manufacturerFieldName);
++    exifFields["Exif.Image.Model"] = r.registerField(modelFieldName);
++    exifFields["Exif.Photo.PixelXDimension"] = r.registerField(widthFieldName);
++    exifFields["Exif.Photo.PixelYDimension"] = r.registerField(heightFieldName);
+     exifFields["Exif.Image.Orientation"] = r.registerField(orientationFieldName,
+         FieldRegister::stringType, -1 ,0);
+     exifFields["Exif.Photo.Flash"] = r.registerField(flashUsedFieldName,
+         FieldRegister::integerType, -1, 0);
+-    exifFields["Exif.Photo.FocalLength"] = r.registerField(focalLengthFieldName,
+-        FieldRegister::floatType, -1, 0);
++    exifFields["Exif.Photo.FocalLength"] = r.registerField(focalLengthFieldName);
+     exifFields["Exif.Photo.FocalLengthIn35mmFilm"] = r.registerField(
+         _35mmEquivalentFieldName, FieldRegister::integerType, -1, 0);
+     exifFields["Exif.Photo.ExposureTime"] =
+@@ -194,15 +191,17 @@
+         r.registerField(meteringModeFieldName, FieldRegister::integerType,-1,0);
+ 
+ 
+-    colorModeField = r.registerField(colorModeFieldName, FieldRegister::stringType,        -1, 0);
+-    ccdWidthField = r.registerField(ccdWidthFieldName, FieldRegister::stringType,        -1, 0);
+-    focusDistField = r.registerField(focusDistFieldName, FieldRegister::stringType,        -1, 0);
+-    exposureField = r.registerField(exposureFieldName, FieldRegister::stringType,        -1, 0);
+-    isoEquivField = r.registerField(isoEquivFieldName, FieldRegister::stringType,        -1, 0);
+-    jpegQualityField = r.registerField(jpegQualityFieldName, FieldRegister::stringType,        -1, 0);
+-    userCommentField = r.registerField(userCommentFieldName, FieldRegister::stringType,        -1, 0);
+-    jpegProcessField = r.registerField(jpegProcessFieldName, FieldRegister::stringType,        -1, 0);
+-    thumbnailField = r.registerField(thumbnailFieldName, FieldRegister::stringType,        -1, 0);
++    colorModeField = r.registerField(colorModeFieldName);
++    ccdWidthField = r.registerField(ccdWidthFieldName);
++    focusDistField = r.registerField(focusDistFieldName);
++    exposureField = r.registerField(exposureFieldName);
++    isoEquivField = r.registerField(isoEquivFieldName);
++    jpegQualityField = r.registerField(jpegQualityFieldName);
++    userCommentField = r.registerField(userCommentFieldName);
++    jpegProcessField = r.registerField(jpegProcessFieldName);
++    thumbnailField = r.registerField(thumbnailFieldName);
++
++    typeField = r.typeField;
+ }
+ 
+ bool
+@@ -262,6 +261,13 @@
+     }
+ 
+     const Exiv2::ExifData& exif = img->exifData();
++    // if there's exif data, this is a photo, otherwise just an image
++    if( exif.size() ) {
++        ar.addValue(factory->typeField, "http://freedesktop.org/standards/xesam/1.0/core#Photo");
++    } else {
++        ar.addValue(factory->typeField, "http://freedesktop.org/standards/xesam/1.0/core#Image");
++    }
++
+     for (Exiv2::ExifData::const_iterator i = exif.begin(); i != exif.end();i++){
+         map<string,const RegisteredField*>::const_iterator f
+             = factory->exifFields.find(i->key());
+--- a/src/streamanalyzer/fieldproperties/chemical.rdfs
++++ b/src/streamanalyzer/fieldproperties/chemical.rdfs
+@@ -12,7 +12,7 @@
+ 	 xmlns:xss="&xss;"
+ 	 xmlns:rdfs="&rdfs;">
+ 
+-<rdfs:Class rdf:about="&xesam;ChemicalContent">
++<rdfs:Class rdf:about="&chemical;ChemicalContent">
+ 	<rdfs:subClassOf rdf:resource="&xesam;Content"/>
+ 	<rdfs:label>chemical:ChemicalContent</rdfs:label>
+ 	<rdfs:comment>Chemical Content</rdfs:comment>
+@@ -29,6 +29,7 @@
+ 	<rdfs:label>chemical:inchi</rdfs:label>
+ 	<rdfs:subPropertyOf rdf:resource="&xesam;id"/>
+ 	<rdfs:domain rdf:resource="&xesam;ChemicalContent"/>
++	<xss:tokenized>false</xss:tokenized>
+ 	<rdfs:comment>IUPAC International Chemical Identifier</rdfs:comment>
+ </rdf:Property>
+ 
+@@ -42,6 +43,7 @@
+ <rdf:Property rdf:about="&chemical;molecularFormula">
+ 	<rdfs:label>chemical:molecularFormula</rdfs:label>
+ 	<rdfs:domain rdf:resource="&xesam;ChemicalContent"/>
++	<xss:tokenized>false</xss:tokenized>
+ 	<rdfs:comment>Molecular Formula</rdfs:comment>
+ </rdf:Property>
+ 
+@@ -76,6 +78,24 @@
+ 	<rdfs:comment>Bond Count</rdfs:comment>
+ </rdf:Property>
+ 
++<rdf:Property rdf:about="&chemical;moleculeCount">
++	<rdfs:label>chemical:moleculeCount</rdfs:label>
++	<rdfs:domain rdf:resource="&xesam;ChemicalContent"/>
++	<rdfs:comment>Molecule Count</rdfs:comment>
++</rdf:Property>
++
++<rdf:Property rdf:about="&chemical;classification">
++	<rdfs:label>chemical:classification</rdfs:label>
++	<rdfs:domain rdf:resource="&xesam;ChemicalContent"/>
++	<rdfs:comment>Indication of some Chemical Class</rdfs:comment>
++</rdf:Property>
++
++<rdf:Property rdf:about="&chemical;isChiral">
++	<rdfs:label>chemical:isChiral</rdfs:label>
++	<rdfs:domain rdf:resource="&xesam;ChemicalContent"/>
++	<rdfs:subPropertyOf rdf:resource="&xesam;classification"/>
++	<rdfs:comment>Flag that indicates if the Content contains Chiral Species</rdfs:comment>
++</rdf:Property>
+ 
+ <rdfs:Class rdf:about="&xesam;ProteinStructure">
+ 	<rdfs:label>chemical:ProteinStructure</rdfs:label>
+@@ -90,6 +110,13 @@
+ 	<rdfs:comment>ProteinDataBase Identifier</rdfs:comment>
+ </rdf:Property>
+ 
++<rdf:Property rdf:about="&chemical;depositionDate">
++	<rdfs:label>chemical:depositionDate</rdfs:label>
++	<rdfs:subPropertyOf rdf:resource="&xesam;creationDate"/>
++	<rdfs:domain rdf:resource="&xesam;ProteinStructure"/>
++	<rdfs:comment>Date on which the PDB Entry was Added to the Database</rdfs:comment>
++</rdf:Property>
++
+ <rdf:Property rdf:about="&chemical;experimentalMethod">
+ 	<rdfs:label>chemical:experimentalMethod</rdfs:label>
+ 	<rdfs:domain rdf:resource="&xesam;ProteinStructure"/>
+--- a/src/streamanalyzer/fieldproperties/CMakeLists.txt
++++ b/src/streamanalyzer/fieldproperties/CMakeLists.txt
+@@ -1,7 +1,9 @@
+ 
+ install(FILES
+ 	xesam.rdfs
+-#	strigi.rdfs
++	xesam-convenience.rdfs
++	strigi.rdfs
++
+ #	chemical.rdfs
+ 
+ 	DESTINATION share/strigi/fieldproperties
+--- a/src/streamanalyzer/fieldproperties/strigi_audio.fieldproperties
++++ /dev/null
+@@ -1,38 +0,0 @@
+-[Field]
+-Uri=audio.channel_count
+-Name=Channel count
+-TypeUri=string
+-Description=Audio channel count
+-Comment=
+-
+-[Field]
+-Uri=audio.duration
+-ParentUri=media.duration
+-Name=Duration
+-TypeUri=string
+-Description=Audio duration
+-Comment=
+-
+-[Field]
+-Uri=audio.artist
+-ParentUri=content.author
+-Name=Artist
+-TypeUri=string
+-Description=Audio Artist
+-Comment=
+-
+-[Field]
+-Uri=audio.title
+-ParentUri=content.title
+-Name=Title
+-TypeUri=string
+-Description=Audio Title
+-Comment=
+-
+-[Field]
+-Uri=audio.album
+-ParentUri=media.album
+-Name=Album
+-TypeUri=string
+-Description=Audio Album
+-Comment=
+--- a/src/streamanalyzer/fieldproperties/strigi_av.fieldproperties
++++ /dev/null
+@@ -1,13 +0,0 @@
+-[Field]
+-Uri=av.audio_codec
+-Name=Audio codec
+-TypeUri=string
+-Description=Audio codec
+-Comment=
+-
+-[Field]
+-Uri=av.video_codec
+-Name=Video codec
+-TypeUri=string
+-Description=Video codec
+-Comment=
+--- a/src/streamanalyzer/fieldproperties/strigi_compressed.fieldproperties
++++ /dev/null
+@@ -1,23 +0,0 @@
+-[Field]
+-Uri=compressed.compression_algorithm
+-ParentUri=content.generator_settings
+-Name=Compression algo
+-TypeUri=string
+-Description=Compression algorithm
+-Comment=
+-
+-[Field]
+-Uri=compressed.compression_level
+-ParentUri=content.generator_settings
+-Name=Compression level
+-TypeUri=string
+-Description=Lossless compression level
+-Comment=
+-
+-[Field]
+-Uri=compressed.target_quality
+-ParentUri=content.generator_settings
+-Name=Target quality
+-TypeUri=string
+-Description=Lossy compression target quality
+-Comment=
+--- a/src/streamanalyzer/fieldproperties/strigi_container.fieldproperties
++++ /dev/null
+@@ -1,13 +0,0 @@
+-[Field]
+-Uri=container.item
+-Name=Contains
+-TypeUri=string
+-Description=Contains item
+-Comment=
+-
+-[Field]
+-Uri=container.item_count
+-Name=Item count
+-TypeUri=string
+-Description=Contained item count
+-Comment=
+--- a/src/streamanalyzer/fieldproperties/strigi_content.fieldproperties
++++ /dev/null
+@@ -1,265 +0,0 @@
+-[Field]
+-Uri=content.creator
+-Name=Creator
+-TypeUri=string
+-Description=Content creator
+-Comment=abstract class, use children. List of entities who created the content(book authors, music band, artist)
+-
+-[Field]
+-Uri=content.author
+-ParentUri=content.creator
+-Name=Author
+-TypeUri=string
+-Description=Content author
+-Comment=Primary content creator(s)
+-
+-[Field]
+-Uri=content.contributor
+-ParentUri=content.creator
+-Name=Contributor
+-TypeUri=string
+-Description=Content contributor
+-Comment=Secondary content creator(s)
+-
+-[Field]
+-Uri=content.maintainer
+-ParentUri=content.creator
+-Name=Maintainer
+-TypeUri=string
+-Description=Content maintainer
+-Comment=Entity keeping the content up to date in general or for a specific purpose.
+-
+-
+-
+-[Field]
+-Uri=content.creation_time
+-Name=Creation time
+-TypeUri=datetime
+-Description=Content creation time
+-Comment=this is different from system.creation_time in that this is the time when the content was actually produced. ID3 tag Year, for e-mail, this is send time etc
+-
+-[Field]
+-Uri=content.last_modified_time
+-Name=Modification time
+-TypeUri=datetime
+-Description=Content last modification time
+-Comment=this is different from system.last_modified_time in that this is the time when the content was actually modified, while system.last_modified_time may reflect file rename or some other operation.
+-
+-[Field]
+-Uri=content.genre
+-Name=Genre
+-TypeUri=string
+-Description=Content genre
+-Comment=music, literature, movie genre. Also can be used for pictures. Regular photos can be considered Documentary.
+-
+-[Field]
+-Uri=content.subject
+-Name=Subject
+-TypeUri=string
+-Description=Content subject
+-Comment= message subject, ODF.subject. Author's subject of the content.
+-
+-[Field]
+-Uri=content.title
+-Name=Title
+-TypeUri=string
+-Description=Content title
+-Comment=Author's title of the content. ODF.title, ID3.title
+-
+-[Field]
+-Uri=content.description
+-Name=Description
+-TypeUri=string
+-Description=Content description
+-Comment=Author's description of the content.ODF.description.
+-
+-[Field]
+-Uri=content.comment
+-Name=Comment
+-TypeUri=string
+-Description=Content comment
+-Comment=Author's comment on the content.
+-
+-[Field]
+-Uri=content.keyword
+-Name=Keyword
+-TypeUri=string
+-Description=Content keyword
+-Comment=
+-
+-[Field]
+-Uri=content.version
+-Name=Version
+-TypeUri=string
+-Description=Content version
+-Comment=application version. document revision
+-
+-[Field]
+-Uri=content.mime_type
+-Name=Mime type
+-TypeUri=string
+-Description=Content mime type
+-Comment=
+-
+-[Field]
+-Uri=content.size
+-Name=Content size
+-TypeUri=integer
+-Description=
+-Comment=unpacked size for archives. for other files this might be the same as system.size, might be actual data size w/o headers(not sure about this yet).
+-
+-[Field]
+-Uri=content.charset
+-Name=Charset
+-TypeUri=string
+-Description=Content character encoding
+-Comment=document character encoding. This will eventually be obsolete.
+-
+-[Field]
+-Uri=content.language
+-Name=Language
+-TypeUri=string
+-Description=Content language
+-Comment=
+-
+-[Field]
+-Uri=content.full_text
+-Name=Full text
+-TypeUri=string
+-Description=Content converted to plain-text
+-Comment=This is indexable text body for documents, for images we might eventually do OCR, and speech recognition for audio(hopefully by the end of the century).
+-
+-[Field]
+-Uri=content.ID
+-Name=ID
+-TypeUri=string
+-Description=Content ID
+-Comment=Generic content ID. Use subproperties.
+-
+-[Field]
+-Uri=content.doi
+-ParentUri=content.ID
+-Name=DOI
+-TypeUri=string
+-Description=Digital Object Identifier
+-Comment=http://www.doi.org/
+-
+-[Field]
+-Uri=content.thumbnail
+-Name=Thumbnail
+-TypeUri=binary
+-Description=Content thumbnail
+-Comment=
+-
+-
+-
+-[Field]
+-Uri=content.legal
+-Name=Legal Info
+-TypeUri=string
+-Description=Content Legal Info
+-Comment=
+-
+-[Field]
+-Uri=content.license_type
+-ParentUri=content.legal
+-Name=License type
+-TypeUri=string
+-Description=Content license type
+-Comment=GPL, BSD, proprietary
+-
+-[Field]
+-Uri=content.license
+-ParentUri=content.legal
+-Name=License
+-TypeUri=string
+-Description=Content license
+-Comment=
+-
+-[Field]
+-Uri=content.copyright
+-ParentUri=content.legal
+-Name=Copyright
+-TypeUri=string
+-Description=Content copyright notice
+-Comment=
+-
+-[Field]
+-Uri=content.disclaimer
+-ParentUri=content.legal
+-Name=Disclaimer
+-TypeUri=string
+-Description=Content disclaimer
+-Comment=
+-
+-[Field]
+-Uri=content.warning
+-ParentUri=content.legal
+-Name=Warning
+-TypeUri=string
+-Description=Warning of nature of content
+-Comment=
+-
+-
+-
+-[Field]
+-Uri=content.generator
+-Name=Generated with
+-TypeUri=string
+-Description=Content generator software
+-Comment=
+-
+-[Field]
+-Uri=content.generator_settings
+-Name=Generator settings
+-TypeUri=string
+-Description=Content generator software settings
+-Comment=
+-
+-[Field]
+-Uri=content.format_subtype
+-Name=Format subtype
+-TypeUri=string
+-Description=Content format subtype
+-Comment=
+-
+-
+-
+-[Field]
+-Uri=content.related
+-Name=Related
+-TypeUri=string
+-Description=Related content
+-Comment=abstract. use children.
+-
+-[Field]
+-Uri=content.depends
+-ParentUri=content.related
+-Name=Depends
+-TypeUri=string
+-Description=Content dependency
+-Comment=
+-
+-[Field]
+-Uri=content.conflicts
+-ParentUri=content.related
+-Name=Conflicts
+-TypeUri=string
+-Description=Content conflicts with
+-Comment=
+-
+-[Field]
+-Uri=content.supercedes
+-ParentUri=content.related
+-Name=Supercedes
+-TypeUri=string
+-Description=Content supercedes
+-Comment=
+-
+-[Field]
+-Uri=content.links
+-ParentUri=content.related
+-Name=Links
+-TypeUri=string
+-Description=Content links to
+-Comment=
+--- a/src/streamanalyzer/fieldproperties/strigi_email.fieldproperties
++++ /dev/null
+@@ -1,46 +0,0 @@
+-[Field]
+-Uri=email.from
+-ParentUri=message.sender
+-Name=From
+-TypeUri=string
+-Description=E-mail sender
+-Comment=
+-
+-[Field]
+-Uri=email.to
+-ParentUri=message.primary_recipient
+-Name=To
+-TypeUri=string
+-Description=E-mail recipient
+-Comment=
+-
+-[Field]
+-Uri=email.cc
+-ParentUri=message.secondary_recipient
+-Name=CC
+-TypeUri=string
+-Description=E-mail carbon copy
+-Comment=
+-
+-[Field]
+-Uri=email.bcc
+-ParentUri=message.secondary_recipient
+-Name=BCC
+-TypeUri=string
+-Description=E-mail blind carbon copy
+-Comment=
+-
+-[Field]
+-Uri=email.subject
+-ParentUri=message.subject
+-Name=Subject
+-TypeUri=string
+-Description=E-mail subject
+-Comment=
+-
+-[Field]
+-Uri=email.content_type
+-Name=Content-type
+-TypeUri=string
+-Description=E-mail content-type
+-Comment=
+--- a/src/streamanalyzer/fieldproperties/strigi_image.fieldproperties
++++ /dev/null
+@@ -1,64 +0,0 @@
+-[Field]
+-Uri=image.resolution.x
+-Name=Resolution X
+-TypeUri=integer
+-Description=Image resolution along X axis
+-Comment=
+-
+-[Field]
+-Uri=image.resolution.y
+-Name=Resolution Y
+-TypeUri=integer
+-Description=Image resolution along Y axis
+-Comment=
+-
+-[Field]
+-Uri=image.width
+-Name=Width
+-TypeUri=integer
+-Description=Image width
+-Comment=
+-
+-[Field]
+-Uri=image.height
+-Name=Height
+-TypeUri=integer
+-Description=Image height
+-Comment=
+-
+-[Field]
+-Uri=image.color_space
+-Name=Color space
+-TypeUri=string
+-Description=Image color space
+-Comment=RGB, RGBA, CMYK, Grayscale, Indexed(palette) and more exotic, for pictures. Something similar exists for video. TODO: complete list
+-
+-[Field]
+-Uri=image.color_depth
+-ParentUri=media.sample_format
+-Name=Color depth
+-TypeUri=string
+-Description=Image color depth
+-Comment=
+-
+-[Field]
+-Uri=image.color_count
+-ParentUri=media.sample_format
+-Name=Color_count
+-TypeUri=string
+-Description=Image color count
+-Comment=For palette
+-
+-[Field]
+-Uri=image.aspect_ratio
+-Name=Aspect ratio
+-TypeUri=string
+-Description=Image aspect ratio
+-Comment=user-friendly representation of dimensions.x/dimensions.y
+-
+-[Field]
+-Uri=image.interlace
+-Name=Interlace
+-TypeUri=string
+-Description=Image interlace mode
+-Comment=none|Adam7|
+--- a/src/streamanalyzer/fieldproperties/strigi_media.fieldproperties
++++ /dev/null
+@@ -1,55 +0,0 @@
+-[Field]
+-Uri=media.codec
+-Name=Codec
+-TypeUri=string
+-Description=Media codec
+-Comment=
+-
+-[Field]
+-Uri=media.bitrate.type
+-Name=Bitrate type
+-TypeUri=string
+-Description=
+-Comment=lossless, CBR, VBR, ABR
+-
+-[Field]
+-Uri=media.bitrate.value
+-Name=Bitrate
+-TypeUri=integer
+-Description=
+-Comment=n/a or file average for lossless and vbr; actual value for CBR, ABR; unit: bit
+-
+-[Field]
+-Uri=media.sample_rate
+-Name=Sample rate
+-TypeUri=integer
+-Description=Media sample rate
+-Comment=FPS for video, sample rate for audio
+-
+-[Field]
+-Uri=media.sample_count
+-Name=Sample count
+-TypeUri=integer
+-Description=Media sample count
+-Comment=1, for still pictures, -1 for (semi-)infinite streams like net radio/tv
+-
+-[Field]
+-Uri=media.sample_format
+-Name=Sample format
+-TypeUri=string
+-Description=Media sample format
+-Comment=color depth for images, sample size for audio. 8/16/24/32/X bit int/float. TODO: complete list
+-
+-[Field]
+-Uri=media.album
+-Name=Album
+-TypeUri=string
+-Description=Media Album
+-Comment=
+-
+-[Field]
+-Uri=media.duration
+-Name=Duration
+-TypeUri=integer
+-Description=Media Duration
+-Comment=
+--- a/src/streamanalyzer/fieldproperties/strigi_message.fieldproperties
++++ /dev/null
+@@ -1,52 +0,0 @@
+-[Field]
+-Uri=message.sender
+-Name=Sender
+-TypeUri=string
+-Description=Message sender
+-Comment=
+-
+-[Field]
+-Uri=message.recipient
+-Name=Recipient
+-TypeUri=string
+-Description=Message recipient
+-Comment=
+-
+-[Field]
+-Uri=message.primary_recipient
+-ParentUri=message.recipient
+-Name=Primary recipient
+-TypeUri=string
+-Description=Message primary recipient
+-Comment=
+-
+-[Field]
+-Uri=message.secondary_recipient
+-ParentUri=message.recipient
+-Name=Secondary recipient
+-TypeUri=string
+-Description=Message secondary recipient
+-Comment=a "witness" recipient along the lines of e-mail cc:
+-
+-[Field]
+-Uri=message.subject
+-ParentUri=content.subject
+-Name=Subject
+-TypeUri=string
+-Description=Message subject
+-Comment=
+-
+-[Field]
+-Uri=message.sent_time
+-ParentUri=content.creation_time
+-Name=Sent time
+-TypeUri=string
+-Description=Message sent time
+-Comment=
+-
+-[Field]
+-Uri=message.specific_ID
+-Name=ID
+-TypeUri=string
+-Description=Protocol-specific message ID
+-Comment= re: email ID tag
+--- a/src/streamanalyzer/fieldproperties/strigi.namespace
++++ /dev/null
+@@ -1 +0,0 @@
+-http://strigi.sourceforge.net/RDF/#
+\ No newline at end of file
+--- a/src/streamanalyzer/fieldproperties/strigi_photo.fieldproperties
++++ /dev/null
+@@ -1,104 +0,0 @@
+-[Field]
+-Uri=photo.camera_manufacturer
+-Name=Camera Manufacturer
+-TypeUri=string
+-Description=
+-Comment=
+-
+-[Field]
+-Uri=photo.camera_model
+-Name=Camera model
+-TypeUri=string
+-Description=
+-Comment=
+-
+-[Field]
+-Uri=photo.focal_length
+-Name=Focal length
+-TypeUri=string
+-Description=
+-Comment=
+-
+-[Field]
+-Uri=photo.exposure_time
+-Name=Exposure time
+-TypeUri=string
+-Description=
+-Comment=
+-
+-[Field]
+-Uri=photo.focus_distance
+-Name=Focus distance
+-TypeUri=string
+-Description=
+-Comment=
+-
+-[Field]
+-Uri=photo.white_balance
+-Name=White balance
+-TypeUri=string
+-Description=
+-Comment=
+-
+-[Field]
+-Uri=photo.flash_used
+-Name=Flash used
+-TypeUri=string
+-Description=
+-Comment=
+-
+-[Field]
+-Uri=photo.iso_equivalent
+-Name=ISO equivalent
+-TypeUri=string
+-Description=
+-Comment=
+-
+-[Field]
+-Uri=photo.orientation
+-Name=Orientation
+-TypeUri=string
+-Description=Photo orientation
+-Comment=
+-
+-[Field]
+-Uri=photo.exposure_program
+-Name=Exposure program
+-TypeUri=string
+-Description=Photo exposure program
+-Comment=
+-
+-[Field]
+-Uri=photo.exposure_bias
+-Name=Exposure bias
+-TypeUri=string
+-Description=Photo exposure bias
+-Comment=
+-
+-[Field]
+-Uri=photo.aperture
+-Name=Aperture
+-TypeUri=string
+-Description=Photo aperture
+-Comment=
+-
+-[Field]
+-Uri=photo.cdd_width
+-Name=CCD width
+-TypeUri=string
+-Description=Photo CCD width
+-Comment=
+-
+-[Field]
+-Uri=photo.metering_mode
+-Name=Metering mode
+-TypeUri=string
+-Description=Photo metering mode
+-Comment=
+-
+-[Field]
+-Uri=photo.35mm_equivalent
+-Name=35mm equivalent
+-TypeUri=string
+-Description=Photo 35mm equivalent
+-Comment=
+--- a/src/streamanalyzer/fieldproperties/strigi.rdfs
++++ b/src/streamanalyzer/fieldproperties/strigi.rdfs
+@@ -12,6 +12,13 @@
+ 	 xmlns:xss="&xss;"
+ 	 xmlns:rdfs="&rdfs;">
+ 
++<rdf:Property rdf:about="&rdf;type">
++	<rdfs:label>rdf:type</rdfs:label>
++	<rdfs:domain rdf:resource="&rdfs;Resource"/>
++	<rdfs:range rdf:resource="&rdfs;Class"/>
++	<rdfs:comment>Declaring this here so that it's picked up by FieldPropertiesDb</rdfs:comment>
++</rdf:Property>
++
+ <rdf:Property rdf:about="&strigi;depth">
+ 	<rdfs:label>strigi:depth</rdfs:label>
+ 	<rdfs:domain rdf:resource="&xesam;Source"/>
+@@ -26,4 +33,36 @@
+ 
+ 
+ 
++<rdf:Property rdf:about="&strigi;codeLineCount">
++	<rdfs:label>strigi:codeLineCount</rdfs:label>
++	<rdfs:domain rdf:resource="&xesam;SourceCode"/>
++	<rdfs:comment>Source code code line count</rdfs:comment>
++</rdf:Property>
++
++<rdf:Property rdf:about="&strigi;commentLineCount">
++	<rdfs:label>strigi:commentLineCount</rdfs:label>
++	<rdfs:domain rdf:resource="&xesam;SourceCode"/>
++	<rdfs:comment>Source code comment line count</rdfs:comment>
++</rdf:Property>
++
++
++
++<rdfs:Class rdf:about="&strigi;Cursor">
++	<rdfs:subClassOf rdf:resource="&xesam;Visual"/>
++	<rdfs:label>strigi:Cursor</rdfs:label>
++	<rdfs:comment>Cursor is an image with a hot spot.</rdfs:comment>
++</rdfs:Class>
++
++<rdf:Property rdf:about="&strigi;hotSpotX">
++	<rdfs:label>strigi:hotSpotX</rdfs:label>
++	<rdfs:domain rdf:resource="&strigi;Cursor"/>
++	<rdfs:comment>Cursor hot spot X coordinate</rdfs:comment>
++</rdf:Property>
++
++<rdf:Property rdf:about="&strigi;hotSpotY">
++	<rdfs:label>strigi:hotSpotY</rdfs:label>
++	<rdfs:domain rdf:resource="&strigi;Cursor"/>
++	<rdfs:comment>Cursor hot spot Y coordinate</rdfs:comment>
++</rdf:Property>
++
+ </rdf:RDF>
+--- a/src/streamanalyzer/fieldproperties/strigi_software.fieldproperties
++++ /dev/null
+@@ -1,39 +0,0 @@
+-[Field]
+-Uri=software.name
+-ParentUri=content.title
+-Name=Name
+-TypeUri=string
+-Description=Software name
+-Comment=
+-
+-[Field]
+-Uri=software.version
+-ParentUri=content.version
+-Name=Version
+-TypeUri=string
+-Description=Software version
+-Comment=
+-
+-[Field]
+-Uri=software.depends
+-Name=Depends on
+-TypeUri=string
+-Description=Software depends on
+-Comment=
+-
+-[Field]
+-Uri=software.section
+-ParentUri=content.keyword
+-Name=Section
+-TypeUri=string
+-Description=Software section
+-Comment=
+-
+-[Field]
+-Uri=software.maintainer
+-ParentUri=content.author
+-Name=Name
+-TypeUri=string
+-Description=Software maintainer
+-Comment=maintainer is the author of package itself.
+-
+--- a/src/streamanalyzer/fieldproperties/strigi_system.fieldproperties
++++ /dev/null
+@@ -1,76 +0,0 @@
+-[Field]
+-Uri=system.owner
+-Name=Owner
+-TypeUri=string
+-Description=File owner
+-Comment=
+-
+-[Field]
+-Uri=system.ID
+-Name=ID
+-TypeUri=integer
+-Description=Unique system ID
+-Comment=unique ID within the system, or who knows even network
+-
+-[Field]
+-Uri=system.creation_time
+-Name=Creation time
+-TypeUri=datetime
+-Description=File creation time
+-Comment=time when the file was created *locally*, unlike content.creation_time
+-
+-[Field]
+-Uri=system.last_modified_time
+-Name=Last modified time
+-TypeUri=datetime
+-Description=File last modified time
+-Comment=
+-
+-[Field]
+-Uri=system.last_accessed_time
+-Name=Last accessed time
+-TypeUri=datetime
+-Description=File last accessed time
+-Comment=
+-
+-[Field]
+-Uri=system.hash.sha1
+-Name=Hash
+-TypeUri=binary
+-Description=SHA-1 hash of file contents
+-Comment=
+-
+-[Field]
+-Uri=system.location
+-Name=Location
+-TypeUri=string
+-Description=File location
+-Comment=Path
+-
+-[Field]
+-Uri=system.file_name
+-Name=File name
+-TypeUri=string
+-Description=
+-Comment=
+-
+-[Field]
+-Uri=system.file_extension
+-Name=File extension
+-TypeUri=string
+-Description=
+-Comment=
+-
+-[Field]
+-Uri=system.depth
+-Name=Depth
+-TypeUri=string
+-Description=
+-Comment=
+-
+-[Field]
+-Uri=system.size
+-Name=Size
+-TypeUri=integer
+-Description=File size
+-Comment=actual file/data size as reported by filesystem. For archive contents this is packed size.
+--- a/src/streamanalyzer/fieldproperties/strigi_text.fieldproperties
++++ /dev/null
+@@ -1,20 +0,0 @@
+-[Field]
+-Uri=text.stats.char_count
+-Name=Character count
+-TypeUri=integer
+-Description=Text character count
+-Comment=
+-
+-[Field]
+-Uri=text.stats.word_count
+-Name=Word count
+-TypeUri=integer
+-Description=Text word count
+-Comment=
+-
+-[Field]
+-Uri=text.stats.line_count
+-Name=Line count
+-TypeUri=integer
+-Description=Text line count
+-Comment=
+--- a/src/streamanalyzer/fieldproperties/strigi_trash.fieldproperties
++++ /dev/null
+@@ -1,13 +0,0 @@
+-[Field]
+-Uri=trash.original_location
+-Name=Original location
+-TypeUri=string
+-Description=File original location
+-Comment=
+-
+-[Field]
+-Uri=trash.deletion_time
+-Name=Deletion time
+-TypeUri=string
+-Description=File deletion time
+-Comment=
+--- a/src/streamanalyzer/fieldproperties/strigi_user.fieldproperties
++++ /dev/null
+@@ -1,27 +0,0 @@
+-[Field]
+-Uri=user.tags
+-Name=Tags
+-TypeUri=string
+-Description=User tags
+-Comment=user-assigned tags. tags can be initially populated from paths(i.e. /music/rock/ballads => categories music, rock and ballads)
+-
+-[Field]
+-Uri=user.comment
+-Name=User comment
+-TypeUri=string
+-Description=Comment provided by user
+-Comment=
+-
+-[Field]
+-Uri=user.rating
+-Name=Rating
+-TypeUri=integer
+-Description=User's rating of the file
+-Comment=user's opinion on the quality of file. 0 to 100, 100 being best
+-
+-[Field]
+-Uri=user.usage_intensity
+-Name=Usage intensity
+-TypeUri=integer
+-Description=Usage intensity rating
+-Comment=how often and for how long this file is used. For example play count.
+--- a/src/streamanalyzer/fieldproperties/strigi_video.fieldproperties
++++ /dev/null
+@@ -1,7 +0,0 @@
+-[Field]
+-Uri=video.frame_rate
+-ParentUri=media.sample_rate
+-Name=Frame rate
+-TypeUri=string
+-Description=Video frame rate
+-Comment=
+--- a/src/streamanalyzer/fieldproperties/strigi_xml.fieldproperties
++++ /dev/null
+@@ -1,6 +0,0 @@
+-[Field]
+-Uri=xml.usesNamespace
+-Name=XML Namespace
+-TypeUri=string
+-Description=XML Namespace used in the XML
+-Comment=XML files may use multiple namespaces.
+--- /dev/null
++++ b/src/streamanalyzer/fieldproperties/xesam-convenience.rdfs
+@@ -0,0 +1,396 @@
++<?xml version='1.0' encoding='UTF-8'?>
++<!DOCTYPE rdf:RDF [
++	 <!ENTITY rdf 'http://www.w3.org/1999/02/22-rdf-syntax-ns#'>
++	 <!ENTITY xesam 'http://freedesktop.org/standards/xesam/1.0/core#'>
++	 <!ENTITY xss 'http://freedesktop.org/standards/xesam/1.0/schema#'>
++	 <!ENTITY rdfs 'http://www.w3.org/2000/01/rdf-schema#'>
++]>
++<rdf:RDF xmlns:rdf="&rdf;"
++	 xmlns:xesam="&xesam;"
++	 xmlns:xss="&xss;"
++	 xmlns:rdfs="&rdfs;">
++
++
++
++<rdf:Property rdf:about="&xesam;musicBrainzAlbumID">
++	<rdfs:label>xesam:musicBrainzAlbumID</rdfs:label>
++	<rdfs:domain rdf:resource="&xesam;Audio"/>
++	<rdfs:subPropertyOf rdf:resource="&xesam;id"/>
++	<rdfs:comment>MusicBrainz album ID in UUID format</rdfs:comment>
++</rdf:Property>
++
++<rdf:Property rdf:about="&xesam;musicBrainzArtistID">
++	<rdfs:label>xesam:musicBrainzArtistID</rdfs:label>
++	<rdfs:domain rdf:resource="&xesam;Audio"/>
++	<rdfs:subPropertyOf rdf:resource="&xesam;id"/>
++	<rdfs:comment>MusicBrainz artist ID in UUID format</rdfs:comment>
++</rdf:Property>
++
++<rdf:Property rdf:about="&xesam;musicBrainzAlbumArtistID">
++	<rdfs:label>xesam:musicBrainzAlbumArtistID</rdfs:label>
++	<rdfs:domain rdf:resource="&xesam;Audio"/>
++	<rdfs:subPropertyOf rdf:resource="&xesam;id"/>
++	<rdfs:comment>MusicBrainz album artist ID in UUID format</rdfs:comment>
++</rdf:Property>
++
++<rdf:Property rdf:about="&xesam;musicBrainzTrackID">
++	<rdfs:label>xesam:musicBrainzTrackID</rdfs:label>
++	<rdfs:domain rdf:resource="&xesam;Audio"/>
++	<rdfs:subPropertyOf rdf:resource="&xesam;id"/>
++	<rdfs:comment>MusicBrainz track ID in UUID format</rdfs:comment>
++</rdf:Property>
++
++<rdf:Property rdf:about="&xesam;musicBrainzFingerprint">
++	<rdfs:label>xesam:musicBrainzFingerprint</rdfs:label>
++	<rdfs:domain rdf:resource="&xesam;Audio"/>
++	<rdfs:subPropertyOf rdf:resource="&xesam;fingerprint"/>
++	<rdfs:comment>MusicBrainz track fingerprint</rdfs:comment>
++</rdf:Property>
++
++
++
++
++<rdf:Property rdf:about="&xesam;isrc">
++	<rdfs:label>xesam:isrc</rdfs:label>
++	<rdfs:domain rdf:resource="&xesam;Media"/>
++	<rdfs:subPropertyOf rdf:resource="&xesam;id"/>
++	<rdfs:comment>International Standard Recording Code</rdfs:comment>
++</rdf:Property>
++
++<rdf:Property rdf:about="&xesam;imdbId">
++	<rdfs:label>xesam:imdbId</rdfs:label>
++	<rdfs:domain rdf:resource="&xesam;Video"/>
++	<rdfs:subPropertyOf rdf:resource="&xesam;id"/>
++	<rdfs:comment>IMDB.com video ID</rdfs:comment>
++</rdf:Property>
++
++
++
++
++
++
++
++
++
++
++
++
++
++<rdfs:Class rdf:about="&xesam;PIM">
++	<rdfs:subClassOf rdf:resource="&xesam;Content"/>
++	<rdfs:label>xesam:PIM</rdfs:label>
++	<rdfs:comment>Generic PIM</rdfs:comment>
++</rdfs:Class>
++
++<rdf:Property rdf:about="&xesam;attendee">
++	<rdfs:label>xesam:attendee</rdfs:label>
++	<rdfs:domain rdf:resource="&xesam;Alarm"/>
++	<rdfs:domain rdf:resource="&xesam;Event"/>
++	<rdfs:domain rdf:resource="&xesam;FreeBusy"/>
++	<rdfs:domain rdf:resource="&xesam;Journal"/>
++	<rdfs:domain rdf:resource="&xesam;Task"/>
++	<rdfs:comment>PIM entry attendee</rdfs:comment>
++</rdf:Property>
++
++<rdf:Property rdf:about="&xesam;actionOrganizer">
++	<rdfs:label>xesam:actionOrganizer</rdfs:label>
++	<rdfs:domain rdf:resource="&xesam;Event"/>
++	<rdfs:domain rdf:resource="&xesam;FreeBusy"/>
++	<rdfs:domain rdf:resource="&xesam;Journal"/>
++	<rdfs:domain rdf:resource="&xesam;Task"/>
++	<rdfs:comment>PIM entry organizer</rdfs:comment>
++</rdf:Property>
++
++<rdf:Property rdf:about="&xesam;actionContact">
++	<rdfs:label>xesam:actionContact</rdfs:label>
++	<rdfs:domain rdf:resource="&xesam;Event"/>
++	<rdfs:domain rdf:resource="&xesam;FreeBusy"/>
++	<rdfs:domain rdf:resource="&xesam;Journal"/>
++	<rdfs:domain rdf:resource="&xesam;Task"/>
++	<rdfs:comment>PIM entry contact</rdfs:comment>
++</rdf:Property>
++
++<rdf:Property rdf:about="&xesam;actionURL">
++	<rdfs:label>xesam:actionURL</rdfs:label>
++	<rdfs:domain rdf:resource="&xesam;Event"/>
++	<rdfs:domain rdf:resource="&xesam;FreeBusy"/>
++	<rdfs:domain rdf:resource="&xesam;Journal"/>
++	<rdfs:domain rdf:resource="&xesam;Task"/>
++	<rdfs:comment>PIM entry URL</rdfs:comment>
++</rdf:Property>
++
++<rdf:Property rdf:about="&xesam;actionTrigger">
++	<rdfs:label>xesam:actionTrigger</rdfs:label>
++	<rdfs:domain rdf:resource="&xesam;Alarm"/>
++	<rdfs:domain rdf:resource="&xesam;Event"/>
++	<rdfs:domain rdf:resource="&xesam;Task"/>
++	<rdfs:comment>PIM entry action trigger</rdfs:comment>
++</rdf:Property>
++
++<rdf:Property rdf:about="&xesam;actionEnd">
++	<rdfs:label>xesam:actionEnd</rdfs:label>
++	<rdfs:domain rdf:resource="&xesam;Event"/>
++	<rdfs:domain rdf:resource="&xesam;FreeBusy"/>
++	<rdfs:comment>PIM entry action end</rdfs:comment>
++</rdf:Property>
++
++<rdf:Property rdf:about="&xesam;actionDuration">
++	<rdfs:label>xesam:actionDuration</rdfs:label>
++	<rdfs:domain rdf:resource="&xesam;Alarm"/>
++	<rdfs:domain rdf:resource="&xesam;Event"/>
++	<rdfs:domain rdf:resource="&xesam;FreeBusy"/>
++	<rdfs:domain rdf:resource="&xesam;Task"/>
++	<rdfs:comment>PIM entry action duration</rdfs:comment>
++</rdf:Property>
++
++<rdf:Property rdf:about="&xesam;actionStart">
++	<rdfs:label>xesam:actionStart</rdfs:label>
++	<rdfs:domain rdf:resource="&xesam;Event"/>
++	<rdfs:domain rdf:resource="&xesam;FreeBusy"/>
++	<rdfs:domain rdf:resource="&xesam;Task"/>
++	<rdfs:comment>PIM entry action start</rdfs:comment>
++</rdf:Property>
++
++<rdf:Property rdf:about="&xesam;actionPriority">
++	<rdfs:label>xesam:actionPriority</rdfs:label>
++	<rdfs:domain rdf:resource="&xesam;Event"/>
++	<rdfs:domain rdf:resource="&xesam;Task"/>
++	<rdfs:comment>PIM entry priority</rdfs:comment>
++</rdf:Property>
++
++<rdf:Property rdf:about="&xesam;actionLocation">
++	<rdfs:label>xesam:actionLocation</rdfs:label>
++	<rdfs:domain rdf:resource="&xesam;Event"/>
++	<rdfs:domain rdf:resource="&xesam;Task"/>
++	<rdfs:comment>PIM entry location</rdfs:comment>
++</rdf:Property>
++
++<rdf:Property rdf:about="&xesam;actionStatus">
++	<rdfs:label>xesam:actionStatus</rdfs:label>
++	<rdfs:domain rdf:resource="&xesam;Event"/>
++	<rdfs:domain rdf:resource="&xesam;Journal"/>
++	<rdfs:domain rdf:resource="&xesam;Task"/>
++	<rdfs:comment>PIM entry status</rdfs:comment>
++</rdf:Property>
++
++<rdf:Property rdf:about="&xesam;actionRecurrenceID">
++	<rdfs:label>xesam:actionRecurrenceID</rdfs:label>
++	<rdfs:domain rdf:resource="&xesam;Event"/>
++	<rdfs:domain rdf:resource="&xesam;Journal"/>
++	<rdfs:domain rdf:resource="&xesam;Task"/>
++	<rdfs:comment>PIM entry recurrence ID</rdfs:comment>
++</rdf:Property>
++
++<rdf:Property rdf:about="&xesam;actionRecurrenceDate">
++	<rdfs:label>xesam:actionRecurrenceDate</rdfs:label>
++	<rdfs:domain rdf:resource="&xesam;Event"/>
++	<rdfs:domain rdf:resource="&xesam;Journal"/>
++	<rdfs:domain rdf:resource="&xesam;Task"/>
++	<rdfs:comment>PIM entry recurrence date</rdfs:comment>
++</rdf:Property>
++
++<rdf:Property rdf:about="&xesam;actionRecurrenceRule">
++	<rdfs:label>xesam:actionRecurrenceRule</rdfs:label>
++	<rdfs:domain rdf:resource="&xesam;Event"/>
++	<rdfs:domain rdf:resource="&xesam;Journal"/>
++	<rdfs:domain rdf:resource="&xesam;Task"/>
++	<rdfs:comment>PIM entry recurrence rule</rdfs:comment>
++</rdf:Property>
++
++<rdf:Property rdf:about="&xesam;actionExceptionDate">
++	<rdfs:label>xesam:actionExceptionDate</rdfs:label>
++	<rdfs:domain rdf:resource="&xesam;Event"/>
++	<rdfs:domain rdf:resource="&xesam;Journal"/>
++	<rdfs:domain rdf:resource="&xesam;Task"/>
++	<rdfs:comment>PIM entry exception date</rdfs:comment>
++</rdf:Property>
++
++<rdf:Property rdf:about="&xesam;actionExceptionRule">
++	<rdfs:label>xesam:actionExceptionRule</rdfs:label>
++	<rdfs:domain rdf:resource="&xesam;Event"/>
++	<rdfs:domain rdf:resource="&xesam;Journal"/>
++	<rdfs:domain rdf:resource="&xesam;Task"/>
++	<rdfs:comment>PIM entry exception rule</rdfs:comment>
++</rdf:Property>
++
++<rdf:Property rdf:about="&xesam;actionAccessClassification">
++	<rdfs:label>xesam:actionAccessClassification</rdfs:label>
++	<rdfs:domain rdf:resource="&xesam;Event"/>
++	<rdfs:domain rdf:resource="&xesam;Journal"/>
++	<rdfs:domain rdf:resource="&xesam;Task"/>
++	<rdfs:comment>PIM entry access classification</rdfs:comment>
++</rdf:Property>
++
++<rdf:Property rdf:about="&xesam;actionResources">
++	<rdfs:label>xesam:actionResources</rdfs:label>
++	<rdfs:domain rdf:resource="&xesam;Event"/>
++	<rdfs:domain rdf:resource="&xesam;Task"/>
++	<rdfs:comment>Equipment or resources anticipated for an activity</rdfs:comment>
++</rdf:Property>
++
++<rdf:Property rdf:about="&xesam;actionAlarm">
++	<rdfs:label>xesam:actionResources</rdfs:label>
++	<rdfs:domain rdf:resource="&xesam;Event"/>
++	<rdfs:domain rdf:resource="&xesam;Task"/>
++	<rdfs:comment>PIM activity has alarm</rdfs:comment>
++</rdf:Property>
++
++
++
++
++
++
++<rdfs:Class rdf:about="&xesam;Alarm">
++	<rdfs:subClassOf rdf:resource="&xesam;PIM"/>
++	<rdfs:label>xesam:Alarm</rdfs:label>
++	<rdfs:comment>Alarm</rdfs:comment>
++</rdfs:Class>
++
++<rdf:Property rdf:about="&xesam;alarmRepeat">
++	<rdfs:label>xesam:alarmRepeat</rdfs:label>
++	<rdfs:domain rdf:resource="&xesam;Alarm"/>
++	<rdfs:comment>Alarm repeat</rdfs:comment>
++</rdf:Property>
++
++<rdf:Property rdf:about="&xesam;alarmAction">
++	<rdfs:label>xesam:alarmAction</rdfs:label>
++	<rdfs:domain rdf:resource="&xesam;Alarm"/>
++	<rdfs:comment>Alarm action</rdfs:comment>
++</rdf:Property>
++
++
++
++
++
++
++
++<rdfs:Class rdf:about="&xesam;Event">
++	<rdfs:subClassOf rdf:resource="&xesam;PIM"/>
++	<rdfs:label>xesam:Event</rdfs:label>
++	<rdfs:comment>Event</rdfs:comment>
++</rdfs:Class>
++
++<rdf:Property rdf:about="&xesam;eventTransparrent">
++	<rdfs:label>xesam:eventTransparrent</rdfs:label>
++	<rdfs:domain rdf:resource="&xesam;Event"/>
++	<rdfs:comment>Is event transparrent(makes person busy)</rdfs:comment>
++</rdf:Property>
++
++<rdf:Property rdf:about="&xesam;eventStart">
++	<rdfs:label>xesam:eventStart</rdfs:label>
++	<rdfs:domain rdf:resource="&xesam;Event"/>
++	<rdfs:comment>Event start time</rdfs:comment>
++</rdf:Property>
++
++<rdf:Property rdf:about="&xesam;eventEnd">
++	<rdfs:label>xesam:eventEnd</rdfs:label>
++	<rdfs:domain rdf:resource="&xesam;Event"/>
++	<rdfs:comment>Event end time</rdfs:comment>
++</rdf:Property>
++
++<rdf:Property rdf:about="&xesam;eventLocation">
++	<rdfs:label>xesam:eventLocation</rdfs:label>
++	<rdfs:domain rdf:resource="&xesam;Event"/>
++	<rdfs:comment>Event location</rdfs:comment>
++</rdf:Property>
++
++
++
++
++
++
++<rdfs:Class rdf:about="&xesam;Task">
++	<rdfs:subClassOf rdf:resource="&xesam;PIM"/>
++	<rdfs:label>xesam:Task</rdfs:label>
++	<rdfs:comment>Task</rdfs:comment>
++</rdfs:Class>
++
++<rdf:Property rdf:about="&xesam;taskDue">
++	<rdfs:label>xesam:taskDue</rdfs:label>
++	<rdfs:domain rdf:resource="&xesam;Task"/>
++	<rdfs:comment>Task due date/time</rdfs:comment>
++</rdf:Property>
++
++<rdf:Property rdf:about="&xesam;taskCompleted">
++	<rdfs:label>xesam:taskCompleted</rdfs:label>
++	<rdfs:domain rdf:resource="&xesam;Task"/>
++	<rdfs:comment>Is task completed?</rdfs:comment>
++</rdf:Property>
++
++<rdf:Property rdf:about="&xesam;taskPercentComplete">
++	<rdfs:label>xesam:taskPercentComplete</rdfs:label>
++	<rdfs:domain rdf:resource="&xesam;Task"/>
++	<rdfs:comment>Task completeness</rdfs:comment>
++</rdf:Property>
++
++
++
++
++
++<rdfs:Class rdf:about="&xesam;Journal">
++	<rdfs:subClassOf rdf:resource="&xesam;PIM"/>
++	<rdfs:label>xesam:Journal</rdfs:label>
++	<rdfs:comment>Journal</rdfs:comment>
++</rdfs:Class>
++
++
++
++<rdfs:Class rdf:about="&xesam;FreeBusy">
++	<rdfs:subClassOf rdf:resource="&xesam;PIM"/>
++	<rdfs:label>xesam:FreeBusy</rdfs:label>
++	<rdfs:comment>FreeBusy</rdfs:comment>
++</rdfs:Class>
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++<rdf:Property rdf:about="&xesam;icqContactMedium">
++	<rdfs:label>xesam:icqContactMedium</rdfs:label>
++	<rdfs:subPropertyOf rdf:resource="&xesam;imContactMedium"/>
++	<rdfs:domain rdf:resource="&xesam;Contact"/>
++	<rdfs:comment>Contact ICQ ID</rdfs:comment>
++</rdf:Property>
++
++<rdf:Property rdf:about="&xesam;aimContactMedium">
++	<rdfs:label>xesam:aimContactMedium</rdfs:label>
++	<rdfs:subPropertyOf rdf:resource="&xesam;imContactMedium"/>
++	<rdfs:domain rdf:resource="&xesam;Contact"/>
++	<rdfs:comment>Contact AIM ID</rdfs:comment>
++</rdf:Property>
++
++<rdf:Property rdf:about="&xesam;yahooContactMedium">
++	<rdfs:label>xesam:yahooContactMedium</rdfs:label>
++	<rdfs:subPropertyOf rdf:resource="&xesam;imContactMedium"/>
++	<rdfs:domain rdf:resource="&xesam;Contact"/>
++	<rdfs:comment>Contact Yahoo ID</rdfs:comment>
++</rdf:Property>
++
++<rdf:Property rdf:about="&xesam;msnContactMedium">
++	<rdfs:label>xesam:msnContactMedium</rdfs:label>
++	<rdfs:subPropertyOf rdf:resource="&xesam;imContactMedium"/>
++	<rdfs:domain rdf:resource="&xesam;Contact"/>
++	<rdfs:comment>Contact MSN ID</rdfs:comment>
++</rdf:Property>
++
++<rdf:Property rdf:about="&xesam;skypeContactMedium">
++	<rdfs:label>xesam:skypeContactMedium</rdfs:label>
++	<rdfs:subPropertyOf rdf:resource="&xesam;imContactMedium"/>
++	<rdfs:domain rdf:resource="&xesam;Contact"/>
++	<rdfs:comment>Contact Skype ID</rdfs:comment>
++</rdf:Property>
++
++
++
++
++
++</rdf:RDF>
+--- a/src/streamanalyzer/fieldproperties/xesam.namespace
++++ /dev/null
+@@ -1 +0,0 @@
+-undecided
+--- a/src/streamanalyzer/fieldproperties/xesam.rdfs
++++ b/src/streamanalyzer/fieldproperties/xesam.rdfs
+@@ -77,7 +77,7 @@
+ <rdf:Property rdf:about="&xesam;size">
+ 	<rdfs:label>xesam:size</rdfs:label>
+ 	<rdfs:domain rdf:resource="&xesam;Content"/>
+-	<rdfs:comment>Content size</rdfs:comment>
++	<rdfs:comment>Content/data size in bytes. See also storageSize</rdfs:comment>
+ </rdf:Property>
+ 
+ <rdf:Property rdf:about="&xesam;creator">
+@@ -259,7 +259,7 @@
+ </rdf:Property>
+ 
+ <rdf:Property rdf:about="&xesam;asText">
+-	<rdfs:label>xesam:comment</rdfs:label>
++	<rdfs:label>xesam:asText</rdfs:label>
+ 	<rdfs:domain rdf:resource="&xesam;Content"/>
+ 	<rdfs:comment>Content plain-text representation for indexing purposes</rdfs:comment>
+ </rdf:Property>
+@@ -301,30 +301,54 @@
+ 
+ 
+ 
+-<rdfs:Class rdf:about="&xesam;Folder">
++
++
++<rdfs:Class rdf:about="&xesam;Annotation">
+ 	<rdfs:subClassOf rdf:resource="&xesam;Content"/>
+-	<rdfs:label>xesam:Archive</rdfs:label>
+-	<rdfs:comment>Generic folder</rdfs:comment>
++	<rdfs:label>xesam:Annotation</rdfs:label>
++	<rdfs:comment>Generic annotation. Annotation provides a set of document description properties(like subject, title, description) for a list of objects it links to. It can link to other annotations, however interpretation of this may differ between specific annotation classes..</rdfs:comment>
++</rdfs:Class>
++
++
++<rdfs:Class rdf:about="&xesam;Folder">
++	<rdfs:subClassOf rdf:resource="&xesam;Annotation"/>
++	<rdfs:label>xesam:Folder</rdfs:label>
++	<rdfs:comment>Generic folder. In general, folders represent a tree-like structure(taxonomy), however on occasion this rule may violated in cases like symlinks.</rdfs:comment>
+ </rdfs:Class>
+ 
+ <rdfs:Class rdf:about="&xesam;Project">
+-	<rdfs:subClassOf rdf:resource="&xesam;Content"/>
++	<rdfs:subClassOf rdf:resource="&xesam;Annotation"/>
+ 	<rdfs:label>xesam:Project</rdfs:label>
+ 	<rdfs:comment>Generic project</rdfs:comment>
+ </rdfs:Class>
+ 
+ <rdfs:Class rdf:about="&xesam;MediaList">
+-	<rdfs:subClassOf rdf:resource="&xesam;Content"/>
++	<rdfs:subClassOf rdf:resource="&xesam;Annotation"/>
+ 	<rdfs:label>xesam:MediaList</rdfs:label>
+-	<rdfs:comment>Generic media file list(playlist)</rdfs:comment>
++	<rdfs:comment>Generic media content list(playlist). Linking to other content types is forbidden</rdfs:comment>
+ </rdfs:Class>
+ 
+ <rdfs:Class rdf:about="&xesam;AudioList">
+ 	<rdfs:subClassOf rdf:resource="&xesam;MediaList"/>
+ 	<rdfs:label>xesam:AudioList</rdfs:label>
+-	<rdfs:comment>Generic audio file list(playlist)</rdfs:comment>
++	<rdfs:comment>Generic audio list(playlist). Linking to other content types is forbidden</rdfs:comment>
++</rdfs:Class>
++
++<rdfs:Class rdf:about="&xesam;Tag">
++	<rdfs:subClassOf rdf:resource="&xesam;Annotation"/>
++	<rdfs:label>xesam:Tag</rdfs:label>
++	<rdfs:comment>Tag/keyword. As opposed to folders, there are no limitations on the structure of tags and arbitrary overlaps are possible.</rdfs:comment>
+ </rdfs:Class>
+ 
++<rdfs:Class rdf:about="&xesam;Bookmark">
++	<rdfs:subClassOf rdf:resource="&xesam;Annotation"/>
++	<rdfs:label>xesam:Bookmark</rdfs:label>
++	<rdfs:comment>Bookmark. Currently there's nothing that would distinguish bookmarks and tags</rdfs:comment>
++</rdfs:Class>
++
++
++
++
+ 
+ 
+ 
+@@ -563,279 +587,6 @@
+ 
+ 
+ 
+-<rdfs:Class rdf:about="&xesam;PIM">
+-	<rdfs:subClassOf rdf:resource="&xesam;Content"/>
+-	<rdfs:label>xesam:PIM</rdfs:label>
+-	<rdfs:comment>Generic PIM</rdfs:comment>
+-</rdfs:Class>
+-
+-<rdf:Property rdf:about="&xesam;attendee">
+-	<rdfs:label>xesam:attendee</rdfs:label>
+-	<rdfs:domain rdf:resource="&xesam;Alarm"/>
+-	<rdfs:domain rdf:resource="&xesam;Event"/>
+-	<rdfs:domain rdf:resource="&xesam;FreeBusy"/>
+-	<rdfs:domain rdf:resource="&xesam;Journal"/>
+-	<rdfs:domain rdf:resource="&xesam;Task"/>
+-	<rdfs:comment>PIM entry attendee</rdfs:comment>
+-</rdf:Property>
+-
+-<rdf:Property rdf:about="&xesam;actionOrganizer">
+-	<rdfs:label>xesam:actionOrganizer</rdfs:label>
+-	<rdfs:domain rdf:resource="&xesam;Event"/>
+-	<rdfs:domain rdf:resource="&xesam;FreeBusy"/>
+-	<rdfs:domain rdf:resource="&xesam;Journal"/>
+-	<rdfs:domain rdf:resource="&xesam;Task"/>
+-	<rdfs:comment>PIM entry organizer</rdfs:comment>
+-</rdf:Property>
+-
+-<rdf:Property rdf:about="&xesam;actionContact">
+-	<rdfs:label>xesam:actionContact</rdfs:label>
+-	<rdfs:domain rdf:resource="&xesam;Event"/>
+-	<rdfs:domain rdf:resource="&xesam;FreeBusy"/>
+-	<rdfs:domain rdf:resource="&xesam;Journal"/>
+-	<rdfs:domain rdf:resource="&xesam;Task"/>
+-	<rdfs:comment>PIM entry contact</rdfs:comment>
+-</rdf:Property>
+-
+-<rdf:Property rdf:about="&xesam;actionURL">
+-	<rdfs:label>xesam:actionURL</rdfs:label>
+-	<rdfs:domain rdf:resource="&xesam;Event"/>
+-	<rdfs:domain rdf:resource="&xesam;FreeBusy"/>
+-	<rdfs:domain rdf:resource="&xesam;Journal"/>
+-	<rdfs:domain rdf:resource="&xesam;Task"/>
+-	<rdfs:comment>PIM entry URL</rdfs:comment>
+-</rdf:Property>
+-
+-<rdf:Property rdf:about="&xesam;actionURL">
+-	<rdfs:label>xesam:actionURL</rdfs:label>
+-	<rdfs:domain rdf:resource="&xesam;Event"/>
+-	<rdfs:domain rdf:resource="&xesam;FreeBusy"/>
+-	<rdfs:domain rdf:resource="&xesam;Journal"/>
+-	<rdfs:domain rdf:resource="&xesam;Task"/>
+-	<rdfs:comment>PIM entry URL</rdfs:comment>
+-</rdf:Property>
+-
+-<rdf:Property rdf:about="&xesam;actionTrigger">
+-	<rdfs:label>xesam:actionTrigger</rdfs:label>
+-	<rdfs:domain rdf:resource="&xesam;Alarm"/>
+-	<rdfs:domain rdf:resource="&xesam;Event"/>
+-	<rdfs:domain rdf:resource="&xesam;Task"/>
+-	<rdfs:comment>PIM entry action trigger</rdfs:comment>
+-</rdf:Property>
+-
+-<rdf:Property rdf:about="&xesam;actionEnd">
+-	<rdfs:label>xesam:actionEnd</rdfs:label>
+-	<rdfs:domain rdf:resource="&xesam;Event"/>
+-	<rdfs:domain rdf:resource="&xesam;FreeBusy"/>
+-	<rdfs:comment>PIM entry action end</rdfs:comment>
+-</rdf:Property>
+-
+-<rdf:Property rdf:about="&xesam;actionDuration">
+-	<rdfs:label>xesam:actionDuration</rdfs:label>
+-	<rdfs:domain rdf:resource="&xesam;Alarm"/>
+-	<rdfs:domain rdf:resource="&xesam;Event"/>
+-	<rdfs:domain rdf:resource="&xesam;FreeBusy"/>
+-	<rdfs:domain rdf:resource="&xesam;Task"/>
+-	<rdfs:comment>PIM entry action duration</rdfs:comment>
+-</rdf:Property>
+-
+-<rdf:Property rdf:about="&xesam;actionStart">
+-	<rdfs:label>xesam:actionStart</rdfs:label>
+-	<rdfs:domain rdf:resource="&xesam;Event"/>
+-	<rdfs:domain rdf:resource="&xesam;FreeBusy"/>
+-	<rdfs:domain rdf:resource="&xesam;Task"/>
+-	<rdfs:comment>PIM entry action start</rdfs:comment>
+-</rdf:Property>
+-
+-<rdf:Property rdf:about="&xesam;actionPriority">
+-	<rdfs:label>xesam:actionPriority</rdfs:label>
+-	<rdfs:domain rdf:resource="&xesam;Event"/>
+-	<rdfs:domain rdf:resource="&xesam;Task"/>
+-	<rdfs:comment>PIM entry priority</rdfs:comment>
+-</rdf:Property>
+-
+-<rdf:Property rdf:about="&xesam;actionLocation">
+-	<rdfs:label>xesam:actionLocation</rdfs:label>
+-	<rdfs:domain rdf:resource="&xesam;Event"/>
+-	<rdfs:domain rdf:resource="&xesam;Task"/>
+-	<rdfs:comment>PIM entry location</rdfs:comment>
+-</rdf:Property>
+-
+-<rdf:Property rdf:about="&xesam;actionStatus">
+-	<rdfs:label>xesam:actionStatus</rdfs:label>
+-	<rdfs:domain rdf:resource="&xesam;Event"/>
+-	<rdfs:domain rdf:resource="&xesam;Journal"/>
+-	<rdfs:domain rdf:resource="&xesam;Task"/>
+-	<rdfs:comment>PIM entry status</rdfs:comment>
+-</rdf:Property>
+-
+-<rdf:Property rdf:about="&xesam;actionRecurrenceID">
+-	<rdfs:label>xesam:actionRecurrenceID</rdfs:label>
+-	<rdfs:domain rdf:resource="&xesam;Event"/>
+-	<rdfs:domain rdf:resource="&xesam;Journal"/>
+-	<rdfs:domain rdf:resource="&xesam;Task"/>
+-	<rdfs:comment>PIM entry recurrence ID</rdfs:comment>
+-</rdf:Property>
+-
+-<rdf:Property rdf:about="&xesam;actionRecurrenceDate">
+-	<rdfs:label>xesam:actionRecurrenceDate</rdfs:label>
+-	<rdfs:domain rdf:resource="&xesam;Event"/>
+-	<rdfs:domain rdf:resource="&xesam;Journal"/>
+-	<rdfs:domain rdf:resource="&xesam;Task"/>
+-	<rdfs:comment>PIM entry recurrence date</rdfs:comment>
+-</rdf:Property>
+-
+-<rdf:Property rdf:about="&xesam;actionRecurrenceRule">
+-	<rdfs:label>xesam:actionRecurrenceRule</rdfs:label>
+-	<rdfs:domain rdf:resource="&xesam;Event"/>
+-	<rdfs:domain rdf:resource="&xesam;Journal"/>
+-	<rdfs:domain rdf:resource="&xesam;Task"/>
+-	<rdfs:comment>PIM entry recurrence rule</rdfs:comment>
+-</rdf:Property>
+-
+-<rdf:Property rdf:about="&xesam;actionExceptionDate">
+-	<rdfs:label>xesam:actionExceptionDate</rdfs:label>
+-	<rdfs:domain rdf:resource="&xesam;Event"/>
+-	<rdfs:domain rdf:resource="&xesam;Journal"/>
+-	<rdfs:domain rdf:resource="&xesam;Task"/>
+-	<rdfs:comment>PIM entry exception date</rdfs:comment>
+-</rdf:Property>
+-
+-<rdf:Property rdf:about="&xesam;actionExceptionRule">
+-	<rdfs:label>xesam:actionExceptionRule</rdfs:label>
+-	<rdfs:domain rdf:resource="&xesam;Event"/>
+-	<rdfs:domain rdf:resource="&xesam;Journal"/>
+-	<rdfs:domain rdf:resource="&xesam;Task"/>
+-	<rdfs:comment>PIM entry exception rule</rdfs:comment>
+-</rdf:Property>
+-
+-<rdf:Property rdf:about="&xesam;actionAccessClassification">
+-	<rdfs:label>xesam:actionAccessClassification</rdfs:label>
+-	<rdfs:domain rdf:resource="&xesam;Event"/>
+-	<rdfs:domain rdf:resource="&xesam;Journal"/>
+-	<rdfs:domain rdf:resource="&xesam;Task"/>
+-	<rdfs:comment>PIM entry access classification</rdfs:comment>
+-</rdf:Property>
+-
+-<rdf:Property rdf:about="&xesam;actionResources">
+-	<rdfs:label>xesam:actionResources</rdfs:label>
+-	<rdfs:domain rdf:resource="&xesam;Event"/>
+-	<rdfs:domain rdf:resource="&xesam;Task"/>
+-	<rdfs:comment>Equipment or resources anticipated for an activity</rdfs:comment>
+-</rdf:Property>
+-
+-<rdf:Property rdf:about="&xesam;actionAlarm">
+-	<rdfs:label>xesam:actionResources</rdfs:label>
+-	<rdfs:domain rdf:resource="&xesam;Event"/>
+-	<rdfs:domain rdf:resource="&xesam;Task"/>
+-	<rdfs:comment>PIM activity has alarm</rdfs:comment>
+-</rdf:Property>
+-
+-
+-
+-
+-
+-
+-<rdfs:Class rdf:about="&xesam;Alarm">
+-	<rdfs:subClassOf rdf:resource="&xesam;PIM"/>
+-	<rdfs:label>xesam:Alarm</rdfs:label>
+-	<rdfs:comment>Alarm</rdfs:comment>
+-</rdfs:Class>
+-
+-<rdf:Property rdf:about="&xesam;alarmRepeat">
+-	<rdfs:label>xesam:alarmRepeat</rdfs:label>
+-	<rdfs:domain rdf:resource="&xesam;Alarm"/>
+-	<rdfs:comment>Alarm repeat</rdfs:comment>
+-</rdf:Property>
+-
+-<rdf:Property rdf:about="&xesam;alarmAction">
+-	<rdfs:label>xesam:alarmAction</rdfs:label>
+-	<rdfs:domain rdf:resource="&xesam;Alarm"/>
+-	<rdfs:comment>Alarm action</rdfs:comment>
+-</rdf:Property>
+-
+-
+-
+-
+-
+-
+-
+-<rdfs:Class rdf:about="&xesam;Event">
+-	<rdfs:subClassOf rdf:resource="&xesam;PIM"/>
+-	<rdfs:label>xesam:Event</rdfs:label>
+-	<rdfs:comment>Event</rdfs:comment>
+-</rdfs:Class>
+-
+-<rdf:Property rdf:about="&xesam;eventTransparrent">
+-	<rdfs:label>xesam:eventTransparrent</rdfs:label>
+-	<rdfs:domain rdf:resource="&xesam;Event"/>
+-	<rdfs:comment>Is event transparrent(makes person busy)</rdfs:comment>
+-</rdf:Property>
+-
+-<rdf:Property rdf:about="&xesam;eventStart">
+-	<rdfs:label>xesam:eventStart</rdfs:label>
+-	<rdfs:domain rdf:resource="&xesam;Event"/>
+-	<rdfs:comment>Event start time</rdfs:comment>
+-</rdf:Property>
+-
+-<rdf:Property rdf:about="&xesam;eventEnd">
+-	<rdfs:label>xesam:eventEnd</rdfs:label>
+-	<rdfs:domain rdf:resource="&xesam;Event"/>
+-	<rdfs:comment>Event end time</rdfs:comment>
+-</rdf:Property>
+-
+-<rdf:Property rdf:about="&xesam;eventLocation">
+-	<rdfs:label>xesam:eventLocation</rdfs:label>
+-	<rdfs:domain rdf:resource="&xesam;Event"/>
+-	<rdfs:comment>Event location</rdfs:comment>
+-</rdf:Property>
+-
+-
+-
+-
+-
+-
+-<rdfs:Class rdf:about="&xesam;Task">
+-	<rdfs:subClassOf rdf:resource="&xesam;PIM"/>
+-	<rdfs:label>xesam:Task</rdfs:label>
+-	<rdfs:comment>Task</rdfs:comment>
+-</rdfs:Class>
+-
+-<rdf:Property rdf:about="&xesam;taskDue">
+-	<rdfs:label>xesam:taskDue</rdfs:label>
+-	<rdfs:domain rdf:resource="&xesam;Task"/>
+-	<rdfs:comment>Task due date/time</rdfs:comment>
+-</rdf:Property>
+-
+-<rdf:Property rdf:about="&xesam;taskCompleted">
+-	<rdfs:label>xesam:taskCompleted</rdfs:label>
+-	<rdfs:domain rdf:resource="&xesam;Task"/>
+-	<rdfs:comment>Is task completed?</rdfs:comment>
+-</rdf:Property>
+-
+-<rdf:Property rdf:about="&xesam;taskPercentComplete">
+-	<rdfs:label>xesam:taskPercentComplete</rdfs:label>
+-	<rdfs:domain rdf:resource="&xesam;Task"/>
+-	<rdfs:comment>Task completeness</rdfs:comment>
+-</rdf:Property>
+-
+-
+-
+-
+-
+-<rdfs:Class rdf:about="&xesam;Journal">
+-	<rdfs:subClassOf rdf:resource="&xesam;PIM"/>
+-	<rdfs:label>xesam:Journal</rdfs:label>
+-	<rdfs:comment>Journal</rdfs:comment>
+-</rdfs:Class>
+-
+-
+-
+-<rdfs:Class rdf:about="&xesam;FreeBusy">
+-	<rdfs:subClassOf rdf:resource="&xesam;PIM"/>
+-	<rdfs:label>xesam:FreeBusy</rdfs:label>
+-	<rdfs:comment>FreeBusy</rdfs:comment>
+-</rdfs:Class>
+ 
+ 
+ 
+@@ -903,6 +654,7 @@
+ 	<rdfs:comment>Document is an arrangement of various atomic data types with text being the primary data type.</rdfs:comment>
+ </rdfs:Class>
+ 
++
+ <rdf:Property rdf:about="&xesam;documentCategory">
+ 	<rdfs:label>xesam:documentCategory</rdfs:label>
+ 	<rdfs:domain rdf:resource="&xesam;Document"/>
+@@ -924,6 +676,11 @@
+ 
+ 
+ 
++<rdfs:Class rdf:about="&xesam;Documentation">
++	<rdfs:subClassOf rdf:resource="&xesam;Document"/>
++	<rdfs:label>xesam:Documentation</rdfs:label>
++	<rdfs:comment>Documentation is a document containing help, manuals, guides.</rdfs:comment>
++</rdfs:Class>
+ 
+ 
+ 
+@@ -1514,36 +1271,12 @@
+ 	<rdfs:comment>Contact</rdfs:comment>
+ </rdfs:Class>
+ 
+-<rdf:Property rdf:about="&xesam;contactName">
+-	<rdfs:label>xesam:contactName</rdfs:label>
+-	<rdfs:domain rdf:resource="&xesam;Contact"/>
+-	<rdfs:comment>Contact name</rdfs:comment>
+-</rdf:Property>
+-
+-<rdf:Property rdf:about="&xesam;contactPhoto">
+-	<rdfs:label>xesam:contactPhoto</rdfs:label>
+-	<rdfs:domain rdf:resource="&xesam;Contact"/>
+-	<rdfs:comment>Contact photo/avatar</rdfs:comment>
+-</rdf:Property>
+-
+ <rdf:Property rdf:about="&xesam;contactNick">
+ 	<rdfs:label>xesam:contactNick</rdfs:label>
+ 	<rdfs:domain rdf:resource="&xesam;Contact"/>
+ 	<rdfs:comment>Contact nick</rdfs:comment>
+ </rdf:Property>
+ 
+-<rdf:Property rdf:about="&xesam;gender">
+-	<rdfs:label>xesam:gender</rdfs:label>
+-	<rdfs:domain rdf:resource="&xesam;Contact"/>
+-	<rdfs:comment>Contact gender</rdfs:comment>
+-</rdf:Property>
+-
+-<rdf:Property rdf:about="&xesam;birthDate">
+-	<rdfs:label>xesam:birthDate</rdfs:label>
+-	<rdfs:domain rdf:resource="&xesam;Contact"/>
+-	<rdfs:comment>Contact birthDate</rdfs:comment>
+-</rdf:Property>
+-
+ <rdf:Property rdf:about="&xesam;interests">
+ 	<rdfs:label>xesam:interests</rdfs:label>
+ 	<rdfs:domain rdf:resource="&xesam;Contact"/>
+@@ -1570,39 +1303,11 @@
+ 	<rdfs:comment>Contact Jabber ID</rdfs:comment>
+ </rdf:Property>
+ 
+-<rdf:Property rdf:about="&xesam;icqContactMedium">
+-	<rdfs:label>xesam:icqContactMedium</rdfs:label>
+-	<rdfs:subPropertyOf rdf:resource="&xesam;imContactMedium"/>
+-	<rdfs:domain rdf:resource="&xesam;Contact"/>
+-	<rdfs:comment>Contact ICQ ID</rdfs:comment>
+-</rdf:Property>
+-
+-<rdf:Property rdf:about="&xesam;aimContactMedium">
+-	<rdfs:label>xesam:aimContactMedium</rdfs:label>
+-	<rdfs:subPropertyOf rdf:resource="&xesam;imContactMedium"/>
+-	<rdfs:domain rdf:resource="&xesam;Contact"/>
+-	<rdfs:comment>Contact AIM ID</rdfs:comment>
+-</rdf:Property>
+-
+-<rdf:Property rdf:about="&xesam;yahooContactMedium">
+-	<rdfs:label>xesam:yahooContactMedium</rdfs:label>
+-	<rdfs:subPropertyOf rdf:resource="&xesam;imContactMedium"/>
+-	<rdfs:domain rdf:resource="&xesam;Contact"/>
+-	<rdfs:comment>Contact Yahoo ID</rdfs:comment>
+-</rdf:Property>
+-
+-<rdf:Property rdf:about="&xesam;msnContactMedium">
+-	<rdfs:label>xesam:msnContactMedium</rdfs:label>
+-	<rdfs:subPropertyOf rdf:resource="&xesam;imContactMedium"/>
+-	<rdfs:domain rdf:resource="&xesam;Contact"/>
+-	<rdfs:comment>Contact MSN ID</rdfs:comment>
+-</rdf:Property>
+-
+-<rdf:Property rdf:about="&xesam;skypeContactMedium">
+-	<rdfs:label>xesam:skypeContactMedium</rdfs:label>
++<rdf:Property rdf:about="&xesam;ircContactMedium">
++	<rdfs:label>xesam:ircContactMedium</rdfs:label>
+ 	<rdfs:subPropertyOf rdf:resource="&xesam;imContactMedium"/>
+ 	<rdfs:domain rdf:resource="&xesam;Contact"/>
+-	<rdfs:comment>Contact Skype ID</rdfs:comment>
++	<rdfs:comment>Contact IRC ID at server</rdfs:comment>
+ </rdf:Property>
+ 
+ <rdf:Property rdf:about="&xesam;postalAddress">
+@@ -1612,20 +1317,6 @@
+ 	<rdfs:comment>Contact postal address</rdfs:comment>
+ </rdf:Property>
+ 
+-<rdf:Property rdf:about="&xesam;homePostalAddress">
+-	<rdfs:label>xesam:homePostalAddress</rdfs:label>
+-	<rdfs:subPropertyOf rdf:resource="&xesam;postalAddress"/>
+-	<rdfs:domain rdf:resource="&xesam;Contact"/>
+-	<rdfs:comment>Contact home address</rdfs:comment>
+-</rdf:Property>
+-
+-<rdf:Property rdf:about="&xesam;workPostalAddress">
+-	<rdfs:label>xesam:workPostalAddress</rdfs:label>
+-	<rdfs:subPropertyOf rdf:resource="&xesam;postalAddress"/>
+-	<rdfs:domain rdf:resource="&xesam;Contact"/>
+-	<rdfs:comment>Contact work address</rdfs:comment>
+-</rdf:Property>
+-
+ <rdf:Property rdf:about="&xesam;mailingPostalAddress">
+ 	<rdfs:label>xesam:mailingPostalAddress</rdfs:label>
+ 	<rdfs:subPropertyOf rdf:resource="&xesam;postalAddress"/>
+@@ -1640,20 +1331,6 @@
+ 	<rdfs:comment>Contact email address</rdfs:comment>
+ </rdf:Property>
+ 
+-<rdf:Property rdf:about="&xesam;workEmailAddress">
+-	<rdfs:label>xesam:workEmailAddress</rdfs:label>
+-	<rdfs:subPropertyOf rdf:resource="&xesam;emailAddress"/>
+-	<rdfs:domain rdf:resource="&xesam;Contact"/>
+-	<rdfs:comment>Contact work email address</rdfs:comment>
+-</rdf:Property>
+-
+-<rdf:Property rdf:about="&xesam;homeEmailAddress">
+-	<rdfs:label>xesam:homeEmailAddress</rdfs:label>
+-	<rdfs:subPropertyOf rdf:resource="&xesam;emailAddress"/>
+-	<rdfs:domain rdf:resource="&xesam;Contact"/>
+-	<rdfs:comment>Contact home email address</rdfs:comment>
+-</rdf:Property>
+-
+ <rdf:Property rdf:about="&xesam;contactURL">
+ 	<rdfs:label>xesam:contactURL</rdfs:label>
+ 	<rdfs:subPropertyOf rdf:resource="&xesam;contactMedium"/>
+@@ -1682,37 +1359,110 @@
+ 	<rdfs:comment>Contact phone number</rdfs:comment>
+ </rdf:Property>
+ 
+-<rdf:Property rdf:about="&xesam;homePhoneNumber">
+-	<rdfs:label>xesam:homePhoneNumber</rdfs:label>
++<rdf:Property rdf:about="&xesam;cellPhoneNumber">
++	<rdfs:label>xesam:cellPhoneNumber</rdfs:label>
+ 	<rdfs:subPropertyOf rdf:resource="&xesam;phoneNumber"/>
+ 	<rdfs:domain rdf:resource="&xesam;Contact"/>
+-	<rdfs:comment>Contact home phone number</rdfs:comment>
++	<rdfs:comment>Contact cell phone number</rdfs:comment>
+ </rdf:Property>
+ 
+-<rdf:Property rdf:about="&xesam;cellPhoneNumber">
+-	<rdfs:label>xesam:cellPhoneNumber</rdfs:label>
++<rdf:Property rdf:about="&xesam;faxPhoneNumber">
++	<rdfs:label>xesam:faxPhoneNumber</rdfs:label>
+ 	<rdfs:subPropertyOf rdf:resource="&xesam;phoneNumber"/>
+ 	<rdfs:domain rdf:resource="&xesam;Contact"/>
+-	<rdfs:comment>Contact cell phone number</rdfs:comment>
++	<rdfs:comment>Contact fax phone number</rdfs:comment>
++</rdf:Property>
++
++<rdf:Property rdf:about="&xesam;knows">
++	<rdfs:label>xesam:knows</rdfs:label>
++	<rdfs:subPropertyOf rdf:resource="&xesam;related"/>
++	<rdfs:domain rdf:resource="&xesam;Contact"/>
++	<rdfs:comment>FOAF:knows relation</rdfs:comment>
++</rdf:Property>
++
++
++
++
++
++
++<rdfs:Class rdf:about="&xesam;Person">
++	<rdfs:subClassOf rdf:resource="&xesam;Contact"/>
++	<rdfs:label>xesam:Person</rdfs:label>
++	<rdfs:comment>Person</rdfs:comment>
++</rdfs:Class>
++
++<rdf:Property rdf:about="&xesam;personPhoto">
++	<rdfs:label>xesam:personPhoto</rdfs:label>
++	<rdfs:domain rdf:resource="&xesam;Person"/>
++	<rdfs:comment>Contact photo/avatar</rdfs:comment>
++</rdf:Property>
++
++<rdf:Property rdf:about="&xesam;gender">
++	<rdfs:label>xesam:gender</rdfs:label>
++	<rdfs:domain rdf:resource="&xesam;Person"/>
++	<rdfs:comment>Contact gender</rdfs:comment>
++</rdf:Property>
++
++<rdf:Property rdf:about="&xesam;birthDate">
++	<rdfs:label>xesam:birthDate</rdfs:label>
++	<rdfs:domain rdf:resource="&xesam;Person"/>
++	<rdfs:comment>Contact birthDate</rdfs:comment>
++</rdf:Property>
++
++<rdf:Property rdf:about="&xesam;homePostalAddress">
++	<rdfs:label>xesam:homePostalAddress</rdfs:label>
++	<rdfs:subPropertyOf rdf:resource="&xesam;postalAddress"/>
++	<rdfs:domain rdf:resource="&xesam;Person"/>
++	<rdfs:comment>Contact home address</rdfs:comment>
++</rdf:Property>
++
++<rdf:Property rdf:about="&xesam;workPostalAddress">
++	<rdfs:label>xesam:workPostalAddress</rdfs:label>
++	<rdfs:subPropertyOf rdf:resource="&xesam;postalAddress"/>
++	<rdfs:domain rdf:resource="&xesam;Person"/>
++	<rdfs:comment>Contact work address</rdfs:comment>
++</rdf:Property>
++
++<rdf:Property rdf:about="&xesam;workEmailAddress">
++	<rdfs:label>xesam:workEmailAddress</rdfs:label>
++	<rdfs:subPropertyOf rdf:resource="&xesam;emailAddress"/>
++	<rdfs:domain rdf:resource="&xesam;Person"/>
++	<rdfs:comment>Contact work email address</rdfs:comment>
++</rdf:Property>
++
++<rdf:Property rdf:about="&xesam;homeEmailAddress">
++	<rdfs:label>xesam:homeEmailAddress</rdfs:label>
++	<rdfs:subPropertyOf rdf:resource="&xesam;emailAddress"/>
++	<rdfs:domain rdf:resource="&xesam;Person"/>
++	<rdfs:comment>Contact home email address</rdfs:comment>
++</rdf:Property>
++
++<rdf:Property rdf:about="&xesam;homePhoneNumber">
++	<rdfs:label>xesam:homePhoneNumber</rdfs:label>
++	<rdfs:subPropertyOf rdf:resource="&xesam;phoneNumber"/>
++	<rdfs:domain rdf:resource="&xesam;Person"/>
++	<rdfs:comment>Contact home phone number</rdfs:comment>
+ </rdf:Property>
+ 
+ <rdf:Property rdf:about="&xesam;workPhoneNumber">
+ 	<rdfs:label>xesam:workPhoneNumber</rdfs:label>
+ 	<rdfs:subPropertyOf rdf:resource="&xesam;phoneNumber"/>
+-	<rdfs:domain rdf:resource="&xesam;Contact"/>
++	<rdfs:domain rdf:resource="&xesam;Person"/>
+ 	<rdfs:comment>Contact work phone number</rdfs:comment>
+ </rdf:Property>
+ 
+-<rdf:Property rdf:about="&xesam;faxPhoneNumber">
+-	<rdfs:label>xesam:faxPhoneNumber</rdfs:label>
+-	<rdfs:subPropertyOf rdf:resource="&xesam;phoneNumber"/>
+-	<rdfs:domain rdf:resource="&xesam;Contact"/>
+-	<rdfs:comment>Contact fax phone number</rdfs:comment>
+-</rdf:Property>
+ 
+ 
+ 
+ 
++<rdfs:Class rdf:about="&xesam;Organization">
++	<rdfs:subClassOf rdf:resource="&xesam;Contact"/>
++	<rdfs:label>xesam:Organization</rdfs:label>
++	<rdfs:comment>Organization</rdfs:comment>
++</rdfs:Class>
++
++
++
+ 
+ 
+ 
+@@ -1800,7 +1550,7 @@
+ <rdf:Property rdf:about="&xesam;storageSize">
+ 	<rdfs:label>xesam:storageSize</rdfs:label>
+ 	<rdfs:domain rdf:resource="&xesam;Source"/>
+-	<rdfs:comment>Space occupied by the object in the source storage</rdfs:comment>
++	<rdfs:comment>Actual space occupied by the object in the source storage. e.g. compressed file size in archive</rdfs:comment>
+ </rdf:Property>
+ 
+ <rdf:Property rdf:about="&xesam;sourceCreated">
+@@ -1819,20 +1569,20 @@
+ 	<rdfs:label>xesam:userComment</rdfs:label>
+ 	<rdfs:subPropertyOf rdf:resource="&xesam;comment"/>
+ 	<rdfs:domain rdf:resource="&xesam;Source"/>
+-	<rdfs:comment>User comment</rdfs:comment>
++	<rdfs:comment>User-provided comment</rdfs:comment>
+ </rdf:Property>
+ 
+ <rdf:Property rdf:about="&xesam;userKeyword">
+ 	<rdfs:label>xesam:userKeyword</rdfs:label>
+ 	<rdfs:subPropertyOf rdf:resource="&xesam;keyword"/>
+ 	<rdfs:domain rdf:resource="&xesam;Source"/>
+-	<rdfs:comment>User keywords</rdfs:comment>
++	<rdfs:comment>User-provided keywords</rdfs:comment>
+ </rdf:Property>
+ 
+ <rdf:Property rdf:about="&xesam;userRating">
+ 	<rdfs:label>xesam:userRating</rdfs:label>
+ 	<rdfs:domain rdf:resource="&xesam;Source"/>
+-	<rdfs:comment>User rating of the object</rdfs:comment>
++	<rdfs:comment>User-provided rating of the object</rdfs:comment>
+ </rdf:Property>
+ 
+ <rdf:Property rdf:about="&xesam;autoRating">
+@@ -1881,7 +1631,7 @@
+ <rdfs:Class rdf:about="&xesam;OfflineMedia">
+ 	<rdfs:subClassOf rdf:resource="&xesam;Source"/>
+ 	<rdfs:label>xesam:OfflineMedia</rdfs:label>
+-	<rdfs:comment>Generic offline media. e.g. USB drive that is not attached at this momeny.</rdfs:comment>
++	<rdfs:comment>Generic offline media. e.g. USB drive not attached at this moment.</rdfs:comment>
+ </rdfs:Class>
+ 
+ <rdf:Property rdf:about="&xesam;seenAttachedAs">
+@@ -1994,6 +1744,12 @@
+ 	<rdfs:comment>File permissions</rdfs:comment>
+ </rdf:Property>
+ 
++<rdf:Property rdf:about="&xesam;acl">
++	<rdfs:label>xesam:acl</rdfs:label>
++	<rdfs:domain rdf:resource="&xesam;Filelike"/>
++	<rdfs:comment>File access control list</rdfs:comment>
++</rdf:Property>
++
+ <rdf:Property rdf:about="&xesam;owner">
+ 	<rdfs:label>xesam:owner</rdfs:label>
+ 	<rdfs:domain rdf:resource="&xesam;Filelike"/>
+@@ -2018,7 +1774,7 @@
+ <rdfs:Class rdf:about="&xesam;File">
+ 	<rdfs:subClassOf rdf:resource="&xesam;Filelike"/>
+ 	<rdfs:label>xesam:File</rdfs:label>
+-	<rdfs:comment>Regular file</rdfs:comment>
++	<rdfs:comment>Regular file stored in a filesystem</rdfs:comment>
+ </rdfs:Class>
+ 
+ 
+@@ -2116,7 +1872,7 @@
+ <rdfs:Class rdf:about="&xesam;ArchivedFile">
+ 	<rdfs:subClassOf rdf:resource="&xesam;Filelike"/>
+ 	<rdfs:label>xesam:ArchivedFile</rdfs:label>
+-	<rdfs:comment>Generic archived file</rdfs:comment>
++	<rdfs:comment>File stored in an archive</rdfs:comment>
+ </rdfs:Class>
+ 
+ <rdf:Property rdf:about="&xesam;isSourceEncrypted">
+@@ -2149,7 +1905,7 @@
+ <rdfs:Class rdf:about="&xesam;MessageboxMessage">
+ 	<rdfs:subClassOf rdf:resource="&xesam;Source"/>
+ 	<rdfs:label>xesam:MessageboxMessage</rdfs:label>
+-	<rdfs:comment>Generic messagebox message</rdfs:comment>
++	<rdfs:comment>Message stored in a message box</rdfs:comment>
+ </rdfs:Class>
+ 
+ <rdf:Property rdf:about="&xesam;isRead">
+@@ -2161,13 +1917,13 @@
+ <rdf:Property rdf:about="&xesam;isImportant">
+ 	<rdfs:label>xesam:isImportant</rdfs:label>
+ 	<rdfs:domain rdf:resource="&xesam;MessageboxMessage"/>
+-	<rdfs:comment>Is the message important(Kontact tag)</rdfs:comment>
++	<rdfs:comment>Is the message important</rdfs:comment>
+ </rdf:Property>
+ 
+ <rdf:Property rdf:about="&xesam;isInProgress">
+ 	<rdfs:label>xesam:isInProgress</rdfs:label>
+ 	<rdfs:domain rdf:resource="&xesam;MessageboxMessage"/>
+-	<rdfs:comment>Is the message in progress(Kontact tag)</rdfs:comment>
++	<rdfs:comment>Is the message in progress</rdfs:comment>
+ </rdf:Property>
+ 
+ 
+--- a/src/streamanalyzer/fieldpropertiesdb.cpp
++++ b/src/streamanalyzer/fieldpropertiesdb.cpp
+@@ -47,6 +47,7 @@
+ class FieldPropertiesDb::Private {
+ public:
+     map<string, FieldProperties> properties;
++    map<string, FieldProperties> propertiesByAlias;
+     map<string, ClassProperties> classes;
+     static const FieldProperties& emptyField();
+     static const ClassProperties& emptyClass();
+@@ -126,6 +127,18 @@
+         return j->second;
+     }
+ }
++
++const FieldProperties&
++FieldPropertiesDb::propertiesByAlias(const std::string& alias) const {
++    map<std::string, FieldProperties>::const_iterator j
++        = p->propertiesByAlias.find(alias);
++    if (j == p->propertiesByAlias.end()) {
++        return FieldPropertiesDb::Private::emptyField();
++    } else {
++        return j->second;
++    }
++}
++
+ const map<string, FieldProperties>&
+ FieldPropertiesDb::allProperties() const {
+     return p->properties;
+@@ -239,17 +252,35 @@
+     }
+ 
+     copy(pClasses.begin(), pClasses.end(), inserter(classes, classes.end()) );
+-    copy(pProperties.begin(), pProperties.end(),
+-        inserter(properties, properties.end()) );
++
++    // Construct properties and propertiesByAlias lists
++    for (map<string, FieldProperties::Private>::const_iterator prop = pProperties.begin();
++            prop != pProperties.end(); ++prop) {
++        FieldProperties property(prop->second);
++        string alias = prop->second.alias;
++
++        if(alias.size()) {
++            if(propertiesByAlias.find(alias) == propertiesByAlias.end()) {
++                propertiesByAlias[alias] = property;
++            } else {
++                cerr << "Error: alias " << alias << " requested by several properties" << endl;
++            }
++        }
++
++        properties[property.uri()] = property;
++    }
+ 
+     pProperties.clear();
+     pClasses.clear();
+ }
++
++// FIXME (phreedom): should not directly fill properties[]
++//   not all properties from fieldtypes.* are created
+ void
+ FieldPropertiesDb::Private::addEssentialProperties() {
+-    FieldProperties::Private props;
++    FieldProperties::Private props;  
+     props.stored = true;
+-
++/*
+     props.typeuri = FieldRegister::datetimeType;
+     props.uri = FieldRegister::mtimeFieldName;
+     properties[FieldRegister::mtimeFieldName] = props;
+@@ -273,7 +304,7 @@
+ 
+     props.uri = FieldRegister::parentLocationFieldName;
+     props.tokenized = false;
+-    properties[FieldRegister::parentLocationFieldName] = props;
++    properties[FieldRegister::parentLocationFieldName] = props;*/
+ }
+ void
+ FieldPropertiesDb::Private::loadProperties(const string& dir) {
+@@ -473,6 +504,14 @@
+             } else {
+                 currentField.uri.assign(val);
+             }
++        } else if (strcmp(name, "alias") == 0) {
++            warnIfLocale(val.c_str(), currentElementLang);
++            if (currentField.alias.size()) {
++                cerr << "alias is already defined for " << currentField.uri << "."
++                   << endl;
++            } else {
++                currentField.alias.assign(val);
++            }
+         } else if(strcmp(name, "range") == 0) {
+             warnIfLocale(currentField.uri.c_str(), currentElementLang);
+             if (currentField.typeuri.size()) {
+@@ -645,6 +684,12 @@
+     if (p->currentDefinition!=defNone) {
+         if (strcmp((const char *)localname, "Property") == 0) {
+             if (p->currentField.uri.size()) {
++                if(!p->currentField.alias.size()) {
++                    size_t pos;
++                    if( (pos = p->currentField.uri.rfind('#')) != string::npos) {
++                        p->currentField.alias = p->currentField.uri.substr(pos+1);
++                    }
++                }
+                 p->pProperties[p->currentField.uri] = p->currentField;
+                 p->currentField.clear();
+             }
+@@ -708,6 +753,7 @@
+ FieldProperties::Private::clear() {
+     uri.clear();
+     name.clear();
++    alias.clear();
+     description.clear();
+     localized.clear();
+     locales.clear();
+--- a/src/streamanalyzer/fieldpropertiesdb.h
++++ b/src/streamanalyzer/fieldpropertiesdb.h
+@@ -48,6 +48,7 @@
+     ~FieldPropertiesDb();
+ 
+     const FieldProperties& properties(const std::string& uri) const;
++    const FieldProperties& propertiesByAlias(const std::string& alias) const;
+     const std::map<std::string, FieldProperties>& allProperties() const;
+ 
+     const ClassProperties& classes(const std::string& uri) const;
+--- a/src/streamanalyzer/fieldproperties_private.h
++++ b/src/streamanalyzer/fieldproperties_private.h
+@@ -38,6 +38,7 @@
+ public:
+     std::string uri;
+     std::string name;
++    std::string alias;
+     std::string typeuri;
+     std::string description;
+     std::map<std::string,FieldProperties::Localized> localized;
+--- a/src/streamanalyzer/fieldtypes.cpp
++++ b/src/streamanalyzer/fieldtypes.cpp
+@@ -57,8 +57,9 @@
+ const string FieldRegister::embeddepthFieldName = "http://strigi.sf.net/ontologies/0.9#depth";
+ const string FieldRegister::mtimeFieldName = "http://freedesktop.org/standards/xesam/1.0/core#sourceModified";
+ const string FieldRegister::sizeFieldName = "http://freedesktop.org/standards/xesam/1.0/core#size";
++const string FieldRegister::typeFieldName = "http://www.w3.org/1999/02/22-rdf-syntax-ns#type";
+ 
+-const string FieldRegister::defaultNamespace = "strigi.";
++const string FieldRegister::defaultNamespace = "http://strigi.sf.net/ontologies/0.9#";
+ 
+ FieldRegister::FieldRegister() {
+     pathField = registerField(pathFieldName);
+@@ -70,6 +71,7 @@
+     embeddepthField = registerField(embeddepthFieldName);//, integerType, 1, 0);
+     mtimeField = registerField(mtimeFieldName);//, integerType, 1, 0);
+     sizeField = registerField(sizeFieldName);//, integerType, 1, 0);
++    typeField = registerField(typeFieldName);
+ }
+ 
+ FieldRegister::~FieldRegister() {
+--- a/src/streamanalyzer/fieldtypes.h
++++ b/src/streamanalyzer/fieldtypes.h
+@@ -231,6 +231,8 @@
+     static const std::string mtimeFieldName;
+     /** The name of a field for storing the size of a file */
+     static const std::string sizeFieldName;
++    /** The name of a field for storing rdf:type of the file/data */
++    static const std::string typeFieldName;
+ 
+     /** Default namespace for fields */
+     static const std::string defaultNamespace;
+@@ -254,6 +256,9 @@
+     const RegisteredField* mtimeField;
+     /** A field for storing the size of a file */
+     const RegisteredField* sizeField;
++    /** A field for storing rdf:type of the file/data */
++    const RegisteredField* typeField;
++
+ };
+ 
+ }
+--- a/src/streamanalyzer/filelister.cpp
++++ b/src/streamanalyzer/filelister.cpp
+@@ -51,7 +51,7 @@
+ {
+     /*!
+     * @param path string containing path to check
+-    * Appends the terminating char to path.
++    * Removes the terminating char to path.
+     * Under Windows that char is '\', '/' under *nix
+     */
+     string fixPath (string path)
+@@ -73,8 +73,8 @@
+ 
+         char separator = '/';
+ 
+-        if (temp[temp.length() - 1 ] != separator)
+-            temp += separator;
++        if (temp[temp.length() - 1 ] == separator)
++            return temp.substr(0, temp.size() - 1);
+ 
+         return temp;
+     }
+--- a/src/streamanalyzer/id3v2throughanalyzer.cpp
++++ b/src/streamanalyzer/id3v2throughanalyzer.cpp
+@@ -32,6 +32,7 @@
+ const string ID3V2ThroughAnalyzerFactory::composerFieldName("http://freedesktop.org/standards/xesam/1.0/core#composer");
+ const string ID3V2ThroughAnalyzerFactory::genreFieldName("http://freedesktop.org/standards/xesam/1.0/core#genre");
+ const string ID3V2ThroughAnalyzerFactory::trackNumberFieldName("http://freedesktop.org/standards/xesam/1.0/core#trackNumber");
++const string ID3V2ThroughAnalyzerFactory::albumTrackCountFieldName("http://freedesktop.org/standards/xesam/1.0/core#albumTrackCount");
+ const string ID3V2ThroughAnalyzerFactory::discNumberFieldName("http://freedesktop.org/standards/xesam/1.0/core#discNumber");
+ 
+ void
+@@ -42,7 +43,10 @@
+     genreField = r.registerField(genreFieldName);
+     composerField = r.registerField(composerFieldName);
+     trackNumberField = r.registerField(trackNumberFieldName);  //FIXME:id3 track numbers can look like this: 1/10
++    albumTrackCountField = r.registerField(albumTrackCountFieldName);
+     discNumberField = r.registerField(discNumberFieldName);  //FIXME:id3 disc numbers can looklike this: 1/2
++
++    typeField = r.typeField;
+ }
+ 
+ void
+@@ -87,12 +91,13 @@
+     // read the entire tag
+     nread = in->read(buf, size, size);
+     in->reset(0);
+-    if (nread != size) {
++    if (nread != size || !indexable) {
+         return in;
+     }
++    indexable->addValue(factory->typeField, "http://freedesktop.org/standards/xesam/1.0/core#Music");
+     const char* p = buf + 10;
+     buf += size;
+-    while (indexable && p < buf && *p) {
++    while (p < buf && *p) {
+         size = readSize((unsigned char*)p+4, async);
+         if (size < 0 || size > (buf-p)-11) {
+             // cerr << "size < 0: " << size << endl;
+--- a/src/streamanalyzer/id3v2throughanalyzer.h
++++ b/src/streamanalyzer/id3v2throughanalyzer.h
+@@ -49,6 +49,7 @@
+     static const std::string composerFieldName;
+     static const std::string genreFieldName;
+     static const std::string trackNumberFieldName;
++    static const std::string albumTrackCountFieldName;
+     static const std::string discNumberFieldName;
+     const Strigi::RegisteredField* titleField;
+     const Strigi::RegisteredField* artistField;
+@@ -56,7 +57,9 @@
+     const Strigi::RegisteredField* composerField;
+     const Strigi::RegisteredField* genreField;
+     const Strigi::RegisteredField* trackNumberField;
++    const Strigi::RegisteredField* albumTrackCountField;
+     const Strigi::RegisteredField* discNumberField;
++    const Strigi::RegisteredField* typeField;
+     const char* name() const {
+         return "ID3V2ThroughAnalyzer";
+     }
+--- a/src/streamanalyzer/lineplugins/CMakeLists.txt
++++ b/src/streamanalyzer/lineplugins/CMakeLists.txt
+@@ -23,3 +23,4 @@
+ ADD_STRIGILA(xpm xpmlineanalyzer.cpp)
+ ADD_STRIGILA(deb deblineanalyzer.cpp)
+ ADD_STRIGILA(cpp cpplineanalyzer.cpp)
++ADD_STRIGILA(txt txtlineanalyzer.cpp)
+\ No newline at end of file
+--- a/src/streamanalyzer/lineplugins/cpplineanalyzer.cpp
++++ b/src/streamanalyzer/lineplugins/cpplineanalyzer.cpp
+@@ -31,11 +31,13 @@
+ CppLineAnalyzerFactory::registerFields(FieldRegister& reg) {
+     includeField = reg.registerField("http://freedesktop.org/standards/xesam/1.0/core#depends");
+     classField = reg.registerField("http://freedesktop.org/standards/xesam/1.0/core#definesClass");
+-    codeLinesField = reg.registerField("source_code.stats.code_line_count");
+-    commentLinesField = reg.registerField("source_code.stats.comment_line_count");
++    codeLinesField = reg.registerField("http://strigi.sf.net/ontologies/0.9#codeLineCount");
++    commentLinesField = reg.registerField("http://strigi.sf.net/ontologies/0.9#commentLineCount");
+     totalLinesField = reg.registerField("http://freedesktop.org/standards/xesam/1.0/core#lineCount");
++    programmingLanguageField = reg.registerField("http://freedesktop.org/standards/xesam/1.0/core#programmingLanguage");
+ // Include count not required. Include list length is easy to obtain.
+ //    includesField = reg.registerField();
++    typeField = reg.typeField;
+ }
+ 
+ // Analyzer
+@@ -96,6 +98,8 @@
+         analysisResult->addValue(factory->codeLinesField, (int32_t)codeLines);
+         analysisResult->addValue(factory->commentLinesField, (int32_t)commentLines);
+         analysisResult->addValue(factory->totalLinesField, (int32_t)totalLines);
++        analysisResult->addValue(factory->programmingLanguageField, "C++");
++        analysisResult->addValue(factory->typeField, "http://freedesktop.org/standards/xesam/1.0/core#SourceCode");
+ //        analysisResult->addValue(factory->includesField, includes);
+     }
+     ready = true;
+--- a/src/streamanalyzer/lineplugins/cpplineanalyzer.h
++++ b/src/streamanalyzer/lineplugins/cpplineanalyzer.h
+@@ -59,6 +59,10 @@
+     const Strigi::RegisteredField* commentLinesField;
+     const Strigi::RegisteredField* totalLinesField;
+     const Strigi::RegisteredField* includesField;
++    const Strigi::RegisteredField* programmingLanguageField;
++
++    const Strigi::RegisteredField* typeField;
++
+     const char* name() const {
+         return "CppLineAnalyzer";
+     }
+--- a/src/streamanalyzer/lineplugins/deblineanalyzer.cpp
++++ b/src/streamanalyzer/lineplugins/deblineanalyzer.cpp
+@@ -45,6 +45,8 @@
+     maintainerField = r.registerField(maintainerFieldName);
+     sectionField = r.registerField(sectionFieldName);
+     dependsField = r.registerField(dependsFieldName);
++
++    typeField = r.typeField;
+ }
+ 
+ void 
+@@ -63,9 +65,10 @@
+     // it is .deb file after all
+     result=res;
+     finished=0;
++    result->addValue(factory->typeField, "http://freedesktop.org/standards/xesam/1.0/core#SoftwarePackage");
+ }
+ void
+-DebLineAnalyzer::endAnalysis(bool /*complete*/) {
++DebLineAnalyzer::endAnalysis(bool complete) {
+ }
+ 
+ void 
+--- a/src/streamanalyzer/lineplugins/deblineanalyzer.h
++++ b/src/streamanalyzer/lineplugins/deblineanalyzer.h
+@@ -53,6 +53,9 @@
+     const Strigi::RegisteredField* maintainerField;
+     const Strigi::RegisteredField* sectionField;
+     const Strigi::RegisteredField* dependsField;
++
++    const Strigi::RegisteredField* typeField;
++
+     const char* name() const {
+         return "DebLineAnalyzer";
+     }
+--- /dev/null
++++ b/src/streamanalyzer/lineplugins/txtlineanalyzer.cpp
+@@ -0,0 +1,114 @@
++/* This file is part of Strigi Desktop Search
++ *
++ * Copyright (C) 2007 Flavio Castelli <flavio.castelli at gmail.com>
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Library General Public
++ * License as published by the Free Software Foundation; either
++ * version 2 of the License, or (at your option) any later version.
++ *
++ * This library 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
++ * Library General Public License for more details.
++ *
++ * You should have received a copy of the GNU Library General Public License
++ * along with this library; see the file COPYING.LIB.  If not, write to
++ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
++ * Boston, MA 02110-1301, USA.
++ */
++
++#include "txtlineanalyzer.h"
++#include <strigi/strigiconfig.h>
++#include "analysisresult.h"
++#include "fieldtypes.h"
++
++using namespace std;
++using namespace Strigi;
++
++// AnalyzerFactory
++void
++TxtLineAnalyzerFactory::registerFields(FieldRegister& reg) {
++    totalLinesField = reg.registerField("http://freedesktop.org/standards/xesam/1.0/core#lineCount");
++    //TODO: check names
++    totalWordsField = reg.registerField("http://freedesktop.org/standards/xesam/1.0/core#wordsCount");
++    totalCharactersField = reg.registerField("http://freedesktop.org/standards/xesam/1.0/core#charactersCount");
++    maxLineLengthField = reg.registerField("http://freedesktop.org/standards/xesam/1.0/core#maxLineLength");
++    formatField = reg.registerField("http://freedesktop.org/standards/xesam/1.0/core#format");
++}
++
++// Analyzer
++void
++TxtLineAnalyzer::startAnalysis(AnalysisResult* i) {
++    analysisResult = i;
++    totalLines = 0;
++    totalWords = 0;
++    totalCharacters = 0;
++    maxLineLength = 0;
++    dos = false;
++    ready = false;
++}
++void
++TxtLineAnalyzer::handleLine(const char* data, uint32_t length) {
++    bool inWord = false;
++
++    totalLines++;
++    totalCharacters += length;
++
++    if (maxLineLength < length)
++        maxLineLength = length;
++
++    // instead of using regexp use this elementary solution
++    for (unsigned int i = 0; i < length; i++) {
++        bool spacer = true;
++        if (isspace(data[i]) == 0)
++            spacer = false;
++
++        if (!spacer && !inWord) {// beginning of a word
++            totalWords++;
++            inWord = true;
++        }
++        //else if (!spacer && inWord) {/*inside word, do nothing*/}
++        else if (spacer && inWord)
++            inWord = false;
++    }
++
++    //TODO: by now it isn't possible to detect mac formatting
++    //endline should be just '\r'. I don't know if it is still true with latest
++    // versions of OSX, I have tried with tiger and I got a standard unix file.
++    if (length > 0 && data[length-1] == '\r')
++        dos = true;
++
++}
++void
++TxtLineAnalyzer::endAnalysis(bool complete) {
++    // we assume all cpp files must have includes
++    if (complete) {
++        analysisResult->addValue(factory->totalWordsField, (int32_t)totalWords);
++        analysisResult->addValue(factory->totalCharactersField, (int32_t)totalCharacters);
++        analysisResult->addValue(factory->totalLinesField, (int32_t)totalLines);
++        analysisResult->addValue(factory->maxLineLengthField, (int32_t)maxLineLength);
++        if (dos)
++            analysisResult->addValue(factory->formatField, "DOS");
++        else
++            analysisResult->addValue(factory->formatField, "UNIX");
++    }
++    ready = true;
++}
++bool
++TxtLineAnalyzer::isReadyWithStream() {
++    return ready;
++}
++
++//Factory
++class Factory : public AnalyzerFactoryFactory {
++public:
++    list<StreamLineAnalyzerFactory*>
++    streamLineAnalyzerFactories() const {
++        list<StreamLineAnalyzerFactory*> af;
++        af.push_back(new TxtLineAnalyzerFactory());
++        return af;
++    }
++};
++
++STRIGI_ANALYZER_FACTORY(Factory)
+--- /dev/null
++++ b/src/streamanalyzer/lineplugins/txtlineanalyzer.h
+@@ -0,0 +1,74 @@
++/* This file is part of Strigi Desktop Search
++ *
++ * Copyright (C) 2007 Flavio Castelli <flavio.castelli at gmail.com>
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Library General Public
++ * License as published by the Free Software Foundation; either
++ * version 2 of the License, or (at your option) any later version.
++ *
++ * This library 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
++ * Library General Public License for more details.
++ *
++ * You should have received a copy of the GNU Library General Public License
++ * along with this library; see the file COPYING.LIB.  If not, write to
++ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
++ * Boston, MA 02110-1301, USA.
++ */
++#ifndef STRIGI_TXTLINEANALYZER
++#define STRIGI_TXTLINEANALYZER
++
++#include "streamlineanalyzer.h"
++#include "analyzerplugin.h"
++
++namespace Strigi {
++    class RegisteredField;
++}
++class TxtLineAnalyzerFactory;
++
++class STRIGI_PLUGIN_API TxtLineAnalyzer
++    : public Strigi::StreamLineAnalyzer {
++private:
++    Strigi::AnalysisResult* analysisResult;
++    const TxtLineAnalyzerFactory* factory;
++    int totalWords;
++    int totalCharacters;
++    int totalLines;
++    uint32_t maxLineLength;
++    bool dos;
++    bool ready;
++public:
++    TxtLineAnalyzer(const TxtLineAnalyzerFactory* f) :factory(f) {}
++    ~TxtLineAnalyzer() {}
++    const char* name() const { return "TxtLineAnalyzer"; }
++    void startAnalysis(Strigi::AnalysisResult*);
++    void handleLine(const char* data, uint32_t length);
++    void endAnalysis(bool complete);
++    bool isReadyWithStream();
++};
++
++class TxtLineAnalyzerFactory
++    : public Strigi::StreamLineAnalyzerFactory {
++friend class TxtLineAnalyzer;
++private:
++    const Strigi::RegisteredField* totalLinesField;
++    const Strigi::RegisteredField* totalCharactersField;
++    const Strigi::RegisteredField* totalWordsField;
++    const Strigi::RegisteredField* maxLineLengthField;
++    const Strigi::RegisteredField* formatField;
++
++    const Strigi::RegisteredField* typeField;
++
++    const char* name() const {
++        return "TxtLineAnalyzer";
++    }
++    Strigi::StreamLineAnalyzer* newInstance() const {
++        return new TxtLineAnalyzer(this);
++    }
++    void registerFields(Strigi::FieldRegister&);
++};
++
++#endif
++
+--- a/src/streamanalyzer/lineplugins/xpmlineanalyzer.cpp
++++ b/src/streamanalyzer/lineplugins/xpmlineanalyzer.cpp
+@@ -33,6 +33,8 @@
+     widthField = reg.registerField("http://freedesktop.org/standards/xesam/1.0/core#width");
+     heightField = reg.registerField("http://freedesktop.org/standards/xesam/1.0/core#height");
+     numberOfColorsField = reg.registerField("http://freedesktop.org/standards/xesam/1.0/core#colorCount");
++
++    typeField = reg.typeField;
+ }
+ 
+ // Analyzer
+@@ -94,6 +96,7 @@
+         return;
+ 
+     analysisResult->addValue(factory->numberOfColorsField, propertyValue);
++    analysisResult->addValue(factory->typeField, "http://freedesktop.org/standards/xesam/1.0/core#Image");
+ }
+ bool
+ XpmLineAnalyzer::isReadyWithStream() {
+--- a/src/streamanalyzer/lineplugins/xpmlineanalyzer.h
++++ b/src/streamanalyzer/lineplugins/xpmlineanalyzer.h
+@@ -52,6 +52,9 @@
+     const Strigi::RegisteredField* widthField;
+     const Strigi::RegisteredField* heightField;
+     const Strigi::RegisteredField* numberOfColorsField;
++
++    const Strigi::RegisteredField* typeField;
++
+     const char* name() const {
+         return "XpmLineAnalyzer";
+     }
+--- a/src/streamanalyzer/m3ustreamanalyzer.cpp
++++ b/src/streamanalyzer/m3ustreamanalyzer.cpp
+@@ -16,7 +16,7 @@
+  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  * Boston, MA 02110-1301, USA.
+  *
+- *  $Id: m3ustreamanalyzer.cpp 717846 2007-09-27 17:16:00Z evgeny $
++ *  $Id: m3ustreamanalyzer.cpp 742095 2007-11-27 05:56:12Z evgeny $
+  */
+ 
+ #include "m3ustreamanalyzer.h"
+@@ -33,6 +33,8 @@
+ //    tracksField = reg.registerField();
+     trackPathField = reg.registerField("http://freedesktop.org/standards/xesam/1.0/core#links");
+     m3uTypeField = reg.registerField("http://freedesktop.org/standards/xesam/1.0/core#formatSubtype");
++    
++    typeField = reg.typeField;
+ }
+ 
+ // Analyzer
+@@ -80,5 +82,8 @@
+     // tracksField has not been initialized, so don't use it
+     //if (complete && extensionOk)
+         //analysisResult->addValue(factory->tracksField, count);
++    if (complete && extensionOk)
++        analysisResult->addValue(factory->typeField, "http://freedesktop.org/standards/xesam/1.0/core#AudioList");
++
+ }
+ 
+--- a/src/streamanalyzer/m3ustreamanalyzer.h
++++ b/src/streamanalyzer/m3ustreamanalyzer.h
+@@ -16,7 +16,7 @@
+  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  * Boston, MA 02110-1301, USA.
+  *
+- *  $Id: m3ustreamanalyzer.h 696786 2007-08-05 22:14:33Z vandenoever $
++ *  $Id: m3ustreamanalyzer.h 742095 2007-11-27 05:56:12Z evgeny $
+  */
+ 
+ #ifndef M3USTREAMANALYZER_H
+@@ -60,6 +60,8 @@
+     const Strigi::RegisteredField* trackPathField; //The paths to the tracks in the playlist
+     const Strigi::RegisteredField* m3uTypeField; //The type of the m3u file, a simple list or an extended list
+ 
++    const Strigi::RegisteredField* typeField;
++
+     const char* name() const {
+         return "M3uLineAnalyzer";
+     }
+--- a/src/streamanalyzer/odfmimetypelineanalyzer.cpp
++++ b/src/streamanalyzer/odfmimetypelineanalyzer.cpp
+@@ -29,7 +29,8 @@
+ using namespace Strigi;
+ 
+ void OdfMimeTypeLineAnalyzerFactory::registerFields(FieldRegister &reg) {
+-    mimeTypeField = reg.registerField("http://freedesktop.org/standards/xesam/1.0/core#mimeType");
++    mimeTypeField = reg.mimetypeField;
++    typeField = reg.typeField;
+ }
+ 
+ Strigi::StreamLineAnalyzer *OdfMimeTypeLineAnalyzerFactory::newInstance() const {
+@@ -67,6 +68,37 @@
+         m_ready = true;
+         return;
+     }
++/*
++application/vnd.oasis.opendocument.text  odt
++application/vnd.oasis.opendocument.text-template  ott
++application/vnd.oasis.opendocument.text-master  odm
++application/vnd.oasis.opendocument.text-web  oth
++application/vnd.oasis.opendocument.graphics  odg
++application/vnd.oasis.opendocument.graphics-template  otg
++application/vnd.oasis.opendocument.presentation  odp
++application/vnd.oasis.opendocument.presentation-template  otp
++application/vnd.oasis.opendocument.spreadsheet  ods
++application/vnd.oasis.opendocument.spreadsheet-template  ots
++application/vnd.oasis.opendocument.chart  odc
++application/vnd.oasis.opendocument.chart-template  otc
++application/vnd.oasis.opendocument.image  odi
++application/vnd.oasis.opendocument.image-template  oti
++application/vnd.oasis.opendocument.formula  odf
++application/vnd.oasis.opendocument.formula-template  otf
++*/
++
++    char *rdftype = NULL;
++    if( length >= (35+4) && std::strncmp(data+35, "text", 4) == 0 ) {
++        rdftype = "http://freedesktop.org/standards/xesam/1.0/core#TextDocument";
++    } else if ( length >= (35+12) && std::strncmp(data+35, "presentation", 12) == 0 ) {
++        rdftype = "http://freedesktop.org/standards/xesam/1.0/core#Presentation";
++    } else if ( length >= (35+11) && std::strncmp(data+35, "spreadsheet", 11) == 0 ) {
++        rdftype = "http://freedesktop.org/standards/xesam/1.0/core#Spreadsheet";
++    }
++
++    if(rdftype) {
++        m_result->addValue(m_factory->typeField, rdftype);
++    }
+ 
+     std::string mimeType;
+     mimeType.assign(data, length);
+--- a/src/streamanalyzer/odfmimetypelineanalyzer.h
++++ b/src/streamanalyzer/odfmimetypelineanalyzer.h
+@@ -27,6 +27,7 @@
+ class OdfMimeTypeLineAnalyzerFactory : public Strigi::StreamLineAnalyzerFactory {
+ public:
+     const Strigi::RegisteredField *mimeTypeField;
++    const Strigi::RegisteredField *typeField;
+ 
+     const char *name() const {
+         return "OdfMimeTypeLineAnalyzer";
+--- a/src/streamanalyzer/oggthroughanalyzer.cpp
++++ b/src/streamanalyzer/oggthroughanalyzer.cpp
+@@ -37,8 +37,20 @@
+     fields["genre"] = r.registerField("http://freedesktop.org/standards/xesam/1.0/core#genre");
+     fields["codec"] = r.registerField("http://freedesktop.org/standards/xesam/1.0/core#audioCodec");
+     fields["composer"] = r.registerField("http://freedesktop.org/standards/xesam/1.0/core#composer");
++    fields["performer"] = r.registerField("http://freedesktop.org/standards/xesam/1.0/core#performer");
+     fields["date"] = r.registerField("http://freedesktop.org/standards/xesam/1.0/core#contentCreated");
+     fields["description"] = r.registerField("http://freedesktop.org/standards/xesam/1.0/core#description");
++    fields["tracknumber"] = r.registerField("http://freedesktop.org/standards/xesam/1.0/core#trackNumber");
++
++
++    fields["version"] = r.registerField("http://freedesktop.org/standards/xesam/1.0/core#version");
++    fields["isrc"] = r.registerField("http://freedesktop.org/standards/xesam/1.0/core#isrc");
++    fields["copyright"] = r.registerField("http://freedesktop.org/standards/xesam/1.0/core#copyright");
++    fields["license"] = r.registerField("http://freedesktop.org/standards/xesam/1.0/core#license");
++
++// ogg spec fields left unimplemented: ORGANIZATION, LOCATION, CONTACT
++
++    fields["type"] = r.typeField;
+ }
+ 
+ void
+@@ -129,6 +141,8 @@
+     }
+     // set the "codec" value
+     indexable->addValue(factory->fields.find("codec")->second, "Ogg/Vorbis");
++    indexable->addValue(factory->fields.find("type")->second,
++            "http://freedesktop.org/standards/xesam/1.0/core#Music");
+     return in;
+ }
+ bool
+--- a/src/streamanalyzer/queryparser.cpp
++++ b/src/streamanalyzer/queryparser.cpp
+@@ -18,6 +18,7 @@
+  * Boston, MA 02110-1301, USA.
+  */
+ #include "queryparser.h"
++#include "fieldpropertiesdb.h"
+ #include <iostream>
+ #include <cstring>
+ using namespace std;
+@@ -125,8 +126,9 @@
+     // prepend the field names with the xesam namespace
+     // this will be elaborated once the xesam spec continues
+     vector<string>::iterator end(query.fields().end());
++    FieldPropertiesDb& db = FieldPropertiesDb::db();
+     for (vector<string>::iterator i = query.fields().begin(); i != end; ++i) {
+-        *i = "http://freedesktop.org/standards/xesam/1.0/core#" + *i;
++        *i = db.propertiesByAlias(*i).uri();
+     }
+     std::vector<Query>::iterator qend(query.subQueries().end());
+     for (vector<Query>::iterator i = query.subQueries().begin(); i!=qend; ++i) {
+--- a/src/streamanalyzer/throughplugins/authroughanalyzer.cpp
++++ b/src/streamanalyzer/throughplugins/authroughanalyzer.cpp
+@@ -31,14 +31,18 @@
+ const string AuThroughAnalyzerFactory::lengthFieldName("http://freedesktop.org/standards/xesam/1.0/core#mediaDuration");
+ const string AuThroughAnalyzerFactory::sampleRateFieldName("http://freedesktop.org/standards/xesam/1.0/core#audioSampleRate");
+ const string AuThroughAnalyzerFactory::channelsFieldName("http://freedesktop.org/standards/xesam/1.0/core#audioChannels");
+-const string AuThroughAnalyzerFactory::encodingFieldName("media.sample_format");
++const string AuThroughAnalyzerFactory::sampleBitDepthFieldName("http://freedesktop.org/standards/xesam/1.0/core#audioSampleBitDepth");
++const string AuThroughAnalyzerFactory::sampleDataTypeFieldName("http://freedesktop.org/standards/xesam/1.0/core#audioSampleDataType");
+ 
+ void
+ AuThroughAnalyzerFactory::registerFields(FieldRegister& reg) {
+     lengthField = reg.registerField(lengthFieldName);
+     sampleRateField = reg.registerField(sampleRateFieldName);
+     channelsField = reg.registerField(channelsFieldName);
+-    encodingField = reg.registerField(encodingFieldName);
++    sampleBitDepthField = reg.registerField(sampleBitDepthFieldName);
++    sampleDataTypeField = reg.registerField(sampleDataTypeFieldName);
++
++    typeField = reg.typeField;
+ }
+ 
+ // Analyzer
+@@ -82,48 +86,52 @@
+     uint16_t bytesPerSample = 0;
+     switch (encoding) {
+     case 1 :
+-        analysisResult->addValue(factory->encodingField, "8-bit ISDN u-law");
++        analysisResult->addValue(factory->sampleDataTypeField, "ISDN u-law");
+         bytesPerSample = 1;
+         break;
+     case 2 :
+-        analysisResult->addValue(factory->encodingField, "8-bit linear PCM [REF-PCM]");
++        analysisResult->addValue(factory->sampleDataTypeField, "linear PCM [REF-PCM]");
+         bytesPerSample = 1;
+         break;
+     case 3 :
+-        analysisResult->addValue(factory->encodingField, "16-bit linear PCM");
++        analysisResult->addValue(factory->sampleDataTypeField, "linear PCM");
+         bytesPerSample = 2;
+         break;
+     case 4 :
+-        analysisResult->addValue(factory->encodingField, "24-bit linear PCM");
++        analysisResult->addValue(factory->sampleDataTypeField, "linear PCM");
+         bytesPerSample = 3;
+         break;
+     case 5 :
+-        analysisResult->addValue(factory->encodingField, "32-bit linear PCM");
++        analysisResult->addValue(factory->sampleDataTypeField, "linear PCM");
+         bytesPerSample = 4;
+         break;
+     case 6 :
+-        analysisResult->addValue(factory->encodingField, "32-bit IEEE floating point");
++        analysisResult->addValue(factory->sampleDataTypeField, "IEEE floating point");
+         bytesPerSample = 4;
+         break;
+     case 7 :
+-        analysisResult->addValue(factory->encodingField, "64-bit IEEE floating point");
++        analysisResult->addValue(factory->sampleDataTypeField, "IEEE floating point");
+         bytesPerSample = 8;
+         break;
+     case 23 :
+-        analysisResult->addValue(factory->encodingField, "8-bit ISDN u-law compressed");
++        analysisResult->addValue(factory->sampleDataTypeField, "ISDN u-law compressed");
+         bytesPerSample = 1;
+         break;
+     default :
+-        analysisResult->addValue(factory->encodingField, "Unknown");
++        analysisResult->addValue(factory->sampleDataTypeField, "Unknown");
+         bytesPerSample = 0;
+     }
+-
++    if(bytesPerSample) {
++        analysisResult->addValue(factory->sampleBitDepthField, bytesPerSample*8);
++    }
+     // work out length from bytespersample + channels + size
+     if ((0 < channels) && (0 < dataSize) && (dataSize != 0xFFFFFFFF) && (0 < bytesPerSample) && (0 < sampleRate)) {
+         uint32_t length = dataSize / channels / bytesPerSample / sampleRate;
+         analysisResult->addValue(factory->lengthField, length);
+     }
+ 
++    analysisResult->addValue(factory->typeField, "http://freedesktop.org/standards/xesam/1.0/core#Music");
++
+     return in;
+ }
+ 
+--- a/src/streamanalyzer/throughplugins/authroughanalyzer.h
++++ b/src/streamanalyzer/throughplugins/authroughanalyzer.h
+@@ -51,11 +51,17 @@
+     static const std::string lengthFieldName;
+     static const std::string sampleRateFieldName;
+     static const std::string channelsFieldName;
+-    static const std::string encodingFieldName;
++    static const std::string sampleBitDepthFieldName;
++    static const std::string sampleDataTypeFieldName;
++
+     const Strigi::RegisteredField* lengthField;
+     const Strigi::RegisteredField* sampleRateField;
+     const Strigi::RegisteredField* channelsField;
+-    const Strigi::RegisteredField* encodingField;
++    const Strigi::RegisteredField* sampleBitDepthField;
++    const Strigi::RegisteredField* sampleDataTypeField;
++
++    const Strigi::RegisteredField* typeField;
++
+     const char* name() const {
+         return "AuThroughAnalyzer";
+     }
+--- /dev/null
++++ b/src/streamanalyzer/throughplugins/avithroughanalyzer.cpp
+@@ -0,0 +1,553 @@
++/* This file is part of Strigi Desktop Search, ported from code of:
++ * - Shane Wright <me at shanewright.co.uk> (Copyright (C) 2002)
++ *
++ * Copyright (C) 2007 Flavio Castelli <flavio.castelli at gmail.com>
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Library General Public
++ * License as published by the Free Software Foundation; either
++ * version 2 of the License, or (at your option) any later version.
++ *
++ * This library 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
++ * Library General Public License for more details.
++ *
++ * You should have received a copy of the GNU Library General Public License
++ * along with this library; see the file COPYING.LIB.  If not, write to
++ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
++ * Boston, MA 02110-1301, USA.
++ */
++
++#include "avithroughanalyzer.h"
++#include "textutils.h"
++#include <strigi/strigiconfig.h>
++#include "analysisresult.h"
++#include "fieldtypes.h"
++#include <cstring>
++
++using namespace std;
++using namespace Strigi;
++
++// AnalyzerFactory
++
++//TODO: check values!
++const string AviThroughAnalyzerFactory::lengthFieldName( "http://freedesktop.org/standards/xesam/1.0/core#video.length" );
++const string AviThroughAnalyzerFactory::resolutionHeightFieldName( "http://freedesktop.org/standards/xesam/1.0/core#video.resolutionHeight" );
++const string AviThroughAnalyzerFactory::resolutionWidthFieldName( "http://freedesktop.org/standards/xesam/1.0/core#video.resolutionWidth" );
++const string AviThroughAnalyzerFactory::frameRateFieldName( "http://freedesktop.org/standards/xesam/1.0/core#video.framerate" );
++const string AviThroughAnalyzerFactory::videoCodecFieldName( "http://freedesktop.org/standards/xesam/1.0/core#video.videocodec" );
++const string AviThroughAnalyzerFactory::audioCodecFieldName( "http://freedesktop.org/standards/xesam/1.0/core#video.audiocodec" );
++
++void
++AviThroughAnalyzerFactory::registerFields(FieldRegister& reg) {
++    lengthField = reg.registerField(lengthFieldName);
++    resolutionHeightField = reg.registerField(resolutionHeightFieldName);
++    resolutionWidthField = reg.registerField(resolutionWidthFieldName);
++    frameRateField = reg.registerField(frameRateFieldName);
++    videoCodecField = reg.registerField(videoCodecFieldName);
++    audioCodecField = reg.registerField(audioCodecFieldName);
++}
++
++// Analyzer
++void
++AviThroughAnalyzer::setIndexable(AnalysisResult* i) {
++    analysisResult = i;
++}
++
++bool
++AviThroughAnalyzer::read_avi(InputStream* in)
++{
++    static const char sig_riff[] = "RIFF";
++    static const char sig_avi[]  = "AVI ";
++    static const char sig_list[] = "LIST";
++    static const char sig_junk[] = "JUNK";
++    uint32_t charbuf1;
++    uint32_t dwbuf1;
++    const char* c;
++
++    done_avih = false;
++    done_audio = false;
++
++    // read AVI header
++    // this must be RIFF
++    if (4 != in->read ( c, 4, 4))
++        return false;
++    charbuf1 = readLittleEndianUInt32(c);
++    if (memcmp(&charbuf1, sig_riff, 4) != 0)
++        return false;
++
++    if (4 != in->read ( c, 4, 4))
++        return false;
++    dwbuf1 = readLittleEndianUInt32(c);
++
++    // this must be AVI
++    if (4 != in->read ( c, 4, 4))
++        return false;
++    charbuf1 = readLittleEndianUInt32(c);
++    if (memcmp(&charbuf1, sig_avi, 4) != 0)
++        return false;
++
++    // start reading AVI file
++    int counter = 0;
++    bool done = false;
++    do {
++        //printf ("read_avi, in position: %i\n", in->position());
++        // read header
++        if (4 != in->read ( c, 4, 4))
++            return false;
++        charbuf1 = readLittleEndianUInt32(c);
++
++        //printf ("about to handle chunk with ID: %i\n", charbuf1);
++
++        if (memcmp(&charbuf1, sig_list, 4) == 0) {
++            // if list
++            if (!read_list(in))
++                return false;
++        }
++        else if (memcmp(&charbuf1, sig_junk, 4) == 0) {
++            // if junk
++
++            // read chunk size
++            if (4 != in->read ( c, 4, 4))
++                return false;
++            dwbuf1 = readLittleEndianUInt32(c);
++
++            //printf ("Skipping junk chunk length: %i\n", dwbuf1);
++
++            // skip junk
++
++            //TODO: why reset doesn't work?! we've to use skip
++            //in->reset( in->position() + dwbuf1);
++            in->skip (dwbuf1);
++            //printf ("After skip: %i\n", in->position());
++        }
++        else {
++            // something we don't understand yet
++            //printf ("Unknown chunk header found: %i", charbuf1);
++            return false;
++        }
++
++        uint64_t curr = in->position();
++        bool atEnd = false;
++        if (1 != in->read( c, 1, 1))
++            atEnd = true;
++        in->reset ( curr);
++        
++        if (((done_avih) && (strlen(handler_vids) > 0)
++              && (done_audio)) || atEnd) {
++            //printf ("We're done!\n");
++            done = true;
++        }
++
++        // make sure we don't stay here forever
++        ++counter;
++        if (counter > 10)
++            done = true;
++
++    } while (!done);
++
++    return true;
++}
++
++bool
++AviThroughAnalyzer::read_list(InputStream* in)
++{
++    //printf ("read_list, in position: %i\n", in->position());
++    const char sig_hdrl[] = "hdrl";   // header list
++    const char sig_strl[] = "strl";   // ...list
++    const char sig_movi[] = "movi";   // movie list
++
++    const char* c;
++    uint32_t dwbuf1;
++    uint32_t charbuf1;
++
++    //printf ("In read_list()\n");
++
++    // read size & list type
++    if (8 != in->read ( c, 8, 8))
++        return false;
++    dwbuf1 = readLittleEndianUInt32(c);
++    charbuf1 = readLittleEndianUInt32(c+4);
++
++    // read the relevant bits of the list
++    if (memcmp(&charbuf1, sig_hdrl, 4) == 0) {
++        // should be the main AVI header
++        if (!read_avih(in))
++            return false;
++    } else if (memcmp(&charbuf1, sig_strl, 4) == 0) {
++        // should be some stream info
++        if (!read_strl(in))
++            return false;
++    } else if (memcmp(&charbuf1, sig_movi, 4) == 0) {
++        // movie list
++        //printf ("Skipping movi chunk length: %i\n", dwbuf1);
++
++        // skip past it
++        in->reset (in->position() + dwbuf1);
++    } else {
++        // unknown list type
++        //printf ("Unknown list type found: %i\n", charbuf1);
++    }
++
++    return true;
++}
++
++bool
++AviThroughAnalyzer::read_avih(InputStream* in)
++{
++    //printf ("read_avih, in position: %i\n", in->position());
++    static const char sig_avih[] = "avih";   // header list
++
++    uint32_t dwbuf1;
++    uint32_t charbuf1;
++    const char* c;
++
++    // read header and length
++    if (8 != in->read ( c, 8, 8))
++        return false;
++    charbuf1 = readLittleEndianUInt32(c);
++    dwbuf1 = readLittleEndianUInt32(c+4);
++
++    // not a valid avih?
++    if (memcmp(&charbuf1, sig_avih, 4) != 0) {
++        //printf ("Chunk ID error, expected avih, got: %i\n", charbuf1);
++        return false;
++    }
++
++    // read all the avih fields
++    if (56 != in->read ( c, 56, 56))
++        return false;
++
++    avih_microsecperframe = readLittleEndianUInt32(c);
++    avih_maxbytespersec  = readLittleEndianUInt32(c+4);
++    avih_reserved1 = readLittleEndianUInt32(c+8);
++    avih_flags = readLittleEndianUInt32(c+12);
++    avih_totalframes = readLittleEndianUInt32(c+16);
++    avih_initialframes = readLittleEndianUInt32(c+20);
++    avih_streams = readLittleEndianUInt32(c+24);
++    avih_buffersize = readLittleEndianUInt32(c+28);
++    avih_width = readLittleEndianUInt32(c+32);
++    avih_height = readLittleEndianUInt32(c+36);
++    avih_scale = readLittleEndianUInt32(c+40);
++    avih_rate = readLittleEndianUInt32(c+44);
++    avih_start = readLittleEndianUInt32(c+48);
++    avih_length = readLittleEndianUInt32(c+52);
++
++    done_avih = true;
++
++    return true;
++}
++
++bool
++AviThroughAnalyzer::read_strl(InputStream* in)
++{
++    static const char sig_strh[] = "strh";
++    static const char sig_strf[] = "strf";
++        //static const char sig_strd[] = "strd";
++    static const char sig_strn[] = "strn";
++    static const char sig_list[] = "LIST";
++    static const char sig_junk[] = "JUNK";
++
++    //printf ("in strl handler\n");
++
++    uint32_t dwbuf1;    // buffer for block sizes
++    uint32_t charbuf1;
++    const char* c;
++
++        // loop through blocks
++    int counter = 0;
++    while (true) {
++        //printf ("read_strl, while start in position: %i\n", in->position());
++        // read type and size
++        if (8 != in->read ( c, 8, 8))
++            return false;
++        charbuf1 = readLittleEndianUInt32(c); // type
++        dwbuf1 = readLittleEndianUInt32(c+4); // size
++        //printf ("read_strl, dwbuf1 while initial value = %i\n",dwbuf1);
++
++        // detect type
++        if (memcmp(&charbuf1, sig_strh, 4) == 0) {
++            // got strh - stream header
++            //printf ("Found strh, calling read_strh()\n");
++            read_strh(in, dwbuf1);
++        }
++        else if (memcmp(&charbuf1, sig_strf, 4) == 0) {
++            // got strf - stream format
++            //printf ("Found strf, calling read_strf()\n");
++            read_strf(in, dwbuf1);
++        }
++        else if (memcmp(&charbuf1, sig_strn, 4) == 0) {
++            // we ignore strn, but it can be recorded incorrectly so we have
++            // to cope especially
++
++            // skip it
++            //printf ("Skipping strn chunk length: %i\n", dwbuf1);
++            in->reset (in->position() + dwbuf1);
++
++            /*
++            this is a pretty annoying hack; many AVIs incorrectly report the
++            length of the strn field by 1 byte.  Its possible that strn's
++            should be word aligned, but no mention in the specs...
++
++            I'll clean/optimise this a touch soon
++            */
++
++            bool done = false;
++            unsigned char counter = 0;
++            while (!done) {
++                // read next marker
++                if (4 != in->read ( c, 4, 4))
++                    return false;
++                charbuf1 = readLittleEndianUInt32(c); // type
++
++                // does it look ok?
++                if ((memcmp(&charbuf1, sig_list, 4) == 0) ||
++                     (memcmp(&charbuf1, sig_junk, 4) == 0)) {
++                        // yes, go back before it
++                        in->reset(in->position() - 4);
++                        done = true;
++                     } else {
++                        // no, skip one space forward from where we were
++                         in->reset (in->position() - 3);
++                         //printf ("Working around incorrectly marked strn length...\n");
++                     }
++
++                    // make sure we don't stay here too long
++                     ++counter;
++                     if (counter>10)
++                         done = true;
++            }
++        }
++        else if ((memcmp(&charbuf1, sig_list, 4) == 0) ||
++                 (memcmp(&charbuf1, sig_junk, 4) == 0)) {
++            // we have come to the end of our stay here in strl, time to leave
++            //printf ("Found LIST/JUNK, returning...\n");
++            //printf ("Found LIST/JUNK, returning from pos %i ...\n", in->position());
++            // rollback before the id and size
++            in->reset(in->position() - 8);
++
++            // return back to the main avi parser
++            return true;
++        }
++        else {
++            // we have some other unrecognised block type
++            //printf ("Skipping unrecognised block using dwbuf1 = %i\n", dwbuf1);
++            // just skip over it
++            in->reset (in->position() + dwbuf1);
++        } /* switch block type */
++
++        ++counter;
++        if (counter > 10)
++            return true;
++
++    } /* while (true) */
++
++    // we should never get here
++}
++
++bool
++AviThroughAnalyzer::read_strh(InputStream* in, uint32_t blocksize)
++{
++    //printf ("read_strh, in position: %i\n", in->position());
++    static const char sig_vids[] = "vids";   // ...video
++    static const char sig_auds[] = "auds";   // ...audio
++
++    uint32_t strh_flags;
++    uint32_t strh_reserved1;
++    uint32_t strh_initialframes;
++    uint32_t strh_scale;
++    uint32_t strh_rate;
++    uint32_t strh_start;
++    uint32_t strh_length;
++    uint32_t strh_buffersize;
++    uint32_t strh_quality;
++    uint32_t strh_samplesize;
++
++    uint32_t charbuf1;
++    uint32_t charbuf2;
++    const char* c;
++
++    // get stream info type, and handler id
++    if (8 != in->read ( c, 8, 8))
++        return false;
++    charbuf1 = readLittleEndianUInt32(c);
++    charbuf2 = readLittleEndianUInt32(c+4);
++
++    // read the strh fields
++    if (40 != in->read ( c, 40, 40))
++        return false;
++        
++    strh_flags = readLittleEndianUInt32(c);
++    strh_reserved1 = readLittleEndianUInt32(c+4);
++    strh_initialframes = readLittleEndianUInt32(c+8);
++    strh_scale = readLittleEndianUInt32(c+12);
++    strh_rate = readLittleEndianUInt32(c+16);
++    strh_start = readLittleEndianUInt32(c+20);
++    strh_length = readLittleEndianUInt32(c+24);
++    strh_buffersize = readLittleEndianUInt32(c+28);
++    strh_quality = readLittleEndianUInt32(c+32);
++    strh_samplesize = readLittleEndianUInt32(c+36);
++
++    if (memcmp(&charbuf1, sig_vids, 4) == 0) { // we are video!
++        // save the handler
++        memcpy(handler_vids, &charbuf2, 4);
++        //printf ("Video handler: %s\n", handler_vids);
++    }
++    else if (memcmp(&charbuf1, sig_auds, 4) == 0) { // we are audio!
++        // save the handler
++        memcpy(handler_auds, &charbuf2, 4);
++        //printf ("Audio handler: %X\n", handler_auds);
++
++        // we want strf to get the audio codec
++        wantstrf = true;
++    } else {
++        // we are something that we don't understand
++    }
++
++    // do we need to skip ahead any more?  (usually yes , contrary to
++    // the AVI specs I've read...)
++    // note: 48 is 10 * uint32_t + 2*FOURCC; the 10 fields we read above, plus the two character fields
++    //printf ("read_strh, before end position: %i\n", in->position());
++    if (blocksize > 48) {
++        in->reset (in->position() + (blocksize - 48));
++        //printf ("read_strh, new position after reset: %i\n", in->position());
++    }
++
++    return true;
++}
++
++bool
++AviThroughAnalyzer::read_strf(InputStream* in, uint32_t blocksize)
++{
++    const char* c;
++    //printf ("read_strf, in position: %i\n", in->position());
++    
++    // do we want to do the strf?
++    if (wantstrf) {
++        // yes.  we want the audio codec identifier out of it
++
++        // get the 16bit audio codec ID
++        if (2 != in->read ( c, 2, 2))
++            return false;
++        handler_audio = readLittleEndianUInt16(c);
++            
++        //printf ("Read audio codec ID: %X\n", handler_audio);
++        // skip past the rest of the stuff here for now
++        in->reset( in->position() + blocksize - 2);
++        // we have audio
++        done_audio = true;
++
++    } else {
++        //printf ("read_strf: skipping %i\n", blocksize);
++        // no, skip the strf
++        in->reset (in->position() + blocksize);
++    }
++
++    return true;
++}
++
++const char*
++AviThroughAnalyzer::resolve_audio(uint16_t id)
++{
++    /*
++    this really wants to use some sort of KDE global
++    list.  To avoid bloat for the moment it only does
++    a few common codecs
++    */
++
++    static const char codec_unknown[] = "Unknown";
++    static const char codec_01[]  = "Microsoft PCM";
++    static const char codec_02[]  = "Microsoft ADPCM";
++    static const char codec_50[]  = "MPEG";
++    static const char codec_55[]  = "MP3";
++    static const char codec_92[]  = "AC3";
++    static const char codec_160[] = "WMA1";
++    static const char codec_161[] = "WMA2";
++    static const char codec_162[] = "WMA3";
++    static const char codec_2000[] = "DVM";
++    switch (id) {
++        case 0x000 : return codec_unknown; break;
++        case 0x001 : return codec_01; break;
++        case 0x002 : return codec_02; break;
++        case 0x050 : return codec_50; break;
++        case 0x055 : return codec_55; break;
++        case 0x092 : return codec_92; break;
++        case 0x160 : return codec_160; break;
++        case 0x161 : return codec_161; break;
++        case 0x162 : return codec_162; break;
++        case 0x2000 : return codec_2000; break;
++        default : return codec_unknown;
++    }
++
++    return NULL;
++}
++
++InputStream*
++AviThroughAnalyzer::connectInputStream(InputStream* in) {
++    if( !in )
++        return in;
++
++    /***************************************************/
++    // prep
++
++    memset(handler_vids, 0x00, 5);
++    memset(handler_auds, 0x00, 5);
++
++    /***************************************************/
++    // start reading stuff from it
++    wantstrf = false;
++
++    if (!read_avi(in)) {
++        //printf ("read_avi() failed!\n");
++    }
++
++    /***************************************************/
++    // set up our output
++
++    if (done_avih) {
++
++        if (0 != avih_microsecperframe)
++            analysisResult->addValue( factory->frameRateField,
++                                      int (1000000 / avih_microsecperframe ));
++        
++        analysisResult->addValue( factory->resolutionHeightField, avih_width);
++        analysisResult->addValue( factory->resolutionHeightField, avih_height);
++
++        // work out and add length
++        uint64_t mylength = (uint64_t) ((float) avih_totalframes * (float) avih_microsecperframe / 1000000.0);
++        analysisResult->addValue( factory->lengthField, int(mylength));
++
++        if (strlen(handler_vids) > 0)
++            analysisResult->addValue( factory->videoCodecField, handler_vids);
++        else
++            analysisResult->addValue( factory->videoCodecField, "Unknown");
++
++        if (done_audio)
++            analysisResult->addValue( factory->audioCodecField,
++                                      resolve_audio(handler_audio));
++        else
++            analysisResult->addValue( factory->audioCodecField, "None");
++    }
++
++    in->reset(0);   // rewind to the start of the stream
++    return in;
++}
++
++bool
++AviThroughAnalyzer::isReadyWithStream() {
++    return true;
++}
++
++//Factory
++class Factory : public AnalyzerFactoryFactory {
++public:
++    list<StreamThroughAnalyzerFactory*>
++    streamThroughAnalyzerFactories() const {
++        list<StreamThroughAnalyzerFactory*> af;
++        af.push_back(new AviThroughAnalyzerFactory());
++        return af;
++    }
++};
++
++STRIGI_ANALYZER_FACTORY(Factory)
+--- /dev/null
++++ b/src/streamanalyzer/throughplugins/avithroughanalyzer.h
+@@ -0,0 +1,105 @@
++/* This file is part of Strigi Desktop Search
++ *
++ * Copyright (C) 2007 Flavio Castelli <flavio.castelli at gmail.com>
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Library General Public
++ * License as published by the Free Software Foundation; either
++ * version 2 of the License, or (at your option) any later version.
++ *
++ * This library 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
++ * Library General Public License for more details.
++ *
++ * You should have received a copy of the GNU Library General Public License
++ * along with this library; see the file COPYING.LIB.  If not, write to
++ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
++ * Boston, MA 02110-1301, USA.
++ */
++#ifndef STRIGI_AVITHROUGHANALYZER
++#define STRIGI_AVITHROUGHANALYZER
++
++#include "streamthroughanalyzer.h"
++#include "analyzerplugin.h"
++
++#include <string>
++
++namespace Strigi {
++    class RegisteredField;
++}
++class AviThroughAnalyzerFactory;
++
++class STRIGI_PLUGIN_API AviThroughAnalyzer
++    : public Strigi::StreamThroughAnalyzer {
++private:
++    Strigi::AnalysisResult* analysisResult;
++    const AviThroughAnalyzerFactory* factory;
++
++    bool done_avih;
++    uint32_t avih_microsecperframe;
++    uint32_t avih_maxbytespersec;
++    uint32_t avih_reserved1;
++    uint32_t avih_flags;
++    uint32_t avih_totalframes;
++    uint32_t avih_initialframes;
++    uint32_t avih_streams;
++    uint32_t avih_buffersize;
++    uint32_t avih_width;
++    uint32_t avih_height;
++    uint32_t avih_scale;
++    uint32_t avih_rate;
++    uint32_t avih_start;
++    uint32_t avih_length;
++
++    char handler_vids[5];   // leave room for trailing \0
++    char handler_auds[5];
++    uint16_t handler_audio; // the ID of the audio codec
++    bool done_audio;
++    
++    bool wantstrf;
++
++    bool read_avi(Strigi::InputStream* in);
++    bool read_strf(Strigi::InputStream* in, uint32_t blocksize);
++    bool read_strh(Strigi::InputStream* in, uint32_t blocksize);
++    bool read_strl(Strigi::InputStream* in);
++    bool read_avih(Strigi::InputStream* in);
++    bool read_list(Strigi::InputStream* in);
++    const char* resolve_audio(uint16_t id);
++    
++public:
++    AviThroughAnalyzer(const AviThroughAnalyzerFactory* f) :factory(f) {}
++    ~AviThroughAnalyzer() {}
++    void setIndexable(Strigi::AnalysisResult* i);
++    Strigi::InputStream *connectInputStream(Strigi::InputStream *in);
++    bool isReadyWithStream();
++    const char* name() const { return "AviThroughAnalyzer"; }
++};
++
++class AviThroughAnalyzerFactory
++    : public Strigi::StreamThroughAnalyzerFactory {
++friend class AviThroughAnalyzer;
++private:
++    static const std::string lengthFieldName;
++    static const std::string resolutionHeightFieldName;
++    static const std::string resolutionWidthFieldName;
++    static const std::string frameRateFieldName;
++    static const std::string videoCodecFieldName;
++    static const std::string audioCodecFieldName;
++    const Strigi::RegisteredField* lengthField;
++    const Strigi::RegisteredField* resolutionHeightField;
++    const Strigi::RegisteredField* resolutionWidthField;
++    const Strigi::RegisteredField* frameRateField;
++    const Strigi::RegisteredField* videoCodecField;
++    const Strigi::RegisteredField* audioCodecField;
++
++    const char* name() const {
++        return "AviThroughAnalyzer";
++    }
++    Strigi::StreamThroughAnalyzer* newInstance() const {
++        return new AviThroughAnalyzer(this);
++    }
++    void registerFields(Strigi::FieldRegister&);
++};
++
++#endif
+--- a/src/streamanalyzer/throughplugins/CMakeLists.txt
++++ b/src/streamanalyzer/throughplugins/CMakeLists.txt
+@@ -30,6 +30,12 @@
+ ADD_STRIGITA(xbm xbmthroughanalyzer.cpp)
+ ADD_STRIGITA(au  authroughanalyzer.cpp)
+ ADD_STRIGITA(gif gifthroughanalyzer.cpp)
++ADD_STRIGITA(ico icothroughanalyzer.cpp)
++ADD_STRIGITA(sid sidthroughanalyzer.cpp)
++ADD_STRIGITA(rgb rgbthroughanalyzer.cpp)
++ADD_STRIGITA(dds ddsthroughanalyzer.cpp)
++ADD_STRIGITA(wav wavthroughanalyzer.cpp)
++ADD_STRIGITA(avi avithroughanalyzer.cpp)
+ 
+ # disabled until a good check for making sure the file is a tga
+ #ADD_STRIGITA(tga  tgathroughanalyzer.cpp)
+--- /dev/null
++++ b/src/streamanalyzer/throughplugins/ddsthroughanalyzer.cpp
+@@ -0,0 +1,400 @@
++/* This file is part of Strigi Desktop Search, ported from code of:
++ * - Ignacio Castaño <castano at ludicon.com> (Copyright (C) 2002)
++ *
++ * Copyright (C) 2007 Flavio Castelli <flavio.castelli at gmail.com>
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Library General Public
++ * License as published by the Free Software Foundation; either
++ * version 2 of the License, or (at your option) any later version.
++ *
++ * This library 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
++ * Library General Public License for more details.
++ *
++ * You should have received a copy of the GNU Library General Public License
++ * along with this library; see the file COPYING.LIB.  If not, write to
++ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
++ * Boston, MA 02110-1301, USA.
++ */
++
++#include "ddsthroughanalyzer.h"
++#include "textutils.h"
++#include <strigi/strigiconfig.h>
++#include "analysisresult.h"
++#include "fieldtypes.h"
++#include <cstring>
++
++using namespace std;
++using namespace Strigi;
++
++
++namespace {// Private.
++#if !defined(MAKEFOURCC)
++#	define MAKEFOURCC(ch0, ch1, ch2, ch3) \
++        (uint32_t(uint8_t(ch0)) | (uint32_t(uint8_t(ch1)) << 8) | \
++        (uint32_t(uint8_t(ch2)) << 16) | (uint32_t(uint8_t(ch3)) << 24 ))
++#endif
++
++    static const uint32_t FOURCC_DDS = MAKEFOURCC('D', 'D', 'S', ' ');
++    static const uint32_t FOURCC_DXT1 = MAKEFOURCC('D', 'X', 'T', '1');
++    static const uint32_t FOURCC_DXT2 = MAKEFOURCC('D', 'X', 'T', '2');
++    static const uint32_t FOURCC_DXT3 = MAKEFOURCC('D', 'X', 'T', '3');
++    static const uint32_t FOURCC_DXT4 = MAKEFOURCC('D', 'X', 'T', '4');
++    static const uint32_t FOURCC_DXT5 = MAKEFOURCC('D', 'X', 'T', '5');
++    static const uint32_t FOURCC_RXGB = MAKEFOURCC('R', 'X', 'G', 'B');
++
++    static const uint32_t DDSD_CAPS = 0x00000001l;
++    static const uint32_t DDSD_PIXELFORMAT = 0x00001000l;
++    static const uint32_t DDSD_WIDTH = 0x00000004l;
++    static const uint32_t DDSD_HEIGHT = 0x00000002l;
++    static const uint32_t DDSD_PITCH = 0x00000008l;
++
++    static const uint32_t DDSCAPS_TEXTURE = 0x00001000l;
++    static const uint32_t DDSCAPS2_VOLUME = 0x00200000l;
++    static const uint32_t DDSCAPS2_CUBEMAP = 0x00000200l;
++
++    static const uint32_t DDPF_RGB = 0x00000040l;
++    static const uint32_t DDPF_FOURCC = 0x00000004l;
++    static const uint32_t DDPF_ALPHAPIXELS = 0x00000001l;
++
++    enum DDSType {
++        DDS_A8R8G8B8 = 0,
++        DDS_A1R5G5B5 = 1,
++        DDS_A4R4G4B4 = 2,
++        DDS_R8G8B8 = 3,
++        DDS_R5G6B5 = 4,
++        DDS_DXT1 = 5,
++        DDS_DXT2 = 6,
++        DDS_DXT3 = 7,
++        DDS_DXT4 = 8,
++        DDS_DXT5 = 9,
++        DDS_RXGB = 10,
++        DDS_UNKNOWN
++    };
++
++
++    struct DDSPixelFormat {
++        uint32_t size;
++        uint32_t flags;
++        uint32_t fourcc;
++        uint32_t bitcount;
++        uint32_t rmask;
++        uint32_t gmask;
++        uint32_t bmask;
++        uint32_t amask;
++    };
++
++    struct DDSCaps {
++        uint32_t caps1;
++        uint32_t caps2;
++        uint32_t caps3;
++        uint32_t caps4;
++    };
++
++    struct DDSHeader {
++        uint32_t size;
++        uint32_t flags;
++        uint32_t height;
++        uint32_t width;
++        uint32_t pitch;
++        uint32_t depth;
++        uint32_t mipmapcount;
++        uint32_t reserved[11];
++        DDSPixelFormat pf;
++        DDSCaps caps;
++        uint32_t notused;
++    };
++
++    static bool IsValid( const DDSHeader & header )
++    {
++        if( header.size != 124 ) {
++            return false;
++        }
++        const uint32_t required = (DDSD_WIDTH|DDSD_HEIGHT|DDSD_PIXELFORMAT);
++        if( (header.flags & required) != required ) {
++            return false;
++        }
++        if( header.pf.size != 32 ) {
++            return false;
++        }
++        if( !(header.caps.caps1 & DDSCAPS_TEXTURE) ) {
++            return false;
++        }
++        return true;
++    }
++
++    bool
++    readPixelFormat ( InputStream* in, DDSPixelFormat & pf )
++    {
++        const char* c;
++        
++        if (4 != in->read(c, 4, 4))
++            return false;
++        pf.size = readLittleEndianUInt32(c);
++
++        if (4 != in->read(c, 4, 4))
++            return false;
++        pf.flags = readLittleEndianUInt32(c);
++
++        if (4 != in->read(c, 4, 4))
++            return false;
++        pf.fourcc = readLittleEndianUInt32(c);
++
++        if (4 != in->read(c, 4, 4))
++            return false;
++        pf.bitcount = readLittleEndianUInt32(c);
++
++        if (4 != in->read(c, 4, 4))
++            return false;
++        pf.rmask = readLittleEndianUInt32(c);
++
++        if (4 != in->read(c, 4, 4))
++            return false;
++        pf.gmask = readLittleEndianUInt32(c);
++
++        if (4 != in->read(c, 4, 4))
++            return false;
++        pf.bmask = readLittleEndianUInt32(c);
++
++        if (4 != in->read(c, 4, 4))
++            return false;
++        pf.amask = readLittleEndianUInt32(c);
++
++        return true;
++    }
++
++    bool
++    readCaps ( InputStream* in, DDSCaps & caps )
++    {
++        const char* c;
++
++        if (4 != in->read(c, 4, 4))
++            return false;
++        caps.caps1 = readLittleEndianUInt32(c);
++
++        if (4 != in->read(c, 4, 4))
++            return false;
++        caps.caps2 = readLittleEndianUInt32(c);
++
++        if (4 != in->read(c, 4, 4))
++            return false;
++        caps.caps3 = readLittleEndianUInt32(c);
++
++        if (4 != in->read(c, 4, 4))
++            return false;
++        caps.caps4 = readLittleEndianUInt32(c);
++
++        return true;
++    }
++    
++    bool
++    readHeader(InputStream* in, DDSHeader& header)
++    {
++        const char *c;
++
++        if (4 != in->read(c, 4, 4))
++            return false;
++        header.size = readLittleEndianUInt32(c);
++
++        if (4 != in->read(c, 4, 4))
++            return false;
++        header.flags = readLittleEndianUInt32(c);
++
++        if (4 != in->read(c, 4, 4))
++            return false;
++        header.height = readLittleEndianUInt32(c);
++
++        if (4 != in->read(c, 4, 4))
++            return false;
++        header.width = readLittleEndianUInt32(c);
++
++        if (4 != in->read(c, 4, 4))
++            return false;
++        header.pitch = readLittleEndianUInt32(c);
++
++        if (4 != in->read(c, 4, 4))
++            return false;
++        header.depth = readLittleEndianUInt32(c);
++
++        if (4 != in->read(c, 4, 4))
++            return false;
++        header.mipmapcount = readLittleEndianUInt32(c);
++
++        for( int i = 0; i < 11; i++ ) {
++            if (4 != in->read(c, 4, 4))
++                return false;
++            header.reserved[i] = readLittleEndianUInt32(c);
++        }
++
++        if (!readPixelFormat( in, header.pf))
++            return false;
++    
++
++        if (!readCaps ( in, header.caps))
++            return false;
++
++        if (4 != in->read(c, 4, 4))
++            return false;
++        header.notused = readLittleEndianUInt32(c);
++
++        return true;
++    }
++} // namespace
++
++
++// AnalyzerFactory
++
++const string DdsThroughAnalyzerFactory::widthFieldName( "image.width" );
++const string DdsThroughAnalyzerFactory::heightFieldName( "image.height" );
++
++//TODO: check values!
++const string DdsThroughAnalyzerFactory::depthFieldName( "image.color_depth" );
++const string DdsThroughAnalyzerFactory::bitDepthFieldName( "document.stats.image_bit_depth" );
++const string DdsThroughAnalyzerFactory::mipmapCountFieldName ( "document.stats.image_mipmap_count" );
++const string DdsThroughAnalyzerFactory::typeFieldName ( "document.stats.image_type" );
++const string DdsThroughAnalyzerFactory::colorModeFieldName ( "document.stats.image_color_mode" );
++const string DdsThroughAnalyzerFactory::compressionFieldName ( "document.stats.image_compression" );
++
++void
++DdsThroughAnalyzerFactory::registerFields(FieldRegister& reg) {
++    widthField = reg.registerField(widthFieldName);
++    heightField = reg.registerField(heightFieldName);
++    depthField = reg.registerField(depthFieldName);
++    bitDepthField = reg.registerField(bitDepthFieldName);
++    mipmapCountField = reg.registerField(mipmapCountFieldName);
++    typeField = reg.registerField(typeFieldName);
++    colorModeField = reg.registerField(colorModeFieldName);
++    compressionField = reg.registerField(compressionFieldName);
++}
++
++// Analyzer
++void
++DdsThroughAnalyzer::setIndexable(AnalysisResult* i) {
++    analysisResult = i;
++}
++
++InputStream*
++DdsThroughAnalyzer::connectInputStream(InputStream* in) {
++    if( !in )
++        return in;
++
++    const char *c;
++
++    //Remember: dds files are little-endian
++    //read the beginning of the stream and make sure it looks ok
++    
++    if (4 != in->read(c, 4, 4)) {
++       in->reset(0);   // rewind to the start of the stream
++       return in;
++    }
++
++    uint32_t fourcc = readLittleEndianUInt32(c);
++    if (fourcc != FOURCC_DDS) {
++        in->reset(0);   // rewind to the start of the stream
++        return in;
++    }
++
++    // Read image header.
++    DDSHeader header;
++    if (!readHeader (in, header)) {
++        in->reset(0);
++        return in;
++    }
++
++    // Check image file format.
++    if(( in->read(c, 1, 1) != 1 ) || !IsValid( header ) ) {
++        in->reset(0);
++        return in;
++    }
++
++    // Set file info
++    analysisResult->addValue( factory->widthField, header.width );
++    analysisResult->addValue( factory->heightField, header.height );
++    analysisResult->addValue( factory->mipmapCountField, header.mipmapcount );
++
++    // Set file type.
++    if( header.caps.caps2 & DDSCAPS2_CUBEMAP ) {
++        analysisResult->addValue( factory->typeField, "Cube Map Texture");
++    }
++    else if( header.caps.caps2 & DDSCAPS2_VOLUME ) {
++        analysisResult->addValue( factory->typeField, "Volume Texture");
++        analysisResult->addValue( factory->depthField, header.depth);
++    }
++    else {
++        analysisResult->addValue( factory->typeField, "2D Texture");
++    }
++
++    // Set file color depth and compression.
++    if( header.pf.flags & DDPF_RGB ) {
++        analysisResult->addValue( factory->bitDepthField,header.pf.bitcount);
++        analysisResult->addValue( factory->compressionField, "Uncompressed");
++        if( header.pf.flags & DDPF_ALPHAPIXELS )
++            analysisResult->addValue( factory->colorModeField, "RGB/Alpha");
++        else
++            analysisResult->addValue( factory->colorModeField, "RGB");
++    }
++    else if( header.pf.flags & DDPF_FOURCC ) {
++        switch( header.pf.fourcc ) {
++            case FOURCC_DXT1:
++                analysisResult->addValue( factory->bitDepthField, 4);
++                analysisResult->addValue( factory->compressionField, "DXT1");
++                analysisResult->addValue( factory->colorModeField, "RGB");
++                break;
++            case FOURCC_DXT2:
++                analysisResult->addValue( factory->bitDepthField, 16);
++                analysisResult->addValue( factory->compressionField, "DXT2");
++                analysisResult->addValue( factory->colorModeField, "RGB/Alpha");
++                break;
++            case FOURCC_DXT3:
++                analysisResult->addValue( factory->bitDepthField, 16);
++                analysisResult->addValue( factory->compressionField, "DXT3");
++                analysisResult->addValue( factory->colorModeField, "RGB/Alpha");
++                break;
++            case FOURCC_DXT4:
++                analysisResult->addValue( factory->bitDepthField, 16);
++                analysisResult->addValue( factory->compressionField, "DXT4");
++                analysisResult->addValue( factory->colorModeField, "RGB/Alpha");
++                break;
++            case FOURCC_DXT5:
++                analysisResult->addValue( factory->bitDepthField, 16);
++                analysisResult->addValue( factory->compressionField, "DXT5");
++                analysisResult->addValue( factory->colorModeField, "RGB/Alpha");
++                break;
++            case FOURCC_RXGB:
++                analysisResult->addValue( factory->bitDepthField, 16);
++                analysisResult->addValue( factory->compressionField, "RXGB");
++                analysisResult->addValue( factory->colorModeField, "RGB");
++                break;
++            default:
++                analysisResult->addValue( factory->compressionField, "Unknown");
++                break;
++        }
++    }
++    else {
++        analysisResult->addValue( factory->compressionField, "Unknown");
++    }
++
++
++    in->reset(0);   // rewind to the start of the stream
++    return in;
++}
++
++bool
++DdsThroughAnalyzer::isReadyWithStream() {
++    return true;
++}
++
++//Factory
++class Factory : public AnalyzerFactoryFactory {
++public:
++    list<StreamThroughAnalyzerFactory*>
++    streamThroughAnalyzerFactories() const {
++        list<StreamThroughAnalyzerFactory*> af;
++        af.push_back(new DdsThroughAnalyzerFactory());
++        return af;
++    }
++};
++
++STRIGI_ANALYZER_FACTORY(Factory)
+--- /dev/null
++++ b/src/streamanalyzer/throughplugins/ddsthroughanalyzer.h
+@@ -0,0 +1,78 @@
++/* This file is part of Strigi Desktop Search
++ *
++ * Copyright (C) 2007 Flavio Castelli <flavio.castelli at gmail.com>
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Library General Public
++ * License as published by the Free Software Foundation; either
++ * version 2 of the License, or (at your option) any later version.
++ *
++ * This library 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
++ * Library General Public License for more details.
++ *
++ * You should have received a copy of the GNU Library General Public License
++ * along with this library; see the file COPYING.LIB.  If not, write to
++ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
++ * Boston, MA 02110-1301, USA.
++ */
++#ifndef STRIGI_DDSTHROUGHANALYZER
++#define STRIGI_DDSTHROUGHANALYZER
++
++#include "streamthroughanalyzer.h"
++#include "analyzerplugin.h"
++
++#include <string>
++
++namespace Strigi {
++    class RegisteredField;
++}
++class DdsThroughAnalyzerFactory;
++
++class STRIGI_PLUGIN_API DdsThroughAnalyzer
++    : public Strigi::StreamThroughAnalyzer {
++private:
++    Strigi::AnalysisResult* analysisResult;
++    const DdsThroughAnalyzerFactory* factory;
++public:
++    DdsThroughAnalyzer(const DdsThroughAnalyzerFactory* f) :factory(f) {}
++    ~DdsThroughAnalyzer() {}
++    void setIndexable(Strigi::AnalysisResult* i);
++    Strigi::InputStream *connectInputStream(Strigi::InputStream *in);
++    bool isReadyWithStream();
++    const char* name() const { return "DdsThroughAnalyzer"; }
++};
++
++class DdsThroughAnalyzerFactory
++    : public Strigi::StreamThroughAnalyzerFactory {
++friend class DdsThroughAnalyzer;
++private:
++    static const std::string widthFieldName;
++    static const std::string heightFieldName;
++    static const std::string depthFieldName;
++    static const std::string bitDepthFieldName;
++    static const std::string mipmapCountFieldName;
++    static const std::string typeFieldName;
++    static const std::string colorModeFieldName;
++    static const std::string compressionFieldName;
++
++    const Strigi::RegisteredField* widthField;
++    const Strigi::RegisteredField* heightField;
++    const Strigi::RegisteredField* depthField;
++    const Strigi::RegisteredField* bitDepthField;
++    const Strigi::RegisteredField* mipmapCountField;
++    const Strigi::RegisteredField* typeField;
++    const Strigi::RegisteredField* colorModeField;
++    const Strigi::RegisteredField* compressionField;
++
++    const char* name() const {
++        return "DdsThroughAnalyzer";
++    }
++    Strigi::StreamThroughAnalyzer* newInstance() const {
++        return new DdsThroughAnalyzer(this);
++    }
++    void registerFields(Strigi::FieldRegister&);
++};
++
++#endif
+--- a/src/streamanalyzer/throughplugins/gifthroughanalyzer.cpp
++++ b/src/streamanalyzer/throughplugins/gifthroughanalyzer.cpp
+@@ -59,6 +59,9 @@
+     const Strigi::RegisteredField* colorDepthField;
+     const Strigi::RegisteredField* widthField;
+     const Strigi::RegisteredField* heightField;
++
++    const Strigi::RegisteredField* typeField;
++
+     const char* name() const {
+         return "GifThroughAnalyzer";
+     }
+@@ -75,6 +78,8 @@
+     colorDepthField = reg.registerField("http://freedesktop.org/standards/xesam/1.0/core#pixelDataBitDepth");
+     widthField = reg.registerField("http://freedesktop.org/standards/xesam/1.0/core#width");
+     heightField = reg.registerField("http://freedesktop.org/standards/xesam/1.0/core#height");
++
++    typeField = reg.typeField;
+ }
+ 
+ // Analyzer
+@@ -105,6 +110,8 @@
+         analysisResult->addValue(factory->colorDepthField, (uint32_t)colorDepth);
+     }
+ 
++    analysisResult->addValue(factory->typeField, "http://freedesktop.org/standards/xesam/1.0/core#Image");
++
+     return in;
+ }
+ 
+--- /dev/null
++++ b/src/streamanalyzer/throughplugins/icothroughanalyzer.cpp
+@@ -0,0 +1,174 @@
++/* This file is part of Strigi Desktop Search, ported from code of:
++ * - Shane Wright <me at shanewright.co.uk> (Copyright (C) 2002)
++ * - Matthias Lechner <matthias at lmme.de> (Copyright (C) 2007) 
++ *
++ * Copyright (C) 2007 Flavio Castelli <flavio.castelli at gmail.com>
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Library General Public
++ * License as published by the Free Software Foundation; either
++ * version 2 of the License, or (at your option) any later version.
++ *
++ * This library 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
++ * Library General Public License for more details.
++ *
++ * You should have received a copy of the GNU Library General Public License
++ * along with this library; see the file COPYING.LIB.  If not, write to
++ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
++ * Boston, MA 02110-1301, USA.
++ */
++
++#include "icothroughanalyzer.h"
++#include "textutils.h"
++#include <strigi/strigiconfig.h>
++#include "analysisresult.h"
++#include "fieldtypes.h"
++#include <cstring>
++
++using namespace std;
++using namespace Strigi;
++
++// AnalyzerFactory
++
++const string IcoThroughAnalyzerFactory::widthFieldName( "image.width" );
++const string IcoThroughAnalyzerFactory::heightFieldName( "image.height" );
++
++//TODO: check values!
++const string IcoThroughAnalyzerFactory::numberFieldName( "document.stats.image_count" );
++const string IcoThroughAnalyzerFactory::bitsPerPixelFieldName( "image.color_depth" );
++const string IcoThroughAnalyzerFactory::colorCountFieldName( "image.color_count" );
++
++void
++IcoThroughAnalyzerFactory::registerFields(FieldRegister& reg) {
++    widthField = reg.registerField(widthFieldName);
++    heightField = reg.registerField(heightFieldName);
++    numberField = reg.registerField(numberFieldName);
++    bitsPerPixelField = reg.registerField(bitsPerPixelFieldName);
++    colorCountField = reg.registerField(colorCountFieldName);
++}
++
++// Analyzer
++void
++IcoThroughAnalyzer::setIndexable(AnalysisResult* i) {
++    analysisResult = i;
++}
++
++InputStream*
++IcoThroughAnalyzer::connectInputStream(InputStream* in) {
++    if( !in )
++        return in;
++
++    const char *c;
++    int32_t n;
++    
++    // Remember: ICO files are little-endian
++    // read the beginning of the stream and make sure it looks ok
++    
++    n = in->read(c, 6, 6);
++    if (n != 6) {
++       in->reset(0);   // rewind to the start of the stream
++       return in;
++    }
++    uint16_t ico_reserved = readLittleEndianUInt16(c);
++    uint16_t ico_type = readLittleEndianUInt16(c+2);
++    uint16_t ico_count = readLittleEndianUInt16(c+4);
++
++    if ((ico_reserved != 0) || (ico_type != 1) || (ico_count < 1)) {
++        in->reset(0);
++        return in;
++    }
++
++    // now loop through each of the icon entries
++    n = in->read(c, 1, 1);
++    if (n != 1) {
++       in->reset(0);   // rewind to the start of the stream
++       return in;
++    }
++    uint8_t icoe_width = (uint8_t)*c;
++
++    n = in->read(c, 1, 1);
++    if (n != 1) {
++       in->reset(0);   // rewind to the start of the stream
++       return in;
++    }
++    uint8_t icoe_height = (uint8_t)*c;
++
++    n = in->read(c, 1, 1);
++    if (n != 1) {
++       in->reset(0);   // rewind to the start of the stream
++       return in;
++    }
++    uint8_t icoe_colorcount = (uint8_t)*c;
++
++    n = in->read(c, 1, 1);
++    if (n != 1) {
++       in->reset(0);   // rewind to the start of the stream
++       return in;
++    }
++    uint8_t icoe_reserved = (uint8_t)*c;
++
++    n = in->read(c, 2, 2);
++    if (n != 2) {
++       in->reset(0);   // rewind to the start of the stream
++       return in;
++    }
++    uint16_t icoe_planes = readLittleEndianUInt16(c);
++
++    n = in->read(c, 2, 2);
++    if (n != 2) {
++       in->reset(0);   // rewind to the start of the stream
++       return in;
++    }
++    uint16_t icoe_bitcount = readLittleEndianUInt16(c);
++
++    n = in->read(c, 4, 4);
++    if (n != 4) {
++       in->reset(0);   // rewind to the start of the stream
++       return in;
++    }
++    uint32_t icoe_bytesinres = readLittleEndianUInt32(c);
++
++    n = in->read(c, 4, 4);
++    if (n != 4) {
++       in->reset(0);   // rewind to the start of the stream
++       return in;
++    }
++    uint32_t icoe_imageoffset = readLittleEndianUInt32(c);
++
++    // read the data on the 1st icon
++    analysisResult->addValue( factory->numberField, ico_count );
++
++    analysisResult->addValue( factory->widthField, icoe_width );
++    analysisResult->addValue( factory->heightField, icoe_height );
++
++    if (icoe_bitcount > 0)
++        analysisResult->addValue( factory->bitsPerPixelField, icoe_bitcount );
++
++    if (icoe_colorcount > 0)
++        analysisResult->addValue( factory->colorCountField, icoe_colorcount );
++    else if (icoe_bitcount > 0)
++        analysisResult->addValue( factory->colorCountField, 2 ^ icoe_bitcount );
++    
++    in->reset(0);   // rewind to the start of the stream
++    return in;
++}
++
++bool
++IcoThroughAnalyzer::isReadyWithStream() {
++    return true;
++}
++
++//Factory
++class Factory : public AnalyzerFactoryFactory {
++public:
++    list<StreamThroughAnalyzerFactory*>
++    streamThroughAnalyzerFactories() const {
++        list<StreamThroughAnalyzerFactory*> af;
++        af.push_back(new IcoThroughAnalyzerFactory());
++        return af;
++    }
++};
++
++STRIGI_ANALYZER_FACTORY(Factory)
+--- /dev/null
++++ b/src/streamanalyzer/throughplugins/icothroughanalyzer.h
+@@ -0,0 +1,71 @@
++/* This file is part of Strigi Desktop Search
++ *
++ * Copyright (C) 2007 Flavio Castelli <flavio.castelli at gmail.com>
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Library General Public
++ * License as published by the Free Software Foundation; either
++ * version 2 of the License, or (at your option) any later version.
++ *
++ * This library 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
++ * Library General Public License for more details.
++ *
++ * You should have received a copy of the GNU Library General Public License
++ * along with this library; see the file COPYING.LIB.  If not, write to
++ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
++ * Boston, MA 02110-1301, USA.
++ */
++#ifndef STRIGI_ICOTHROUGHANALYZER
++#define STRIGI_ICOTHROUGHANALYZER
++
++#include "streamthroughanalyzer.h"
++#include "analyzerplugin.h"
++
++#include <string>
++
++namespace Strigi {
++    class RegisteredField;
++}
++class IcoThroughAnalyzerFactory;
++
++class STRIGI_PLUGIN_API IcoThroughAnalyzer
++    : public Strigi::StreamThroughAnalyzer {
++private:
++    Strigi::AnalysisResult* analysisResult;
++    const IcoThroughAnalyzerFactory* factory;
++public:
++    IcoThroughAnalyzer(const IcoThroughAnalyzerFactory* f) :factory(f) {}
++    ~IcoThroughAnalyzer() {}
++    void setIndexable(Strigi::AnalysisResult* i);
++    Strigi::InputStream *connectInputStream(Strigi::InputStream *in);
++    bool isReadyWithStream();
++    const char* name() const { return "IcoThroughAnalyzer"; }
++};
++
++class IcoThroughAnalyzerFactory
++    : public Strigi::StreamThroughAnalyzerFactory {
++friend class IcoThroughAnalyzer;
++private:
++    static const std::string numberFieldName;
++    static const std::string widthFieldName;
++    static const std::string heightFieldName;
++    static const std::string bitsPerPixelFieldName;
++    static const std::string colorCountFieldName;
++    const Strigi::RegisteredField* numberField;
++    const Strigi::RegisteredField* widthField;
++    const Strigi::RegisteredField* heightField;
++    const Strigi::RegisteredField* bitsPerPixelField;
++    const Strigi::RegisteredField* colorCountField;
++
++    const char* name() const {
++        return "IcoThroughAnalyzer";
++    }
++    Strigi::StreamThroughAnalyzer* newInstance() const {
++        return new IcoThroughAnalyzer(this);
++    }
++    void registerFields(Strigi::FieldRegister&);
++};
++
++#endif
+--- a/src/streamanalyzer/throughplugins/pcxthroughanalyzer.cpp
++++ b/src/streamanalyzer/throughplugins/pcxthroughanalyzer.cpp
+@@ -38,13 +38,14 @@
+ 
+ void
+ PcxThroughAnalyzerFactory::registerFields(FieldRegister& reg) {
+-    compressionField = reg.registerField(compressionFieldName,
+-        FieldRegister::stringType, 1, 0);
++    compressionField = reg.registerField(compressionFieldName);
+     widthField = reg.registerField(widthFieldName);
+     heightField = reg.registerField(heightFieldName);
+     hResolutionField = reg.registerField(hResolutionFieldName);
+     vResolutionField = reg.registerField(vResolutionFieldName);
+     colorDepthField = reg.registerField(colorDepthFieldName);
++
++    typeField = reg.typeField;
+ }
+ 
+ void
+@@ -84,6 +85,7 @@
+     indexable->addValue(factory->hResolutionField, (int32_t)readLittleEndianUInt16(header+12));
+     indexable->addValue(factory->vResolutionField, (int32_t)readLittleEndianUInt16(header+14));
+ 
++    indexable->addValue(factory->typeField, "http://freedesktop.org/standards/xesam/1.0/core#Image");
+     return in;
+ }
+ bool
+--- a/src/streamanalyzer/throughplugins/pcxthroughanalyzer.h
++++ b/src/streamanalyzer/throughplugins/pcxthroughanalyzer.h
+@@ -55,6 +55,9 @@
+     const Strigi::RegisteredField* compressionField;
+     const Strigi::RegisteredField* hResolutionField;
+     const Strigi::RegisteredField* vResolutionField;
++
++    const Strigi::RegisteredField* typeField;
++
+     const char* name() const {
+         return "PcxThroughAnalyzer";
+     }
+--- /dev/null
++++ b/src/streamanalyzer/throughplugins/rgbthroughanalyzer.cpp
+@@ -0,0 +1,238 @@
++/* This file is part of Strigi Desktop Search, ported from code of:
++ * - Melchior FRANZ <mfranz at kde.org> (Copyright (C) 2004)
++ *
++ * Copyright (C) 2007 Flavio Castelli <flavio.castelli at gmail.com>
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Library General Public
++ * License as published by the Free Software Foundation; either
++ * version 2 of the License, or (at your option) any later version.
++ *
++ * This library 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
++ * Library General Public License for more details.
++ *
++ * You should have received a copy of the GNU Library General Public License
++ * along with this library; see the file COPYING.LIB.  If not, write to
++ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
++ * Boston, MA 02110-1301, USA.
++ */
++
++#include "rgbthroughanalyzer.h"
++#include "textutils.h"
++#include <strigi/strigiconfig.h>
++#include "analysisresult.h"
++#include "fieldtypes.h"
++#include <cstring>
++#include <map>
++#include "config.h"
++
++using namespace std;
++using namespace Strigi;
++
++
++// AnalyzerFactory
++
++const string RgbThroughAnalyzerFactory::widthFieldName( "image.width" );
++const string RgbThroughAnalyzerFactory::heightFieldName( "image.height" );
++
++//TODO: check values!
++const string RgbThroughAnalyzerFactory::bitDepthFieldName( "document.stats.image_bit_depth" );
++const string RgbThroughAnalyzerFactory::imageNameFieldName ( "document.stats.image_name" );
++const string RgbThroughAnalyzerFactory::sharedRowsFieldName ( "document.stats.image_shared_rows" );
++const string RgbThroughAnalyzerFactory::colorModeFieldName ( "document.stats.image_color_mode" );
++const string RgbThroughAnalyzerFactory::compressionFieldName ( "document.stats.image_compression" );
++
++void
++RgbThroughAnalyzerFactory::registerFields(FieldRegister& reg) {
++    widthField = reg.registerField(widthFieldName);
++    heightField = reg.registerField(heightFieldName);
++    bitDepthField = reg.registerField(bitDepthFieldName);
++    imageNameField = reg.registerField(imageNameFieldName);
++    sharedRowsField = reg.registerField(sharedRowsFieldName);
++    colorModeField = reg.registerField(colorModeFieldName);
++    compressionField = reg.registerField(compressionFieldName);
++}
++
++// Analyzer
++void
++RgbThroughAnalyzer::setIndexable(AnalysisResult* i) {
++    analysisResult = i;
++}
++
++InputStream*
++RgbThroughAnalyzer::connectInputStream(InputStream* in) {
++    if( !in )
++        return in;
++
++    const char *c;
++    uint16_t magic;
++    uint8_t  storage;
++    uint8_t  bpc;
++    uint16_t dimension;
++    uint16_t xsize;
++    uint16_t ysize;
++    uint16_t zsize;
++    uint32_t pixmin;
++    uint32_t pixmax;
++    uint32_t dummy;
++    uint32_t colormap;
++
++    //Remember: dds files are big-endian
++    //read the beginning of the stream and make sure it looks ok
++    
++    if (2 != in->read(c, 2, 2)) {
++       in->reset(0);   // rewind to the start of the stream
++       return in;
++    }
++    magic = readBigEndianUInt16(c);
++
++    if (magic != 474) {
++        in->reset(0);
++        return in;
++    }
++
++    if (1 != in->read(c, 1, 1)) {
++        in->reset(0);   // rewind to the start of the stream
++        return in;
++    }
++    storage = (uint8_t)*c;
++
++    if (1 != in->read(c, 1, 1)) {
++        in->reset(0);   // rewind to the start of the stream
++        return in;
++    }
++    bpc = (uint8_t)*c;
++
++    if (8 != in->read(c, 8, 8)) {
++        in->reset(0);   // rewind to the start of the stream
++        return in;
++    }
++    dimension = readBigEndianUInt16(c);
++    xsize = readBigEndianUInt16(c+2);
++    ysize = readBigEndianUInt16(c+4);
++    zsize = readBigEndianUInt16(c+6);
++
++    if (12 != in->read(c, 12, 12)) {
++        in->reset(0);   // rewind to the start of the stream
++        return in;
++    }
++    pixmin = readBigEndianUInt32(c);
++    pixmax = readBigEndianUInt32(c+4);
++    dummy = readBigEndianUInt32(c+8);
++
++    if (80 != in->read(c, 80, 80)) {
++        in->reset(0);   // rewind to the start of the stream
++        return in;
++    }
++    string imagename (c, 80);
++    //TODO: discover why imagename is reported as a NON utf8 string
++    imagename[79] = '\0';
++
++    if (4 != in->read(c, 4, 4)) {
++        in->reset(0);   // rewind to the start of the stream
++        return in;
++    }
++    colormap = readBigEndianUInt32(c);
++
++    if (404 != in->skip( 404)) {
++        in->reset (0);
++        return in;
++    }
++
++    if (dimension == 1)
++        ysize = 1;
++
++    //determine fileSize
++    uint64_t fileSize;
++    uint64_t pos;
++    pos = in->position();
++    fileSize = pos;
++    uint64_t skipped;
++    do{
++        skipped = in->skip( 8192);
++        fileSize += skipped;
++    } while (skipped != 0);
++
++    // restore file position
++    in->reset (pos);
++    
++    analysisResult->addValue( factory->widthField, xsize );
++    analysisResult->addValue( factory->heightField, ysize );
++    analysisResult->addValue( factory->bitDepthField, zsize * 8 * bpc );
++    analysisResult->addValue( factory->imageNameField, imagename);
++
++    if (zsize == 1)
++        analysisResult->addValue( factory->colorModeField, "Grayscale");
++    else if (zsize == 2)
++        analysisResult->addValue( factory->colorModeField, "Grayscale/Alpha");
++    else if (zsize == 3)
++        analysisResult->addValue( factory->colorModeField, "RGB");
++    else if (zsize == 4)
++        analysisResult->addValue( factory->colorModeField, "RGB/Alpha");
++
++    if (!storage)
++        analysisResult->addValue( factory->compressionField, "Uncompressed");
++    else if (storage == 1) {
++        long compressed = fileSize - 512;
++        long verbatim = xsize * ysize * zsize;
++        char buff[50];
++        snprintf (buff, 50, "%.1f", compressed * 100.0 / verbatim);
++        analysisResult->addValue( factory->compressionField,
++                                  string ("Runlength Encoded, ") + buff);
++
++        long k;
++        uint32_t offs;
++        map<uint32_t, uint> pixelMap;
++        map<uint32_t, uint>::iterator it;
++        map<uint32_t, uint>::iterator end = pixelMap.end();
++        for (k = 0; k < (ysize * zsize); k++) {
++            
++            if (4 != in->read(c, 4, 4)) {
++                in->reset(0);   // rewind to the start of the stream
++                return in;
++            }
++            offs = readBigEndianUInt32 (c);
++            
++            if ((it = pixelMap.find(offs)) != end)
++                it->second = it->second + 1;
++            else
++                pixelMap[offs] = 0;
++        }
++
++        for (k = 0, it = pixelMap.begin(); it != end; ++it){
++            k += it->second;
++        }
++        if (k) {
++            snprintf (buff, 50, "%.1f", k * 100.0 / (ysize * zsize));
++            analysisResult->addValue( factory->sharedRowsField, buff);
++        }
++        else
++            analysisResult->addValue( factory->sharedRowsField, "None");
++    } else
++        analysisResult->addValue( factory->compressionField, "Unknown");
++
++    
++    
++    in->reset(0);   // rewind to the start of the stream
++    return in;
++}
++
++bool
++RgbThroughAnalyzer::isReadyWithStream() {
++    return true;
++}
++
++//Factory
++class Factory : public AnalyzerFactoryFactory {
++public:
++    list<StreamThroughAnalyzerFactory*>
++    streamThroughAnalyzerFactories() const {
++        list<StreamThroughAnalyzerFactory*> af;
++        af.push_back(new RgbThroughAnalyzerFactory());
++        return af;
++    }
++};
++
++STRIGI_ANALYZER_FACTORY(Factory)
+--- /dev/null
++++ b/src/streamanalyzer/throughplugins/rgbthroughanalyzer.h
+@@ -0,0 +1,76 @@
++/* This file is part of Strigi Desktop Search
++ *
++ * Copyright (C) 2007 Flavio Castelli <flavio.castelli at gmail.com>
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Library General Public
++ * License as published by the Free Software Foundation; either
++ * version 2 of the License, or (at your option) any later version.
++ *
++ * This library 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
++ * Library General Public License for more details.
++ *
++ * You should have received a copy of the GNU Library General Public License
++ * along with this library; see the file COPYING.LIB.  If not, write to
++ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
++ * Boston, MA 02110-1301, USA.
++ */
++#ifndef STRIGI_RGBTHROUGHANALYZER
++#define STRIGI_RGBTHROUGHANALYZER
++
++#include "streamthroughanalyzer.h"
++#include "analyzerplugin.h"
++
++#include <string>
++
++namespace Strigi {
++    class RegisteredField;
++}
++class RgbThroughAnalyzerFactory;
++
++class STRIGI_PLUGIN_API RgbThroughAnalyzer
++    : public Strigi::StreamThroughAnalyzer {
++private:
++    Strigi::AnalysisResult* analysisResult;
++    const RgbThroughAnalyzerFactory* factory;
++public:
++    RgbThroughAnalyzer(const RgbThroughAnalyzerFactory* f) :factory(f) {}
++    ~RgbThroughAnalyzer() {}
++    void setIndexable(Strigi::AnalysisResult* i);
++    Strigi::InputStream *connectInputStream(Strigi::InputStream *in);
++    bool isReadyWithStream();
++    const char* name() const { return "RgbThroughAnalyzer"; }
++};
++
++class RgbThroughAnalyzerFactory
++    : public Strigi::StreamThroughAnalyzerFactory {
++friend class RgbThroughAnalyzer;
++private:
++    static const std::string widthFieldName;
++    static const std::string heightFieldName;
++    static const std::string bitDepthFieldName;
++    static const std::string imageNameFieldName;
++    static const std::string sharedRowsFieldName;
++    static const std::string colorModeFieldName;
++    static const std::string compressionFieldName;
++
++    const Strigi::RegisteredField* widthField;
++    const Strigi::RegisteredField* heightField;
++    const Strigi::RegisteredField* bitDepthField;
++    const Strigi::RegisteredField* imageNameField;
++    const Strigi::RegisteredField* sharedRowsField;
++    const Strigi::RegisteredField* colorModeField;
++    const Strigi::RegisteredField* compressionField;
++
++    const char* name() const {
++        return "RgbThroughAnalyzer";
++    }
++    Strigi::StreamThroughAnalyzer* newInstance() const {
++        return new RgbThroughAnalyzer(this);
++    }
++    void registerFields(Strigi::FieldRegister&);
++};
++
++#endif
+--- /dev/null
++++ b/src/streamanalyzer/throughplugins/sidthroughanalyzer.cpp
+@@ -0,0 +1,166 @@
++/* This file is part of Strigi Desktop Search, ported from code of:
++ * - Rolf Magnus <ramagnus at kde.org> (2003)
++ *
++ * Copyright (C) 2007 Flavio Castelli <flavio.castelli at gmail.com>
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Library General Public
++ * License as published by the Free Software Foundation; either
++ * version 2 of the License, or (at your option) any later version.
++ *
++ * This library 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
++ * Library General Public License for more details.
++ *
++ * You should have received a copy of the GNU Library General Public License
++ * along with this library; see the file COPYING.LIB.  If not, write to
++ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
++ * Boston, MA 02110-1301, USA.
++ */
++
++#include "sidthroughanalyzer.h"
++#include "textutils.h"
++#include <strigi/strigiconfig.h>
++#include "analysisresult.h"
++#include "fieldtypes.h"
++#include <cstring>
++
++#include <iostream>
++
++using namespace std;
++using namespace Strigi;
++
++// AnalyzerFactory
++
++const string SidThroughAnalyzerFactory::titleFieldName("http://freedesktop.org/standards/xesam/1.0/core#title");
++const string SidThroughAnalyzerFactory::artistFieldName("http://freedesktop.org/standards/xesam/1.0/core#artist");
++
++//TODO: check values!
++const string SidThroughAnalyzerFactory::trackNumberFieldName("http://freedesktop.org/standards/xesam/1.0/core#albumTrackCount");
++const string SidThroughAnalyzerFactory::versionFieldName( "document.stats.version" );
++const string SidThroughAnalyzerFactory::copyrightFieldName( "document.stats.copyright" );
++
++void
++SidThroughAnalyzerFactory::registerFields(FieldRegister& reg) {
++    titleField = reg.registerField(titleFieldName);
++    artistField = reg.registerField(artistFieldName);
++    trackNumberField = reg.registerField(trackNumberFieldName);
++    versionField = reg.registerField(versionFieldName);
++    copyrightField = reg.registerField(copyrightFieldName);
++}
++
++// Analyzer
++void
++SidThroughAnalyzer::setIndexable(AnalysisResult* i) {
++    analysisResult = i;
++}
++
++InputStream*
++SidThroughAnalyzer::connectInputStream(InputStream* in) {
++    if( !in )
++        return in;
++
++    const char *c;
++    int version;
++    int num_songs;
++    int start_song;
++    string title;
++    string artist;
++    string copyright;
++
++    // read the beginning of the stream and make sure it looks ok
++    if (4 != in->read(c, 4, 4)) {
++       in->reset(0);   // rewind to the start of the stream
++       return in;
++    }
++    uint32_t header1 = readLittleEndianUInt32(c);
++    
++    if (strncmp((char*) &header1, "PSID", 4)) {
++        in->reset(0);
++        cout << "reset\n";
++        return in;
++    }
++
++    //read version
++    if (2 != in->read(c, 2, 2)) {
++        in->reset(0);
++        return in;
++    }
++    version = readBigEndianUInt16(c);
++
++    //jump to 0xE
++    if (8 != in->skip(8)) {
++        in->reset(0);
++        return in;
++    }
++
++    //read number of songs
++    if (2 != in->read(c, 2, 2)) {
++        in->reset(0);
++        return in;
++    }
++    num_songs = readBigEndianUInt16(c);
++
++    //start song
++    if (2 != in->read(c, 2, 2)) {
++        in->reset(0);
++        return in;
++    }
++    start_song = readBigEndianUInt16(c);
++
++    //jump to 0x16
++    if (4 != in->skip(4)) {
++        in->reset(0);
++        return in;
++    }
++
++    //title
++    if (32 != in->read(c, 32, 32)) {
++        in->reset(0);
++        return in;
++    }
++    title = c;
++
++    //artist
++    if (32 != in->read(c, 32, 32)) {
++        in->reset(0);
++        return in;
++    }
++    artist = c;
++
++    //copyright
++    if (32 != in->read(c, 32, 32)) {
++        in->reset(0);
++        return in;
++    }
++    copyright = c;
++    
++    // read the data on the 1st icon
++    analysisResult->addValue( factory->artistField, artist );
++    analysisResult->addValue( factory->titleField, title );
++    analysisResult->addValue( factory->copyrightField, copyright );
++    analysisResult->addValue( factory->trackNumberField, num_songs );
++    analysisResult->addValue( factory->versionField, version );
++    
++    in->reset(0);   // rewind to the start of the stream
++    return in;
++}
++
++bool
++SidThroughAnalyzer::isReadyWithStream() {
++    return true;
++}
++
++//Factory
++class Factory : public AnalyzerFactoryFactory {
++public:
++    list<StreamThroughAnalyzerFactory*>
++    streamThroughAnalyzerFactories() const {
++        list<StreamThroughAnalyzerFactory*> af;
++        af.push_back(new SidThroughAnalyzerFactory());
++        return af;
++    }
++};
++
++STRIGI_ANALYZER_FACTORY(Factory)
+--- /dev/null
++++ b/src/streamanalyzer/throughplugins/sidthroughanalyzer.h
+@@ -0,0 +1,71 @@
++/* This file is part of Strigi Desktop Search
++ *
++ * Copyright (C) 2007 Flavio Castelli <flavio.castelli at gmail.com>
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Library General Public
++ * License as published by the Free Software Foundation; either
++ * version 2 of the License, or (at your option) any later version.
++ *
++ * This library 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
++ * Library General Public License for more details.
++ *
++ * You should have received a copy of the GNU Library General Public License
++ * along with this library; see the file COPYING.LIB.  If not, write to
++ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
++ * Boston, MA 02110-1301, USA.
++ */
++#ifndef STRIGI_SIDTHROUGHANALYZER
++#define STRIGI_SIDTHROUGHANALYZER
++
++#include "streamthroughanalyzer.h"
++#include "analyzerplugin.h"
++
++#include <string>
++
++namespace Strigi {
++    class RegisteredField;
++}
++class SidThroughAnalyzerFactory;
++
++class STRIGI_PLUGIN_API SidThroughAnalyzer
++    : public Strigi::StreamThroughAnalyzer {
++private:
++    Strigi::AnalysisResult* analysisResult;
++    const SidThroughAnalyzerFactory* factory;
++public:
++    SidThroughAnalyzer(const SidThroughAnalyzerFactory* f) :factory(f) {}
++    ~SidThroughAnalyzer() {}
++    void setIndexable(Strigi::AnalysisResult* i);
++    Strigi::InputStream *connectInputStream(Strigi::InputStream *in);
++    bool isReadyWithStream();
++    const char* name() const { return "SidThroughAnalyzer"; }
++};
++
++class SidThroughAnalyzerFactory
++    : public Strigi::StreamThroughAnalyzerFactory {
++friend class SidThroughAnalyzer;
++private:
++    static const std::string titleFieldName;
++    static const std::string artistFieldName;
++    static const std::string copyrightFieldName;
++    static const std::string versionFieldName;
++    static const std::string trackNumberFieldName; //TODO: is this the right definition of the total number of songs available?
++    const Strigi::RegisteredField* titleField;
++    const Strigi::RegisteredField* artistField;
++    const Strigi::RegisteredField* copyrightField;
++    const Strigi::RegisteredField* versionField;
++    const Strigi::RegisteredField* trackNumberField;
++
++    const char* name() const {
++        return "SidThroughAnalyzer";
++    }
++    Strigi::StreamThroughAnalyzer* newInstance() const {
++        return new SidThroughAnalyzer(this);
++    }
++    void registerFields(Strigi::FieldRegister&);
++};
++
++#endif
+--- a/src/streamanalyzer/throughplugins/tgathroughanalyzer.cpp
++++ b/src/streamanalyzer/throughplugins/tgathroughanalyzer.cpp
+@@ -28,7 +28,7 @@
+ using namespace Strigi;
+ 
+ // AnalyzerFactory
+-const string TgaThroughAnalyzerFactory::compressionFieldName("compressed.compression_algorithm");
++const string TgaThroughAnalyzerFactory::compressionFieldName("http://freedesktop.org/standards/xesam/1.0/core#compressionAlgorithm");
+ const string TgaThroughAnalyzerFactory::colorDepthFieldName("http://freedesktop.org/standards/xesam/1.0/core#pixelDataBitDepth");
+ const string TgaThroughAnalyzerFactory::colorModeFieldName("http://freedesktop.org/standards/xesam/1.0/core#colorSpace");
+ const string TgaThroughAnalyzerFactory::widthFieldName("http://freedesktop.org/standards/xesam/1.0/core#width");
+@@ -41,6 +41,8 @@
+     colorModeField = reg.registerField(colorModeFieldName);
+     widthField = reg.registerField(widthFieldName);
+     heightField = reg.registerField(heightFieldName);
++
++    typeField = reg.typeField;
+ }
+ 
+ // Analyzer
+@@ -110,6 +112,7 @@
+ 
+     uint8_t colorDepth = *(buf+16);
+     analysisResult->addValue(factory->colorDepthField, colorDepth);
++    analysisResult->addValue(factory->typeField, "http://freedesktop.org/standards/xesam/1.0/core#Image");
+ 
+     return in;
+ }
+--- a/src/streamanalyzer/throughplugins/tgathroughanalyzer.h
++++ b/src/streamanalyzer/throughplugins/tgathroughanalyzer.h
+@@ -55,6 +55,9 @@
+     const Strigi::RegisteredField* compressionField;
+     const Strigi::RegisteredField* widthField;
+     const Strigi::RegisteredField* heightField;
++
++    const Strigi::RegisteredField* typeField;
++
+     const char* name() const {
+         return "TgaThroughAnalyzer";
+     }
+--- /dev/null
++++ b/src/streamanalyzer/throughplugins/wavthroughanalyzer.cpp
+@@ -0,0 +1,213 @@
++/* This file is part of Strigi Desktop Search, ported from code of:
++ * - Ryan Cumming <bodnar42 at phalynx.dhs.org> (Copyright (C) 2002)
++ *
++ * Copyright (C) 2007 Flavio Castelli <flavio.castelli at gmail.com>
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Library General Public
++ * License as published by the Free Software Foundation; either
++ * version 2 of the License, or (at your option) any later version.
++ *
++ * This library 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
++ * Library General Public License for more details.
++ *
++ * You should have received a copy of the GNU Library General Public License
++ * along with this library; see the file COPYING.LIB.  If not, write to
++ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
++ * Boston, MA 02110-1301, USA.
++ */
++
++#include "wavthroughanalyzer.h"
++#include "textutils.h"
++#include <strigi/strigiconfig.h>
++#include "analysisresult.h"
++#include "fieldtypes.h"
++#include <cstring>
++
++using namespace std;
++using namespace Strigi;
++
++// AnalyzerFactory
++
++
++//TODO: check values!
++const string WavThroughAnalyzerFactory::sampleSizeFieldName( "audio.sampleSize" );
++const string WavThroughAnalyzerFactory::sampleRateFieldName( "audio.sampleRate" );
++const string WavThroughAnalyzerFactory::channelsFieldName( "audio.channels" );
++const string WavThroughAnalyzerFactory::lengthFieldName ("audio.length");
++
++
++void
++WavThroughAnalyzerFactory::registerFields(FieldRegister& reg) {
++    sampleSizeField = reg.registerField(sampleSizeFieldName);
++    sampleRateField = reg.registerField(sampleRateFieldName);
++    channelsField = reg.registerField(channelsFieldName);
++    lengthField = reg.registerField(lengthFieldName);
++}
++
++// Analyzer
++void
++WavThroughAnalyzer::setIndexable(AnalysisResult* i) {
++    analysisResult = i;
++}
++
++InputStream*
++WavThroughAnalyzer::connectInputStream(InputStream* in) {
++    if( !in )
++        return in;
++
++    const char *c;
++    uint32_t format_size;
++    uint16_t format_tag;
++    uint16_t channel_count;
++    uint32_t sample_rate;
++    uint32_t bytes_per_second;
++    uint16_t bytes_per_sample;
++    uint16_t sample_size;
++    uint32_t data_size;
++    uint32_t unknown_chunk_size;
++    uint16_t unknown_chunk16;
++    bool have_fmt = false;
++    bool have_data = false;
++    bool eof = false;
++
++    static const char riff_signature[] = "RIFF";
++    static const char wav_signature[] = "WAVE";
++    static const char fmt_signature[] = "fmt ";
++    static const char data_signature[] = "data";
++    uint32_t signature_buffer;
++
++    // Remember: WAV files are little-endian
++    // Read and verify the RIFF signature
++    if (4 != in->read(c, 4, 4)) {
++        in->reset(0);   // rewind to the start of the stream
++        return in;
++    }
++    signature_buffer = readLittleEndianUInt32(c);
++
++    if (memcmp(&signature_buffer, riff_signature, 4)) {
++        in->reset(0);
++        return in;
++    }
++
++    // Skip the next bit (total file size, pretty useless)
++    if (4 != in->skip (4)) {
++        in->reset(0);
++        return in;
++    }
++
++    // Read and verify the WAVE signature
++    if (4 != in->read(c, 4, 4)) {
++        in->reset(0);   // rewind to the start of the stream
++        return in;
++    }
++    signature_buffer = readLittleEndianUInt32(c);
++
++    if (memcmp(&signature_buffer, wav_signature, 4)) {
++        in->reset(0);   // rewind to the start of the stream
++        return in;
++    }
++
++    // pretty dumb scanner, but better than what we had!
++    do
++    {
++        if (4 != in->read(c, 4, 4)) {
++            in->reset(0);   // rewind to the start of the stream
++            return in;
++        }
++        signature_buffer = readLittleEndianUInt32(c);
++        
++        if (!memcmp(&signature_buffer, fmt_signature, 4)) {
++            if (20 != in->read(c, 20, 20)) {
++                in->reset(0);   // rewind to the start of the stream
++                return in;
++            }
++
++            format_size = readLittleEndianUInt32 (c);
++            format_tag = readLittleEndianUInt16 (c+4);
++            channel_count = readLittleEndianUInt16 (c+6);
++            sample_rate = readLittleEndianUInt32 (c+8);
++            bytes_per_second = readLittleEndianUInt32 (c+12);
++            bytes_per_sample = readLittleEndianUInt16 (c+16);
++            sample_size = readLittleEndianUInt16 (c+18);
++            have_fmt = true;
++            if ( format_size > 16 ) {
++                for (unsigned int i = 0; i < (format_size-16+1)/2; i++) {
++                    if (2 != in->skip(2)) {
++                        in->reset (0);
++                        return in;
++                    }
++                }
++            }
++        }
++        else if (!memcmp(&signature_buffer, data_signature, 4)) {
++            if (4 != in->read(c, 4, 4)) {
++                in->reset(0);   // rewind to the start of the stream
++                return in;
++            }
++            data_size = readLittleEndianUInt32 (c);
++            have_data = true;
++        }
++        else {
++            if (4 != in->read(c, 4, 4)) {
++                in->reset(0);   // rewind to the start of the stream
++                return in;
++            }
++            unknown_chunk_size = readLittleEndianUInt32 (c);
++            for (unsigned int i = 0; i < (unknown_chunk_size+1)/2; i++) {
++                if (in->skip (2)) {
++                    in->reset(0);   // rewind to the start of the stream
++                    return in;
++                }
++            }
++        }
++        if (have_data && have_fmt)
++            break;
++
++        if (1 != in->read(c, 1, 1))
++            eof = true;
++        else
++            in->reset(in->position() - 1);
++        
++    } while (!eof);
++
++    if ( (!have_data) || (!have_fmt) ) {
++        in->reset (0);
++        return in;
++    }
++
++    // These values are downright illegal
++    if ((!channel_count) || (!bytes_per_second)) {
++        in->reset (0);
++        return in;
++    }
++
++    analysisResult->addValue( factory->sampleSizeField, sample_size );
++    analysisResult->addValue( factory->sampleRateField, sample_rate);
++    analysisResult->addValue( factory->channelsField, channel_count);
++    unsigned int wav_seconds = data_size / bytes_per_second;
++    analysisResult->addValue( factory->lengthField, wav_seconds);
++
++    in->reset(0);   // rewind to the start of the stream
++    return in;
++}
++
++bool
++WavThroughAnalyzer::isReadyWithStream() {
++    return true;
++}
++
++//Factory
++class Factory : public AnalyzerFactoryFactory {
++public:
++    list<StreamThroughAnalyzerFactory*>
++    streamThroughAnalyzerFactories() const {
++        list<StreamThroughAnalyzerFactory*> af;
++        af.push_back(new WavThroughAnalyzerFactory());
++        return af;
++    }
++};
++
++STRIGI_ANALYZER_FACTORY(Factory)
+--- /dev/null
++++ b/src/streamanalyzer/throughplugins/wavthroughanalyzer.h
+@@ -0,0 +1,69 @@
++/* This file is part of Strigi Desktop Search
++ *
++ * Copyright (C) 2007 Flavio Castelli <flavio.castelli at gmail.com>
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Library General Public
++ * License as published by the Free Software Foundation; either
++ * version 2 of the License, or (at your option) any later version.
++ *
++ * This library 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
++ * Library General Public License for more details.
++ *
++ * You should have received a copy of the GNU Library General Public License
++ * along with this library; see the file COPYING.LIB.  If not, write to
++ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
++ * Boston, MA 02110-1301, USA.
++ */
++#ifndef STRIGI_WAVTHROUGHANALYZER
++#define STRIGI_WAVTHROUGHANALYZER
++
++#include "streamthroughanalyzer.h"
++#include "analyzerplugin.h"
++
++#include <string>
++
++namespace Strigi {
++    class RegisteredField;
++}
++class WavThroughAnalyzerFactory;
++
++class STRIGI_PLUGIN_API WavThroughAnalyzer
++    : public Strigi::StreamThroughAnalyzer {
++private:
++    Strigi::AnalysisResult* analysisResult;
++    const WavThroughAnalyzerFactory* factory;
++public:
++    WavThroughAnalyzer(const WavThroughAnalyzerFactory* f) :factory(f) {}
++    ~WavThroughAnalyzer() {}
++    void setIndexable(Strigi::AnalysisResult* i);
++    Strigi::InputStream *connectInputStream(Strigi::InputStream *in);
++    bool isReadyWithStream();
++    const char* name() const { return "WavThroughAnalyzer"; }
++};
++
++class WavThroughAnalyzerFactory
++    : public Strigi::StreamThroughAnalyzerFactory {
++friend class WavThroughAnalyzer;
++private:
++    static const std::string sampleSizeFieldName;
++    static const std::string sampleRateFieldName;
++    static const std::string channelsFieldName;
++    static const std::string lengthFieldName;
++    const Strigi::RegisteredField* sampleSizeField;
++    const Strigi::RegisteredField* sampleRateField;
++    const Strigi::RegisteredField* channelsField;
++    const Strigi::RegisteredField* lengthField;
++
++    const char* name() const {
++        return "WavThroughAnalyzer";
++    }
++    Strigi::StreamThroughAnalyzer* newInstance() const {
++        return new WavThroughAnalyzer(this);
++    }
++    void registerFields(Strigi::FieldRegister&);
++};
++
++#endif
+--- a/src/streamanalyzer/throughplugins/xbmthroughanalyzer.cpp
++++ b/src/streamanalyzer/throughplugins/xbmthroughanalyzer.cpp
+@@ -30,19 +30,17 @@
+ // AnalyzerFactory
+ const string XbmThroughAnalyzerFactory::widthFieldName("http://freedesktop.org/standards/xesam/1.0/core#width");
+ const string XbmThroughAnalyzerFactory::heightFieldName("http://freedesktop.org/standards/xesam/1.0/core#height");
+-const string XbmThroughAnalyzerFactory::xHotFieldName("cursor.hot_spot.x");
+-const string XbmThroughAnalyzerFactory::yHotFieldName("cursor.hot_spot.y");
++const string XbmThroughAnalyzerFactory::xHotFieldName("http://strigi.sf.net/ontologies/0.9#hotSpotX");
++const string XbmThroughAnalyzerFactory::yHotFieldName("http://strigi.sf.net/ontologies/0.9#hotSpotY");
+ 
+ void
+ XbmThroughAnalyzerFactory::registerFields(FieldRegister& reg) {
+-    widthField = reg.registerField(widthFieldName,
+-        FieldRegister::integerType, 1, 0);
+-    heightField = reg.registerField(heightFieldName,
+-        FieldRegister::integerType, 1, 0);
+-    xHotField = reg.registerField(xHotFieldName,
+-        FieldRegister::integerType, 1, 0);
+-    yHotField = reg.registerField(yHotFieldName,
+-        FieldRegister::integerType, 1, 0);
++    widthField = reg.registerField(widthFieldName);
++    heightField = reg.registerField(heightFieldName);
++    xHotField = reg.registerField(xHotFieldName);
++    yHotField = reg.registerField(yHotFieldName);
++
++    typeField = reg.typeField;
+ }
+ 
+ // Analyzer
+@@ -141,6 +139,8 @@
+         }
+     }
+ 
++    analysisResult->addValue(factory->typeField, "http://strigi.sf.net/ontologies/0.9#Cursor");
++
+     return in;
+ }
+ 
+--- a/src/streamanalyzer/throughplugins/xbmthroughanalyzer.h
++++ b/src/streamanalyzer/throughplugins/xbmthroughanalyzer.h
+@@ -56,6 +56,9 @@
+     const Strigi::RegisteredField* heightField;
+     const Strigi::RegisteredField* xHotField;
+     const Strigi::RegisteredField* yHotField;
++
++    const Strigi::RegisteredField* typeField;
++
+     const char* name() const {
+         return "XbmThroughAnalyzer";
+     }
+--- a/src/streamanalyzer/variant.cpp
++++ b/src/streamanalyzer/variant.cpp
+@@ -64,7 +64,9 @@
+ Variant::Variant(const Variant& v) :p(new VariantPrivate(*v.p)) {
+ }
+ Variant::~Variant() {
++  delete p;
+ }
++
+ Variant::Type
+ Variant::type() const { return p->vartype; }
+ const Variant&
+--- a/src/streamanalyzer/xesam/StrigiQueryBuilder.cc
++++ b/src/streamanalyzer/xesam/StrigiQueryBuilder.cc
+@@ -139,7 +139,7 @@
+ 
+     STRIGI_LOG_DEBUG ("StrigiQueryBuilder.on_selection", msg.str())
+ 
+-    msg.clear();
++    msg.str("");
+     msg << "field names are ";
+ 
+     for (set<string>::const_iterator iter = field_names.begin();
+@@ -163,11 +163,11 @@
+     //TODO: handle modifiers.m_phrase
+     parsedQuery.term().setSlack(modifiers.m_slack);
+ 
+-    msg.clear();
++    msg.str("");
+     msg << "there're " << field_values.size() << " field values";
+     STRIGI_LOG_DEBUG ("StrigiQueryBuilder.on_selection", msg.str())
+ 
+-    msg.clear();
++    msg.str("");
+     msg << "field values are ";
+ 
+     for (vector<string>::const_iterator valueIter = field_values.begin();
+@@ -184,7 +184,7 @@
+ 
+     parsedQuery.setNegate(modifiers.m_negate);
+ 
+-    msg.clear();
++    msg.str("");
+     msg << "collector is | "
+         << (m_collector.m_collector == And ? "AND" : "OR" ) << " |";
+     STRIGI_LOG_DEBUG ("StrigiQueryBuilder.on_selection", msg.str())
+--- a/src/streamanalyzer/xesam/XesamQLParser.cc
++++ b/src/streamanalyzer/xesam/XesamQLParser.cc
+@@ -212,7 +212,7 @@
+         return true;
+     }
+ 
+-    msg.clear();
++    msg.str("");
+     msg << pLocalName << " " << xmlTextReaderHasValue(reader);
+     STRIGI_LOG_DEBUG ("XesamQLParser.process_node",msg.str())
+ 
+@@ -220,7 +220,7 @@
+     {
+         if (xmlStrncmp(pLocalName, BAD_CAST"request", 7) != 0)
+         {
+-            msg.clear();
++            msg.str("");
+             msg << "expected request, found " << pLocalName;
+             STRIGI_LOG_ERROR ("XesamQLParser.process_node", msg.str())
+ 
+--- a/src/strigicmd/strigicmd.cpp
++++ b/src/strigicmd/strigicmd.cpp
+@@ -45,39 +45,6 @@
+ map<char, string> options;
+ vector<string> arguments;
+ 
+-AnalyzerConfiguration::FieldType
+-operator|(AnalyzerConfiguration::FieldType a, AnalyzerConfiguration::FieldType b){
+-    return static_cast<AnalyzerConfiguration::FieldType>((int)a|(int)b);
+-}
+-
+-class CustomAnalyzerConfiguration: public AnalyzerConfiguration {
+-public:
+-
+-//    None       = 0x0000 /**< No hint. */,
+-//    Binary     = 0x0001 /**< The field should be stored as binary data. */,
+-//    Compressed = 0x0002 /**< If the field is stored, the data
+-//                             should be compressed. */,
+-//    Indexed    = 0x0004 /**< The field should be indexed. */,
+-//    Stored     = 0x0020 /**< The field should be stored. */,
+-//    Tokenized  = 0x0040 /**< If the field contains text, it
+-//                             should be tokenized. */
+-    AnalyzerConfiguration::FieldType indexType(const RegisteredField* field) const {
+-	if (string("chemistry.inchi").compare(field->key()) == 0) {
+-	    return Stored|Indexed;
+-	} else if (string("chemistry.molecular_formula").compare(field->key()) == 0) {
+-	    return Stored|Indexed;
+-/*	} else if (string("chemistry.").compare(field->key()) == 0) {
+-	    return Binary|Stored|Indexed;
+-	} else if (string("chemistry.").compare(field->key()) == 0) {
+-	    return Binary|Stored|Indexed;
+-	} else if (string("chemistry.").compare(field->key()) == 0) {
+-	    return Binary|Stored|Indexed; */
+-	} else {
+-	    return Tokenized|Stored|Indexed;
+-	}
+-    }
+-};
+-
+ void
+ parseArguments(int argc, char** argv) {
+     // parse arguments
+@@ -127,7 +94,7 @@
+     pe("  %s create [-j num] -t backend -d indexdir [-i include] [-x exclude] files/dirs\n", cmd);
+     pe("  %s deindex -t backend -d indexdir files/dirs\n", cmd);
+     pe("  %s get -t backend -d indexdir files\n", cmd);
+-    pe("  %s listFiles -t backend -d indexdir\n", cmd);
++    pe("  %s listFiles -t backend -d indexdir [parent dir]\n", cmd);
+     pe("  %s listFields -t backend -d indexdir\n", cmd);
+     //TODO: find a better definition for query?
+     pe("  %s query -t backend -d indexdir queries\n", cmd);
+@@ -278,7 +245,6 @@
+     filters.push_back(make_pair<bool,string>(true, included_filter));
+     filters.push_back(make_pair<bool,string>(false, excluded_filter));
+     
+-    //CustomAnalyzerConfiguration config;
+     AnalyzerConfiguration config;
+     config.setFilters(filters);
+ 
+@@ -368,8 +334,17 @@
+     if (manager == 0) {
+         return usage(argc, argv);
+     }
++
+     IndexReader* reader = manager->indexReader();
+-    listFiles(reader, "");
++    if (arguments.empty())
++        listFiles(reader, "");
++
++    for (vector<string>::iterator iter = arguments.begin();
++         iter != arguments.end(); iter++) {
++        cout << "indexed files under " << *iter << endl;
++        listFiles(reader, *iter);
++    }
++    
+     IndexPluginLoader::deleteIndexManager(manager);
+     return 0;
+ }
+--- a/src/xmlindexer/xmlindexwriter.h
++++ b/src/xmlindexer/xmlindexwriter.h
+@@ -79,11 +79,14 @@
+                 out << "&lt;";
+             } else if (c == '>') {
+                 out << "&gt;";
+-            } else if (isspace(c)) {
+-                if (!lastwhite) {
++            } else if (isspace(c) != 0) {
++                // we've to handle dos formatting
++                //'\r' char is ignored, it isn't wroten to out and doesn't
++                //change lastwhite value (so the following '\n' will be handled)
++                if (!lastwhite && (c!= '\r')) {
+                     out.put(c);
++                    lastwhite = true;
+                 }
+-                lastwhite = true;
+             } else {
+                 lastwhite = false;
+                 out.put(c);
+--- a/src/xsd/CMakeLists.txt
++++ b/src/xsd/CMakeLists.txt
+@@ -20,7 +20,8 @@
+ endif (LIBXML2_FOUND)
+ 
+ # java is required to compile the xsd parser
+-find_package(Java REQUIRED)
++OPTION(ENABLE_REGENERATEXSD "regenerate xsd parser from *.xsd files(not normally required)" ON)
++FIND_OPTIONAL_DEP(Java ENABLE_REGENERATEXSD JAVA_COMPILE "generating xsd parser from *.xsd files")
+ 
+ # loop over all xsd files, the next line does not work everywhere,
+ # so we dont use it currently
+@@ -57,4 +58,3 @@
+   target_link_libraries(${XSDNAME}test ${XSDNAME} xmlstream)
+ 
+ endforeach (XSDFILE ${XSDFILES})
+-
+--- a/tests/CMakeLists.txt
++++ b/tests/CMakeLists.txt
+@@ -8,7 +8,9 @@
+ 
+ # cppunit requires exception support
+ IF(NOT WIN32)
+-    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fexceptions")
++    IF (CMAKE_COMPILER_IS_GNUCXX)
++        set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fexceptions")
++    ENDIF(CMAKE_COMPILER_IS_GNUCXX)
+ ENDIF(NOT WIN32)
+ 
+ # a convenience library that adds a unified way of build a test executable
+--- a/tests/indextesters/indextest.cpp
++++ b/tests/indextesters/indextest.cpp
+@@ -17,6 +17,9 @@
+  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  * Boston, MA 02110-1301, USA.
+  */
++
++#include <stdlib.h>
++
+ #include "indextest.h"
+ #include "indexmanager.h"
+ #include "indexpluginloader.h"
+--- a/tests/streamanalyzer/xesam/xesam2strigitest.cpp
++++ b/tests/streamanalyzer/xesam/xesam2strigitest.cpp
+@@ -25,6 +25,7 @@
+ #include <fstream>
+ #include <stdlib.h>
+ #include <unistd.h>
++#include <string.h>
+ 
+ using namespace std;
+ using namespace strigiunittest;
+--- a/tests/test_runner.cpp
++++ b/tests/test_runner.cpp
+@@ -20,13 +20,19 @@
+ 
+ #include <cppunit/TestCaller.h>
+ #include <cppunit/extensions/TestFactoryRegistry.h>
++#include <cppunit/CompilerOutputter.h>
++#include <cppunit/TextTestProgressListener.h>
+ #include <cppunit/TestResult.h>
+ #include <cppunit/TextTestRunner.h>
++#include <cppunit/TestResultCollector.h>
++#include <stdexcept>
+ 
+ #include "strigilogging.h"
+ #include "config.h"
+ 
+ #include <iostream>
++#include <stdlib.h>
++
+ using namespace std;
+ 
+ int main() {
+@@ -41,24 +47,48 @@
+         BINARYDIR"/src/estraierindexer:"
+         BINARYDIR"/src/sqliteindexer", 1);
+ 
+-cerr << BINARYDIR << endl;
++    cerr << BINARYDIR << endl;
+ 
+     STRIGI_LOG_INIT_BASIC()
+ 
+     // Get the top level suite from the registry
+-    CppUnit::Test *suite = CppUnit::TestFactoryRegistry::getRegistry().makeTest();
++    CppUnit::Test *suite;
++    suite = CppUnit::TestFactoryRegistry::getRegistry().makeTest();
+ 
+     // Adds the test to the list of test to run
+     CppUnit::TextTestRunner runner;
+     runner.addTest( suite );
++    
++    // Create the event manager and test controller
++    CppUnit::TestResult controller;
++
++    // Add a listener that colllects test result
++    CppUnit::TestResultCollector result;
++    controller.addListener( &result );
++
++    // Add a listener that print dots as test run.
++    CppUnit::TextTestProgressListener progress;
++    controller.addListener( &progress );
++
++    try
++    {
++//         std::cout << "Running "  <<  testPath;
++        runner.run( controller);
++
++        std::cerr << std::endl;
++
++     // Print test in a compiler compatible format.
++        CppUnit::CompilerOutputter outputter( &result, std::cerr );
++        outputter.write();
++    }
++    catch ( std::invalid_argument &e )  // Test path not resolved
++    {
++        std::cerr  <<  std::endl
++                <<  "ERROR: "  <<  e.what()
++                << std::endl;
++        return 0;
++    }
+ 
+-    // Change the default outputter to a compiler error format outputter
+-//     runner.setOutputter( new CppUnit::CompilerOutputter( &runner.result(),
+-//                          std::cerr ) );
+-  // Run the tests.
+-    bool wasSucessful = runner.run();
+-
+-  // Return error code 1 if the one of test failed.
+-    return wasSucessful ? 0 : 1;
++    return result.wasSuccessful() ? 0 : 1;
+ }
+ 

Modified: kde-extras/strigi/trunk/debian/patches/series
===================================================================
--- kde-extras/strigi/trunk/debian/patches/series	2008-01-13 01:38:36 UTC (rev 8941)
+++ kde-extras/strigi/trunk/debian/patches/series	2008-01-13 11:15:45 UTC (rev 8942)
@@ -1 +1 @@
-01_strigi_branch_r729946.diff
+01_strigi_branch_r760102.diff

Modified: kde-extras/strigi/trunk/debian/rules
===================================================================
--- kde-extras/strigi/trunk/debian/rules	2008-01-13 01:38:36 UTC (rev 8941)
+++ kde-extras/strigi/trunk/debian/rules	2008-01-13 11:15:45 UTC (rev 8942)
@@ -4,14 +4,22 @@
 UPFILENAME = $(DEB_SOURCE_PACKAGE)-$(shell echo $(DEB_UPSTREAM_VERSION) | sed 's/~/-/').tar.bz2
 URL = http://www.vandenoever.info/software/strigi/$(UPFILENAME)
 
-include debian/cmake.mk
+include /usr/share/cdbs/1/class/cmake.mk
 include /usr/share/cdbs/1/rules/debhelper.mk
 include /usr/share/cdbs/1/rules/patchsys-quilt.mk
 include /usr/share/cdbs/1/rules/utils.mk
 
-#DEB_CMAKE_EXTRA_FLAGS = -DCMAKE_BUILD_TYPE=debugfull -DENABLE_DBUS:BOOL=ON -DENABLE_INOTIFY:BOOL=OFF -DENABLE_LOG4CXX:BOOL=OFF
-DEB_DH_INSTALL_ARGS = --sourcedir=debian/tmp
-#DEB_STRIP_EXCLUDE = so
+CURRENTVERSION := $(shell head -1 debian/changelog | sed 's/[^(]*(\([^)]*\)).*/\1/')
+
+#DEB_CMAKE_EXTRA_FLAGS := -DCMAKE_BUILD_TYPE=debugfull -DENABLE_DBUS:BOOL=ON -DENABLE_INOTIFY:BOOL=OFF -DENABLE_LOG4CXX:BOOL=OFF
+DEB_CMAKE_EXTRA_FLAGS += \
+	-DCMAKE_CXX_COMPILER:FILEPATH="g++" \
+	-DCMAKE_SHARED_LINKER_FLAGS="-Wl,--no-undefined -Wl,--as-needed" \
+	-DCMAKE_MODULE_LINKER_FLAGS="-Wl,--no-undefined -Wl,--as-needed" \
+	-DCMAKE_EXE_LINKER_FLAGS="-Wl,--no-undefined -Wl,--as-needed"
+DEB_DH_INSTALL_ARGS := --sourcedir=debian/tmp
+DEB_DH_MAKESHLIBS_ARGS_ALL := -V
+#DEB_STRIP_EXCLUDE := so
 #DEB_STRIP_EXCLUDE += strigi
 
 binary-install/deskbar-plugins-strigi::
@@ -19,6 +27,10 @@
 		debian/deskbar-plugins-strigi/usr/lib/deskbar-applet/handlers/strigi.py
 	dh_pysupport /usr/lib/deskbar-applet/handlers
 
+clean::
+	# generate on build
+	rm -f debian/shlibs.local
+
 get-orig-source:
 	@@dh_testdir
 	@@[ -d ../tarballs/. ]||mkdir -p ../tarballs
@@ -27,3 +39,9 @@
 	@@echo Converting $(UPFILENAME) to $(FILENAME)
 	@@bzcat ../tarballs/$(UPFILENAME) | gzip -9 > ../tarballs/$(FILENAME)
 
+# Generate shlibs local files
+$(patsubst %,binary-fixup/%,$(DEB_ALL_PACKAGES)) :: binary-fixup/%: binary-strip/%
+	if test -e debian/$(cdbs_curpkg)/DEBIAN/shlibs ; then \
+		sed 's/>=[^)]*/= $(CURRENTVERSION)/' debian/$(cdbs_curpkg)/DEBIAN/shlibs >> debian/shlibs.local ;\
+	fi
+




More information about the pkg-kde-commits mailing list