diff --git a/hamster/applet.py b/hamster/applet.py
index d55e827..d312508 100755
--- a/hamster/applet.py
+++ b/hamster/applet.py
@@ -40,7 +40,7 @@ from hamster.configuration import GconfStore
 
 from hamster import stuff
 from hamster.KeyBinder import *
-from hamster.hamsterdbus import HAMSTER_URI, HamsterDbusController 
+from hamster.hamsterdbus import HAMSTER_URI, HamsterDbusController
 
 # controllers for other windows
 from hamster.edit_activity import CustomFactController
@@ -546,9 +546,6 @@ Now, start tracking!
             self._gui.get_object('stop_tracking').set_sensitive(0);
         
         
-        # Hamster DBusController current activity updating
-        self.dbusController.update_activity(label)
-
     def check_user(self):
         if not self.notify_interval: #no interval means "never"
             return
@@ -698,12 +695,15 @@ Now, start tracking!
 
     def __update_fact(self):
         """dbus controller current fact updating"""
-        if self.last_activity and self.last_activity['end_time'] is None:
-            self.dbusController.update_fact(self.last_activity["name"])
+        last_activity_id = 0
+        
+        if not self.last_activity:
+            self.dbusController.TrackingStopped()
         else:
-            self.dbusController.update_fact(_(u'No activity'))
-
+            last_activity_id = self.last_activity['id']
 
+        self.dbusController.FactUpdated(last_activity_id)
+            
     def __show_toggle(self, event, is_active):
         """main window display and positioning"""
         self.button.set_active(is_active)
@@ -887,7 +887,6 @@ Now, start tracking!
     def after_fact_update(self, event, date):
         self.load_day()
         self.update_label()
-    
         self.__update_fact()
 
     """global shortcuts"""
diff --git a/hamster/hamsterdbus.py b/hamster/hamsterdbus.py
index d89c6f3..b86d84b 100644
--- a/hamster/hamsterdbus.py
+++ b/hamster/hamsterdbus.py
@@ -1,6 +1,7 @@
 # - coding: utf-8 -
 
 # Copyright (C) 2008, J. Félix Ontañón <fontanon at emergya dot es>
+# Thanks to John Carr for helpful patching
 
 # This file is part of Project Hamster.
 
@@ -19,29 +20,206 @@
 
 import dbus
 import dbus.service
+import datetime
+from calendar import timegm
 
-HAMSTER_URI = "org.gnome.hamster"
-HAMSTER_PATH = "/org/gnome/hamster"
+from hamster import storage
+
+# DBus service parameters
+HAMSTER_URI = "org.gnome.Hamster"
+HAMSTER_PATH = "/org/gnome/Hamster"
+
+# Data-keys used in hamster to refer 
+# facts, categories and activities
+FCT_KEY = 'id'
+ACT_KEY = 'name'
+CAT_KEY = 'category'
+DSC_KEY = 'description'
+SRT_KEY = 'start_time'
+END_KEY = 'end_time'
 
 class HamsterDbusController(dbus.service.Object):
-    activity = "Undefined"
-    fact = "Undefined"
+    # Non-initialized current fact id
+    current_fact_id = 0
 
     def __init__(self, bus_name):
+        """HamsterDbusController encapsulates the dbus api logic
+        for the hamster-applet and performs the necesary conversion
+        between dbus types and hamster-applet data types
+        """
         dbus.service.Object.__init__(self, bus_name, HAMSTER_PATH)
 
-    @dbus.service.method(HAMSTER_URI)
-    def get_activity(self):
-        return self.activity
+    @staticmethod
+    def to_dbus_fact(fact):
+        """Perform the conversion between fact database query and 
+        dbus supported data types
+        """
 
-    @dbus.service.signal(HAMSTER_URI)
-    def update_activity(self, activity):
-        self.activity = activity
+        # Default fact values
+        dbus_fact = {FCT_KEY: 0, ACT_KEY:'', CAT_KEY:'', DSC_KEY:'',
+                SRT_KEY:0, END_KEY:0}
+
+        if fact:
+            # Workaround for fill values
+            fact_keys = fact.keys()
+
+            for key in (FCT_KEY, ACT_KEY, CAT_KEY, DSC_KEY):
+                if key in fact_keys and fact[key]: 
+                    dbus_fact[key] = fact[key]
+    
+            for key in (SRT_KEY, END_KEY):
+                if key in fact_keys and fact[key]:
+                    # Convert datetime to unix timestamp (seconds since epoch)
+                    dbus_fact[key] = timegm(fact[key].timetuple())
+
+        return dbus_fact
+
+    @dbus.service.method(HAMSTER_URI, out_signature='a{sv}')
+    def GetCurrentFact(self):
+        """Gets the current displaying fact
+        Returns Dict of:
+        i id: Unique fact identifier
+        s name: Activity name
+        s category: Category name
+        s description: Description of the fact
+        u start_time: Seconds since epoch (timestamp)
+        u end_time: Seconds since epoch (timestamp)
+        """
+        return HamsterDbusController.to_dbus_fact(storage.get_last_activity())
+
+    @dbus.service.method(HAMSTER_URI, in_signature='i', out_signature='a{sv}')
+    def GetFactById(self, fact_id):
+        """Gets the current displaying fact
+        Parameters:
+        i id: Unique fact identifier
+        Returns Dict of:
+        i id: Unique fact identifier
+        s name: Activity name
+        s category: Category name
+        s description: Description of the fact
+        u start_time: Seconds since epoch (timestamp)
+        u end_time: Seconds since epoch (timestamp)
+        """
+        return HamsterDbusController.to_dbus_fact(storage.get_fact(fact_id))
+
+    @dbus.service.method(HAMSTER_URI, out_signature='a(ss)')
+    def GetActivities(self):
+        """Gets all defined activities with matching category
+        Returns Array of:
+        s activity: Activity name
+        s category: Category name
+        """
+        activities = []
+        for act in storage.get_autocomplete_activities():
+            activities.append((act[ACT_KEY] or '', act[CAT_KEY] or ''))
+        return activities
+
+    @dbus.service.method(HAMSTER_URI, out_signature='as')
+    def GetCategories(self):
+        """Gets all defined categories
+        Returns Array of:
+        s category: Category name
+        """
+        categories = []
+        for i in storage.get_category_list():
+            categories.append(i[ACT_KEY] or '')
+        return categories
+
+    @dbus.service.method(HAMSTER_URI, in_signature='suu', out_signature='i')
+    def AddFact(self, activity, start_time, end_time):
+        """Add a new fact
+        Parameters:
+        s activity: Activity name with optional category and/or description
+                    in the form 'activity_name[@category_name][,description]'
+                    Activity and matching category will be refered or created 
+                    on the fly.
+        u start_time: Seconds since epoch (timestamp). Use 0 for 'now'
+        u end_time: Seconds since epoch (timestamp). 
+                    Use 0 for i 'in progress task'
+        """
+        #TODO: Assert start > end ?
+        start, end = None, None
+
+        if start_time:
+            start = datetime.datetime.utcfromtimestamp(start_time)
+        if end_time:
+            end = datetime.datetime.utcfromtimestamp(end_time)
+
+        fact = storage.add_fact(activity, start, end)
+        return fact[FCT_KEY]
+
+    @dbus.service.method(HAMSTER_URI, in_signature='ss')
+    def AddActivity(self, activity, category):
+        """Add a new activity
+        Parameters:
+        s activity: Activity name
+        s category: Category name. It will be created if it doesn't exists
+                    Use '' for Unsorted activity
+        """
+        category_id = None
+
+        if category:
+            category_id = storage.get_category_by_name(category) \
+                    or storage.add_category(category)
+
+        storage.add_activity(activity, category_id)
+
+    @dbus.service.method(HAMSTER_URI, in_signature='s')
+    def AddCategory(self, category):
+        """Add a new category
+        Parameters:
+        s category: category name
+        """
+        if category and not storage.get_category_by_name(category):
+            storage.add_category(category)
 
     @dbus.service.method(HAMSTER_URI)
-    def get_fact(self):
-        return self.fact
+    def StopTracking(self):
+        """Stops the current fact tracking"""
+        last_activity = storage.get_last_activity()
+        if last_activity:
+            storage.touch_fact(last_activity)
+
+    @dbus.service.method(HAMSTER_URI, in_signature='i')
+    def RemoveFact(self, fact_id):
+        """Removes a fact
+        Parameters:
+        i id: Unique fact identifier
+        """
+        storage.remove_fact(fact_id)
+
+    @dbus.service.method(HAMSTER_URI, in_signature='ss')
+    def RemoveActivity(self, activity, category):
+        """Removes an activity
+        Parameters:
+        s activity: Activity name
+        s category: Category name. Use '' for Unsorted activity
+        """
+        category_id = storage.get_category_by_name(category)
+        activity_id = storage.get_activity_by_name(activity, category_id)
+
+        if activity_id:
+            storage.remove_activity(activity_id)
+
+    @dbus.service.method(HAMSTER_URI, in_signature='s')
+    def RemoveCategory(self, category):
+        """Removes a category
+        Parameters:
+        s category: Category name
+        """
+        category_id = storage.get_category_by_name(category)
+        if category_id:
+            storage.remove_category(category_id)
+
+    @dbus.service.signal(HAMSTER_URI, signature='i')
+    def FactUpdated(self, fact_id):
+        """Notice fact changes
+        Parameters:
+        i id: Unique fact identifier
+        """
+        self.current_fact_id = fact_id
 
     @dbus.service.signal(HAMSTER_URI)
-    def update_fact(self, fact):
-        self.fact = fact
+    def TrackingStopped(self):
+        """Notice the fact tracking has been stopped"""
+        self.current_fact_id = 0
diff --git a/hamster/storage.py b/hamster/storage.py
index f56fbeb..d83e1c4 100644
--- a/hamster/storage.py
+++ b/hamster/storage.py
@@ -119,4 +119,9 @@ class Storage(object):
 
     def get_category_list(self):
         return self.__get_category_list()
-        
+
+    def get_category_by_name(self, category):
+        return self.__get_category_by_name(category)
+
+    def get_activity_by_name(self, activity, category_id):
+        return self.__get_activity_by_name(activity, category_id)
diff --git a/tests/hamsterdbus_test.py b/tests/hamsterdbus_test.py
new file mode 100644
index 0000000..6bb0b28
--- /dev/null
+++ b/tests/hamsterdbus_test.py
@@ -0,0 +1,174 @@
+import dbus
+import unittest
+import datetime as dt
+
+from string import letters
+from random import choice
+from calendar import timegm
+
+from hamster.hamsterdbus import HAMSTER_PATH, HAMSTER_URI
+
+def rndstr(length=10):
+    result = ''
+    for i in range(1,10): 
+        result += choice(letters)
+
+    return result
+
+class TestTracking(unittest.TestCase):
+    def setUp(self):
+        self.bus = dbus.SessionBus()
+        self.hamster = self.bus.get_object(HAMSTER_URI, HAMSTER_PATH)
+
+        self.addfact = self.hamster.get_dbus_method('AddFact')
+        self.getfactbyid = self.hamster.get_dbus_method('GetFactById')
+        self.removefact = self.hamster.get_dbus_method('RemoveFact')
+        self.getcurrentfact = self.hamster.get_dbus_method('GetCurrentFact')
+        self.addactivity = self.hamster.get_dbus_method('AddActivity')
+        self.getactivities = self.hamster.get_dbus_method('GetActivities')
+        self.removeactivity = self.hamster.get_dbus_method('RemoveActivity')
+        self.addcategory = self.hamster.get_dbus_method('AddCategory')
+        self.getcategories = self.hamster.get_dbus_method('GetCategories')
+        self.removecategory = self.hamster.get_dbus_method('RemoveCategory')
+        self.stoptracking = self.hamster.get_dbus_method('StopTracking')
+
+    def test_addfact(self):
+        fact = self.__rndfactgenerator()
+
+        activity = fact['name'] + '@' + fact['category'] + ',' + \
+                fact['description']
+        fact_id = self.addfact(activity, fact['start_time'], fact['end_time'])
+        self.failUnless(type(fact_id) == dbus.Int32 and fact_id != 0, 
+            'expected non-zero dbus.Int32 as return value')
+
+        dbfact = self.getfactbyid(fact_id)
+        self.assertEqual(fact['name'], dbfact['name'], 
+                'expected same activity name')
+        self.assertEqual(fact['category'], dbfact['category'], 
+                'expected same category name')
+        self.assertEqual(fact['description'], dbfact['description'], 
+                'expected same description name')
+        self.assertEqual(fact['start_time'], dbfact['start_time'], 
+                'expected same start_time')
+        self.assertEqual(fact['end_time'], dbfact['end_time'], 
+                'expected same end_time')
+
+        self.removeactivity(dbfact['name'], dbfact['category'])
+        result = self.__findactivity(dbfact['name'], dbfact['category'])
+        self.assertFalse(result, 'not expecting %s@%s in database' % \
+                (dbfact['name'], dbfact['category']))
+
+        self.removecategory(dbfact['category'])
+        result = self.__findcategory(dbfact['category'])
+        self.assertFalse(result, 'not expecting %s in database' % \
+                dbfact['category'])
+
+        self.removefact(fact_id)
+        deletedfact = self.getfactbyid(fact_id)
+        self.assertEqual(deletedfact['name'], '', 
+                'expected no name on deleted fact')
+        self.assertEqual(deletedfact['category'], '', 
+                'expected no category on deleted fact')
+        self.assertEqual(deletedfact['description'], '',
+                'expected no description on deleted fact')
+        self.assertEqual(deletedfact['start_time'], 0,
+                'expected no start_time on deleted fact')
+        self.assertEqual(deletedfact['end_time'], 0, 
+                'expected no end_time on deleted fact')
+
+    def test_getcurrent_stop(self):
+        fact = self.__rndfactgenerator()
+
+        activity = fact['name'] + '@' + fact['category'] + ',' + \
+                fact['description']
+        fact_id = self.addfact(activity, fact['start_time'], 0)
+        self.failUnless(type(fact_id) == dbus.Int32 and fact_id != 0, 
+            'expected non-zero dbus.Int32 as return value')
+
+        current = self.getcurrentfact()
+        self.assertEqual(fact['name'], current['name'], 
+                'expected same activity name')
+        self.assertEqual(fact['category'], current['category'], 
+                'expected same category name')
+        self.assertEqual(fact['description'], current['description'], 
+                'expected same description name')
+        self.assertEqual(fact['start_time'], current['start_time'], 
+                'expected same start_time')
+        self.assertEqual(0, current['end_time'], 
+                'expected same end_time')
+
+        self.stoptracking()
+        current = self.getcurrentfact()
+        self.assertEqual(current['name'], '', 
+                'expected no name on deleted fact')
+        self.assertEqual(current['category'], '', 
+                'expected no category on deleted fact')
+        self.assertEqual(current['description'], '',
+                'expected no description on deleted fact')
+        self.assertEqual(current['start_time'], 0,
+                'expected no start_time on deleted fact')
+        self.assertEqual(current['end_time'], 0, 
+                'expected no end_time on deleted fact')
+
+        self.removeactivity(fact['name'], fact['category'])
+        result = self.__findactivity(fact['name'], fact['category'])
+        self.assertFalse(result, 'not expecting %s@%s in database' % \
+                (fact['name'], fact['category']))
+
+        self.removecategory(fact['category'])
+        result = self.__findcategory(fact['category'])
+        self.assertFalse(result, 'not expecting %s in database' % \
+                fact['category'])
+
+    def test_activity(self):
+        act = rndstr()
+        cat = rndstr()
+
+        self.addactivity(act, cat)
+        result = self.__findactivity(act, cat)
+        self.assertTrue(result, 'expecting %s@%s has been created' % (act, cat))
+
+        self.removeactivity(act, cat)
+        result = self.__findactivity(act, cat)
+        self.assertFalse(result, 'not expecting %s@%s in database' % (act, cat))
+
+        self.removecategory(cat)
+        result = self.__findcategory(cat)
+        self.assertFalse(result, 'not expecting %s in database' % cat)
+
+    def test_category(self):
+        cat = rndstr()
+
+        self.addcategory(cat)
+        result = self.__findcategory(cat)
+        self.assertTrue(result, 'expecting %s has been created' % cat)
+
+        self.removecategory(cat)
+        result = self.__findcategory(cat)
+        self.assertFalse(result, 'not expecting %s in database' % cat)
+
+    def __rndfactgenerator(self):
+        fact = {'name':rndstr(), 'category':rndstr(), 
+                'description':rndstr(), 
+                'start_time':timegm(dt.datetime.now().timetuple()), 
+                'end_time':timegm((dt.datetime.now() + \
+                        dt.timedelta(hours=1)).timetuple())}
+        return fact
+
+    def __findactivity(self, act, cat):
+        found = False
+        for activity, category in self.getactivities():
+            if activity.lower() == act.lower() and \
+                    category.lower() == cat.lower():
+                found = True
+        return found
+
+    def __findcategory(self, cat):
+        found = False
+        for category in self.getcategories():
+            if category.lower() == cat.lower():
+                found = True
+        return found
+
+if __name__ == '__main__':
+    unittest.main()
