diff --git flag.inc flag.inc
index 53b900c..9546520 100644
--- flag.inc
+++ flag.inc
@@ -410,7 +410,12 @@ class flag_flag {
 
   /**
    * Returns TRUE if the user can flag, or unflag, the given content.
-   *
+   * 
+   * Every flag implementation that implements own access methods should NOT 
+   * use parent::access() and parent::access_multiple() but rather
+   * copy these checks into it's own methods because order of checks is
+   * critical and modules should have last vote in the process.
+   * 
    * @param $content_id
    *   The content ID to flag/unflag.
    * @param $account
@@ -1131,7 +1136,13 @@ class flag_node extends flag_flag {
   }
 
   function access_multiple($content_ids, $account = NULL) {
-    $access = parent::access_multiple($content_ids, $account);
+    $account = isset($account) ? $account : $GLOBALS['user'];
+    $access = array();
+
+    // First check basic user access for this action.
+    foreach ($content_ids as $content_id => $action) {
+      $access[$content_id] = $this->user_access($content_ids[$content_id], $account);
+    }
 
     // Ensure that only flaggable node types are granted access. This avoids a
     // node_load() on every type, usually done by applies_to_content_id().
@@ -1141,7 +1152,17 @@ class flag_node extends flag_flag {
     while ($row = db_fetch_object($result)) {
       $access[$row->content_id] = FALSE;
     }
-
+    
+    // Merge in module-defined access.
+    foreach (module_implements('flag_access_multiple') as $module) {
+      $module_access = module_invoke($module, 'flag_access_multiple', $this, $content_ids, $account);
+      foreach ($module_access as $content_id => $content_access) {
+        if (isset($content_access)) {
+          $access[$content_id] = $content_access;
+        }
+      }
+    }
+    
     return $access;
   }
 
@@ -1307,7 +1328,12 @@ class flag_comment extends flag_flag  {
 
   function access_multiple($content_ids, $account = NULL) {
     $account = isset($account) ? $account : $GLOBALS['user'];
-    $access = parent::access_multiple($content_ids, $account);
+    $access = array();
+
+    // First check basic user access for this action.
+    foreach ($content_ids as $content_id => $action) {
+      $access[$content_id] = $this->user_access($content_ids[$content_id], $account);
+    }
 
     // Ensure node types are granted access. This avoids a
     // node_load() on every type, usually done by applies_to_content_id().
@@ -1317,7 +1343,17 @@ class flag_comment extends flag_flag  {
     while ($row = db_fetch_object($result)) {
       $access[$row->content_id] = FALSE;
     }
-
+    
+    // Merge in module-defined access.
+    foreach (module_implements('flag_access_multiple') as $module) {
+      $module_access = module_invoke($module, 'flag_access_multiple', $this, $content_ids, $account);
+      foreach ($module_access as $content_id => $content_access) {
+        if (isset($content_access)) {
+          $access[$content_id] = $content_access;
+        }
+      }
+    }
+    
     return $access;
   }
 
@@ -1447,20 +1483,48 @@ class flag_user extends flag_flag {
   }
 
   function access($content_id, $action = NULL, $account = NULL) {
-    $access = parent::access($content_id, $action, $account);
-    $account = isset($account) ? $account : $GLOBALS['user'];
+    if (!isset($account)) {
+      $account = $GLOBALS['user'];
+    }
+
+    if (isset($content_id) && !$this->applies_to_content_id($content_id) ){
+      // Flag does not apply to this content.
+      return FALSE;
+    }
+
+    if (!isset($action)) {
+      $uid = $account->uid;
+      $sid = flag_get_sid($uid);
+      $action = $this->is_flagged($content_id, $uid, $sid) ? 'unflag' : 'flag';
+    }
+
+    // Base initial access on the user's basic permission to use this flag.
+    $access = $this->user_access($action, $account);
 
     // Prevent users from flagging themselves.
     if ($this->access_uid == 'others' && $content_id == $account->uid) {
       $access = FALSE;
     }
-
+    
+    // Allow modules to disallow (or allow) access to flagging.
+    $access_array = module_invoke_all('flag_access', $this, $content_id, $action, $account);
+    foreach ($access_array as $set_access) {
+      if (isset($set_access)) {
+        $access = $set_access;
+      }
+    }
+    
     return $access;
   }
 
   function access_multiple($content_ids, $account = NULL) {
     $account = isset($account) ? $account : $GLOBALS['user'];
-    $access = parent::access_multiple($content_ids, $account);
+    $access = array();
+
+    // First check basic user access for this action.
+    foreach ($content_ids as $content_id => $action) {
+      $access[$content_id] = $this->user_access($content_ids[$content_id], $account);
+    }
 
     // Exclude anonymous.
     if (array_key_exists(0, $access)) {
@@ -1471,7 +1535,17 @@ class flag_user extends flag_flag {
     if ($this->access_uid == 'others' && array_key_exists($account->uid, $access)) {
       $access[$account->uid] = FALSE;
     }
-
+    
+    // Merge in module-defined access.
+    foreach (module_implements('flag_access_multiple') as $module) {
+      $module_access = module_invoke($module, 'flag_access_multiple', $this, $content_ids, $account);
+      foreach ($module_access as $content_id => $content_access) {
+        if (isset($content_access)) {
+          $access[$content_id] = $content_access;
+        }
+      }
+    }
+    
     return $access;
   }
 
