diff --git a/warden3/warden_server/warden_server.py b/warden3/warden_server/warden_server.py
index b80951c545c717aa87f2e5cfdef2cd91cae23e7a..11ce067f26d26fa900d86fd80f76adafe0556adf 100755
--- a/warden3/warden_server/warden_server.py
+++ b/warden3/warden_server/warden_server.py
@@ -193,25 +193,25 @@ class X509Authenticator(NoAuthenticator):
 
 
     def authorize(self, env, client, method, event, args):
+        # Authorize for debug
+        if (method == 'getDebug'):
+            return client if client[0]['debug'] == 1 else None
+
         cl = None
         service = event['Node'][0]['Name']
+        test = 'Test' in event['Category']        
         
-        for i in range(len(client)):
-            if client[i]['service'] == service:
-                cl = client[i]
+        for clx in client:
+            if clx['service'] == service:
+                cl = clx
                 break
 
         if cl is None:
             return None
         
-        # logging.debug(cl)
-        # logging.debug(method)
-        # logging.debug(service)            
-     
-        # return True if (method == 'getEvents' and cl['read'])
+        # Authorize for sending events
         if ((method == 'sendEvents' and cl['write'] == 1) or
-            (method == 'getDebug' and cl['debug'] == 1) or
-            (method == 'sendEvents' and cl['test'] == 1 and service == 'Test')):
+            (method == 'sendEvents' and cl['test'] == 1 and test)):
             return cl
 
         return None
@@ -275,7 +275,7 @@ class MySQL(Object):
 
     def get_client_by_name(self, name):
         format_strings = ','.join(['%s'] * len(name))
-        self.crs.execute("SELECT `id`, `hostname`, `service`, `identity`, `read`, `write`, `debug`, `test` FROM `clients2` WHERE `valid` = 1 AND `hostname` IN (%s)" % format_strings, tuple(name))
+        self.crs.execute("SELECT cl.`id`, cl.`hostname`, s.`service`, s.`service_id`, s.`identity`, cl.`read`, s.`write`, s.`test`, cl.`debug` FROM `clients3` cl LEFT JOIN `services` s ON cl.`id` = s.`client_id` WHERE cl.`valid` = 1 AND s.`valid` = 1 AND `hostname` IN (%s)" % format_strings, tuple(name))
         row = self.crs.fetchall()
         
         return row if row else None
@@ -319,17 +319,22 @@ class MySQL(Object):
         sqlwhere = []
         sqltemp = {}
 
-
         if cat is not None and nocat is not None:
             raise Error("Unrealizable conditions. Choose cat or nocat option.", 500, method='getEvents', 
                         exc=sys.exc_info(), detail={'cat': cat, 'nocat' : nocat})
 
         if cat is not None or nocat is not None:
             if cat is not None:
-                sqltemp['cat'] = generateDynamicQuery(self, "Category", "category_id IN (%s)", json.loads(cat))
+                parent_cats = []
+                sqltemp['cat'] = generateDynamicQuery(self, "Category", "category_id IN (%s)", json.loads(cat), parent_cats)
+                for pcats in parent_cats:
+                    sqltemp['cat'] += " %s category_id DIV %s = 1 " % (("OR" if sqltemp['cat'] else ""), pcats)
             if nocat is not None:
-                sqltemp['cat'] = generateDynamicQuery(self, "Category", "category_id NOT IN (%s)", json.loads(nocat))
-
+                parent_cats = []
+                sqltemp['cat'] = generateDynamicQuery(self, "Category", "category_id NOT IN (%s)", json.loads(nocat), parent_cats)
+                for pcats in parent_cats:
+                    sqltemp['cat'] += " %s category_id DIV %s = 1 " % (("OR" if sqltemp['cat'] else ""), pcats)
+                
             sqlwhere.append("e.id IN (SELECT event_id FROM event_category_mapping4 WHERE %s)" % sqltemp['cat'])
 
         if tag is not None and notag is not None:
@@ -369,12 +374,20 @@ class MySQL(Object):
         #sqlwhere = sqlwhere[:-4]
         and_op = "" if not sqlwhere_string else "AND"
 
-        # logging.debug("SELECT e.id, e.data FROM clients2 cl RIGHT JOIN events4 e ON cl.id = e.client_id WHERE e.id > %s AND %s %s e.valid = 1 LIMIT %s" % (str(id), sqlwhere_string, and_op, str(count)))
+        logging.debug("SELECT e.id, e.data FROM clients2 cl RIGHT JOIN events4 e ON cl.id = e.client_id WHERE e.id > %s AND %s %s e.valid = 1 LIMIT %s" % (str(id), sqlwhere_string, and_op, str(count)))
         self.crs.execute("SELECT e.id, e.data FROM clients2 cl RIGHT JOIN events4 e ON cl.id = e.client_id WHERE e.id > %s AND %s %s e.valid = 1 LIMIT %s" % (str(id), sqlwhere_string, and_op, str(count)))
         row = self.crs.fetchall()
 
+        if row:
+            maxid = max(r['id'] for r in row)
+        else:
+            maxid = self.getLastEventId()
+
+        # logging.debug("MAX ID = %s", str(maxid))
+
         return {
-            "lastid": row[-1]['id'] if row else str(id),
+            "lastid": maxid,
+            # "lastid": row[-1]['id'] if row else str(id),
             "events": [row[i]['data'] for i in range(len(row))]
         }
 
@@ -409,7 +422,31 @@ class MySQL(Object):
     
         return errs
 
-    def map_id (self, section, key):
+    def insertLastReceivedId(self, client, id):
+        logging.debug("INSERT INTO last_events(client_id, event_id, timestamp) VALUES(%s, %s, NOW())" % (str(client[0]['id']), id))
+        self.crs.execute("INSERT INTO last_events(client_id, event_id, timestamp) VALUES(%s, %s, NOW())" % (str(client[0]['id']), id))
+
+    def getLastEventId(self):
+        self.crs.execute("SELECT MAX(id) as id FROM events4")
+        row = self.crs.fetchone()
+
+        return row['id'] if row['id'] is not None else 0
+
+    def getLastReceivedId(self, client):
+        logging.debug("IN getLastReceivedId")
+        client_id = client[0]['id'] 
+        logging.debug("getLastReceivedId (client_id) = %s", str(client_id))
+
+        logging.debug("SELECT MAX(event_id) as id FROM last_events WHERE client_id = %s" % (str(client_id)))
+        self.crs.execute("SELECT MAX(event_id) as id FROM last_events WHERE client_id = %s" % (str(client_id)))
+        row = self.crs.fetchone()
+
+        logging.debug("getLastReceivedId - %s" % str(row['id']))
+
+        return row['id'] if row is not None else 0
+
+
+    def map_id (self, section, key, strict = False):
         # Should by placed in config file
         data = {}
         data['Tag'] = {
@@ -429,41 +466,51 @@ class MySQL(Object):
                 "Other" : 99
                 }
 
-        data['Category'] = {  
+        data['Category'] = {
+                        "Abusive" : 100,  
                         "Abusive.Spam" : 101,
                         "Abusive.Harassment" : 102,
                         "Abusive.Child" : 103,
                         "Abusive.Sexual" : 104,
                         "Abusive.Violence" : 105,
+                        "Malware" : 200,
                         "Malware.Virus" : 201,
                         "Malware.Worm" : 202,
                         "Malware.Trojan" : 203,
                         "Malware.Spyware" : 204,
                         "Malware.Dialer" : 205,
                         "Malware.Rootkit" : 206,
+                        "Recon.Scanning" : 3,
                         "Recon.Scanning" : 301,
                         "Recon.Sniffing" : 302,
                         "Recon.SocialEngineering" : 303,
                         "Recon.Searching" : 304,
+                        "Attempt" : 400,
                         "Attempt.Exploit" : 401,
                         "Attempt.Login" : 402,
                         "Attempt.NewSignature" : 403,
+                        "Intrusion" : 500,
                         "Intrusion.AdminCompromise" : 501,
                         "Intrusion.UserCompromise" : 502,
                         "Intrusion.AppCompromise" : 503,
                         "Intrusion.Botnet" : 504,
+                        "Availability" : 600,
                         "Availability.DoS" : 601,
                         "Availability.DDoS" : 602,
                         "Availability.Sabotage" : 603,
                         "Availability.Outage" : 604,
+                        "Information" : 700,
                         "Information.UnauthorizedAccess" : 701,
                         "Information.UnauthorizedModification" : 702,
+                        "Fraud" : 800,
                         "Fraud.UnauthorizedUsage" : 801,
                         "Fraud.Copyright" : 802,
                         "Fraud.Masquerade" : 803,
                         "Fraud.Phishing" : 804,
                         "Fraud.Scam" : 805,
+                        "Vulnerable" : 900,
                         "Vulnerable.Open" : 901,
+                        "Anomaly" : 1000,
                         "Anomaly.Traffic" : 1001,
                         "Anomaly.Connection" : 1002,
                         "Anomaly.Protocol" : 1003,
@@ -477,16 +524,27 @@ class MySQL(Object):
         try:
             return data[section][key]
         except:
-            return data[section]['Other']
+            #Return 0 for strict mode (searching), otherwise map everything else to 'Other'
+            return 0 if strict else data[section]['Other']
+
+
+def generateDynamicQuery(self, section, query_string, variables, parent_cats = []):
+    variables_id = []
+    # parent_cats = []
 
-def generateDynamicQuery(self, section, query_string, variables):
-    variables_id = [self.map_id(section, v) for v in variables]
+    for v in variables:
+        mapped_id = self.map_id(section, v, True)
+        if mapped_id % 100 != 0:
+            variables_id.append(mapped_id)
+        else:
+            parent_cats.append(mapped_id)
+
+    # variables_id = [self.map_id(section, v) for v in variables if self.map_id(section, v) % 100 != 0]
     format_strings = ','.join(['\'%s\''] * len(variables_id))
     temp_string = query_string % format_strings
     
     return temp_string % tuple(variables_id)
 
-
 def expose(meth):
     meth.exposed = True
     return meth
@@ -627,6 +685,10 @@ class WardenHandler(Object):
 
     @expose
     def getDebug(self, _env, _client):
+        auth = self.auth.authorize(_env, _client, 'getDebug', None, None)
+        if not auth:
+            raise Error("I'm watching YOU. (Authorization)", 403, method='getDebug', detail={"client": _client})
+        
         return {
             "environment": _env,
             "database": self.db.get_debug()
@@ -656,6 +718,27 @@ class WardenHandler(Object):
         except (ValueError, TypeError):
             id=0
 
+        if id == 0: 
+            try:
+                id = self.db.getLastReceivedId(_client)
+                # logging.debug("Last received ID for %s is %s" % (_client['hostname'], str(id)))
+            except Exception, e:
+                logging.error(e)
+                id = 0
+                
+        if id == 0:
+            try:
+                id = self.db.getLastEventId()
+            except Exception as e:
+                raise Error("Last event id receiving error", 500, detail={"client": _client})
+  
+            self.db.insertLastReceivedId(_client, id)
+
+            return {
+                "lastid": id,
+                "events": []
+            }
+
         try:
             count = int(count)
         except (ValueError, TypeError):
@@ -669,6 +752,9 @@ class WardenHandler(Object):
         logging.info("getEvents(%d, %d, %s, %s, %s, %s, %s, %s): sending %d events" % (
             id, count, cat, nocat, tag, notag, group, nogroup, len(res["events"])))
 
+        self.db.insertLastReceivedId(_client, res['lastid'])
+        logging.debug("lastid inserting: %s" % {'lastid': res['lastid'], 'client' : _client})
+
         return res