diff --git contrib/flag_friend.activity.inc contrib/flag_friend.activity.inc
new file mode 100644
index 0000000..5b39295
--- /dev/null
+++ contrib/flag_friend.activity.inc
@@ -0,0 +1,47 @@
+<?php
+// $Id$
+
+/**
+ * @file: Activity module integration for the Flag Friend.
+ */
+
+/**
+ * Implementation of hook_activity_info().
+ * 
+ * FIXME: May still need work.
+ */
+function flag_friend_activity_info() {
+  $flag = flag_get_flag('friend');
+  $info = new stdClass();
+  $info->api = 2;
+  $info->name = 'flag_friend';
+  $info->object_type = 'flag_friend';
+  $info->objects = array('requestor' => 'user', 'requestee' => 'flag_friend'); // array keys are the labels
+  $info->hooks = array('flag_friend' => array('approve', 'request', 'deny', 'remove'));
+  $info->realms = array('flag_friend' => $flag->title);
+  return $info;
+}
+
+/**
+ * Implementation of hook_activity_grants().
+ */
+function flag_friend_activity_grants($activity) {
+  return array(
+    'flag_friend' => array($activity->uid), // the id that will be used
+  );
+}
+
+/**
+ * Implementation of hook_activity_access_grants().
+ * 
+ * FIXME: May still need work like adding $flag object or flag id to the 
+ * flag_friend_get_friends() function.
+ */
+function flag_friend_activity_access_grants($account) {
+  $friends = flag_friend_get_friends($account->uid);
+  $realm_ids = array();
+  if (!empty($friends)) {
+    $realm_ids['flag_friend'] = array_keys($friends);
+  }
+  return $realm_ids;
+}
diff --git contrib/flag_friend.author_pane.inc contrib/flag_friend.author_pane.inc
new file mode 100644
index 0000000..e4580de
--- /dev/null
+++ contrib/flag_friend.author_pane.inc
@@ -0,0 +1,64 @@
+<?php
+// $Id$
+
+/**
+ * @file: Author Pane 2.x module integration for the Flag Friend.
+ */
+
+/**
+ * Implementation of hook_preprocess_author_pane().
+ */
+function flag_friend_preprocess_author_pane(&$variables) {
+  global $user;
+  $account_id = $variables['account']->uid;
+  // Author Pane 2.x has "caller" variable to let different modules have their
+  // own templates and thus preprocesses. We must check it so we insert link 
+  // only when it's needed.  
+  $caller = $variables['caller'];
+  $supported_callers = variable_get($flag_friend_author_pane_callers, array('advanced_forum', 'advanced_profile'));
+  if (empty($caller) || !in_array($caller, $supported_callers)) {
+    return;
+  }
+  // User can have arbitrary number of flags and we can't know which ones need 
+  // processing. Simplest thing we can come up with is to include "friend" flag
+  // by default since it was supported in 1.x branch.
+  $supported_flag = variable_get($flag_friend_author_pane_flag, 'friend');  
+  $flag = flag_get_flag($supported_flag);
+  if (!$flag) {
+    return;
+  }
+  
+  // Accessing the user profile is the only way to be able to see the friend
+  // flag out-of-the-box so I feel it's pretty safe to use this permisssion.
+  if ($account_id != 0 && user_access('access user profiles') && $user->uid != $account_id) {
+    
+    $status = flag_friend_relationship_status($flag, $user->uid, $account_id);
+    $action = ($flag->is_flagged($account_id)) ? 'unflag' : 'flag';
+    // Transform Flag action to a Flag Friend operation.
+    $op = _flag_friend_get_op($action, $status);
+    if (!$op) {
+      return;
+    }
+    switch ($op) {
+      case 'approve':
+      case 'request':
+        $image_path = $variables['image_path'] . "/buddy-add.png";
+        break;
+        
+      case 'deny':  
+      case 'cancel':
+      case 'remove':        
+        $image_path = $variables['image_path'] . "/buddy-remove.png";
+    }
+    $link = flag_friend_flag_link($flag, $action, $account_id);
+    $variables['flag_friend_link'] = $link;
+    
+    $image = theme('image', $image_path, $link['title'], $link['attributes']['title'], NULL, FALSE);
+    $options = array(
+      'query' => drupal_get_destination(),
+      'html' => TRUE,
+      'attributes'  => $link['attributes'],
+    );
+    $variables['flag_friend'] = l($image, $link['href'], $options);
+  }
+}
diff --git contrib/flag_friend.popups.inc contrib/flag_friend.popups.inc
new file mode 100644
index 0000000..93e05bb
--- /dev/null
+++ contrib/flag_friend.popups.inc
@@ -0,0 +1,27 @@
+<?php
+// $Id$
+
+/**
+ * @file: Popups module integration for the Flag Friend.
+ */
+
+// add a little notice to our popups
+drupal_add_js(drupal_get_path('module', 'flag_friend') .'/flag_friend.popups.js');
+
+/**
+ * Implementation of hook_popups().
+ */
+function flag_friend_popups() {
+  return array(
+    'user/*' => array( // any user page
+      'span.flag-friend a' => array(
+        'afterSubmit' => 'Drupal.flagFriendPopupsAfterSubmit',
+      ),
+    ),
+    'user/*/friends/*' => array( // friend views
+      'span.friend a' => array(
+        'afterSubmit' => 'Drupal.flagFriendPopupsAfterSubmit',
+      ),
+    ),
+  );
+}
diff --git contrib/flag_friend.token.inc contrib/flag_friend.token.inc
new file mode 100644
index 0000000..9c2b58d
--- /dev/null
+++ contrib/flag_friend.token.inc
@@ -0,0 +1,40 @@
+<?php
+// $Id$
+
+/**
+ * @file: Token module integration for the Flag Friend.
+ */
+
+/**
+ * Implementation of hook_token_list().
+ */
+function flag_friend_token_list($type = 'all') {
+  if ($type == 'flag_friend') {
+    $tokens = array();
+    $tokens['flag_friend'] = array(
+      'requestor' => t('The name of the user who originally made the request.'),
+      'requestee' => t('The name of the user who originally received the request.'),
+      'requestor-uid' => t("Requestor's ID."),
+      'requestee-uid' => t("Requestee's ID."),
+      'requestor-url' => t("The URL of the requestor's profile page."),
+      'requestee-url' => t("The URL of the requestee's profile page.")
+    );
+    return $tokens;
+  }
+}
+
+/**
+ * Implementation of hook_token_values().
+ */
+function flag_friend_token_values($type, $object = NULL, $options = array()) {
+  if (($type == 'flag_friend') && !empty($object)) {
+    $data = array();
+    $data['requestor'] = $object->friend->name;
+    $data['requestee'] = $object->name;
+    $data['requestor-uid'] = $object->friend->uid;
+    $data['requestee-uid'] = $object->uid;
+    $data['requestor-url'] = base_path().drupal_get_path_alias('user/'.$object->friend->uid);
+    $data['requestee-url'] = base_path().drupal_get_path_alias('user/'.$object->uid);
+    return $data;
+  }
+}
diff --git contrib/flag_friend.trigger.inc contrib/flag_friend.trigger.inc
new file mode 100644
index 0000000..34158a1
--- /dev/null
+++ contrib/flag_friend.trigger.inc
@@ -0,0 +1,74 @@
+<?php
+// $Id$
+
+/**
+ * @file: Trigger module integration for the Flag Friend.
+ */
+
+/**
+ * Implementation of hook_hook_info().
+ *
+ * Provide some triggers so that actions can be performed at various stages.
+ */
+function flag_friend_hook_info() {
+  return array(
+    'flag_friend' => array(
+      'flag_friend' => array(
+        'approve' => array(
+          'runs when' => t("A user approves another's relationship request."),
+        ),
+        'request' => array(
+          'runs when' => t("A user requested another's relationship."),
+        ),
+        'deny' => array(
+          'runs when' => t("A user denies another's relationship request."),
+        ),
+        'remove' => array(
+          'runs when' => t("A user cancels relationship with another user."),
+        ),
+      ),
+    ),
+  );
+}
+
+/**
+ * Implementation of hook_trigger_name().
+ * 
+ * FIXME: May still need work.
+ */
+function flag_friend_flag_friend($op, $friend, $user, $flag) {
+  if (function_exists('_trigger_get_hook_aids')) {
+    $aids = _trigger_get_hook_aids('flag_friend', $op);
+  
+    switch ($op) {
+      // in this case, the users performing the operations are flipped
+      case 'deny':
+        $user->friend = $friend;
+        $context = array(
+          'hook' => 'flag_friend',
+          'op' => $op,
+          'user' => $friend,
+          'flag_friend' => $user,
+          'flag' => $flag,
+        );
+        break;
+      // these are normal
+      case 'approve':
+      case 'request':
+      case 'remove':
+      case 'cancel':
+        $friend->friend = $user;
+        $context = array(
+          'hook' => 'flag_friend',
+          'op' => $op,
+          'user' => $user,
+          'flag_friend' => $friend,
+          'flag' => $flag,
+        );
+        break;
+    }
+    if ($aids) {
+      actions_do(array_keys($aids), $friend, $context);
+    }
+  }
+}
diff --git flag_friend.install flag_friend.install
index 56cc8bf..9c73897 100644
--- flag_friend.install
+++ flag_friend.install
@@ -46,11 +46,19 @@ function flag_friend_schema() {
         'type' => 'int', 
         'not null' => FALSE, 
         'disp-width' => '11'
-      )
+      ),
+      'fid' => array(
+        'type' => 'serial',
+        'size' => 'small',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+      ),
     ),
-    'primary key' => array('uid', 'friend_uid'),
+    'primary key' => array('uid', 'friend_uid', 'fid'),
     'indexes' => array(
       'friend_uid' => array('friend_uid'),
+      'uid_fid' => array('uid', 'fid'),
+      'fid' => array('fid'),
     ),
   );
 
@@ -88,3 +96,126 @@ function flag_friend_update_6001() {
   db_add_index($ret, 'flag_friend', 'friend_uid', array('friend_uid'));
   return $ret;
 }
+
+/**
+ * Perform 2.x branch updates:
+ * - Upgrade default "friend" flag.  
+ * - Add flag id column to the flag_friend table
+ * - Set (fid = "friend" flag fid) for existing relationships 
+ * - New primary key including "fid" column and new indexes.
+ * - Bulk flag users in relationships. 
+ * - Insert symmetric (with uid, friend_uid reversed) record for every 
+ *   relationship.
+ * 
+ * Personal user notification settings should be upgraded in
+ * flag_friend_mail_update_6000().
+ */
+function flag_friend_update_6200(&$sandbox) {
+  $ret = array();
+  $users_per_step = 50;
+  $flag = flag_get_flag('friend');
+  if (!isset($sandbox['current'])) {
+    
+    // Count batch steps.
+    // 5 to upgrade flag and DB schema
+    $sandbox['max'] = 5;
+    $rels = db_result(db_query('SELECT COUNT(*) FROM {flag_friend}'));
+    if ($rels) {
+      if (!$flag) {
+        $ret['#abort'] = array('success' => FALSE, 'query' => 'Your flag_friend table contains relationships but "friend" flag is not enabled. Please enable "friend" flag and repeat upgrade process.');
+        return $ret;
+      }
+      // 2 steps to bulk flag existing friends,
+      // 3 steps to mirror flag_friend table
+      $sandbox['max'] = $sandbox['max'] + 5;
+      // and +1 step for every $users_per_step to update their flag counts.
+      // Temporary disabled. See "default:" case switch below.
+      //$sandbox['count_users'] = db_result(db_query('SELECT COUNT(uid) FROM {users}'));
+      //$sandbox['max'] = $sandbox['max'] + ceil($sandbox['count_users'] / $users_per_step);
+    }
+    $sandbox['current'] = 1;
+  }
+  // Process batch.
+  switch($sandbox['current']) {
+    case 1:
+      // Add 'fid' column and upgrade friend flag.
+      $sandbox['current'] = 1;
+      $spec = array(
+        'type' => 'int',
+        'size' => 'small',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+      );
+      // If default flag is enabled, upgrade it.
+      if ($flag) {
+        $spec['initial'] = $flag->fid;
+        $flag->link_type = 'msg_confirm';
+        // Apply link defaults.
+        foreach (_flag_friend_default_link_options() as $key => $value) {
+          $flag->$key = $value;
+        }
+        $flag->save;
+      }
+      // Add fid column with initial value for "friend" flag.
+      db_add_field($ret, 'flag_friend', 'fid', $spec);
+      break;
+    
+    case 2: 
+      // Change primary key.
+      db_drop_primary_key($ret, 'flag_friend');
+      break;
+      
+    case 3:
+      db_add_primary_key($ret, 'flag_friend', array('uid', 'friend_uid', 'fid'));
+      break;
+      
+    case 4:
+      // Add new indexes.
+      db_add_index($ret, 'flag_friend', 'fid', array('fid'));
+      break;
+      
+    case 5:
+      db_add_index($ret, 'flag_friend', 'uid_fid', array('uid', 'fid'));
+      break;
+  
+    case 6:
+      // Bulk flag users in each relationship (in 2.x we don't unflag users 
+      // unless relationship is breaking).
+      $ret[] = update_sql("INSERT INTO {flag_content} (fid, content_type, content_id, uid, sid, timestamp) SELECT $flag->fid, 'user', friend_uid, uid, 0, created FROM {flag_friend}");
+      break;
+
+    case 7:
+      $ret[] = update_sql("INSERT INTO {flag_content} (fid, content_type, content_id, uid, sid, timestamp) SELECT $flag->fid, 'user', uid, friend_uid, 0, created FROM {flag_friend}");
+      break;
+      
+    case 8:
+      // Insert symmetrical records for relationships using temporary table.
+      // This should work out fast even for millions of entries.
+      $ret[] = update_sql('CREATE TABLE {flag_friend_copy} SELECT * FROM {flag_friend}');
+      break;
+      
+    case 9:
+      $ret[] = update_sql('INSERT INTO {flag_friend} (uid, friend_uid, created, fid) SELECT friend_uid, uid, created, fid FROM {flag_friend_copy}');
+      break;
+      
+    case 10:
+      $ret[] = update_sql('DROP TABLE {flag_friend_copy}');
+      break;
+      
+    default:
+      // Update flag counts. Temporary disabled until 
+      // 1) we are 100% sure that we need it
+      // 2) we figure out faster way (e.g. directly in mysql) cause with 
+      // 1xxxxx of users that could go for hours.
+      /* 
+      $from = (($sandbox['current'] - 7) * $users_per_step) +1;
+      $result = db_query_range('SELECT uid from {users}', array(), $from, $users_per_step);
+      while($user = db_fetch_array($result)) {
+        $flag->_update_count($user['uid']);
+      }
+      */
+  }
+  $ret['#finished'] = $sandbox['current'] / $sandbox['max'];
+  $sandbox['current']++;
+  return $ret;
+}
diff --git flag_friend.module flag_friend.module
index 82a543d..2c5145d 100644
--- flag_friend.module
+++ flag_friend.module
@@ -6,251 +6,147 @@
  * Written by Jerad Bitner (sirkitree.net)
  */
 
-// define our statuses
-define('FLAG_FRIEND_BOTH', 0);
-define('FLAG_FRIEND_FLAGGED', 1);
-define('FLAG_FRIEND_UNFLAGGED', 2);
-define('FLAG_FRIEND_APPROVAL', 3);
-define('FLAG_FRIEND_PENDING', 4);
-
-/**
- * Implementation of hook_flag().
- */
-function flag_friend_flag($event, $flag, $content_id, $account) {
-  if ($flag->name == 'friend') {
-    if ($event == 'flag') {
-
-      // See the status of the friendship.
-      $status = flag_friend_determine_friend_status($flag, $account->uid, $content_id, TRUE);
-      $friend_account = user_load(array('uid' => $content_id));
-
-      // If both are now flagged, we record the relationship and remove the flags.
-      if ($status === FLAG_FRIEND_BOTH) {
-        // Since these users have flagged eachother, we create the relationship in the flag_friend table.
-        db_query("INSERT INTO {flag_friend} VALUES(%d, %d, %d)", $account->uid, $content_id, $_SERVER['REQUEST_TIME']);
-
-        // Remove any message entries for either user.
-        flag_friend_message('unflag', $flag, $account->uid, $content_id);
-        flag_friend_message('unflag', $flag, $content_id, $account->uid);
-
-        // Then remove the flags.
-        $flag->flag('unflag', $content_id, $account);
-        $flag->flag('unflag', $account->uid, $friend_account);
-
-        // fire trigger
-        module_invoke_all('flag_friend', 'approve', $friend_account, $account);
-      }
-      else {
-        // fire trigger
-        module_invoke_all('flag_friend', 'request', $friend_account, $account);
-      }
-    }
-  }
-}
-
+// Define our statuses
+define('FLAG_FRIEND_UNFLAGGED', 0);
+define('FLAG_FRIEND_APPROVAL', 1);
+define('FLAG_FRIEND_PENDING', 2);
+define('FLAG_FRIEND_BOTH', 3);
+define('FLAG_FRIEND_RELATIONSHIP', 4);
+// Symmetric state to the FLAG_FRIEND_BREAKING. It is invalid state because 
+// a user in the process of breaking relationship always unflags another party,
+// not himself. 
+define('FLAG_FRIEND_ERROR', 5);
+// New transitional state in the relationship breaking process.
+define('FLAG_FRIEND_BREAKING', 6);
 /**
- * Implementation of hook_init().
+ * 
+ * Flag Friend own functions.
+ * 
  */
-function flag_friend_init() {
-  // add a little notice to our popups
-  if (module_exists('popups')) {
-    drupal_add_js(drupal_get_path('module', 'flag_friend') .'/flag_friend.popups.js');
-  }
-}
 
 /**
- * Implementation of hook_preprocess_flag().
+ * Save relationship request message.
+ * 
+ * New approach is to never delete messages. This allows potentially to have 
+ * history for example to find abusive messages.
+ * $fcid is auto-incremented field so old messages will do no harm. 
+ * 
  */
-function flag_friend_preprocess_flag(&$vars) {
-  // this hook preprocesses ALL flag links, so make sure we have ours
-  if ($vars['flag']->name == 'friend') {
-    global $user;
-    
-    // Determine what the status in the friend process is.
-    $status = flag_friend_determine_friend_status($vars['flag'], $user->uid, $vars['content_id']);
-    switch ($status) {
-      case FLAG_FRIEND_PENDING:
-        $vars['link_text'] = t('Friend Requested. Cancel?');
-        break;
-
-      case FLAG_FRIEND_FLAGGED:
-        // Make this link into a remove link with
-        $vars['action'] = 'unflag';
-        $vars['link_href'] = str_replace('flag/confirm/flag', 'flag/confirm/unfriend', $vars['link_href']);
-        $vars['link_text'] = t($vars['flag']->unflag_short);
-        $vars['flag_name_css'] = 'unfriend';
-        $vars['link_title'] = t($vars['flag']->unflag_long);
-        break;
-
-      case FLAG_FRIEND_APPROVAL:
-        $vars['link_text'] = t('Approve');
-        break;
-    }
-  }
+function flag_friend_save_message($fcid, $message) {
+  db_query("INSERT INTO {flag_friend_message} VALUES(%d, '%s')", $fcid, $message);
 }
 
-/**
- * Implementation of hook_perm().
- */
-function flag_friend_perm() {
-  return array('receive friend email notification');
-}
 
 /**
- * Implementation of hook_views_api().
+ * Retrieve our flag's message.
  */
-function flag_friend_views_api() {
-  return array(
-    'api' => 2.0,
-    'path' => drupal_get_path('module', 'flag_friend') .'/includes',
-  );
+function flag_friend_get_message($fcid) {
+  $result = db_result(db_query("SELECT message FROM {flag_friend_message} WHERE fcid = %d", $fcid));
+  return ($result) ? $result : FALSE;
 }
 
 /**
- * Retrieve pending friend flags.
+ * Retrieve a list of relationship terminating accounts where user is 
+ * originating party.
  *
- * @param $flag
- *   The flag object.
- * @param $content_id
- *   The content we're operating on.
+ * @param $uid
+ *   The user id.
+ * @param $fid
+ *   The relationship (Flag) id.
  * @param $reset
  *   Boolean trigger to reset the static cache.
  * @return
- *   Array of pending friend flags.
+ *   Array of user objects.
  */
-function flag_friend_get_flags($flag, $content_id, $reset = NULL) {
-  static $flagged_content;
-  $uid = $content_id;
-  $content_type = $flag->content_type;
-
-  if (!isset($flagged_content[$uid][$content_type][$content_id]) || $reset) {
-    $flags = flag_get_flags($flag->content_type);
-    $flagged_content[$uid][$content_type][$content_id] = array();
-    // get flags with messages
-    $result = db_query("SELECT fc.*, ffm.message FROM {flag_content} fc LEFT JOIN {flag_friend_message} ffm ON ffm.fcid = fc.fcid WHERE fc.fid = %d AND fc.content_type = '%s' AND fc.content_id = %d", $flag->fid, $content_type, $content_id);
-    while ($new_flag = db_fetch_object($result)) {
-      $fcid = flag_friend_get_fcid($flag, $content_id, $new_flag->uid);
-      $flagged_content[$uid][$content_type][$content_id][$fcid] = $new_flag;
-      $flagged_content[$uid][$content_type][$content_id][$fcid]->user = user_load(array('uid' => $new_flag->uid));
+function flag_friend_get_terminating_accounts($uid, $fid, $reset = NULL) {
+  static $rels = array();
+  if (!isset($rels[$uid][$fid]) || $reset) {
+    $rels[$uid] = array();
+    $rels[$uid][$fid] = array();
+    $result = db_query("SELECT friend_uid FROM {flag_friend} WHERE uid = %d AND fid = %d", $uid, $fid);
+    while ($rel = db_fetch_object($result)) {
+      $rels[$uid][$fid][$rel->friend_uid] = user_load(array('uid' => $rel->friend_uid));
     }
   }
-
-  return $flagged_content[$uid][$content_type][$content_id];
+  return $rels[$uid][$fid];
 }
 
 /**
- * Retrieve a list of friends for the given user.
+ * Retrieve a list of relationship originating accounts where user is 
+ * terminating party.
  *
  * @param $uid
  *   The user id.
+ * @param $fid
+ *   The relationship (Flag) id.
  * @param $reset
  *   Boolean trigger to reset the static cache.
  * @return
  *   Array of user objects.
  */
-function flag_friend_get_friends($uid, $reset = NULL) {
-  static $friends;
-
-  if (!isset($friends[$uid]) || $reset) {
-    $friends[$uid] = array();
-    $result = db_query("SELECT * FROM {flag_friend} WHERE uid = %d OR friend_uid = %d", $uid, $uid);
-    while ($friend = db_fetch_object($result)) {
-      // if the current user is in the uid column
-      if ($friend->uid == $uid) {
-        // load the friend_uid
-        $friends[$uid][$friend->friend_uid] = user_load(array('uid' => $friend->friend_uid));
-      }
-      else { // the current user is the friend_uid
-        // load the uid column as the friend
-        $friends[$uid][$friend->uid] = user_load(array('uid' => $friend->uid));
-      }
+function flag_friend_get_originating_accounts($uid, $fid, $reset = NULL) {
+  static $rels = array();
+  if (!isset($rels[$uid][$fid]) || $reset) {
+    $rels[$uid] = array();
+    $rels[$uid][$fid] = array();
+    $result = db_query("SELECT uid FROM {flag_friend} WHERE friend_uid = %d AND fid = %d", $uid, $fid);
+    while ($rel = db_fetch_object($result)) {
+      $rels[$uid][$fid][$rel->uid] = user_load(array('uid' => $rel->uid));
     }
   }
-
-  return $friends[$uid];
+  return $rels[$uid][$fid];
 }
 
 /**
- * Retrieve the number of friends for the given user.
+ * Retrieve the number of active relationships where user is originating party.
+ * 
+ * Note that "originating party" in relationship isn't equal to 
+ * "requesting party" - user could request a relationship and become 
+ * "terminating party" in it. Example: son sends request to his mother to 
+ * accept their relationship. Mother accepts, and son becomes 
+ * "terminating party" in a "mother -> sun" 1 way relationship. 
  *
  * @param $uid
  *   The user id.
+ * @param $fid
+ *   The relationship (Flag) id.
  * @param $reset
  *   Boolean trigger to reset the static cache.
  * @return
- *   Number of friends.
- */
-function flag_friend_get_friend_count($uid, $reset = NULL) {
-  static $friend_count;
-
-  if (!isset($friend_count[$uid]) || $reset) {
-    $sql = "SELECT COUNT(1) FROM {flag_friend} WHERE uid = %d OR friend_uid = %d";
-    $friend_count[$uid] = db_result(db_query($sql, $uid, $uid));
-  }
-
-  return $friend_count[$uid];
-}
-
-/**
- * Implementation of hook_user().
+ *   Number of relationships.
  */
-function flag_friend_user($op, &$edit, &$account, $category = NULL) {
-  switch ($op) {
-    case 'form':
-      if ($category == 'account') {
-        // The user account edit form is about to be displayed. The module should present the form elements it wishes to inject into the form.
-        $form = array();
-        $form['friend_notification'] = array(
-          '#type' => 'select',
-          '#title' => t('Friend notification'),
-          '#description' => t('Would you like to be notified when someone wants to be friends with you?'),
-          '#multiple' => FALSE,
-          '#options' => array(0 => t('Yes'), -1 => t('No')),
-          '#default_value' => isset($account->friend_notification) ? $account->friend_notification : FLAG_FRIEND_NOTIFICATION,
-          '#weight' => -10,
-        );
-        return $form;
-      }
-      break;
-    case 'view':
-      global $user;
-      // Remove link if we're looking at our own so we cannot friend ourself
-      $flag = flag_get_flag('friend');
-      if ($user->uid == $account->uid) {
-        if ($account->content['flags'][$flag->name]) {
-          unset($account->content['flags'][$flag->name]);
-        }
-      }
-      break;
-    case 'delete':
-      // remove any friend relationships if an account is removed
-      db_query("DELETE FROM {flag_friend} WHERE uid = %d OR friend_uid = %d", $account->uid, $account->uid);
-      break;
+function flag_friend_get_originating_count($uid, $fid, $reset = NULL) {
+  static $rels_count = array();
+  if (!isset($rels_count[$uid][$fid]) || $reset) {
+    $rels_count[$uid] = array();
+    $rels_count[$uid][$fid] = db_result(db_query("SELECT COUNT(1) FROM {flag_friend} WHERE uid = %d AND fid = %d", $uid, $fid));
   }
+  return $rels_count[$uid][$fid];
 }
 
 /**
- * Create a denial link.
+ * Retrieve the number of active relationships where user is terminating party.
  *
- * @param $type
- *   String to determine what type of link to create.
  * @param $uid
- *   The id of the user we're creating this to flag.
+ *   The user id.
+ * @param $fid
+ *   The relationship (Flag) id.
+ * @param $reset
+ *   Boolean trigger to reset the static cache.
+ * @return
+ *   Number of relationships.
  */
-function flag_friend_create_link($type, $uid) {
-  $flag = flag_get_flag('friend');
-  if ($type == 'unfriend') {
-    $link = str_replace(t('Approve'), t('Deny'), str_replace('unflag', 'unfriend', $flag->theme('unflag', $uid)));
-    return $link;
-  }
-  else {
-    $link = str_replace(t('Approve'), t('Deny'), $flag->theme('unflag', $uid));
-    return $link;
+function flag_friend_get_terminating_count($uid, $fid, $reset = NULL) {
+  static $rels_count = array();
+  if (!isset($rels_count[$uid][$fid]) || $reset) {
+    $rels_count[$uid] = array();
+    $rels_count[$uid][$fid] = db_result(db_query("SELECT COUNT(1) FROM {flag_friend} WHERE friend_uid = %d AND fid = %d", $uid, $fid));
   }
+  return $rels_count[$uid][$fid];
 }
 
 /**
- * Determines the status of the friendship by testing various conditions.
+ * Determines the status of the relationship by testing various conditions.
  *
  * @param $flag
  *   The flag object.
@@ -262,358 +158,432 @@ function flag_friend_create_link($type, $uid) {
  *   A string describing the status of the relationship.
  * @todo: this could possibly go into hook_flag_access once available.
  */
-function flag_friend_determine_friend_status($flag, $uid1, $uid2, $reset = NULL) {
+function flag_friend_relationship_status($flag, $uid1, $uid2, $reset = NULL) {
   static $status_cache = array();
   if ($reset) {
     unset($status_cache);
   }
-  // always keep these in the same order
-  if ($uid1 > $uid2) {
-    $key1 = $uid1;
-    $key2 = $uid2;
-  }
-  else {
-    $key1 = $uid2;
-    $key2 = $uid1;
-  }
-
-  if (isset($flag)) {
-    if (!isset($status_cache[$key1][$key2])) {
-      $you_are_flagged = $flag->is_flagged($uid1, $uid2);
-      $they_are_flagged = $flag->is_flagged($uid2, $uid1);
-      $friends = db_result(db_query("SELECT * FROM {flag_friend} WHERE (uid = %d AND friend_uid = %d) OR (uid = %d AND friend_uid = %d)", $uid1, $uid2, $uid2, $uid1));
+  $fid = $flag->fid;
+  if (!isset($status_cache[$uid1][$uid2][$fid])) {
+    // Always check both flags and relationship for consistency.
+    $you_are_flagged = $flag->is_flagged($uid1, $uid2);
+    $they_are_flagged = $flag->is_flagged($uid2, $uid1);
+    $relationship = db_result(db_query("SELECT * FROM {flag_friend} WHERE uid = %d AND friend_uid = %d AND fid = %d", $uid1, $uid2, $fid));
+    if ($relationship) {
       // see if these users have flagged eachother
       if ($you_are_flagged && $they_are_flagged) {
-        $status_cache[$key1][$key2] = FLAG_FRIEND_BOTH;
-      }
-      elseif ($friends) {
-        $status_cache[$key1][$key2] = FLAG_FRIEND_FLAGGED;
-      }
-      elseif (!$you_are_flagged && !$they_are_flagged) {
-        $status_cache[$key1][$key2] = FLAG_FRIEND_UNFLAGGED;
+        $status = FLAG_FRIEND_RELATIONSHIP;  
       }
+      // new transitional state in the relationship breaking process.
       elseif ($you_are_flagged && !$they_are_flagged) {
-        $status_cache[$key1][$key2] = FLAG_FRIEND_APPROVAL;
+        $status = FLAG_FRIEND_BREAKING;
       }
-      elseif (!$you_are_flagged && $they_are_flagged) {
-        $status_cache[$key1][$key2] = FLAG_FRIEND_PENDING;
+      else {
+        $status = FLAG_FRIEND_ERROR;
       }
     }
-  }
-  return $status_cache[$key1][$key2];
-}
-
-/**
- * Implementation of hook_form_FORM_ID_alter().
- */
-function flag_friend_form_flag_confirm_alter(&$form, &$form_state) {
-  if ($form['flag_name']['#value'] == 'friend') {
-    $action = $form['action']['#value'];
-    $flag = flag_get_flag('friend');
-    $content_id = $form['content_id']['#value'];
-    $token = isset($_REQUEST['token']) ? $_REQUEST['token'] : '';
-
-    switch ($action) {
-      case 'flag':
-        $flag_form = flag_friend_message_form($action, $flag, $content_id, $token);
-        $form = array_merge($form, $flag_form);
-        unset($form['actions']['submit']);
-        unset($form['actions']['cancel']);
-        $form['#submit'][] = 'flag_friend_form_submit';
-        break;
-      case 'unflag':
-      case 'unfriend':
-        $unflag_form = flag_friend_unfriend_form($action, $flag, $content_id, $token);
-        $form = array_merge($form, $unflag_form);
-        $form['#submit'][] = 'flag_friend_form_submit';
-        // switch the order in which we submit so the fcid can still be found
-        $form['#submit'] = array_reverse($form['#submit']);
-        break;
+    else {
+      if ($you_are_flagged && $they_are_flagged) {
+        $status = FLAG_FRIEND_BOTH;
+      }
+      if (!$you_are_flagged && !$they_are_flagged) {
+        $status = FLAG_FRIEND_UNFLAGGED;
+      }
+      if ($you_are_flagged && !$they_are_flagged) {
+        $status = FLAG_FRIEND_APPROVAL;
+      }
+      if (!$you_are_flagged && $they_are_flagged) {
+        $status = FLAG_FRIEND_PENDING;
+      }
     }
+    $status_cache[$uid1][$uid2][$fid] = $status;
   }
+  return $status_cache[$uid1][$uid2][$fid];
 }
 
 /**
- * Form to send a message to a user before friend flagging.
+ * Return flag friend default link options.
  */
-function flag_friend_message_form($action, $flag, $content_id, $token) {
-  $form['current'] = array('#type' => 'value', '#value' => func_get_args());
-  $name = db_result(db_query("SELECT name FROM {users} WHERE uid = %d", $content_id));
-  $form['flag_friend_message'] = array(
-    '#type' => 'textarea',
-    '#title' => t('Send @name a message (optional)', array('@name' => $name)),
-    '#description' => t('Enter a message to send to this user.'),
-    '#cols' => 60,
-    '#rows' => 5,
-  );
-  $form['flag_friend_submit'] = array(
-    '#type' => 'submit',
-    '#value' => t('Send'),
-    '#suffix' => l(t('Cancel'), $_GET['destination']),
-  );
-  $form['#theme'] = 'flag_friend_message_form';
-  return $form;
-}
-
-/**
- * Form to confirm an unfriend flagging.
+function _flag_friend_default_link_options() {
+  $options = array();
+  
+  // Request
+  $options['request_short'] = 'Add friend';
+  $options['request_long'] = 'Add [user] to your list of friends.';
+  $options['request_question'] = 'Are you sure you want to add [user] to your list of friends?';
+  $options['request_msg'] = 'Hello [user], please let me add you to my friend list.';
+  $options['request_msg_title'] = 'Send [user] a message (optional)';
+  $options['request_msg_desc'] = 'Enter a message to send to this user.';
+  $options['request_yes'] = 'Send';
+  $options['request_no'] = 'Cancel';
+  $options['request_success_message'] = 'Request sent successfully.';
+  $options['request_failed_message'] = 'Request failed.';
+
+  // Cancel pending
+  $options['cancel_short'] = 'Friend Requested. Cancel?';
+  $options['cancel_long'] = 'Click here to cancel this request.';
+  $options['cancel_question'] = 'Are you sure you want to cancel your pending friend request?';
+  $options['cancel_yes'] = 'Yes';
+  $options['cancel_no'] = 'No';
+  $options['cancel_success_message'] = 'Your friendship request to [user] was canceled.';
+  $options['cancel_failed_message'] = 'Friendship request cancellation failed.';
+  
+  // Approve. Default is same as request, but we let define different strings.
+  $options['approve_short'] = 'Approve';
+  $options['approve_long'] = 'Add [user] to your list of friends.';
+  $options['approve_question'] = 'Are you sure you want to add [user] to your list of friends?';
+  $options['approve_yes'] = 'Yes';
+  $options['approve_no'] = 'No';
+  $options['approve_success_message'] = '[user] has been added to your list of friends.';
+  $options['approve_failed_message'] = "Couldn't add [user] to your list of friends.";
+  
+  // Deny
+  $options['deny_short'] = 'Deny';
+  $options['deny_long'] = "Deny [user]'s friendship request.";
+  $options['deny_question'] = "Are you sure you don't want to be friends with [user]?";
+  $options['deny_yes'] = 'Yes';
+  $options['deny_no'] = 'No';
+  $options['deny_success_message'] = "[user]'s friendship request has been denied.";
+  $options['deny_failed_message'] = "Couldn't deny [user]'s friendship request.";
+    
+  // Remove
+  $options['remove_short'] = 'Remove friend';
+  $options['remove_long'] = 'Remove [user] from your list of friends.';
+  $options['remove_question'] = 'Are you sure you want to remove [user] from your list of friends?';
+  $options['remove_yes'] = 'Remove';
+  $options['remove_no'] = 'Cancel';
+  $options['remove_success_message'] = '[user] has been removed from your list of friends.';
+  $options['remove_failed_message'] = 'Failed to remove [user] from your list of friends.';
+    
+  return $options;
+}
+
+/**
+ * Sort of public API to manage Flag Friend relationships. Handles both Flag
+ * states and flag_friend table entries.
+ * 
+ * Using transactions because whole operation is not atomic and DB could end up
+ * in an inconsistent state.
+ * 
+ * @param $op
+ *  One of the following operations:
+ *    "create" - creates relationship and runs Flag Friend triggers.
+ *    "create_no_trigger" - same as create but skips Flag Friend triggers.
+ *    "delete" - deletes relationship and runs Flag Friend triggers.
+ *    "delete_no_trigger" - same as delete but skips Flag Friend triggers.
+ *     
+ * @param $account
+ *  first user object
+ * @param $content_id
+ *  second user's id
+ * @param $flag
+ *  flag object
+ * @return boolean
+ *  TRUE on success, FALSE otherwise.
  */
-function flag_friend_unfriend_form($action, $flag, $content_id, $token) {
-  global $user;
-  $form['current'] = array('#type' => 'value', '#value' => func_get_args());
-
-  $status = flag_friend_determine_friend_status($flag, $user->uid, $content_id);
-  switch ($status) {
-    case FLAG_FRIEND_PENDING:
-      // pending
-      $question = t('Are you sure you want to cancel your pending friend request?');
-    break;
-    case FLAG_FRIEND_APPROVAL:
-      // denial
-      $question = t('Are you sure you don\'t want to be friends with this user?');
+function flag_friend_relationship($op, $account, $content_id = NULL, $flag = NULL) {  
+  // Start transaction.
+  _flag_friend_transaction('BEGIN');
+  
+  switch ($op) {
+    case 'create':
+      $result = _flag_friend_flag_both('flag', $account, $content_id, $flag);
       break;
-    default:
-      // unfriend
-      $question = $flag->get_label('unflag_confirmation', $content_id);
+    
+    case 'create_no_trigger':
+      // Run "create" operation with semaphore set, so our hook_flag()
+      // doesn't stand on our way.
+      global $flag_friend_no_action_required;
+      $flag_friend_no_action_required = TRUE;
+      $result = _flag_friend_flag_both('flag', $account, $content_id, $flag);
+      unset($flag_friend_no_action_required);
+      // Manually create relationship in the DB because of the semaphore.
+      if ($result) {
+        $result = _flag_friend_relationship_db('create', $account, $content_id, $flag);
+      }
+      break;
+      
+    case 'delete':
+      $result = _flag_friend_flag_both('unflag', $account, $content_id, $flag);
       break;
+      
+    case 'delete_no_trigger':
+      // Run "delete" operation with semaphore set, so our hook_flag()
+      // doesn't stand on our way.
+      global $flag_friend_no_action_required;
+      $flag_friend_no_action_required = TRUE;
+      $result = _flag_friend_flag_both('unflag', $account, $content_id, $flag);
+      unset($flag_friend_no_action_required);
+      // Manually create relationship in the DB because of the semaphore.
+      if ($result) {
+        $result = _flag_friend_relationship_db('delete', $account, $content_id, $flag);
+      }
   }
-  $path = $_REQUEST['destination'];
-  $form = confirm_form($form, $question, $path);
-  $form['#theme'] = 'flag_friend_unfriend_form';
-  return $form;
-}
-
-/**
- * Submit handler.
- *
- * @see flag_friend_message_form().
- * @see flag_friend_unfriend_form().
- */
-function flag_friend_form_submit($form, &$form_state) {
-  global $user;
-  $action = $form_state['values']['current'][0];
-  $flag = $form_state['values']['current'][1];
-  $content_id = $form_state['values']['current'][2];
-  $token = $form_state['values']['current'][3];
-  $status = flag_friend_determine_friend_status($flag, $user->uid, $content_id, TRUE);
   
-  if (isset($form_state['values']['flag_friend_message'])) {
-    $flag->friend_message = $form_state['values']['flag_friend_message'];
-    // Record message only if user pending request.
-    if ($status === FLAG_FRIEND_PENDING) {
-      flag_friend_message($action, $flag, $content_id, $user->uid);
-    }
-    flag_friend_message_email($status, $flag, $content_id, $user);
-  }
-  // the only time we want to unfriend, is if $status = FLAGGED or APPROVAL
-  elseif ($status === FLAG_FRIEND_FLAGGED || $status === FLAG_FRIEND_APPROVAL) {
-    flag_friend_unfriend($action, $flag, $content_id, $user, $status);
+  // commit or rollback
+  if ($result) {
+    _flag_friend_transaction('COMMIT');
+    return TRUE;
   }
-  elseif ($status === FLAG_FRIEND_PENDING) {
-    // Clean message when user cancel own request.
-    flag_friend_message($action, $flag, $content_id, $user->uid);
+  else {
+    _flag_friend_transaction('ROLLBACK');
+    return FALSE;
   }
 }
 
 /**
- * Menu callback to either unflag yourself, or remove the relationship record.
- *
- * @param $event
- *   String designator to see what we're doing. (flag, unflag, unfriend)
- * @param $flag_name
- *   The name of the flag, should only be 'friend'.
- * @param $content_id
- *   The id of the content we're operating on. (uid)
- * @param $status
- *   Status integer to see where we are in the friend process.
+ * Helper function to wrap our operations in transactions if they are enabled.
  */
-function flag_friend_unfriend($event, $flag, $content_id, $account, $status) {
-  global $user;
-
-  // 'Denial' and 'Pending - Cancel?'
-  if ($event == 'unflag') {
-    if ($status == FLAG_FRIEND_APPROVAL) {
-      // Denial - the content_id is actually the account param in this case
-      $account = user_load(array('uid' => $content_id));
-      // and the $user->uid is actually the content(_id) we're unflagging
-      $content_id = $user->uid;
-
-      // Fire trigger
-      module_invoke_all('flag_friend', 'deny', $user, $account);
-    }
-    // remove any messages
-    flag_friend_message($event, $flag, $content_id, $account->uid);
-    // unflag
-    $flag->flag($event, $content_id, $account);
-  }
-  elseif ($event == 'unfriend') {
-    // remove the friend relationship    
-    db_query('DELETE FROM {flag_friend} WHERE (uid = %d AND friend_uid = %d) OR (uid = %d AND friend_uid = %d)', $user->uid, $content_id, $content_id, $user->uid);
-
-    // Denial - the content_id is actually the account param in this case
-    $account = user_load(array('uid' => $content_id));
-    
-    // Fire trigger
-    module_invoke_all('flag_friend', 'remove', $account, $user);
-  }
+function _flag_friend_transaction($op) {
+  if (variable_get('flag_friend_use_transactions', FALSE)) {
+    db_query($op); 
+  } 
 }
 
 /**
- * API callback function to update our new field.
+ * Run flag action for both users. Let our hook_flag() handle the relationship.
+ * and catch "rollback" if our hook_flag() operation failed to complete.
  */
-function flag_friend_message($action, $flag, $content_id, $account_uid) {
-  $fcid = flag_friend_get_fcid($flag, $content_id, $account_uid);
-  if ($action == 'flag' && $flag->friend_message) {
-    db_query("INSERT INTO {flag_friend_message} VALUES(%d, '%s')", $fcid, $flag->friend_message);
-  }
-  elseif ($action == 'unflag') {
-    db_query("DELETE FROM {flag_friend_message} WHERE fcid = %d", $fcid);
+function _flag_friend_flag_both($action, $account, $content_id, $flag) {
+  global $flag_friend_rollback;
+  $status = flag_friend_relationship_status($flag, $account->uid, $content_id, TRUE);
+  if (($status == FLAG_FRIEND_UNFLAGGED && $action == 'flag') ||
+      ($status == FLAG_FRIEND_RELATIONSHIP && $action == 'unflag')) {
+    $result1 = $flag->flag($action, $content_id, $account);
+    if (!$result1) {
+      return FALSE;
+    }
+    $content_account = user_load(array('uid' => $content_id));
+    // Don't forget to catch our global "rollback" flag.
+    if ($flag->flag($action, $account->uid, $content_account) && !isset($flag_friend_rollback)) {
+      return TRUE;
+    }
+    else {
+      unset($flag_friend_rollback);
+    }
   }
+  return FALSE;
 }
 
+
 /**
- * Retrieves the fcid of a flag.
- *
- * NOTE: hopefully fcid will be passed into the hook_flag() at some point
- *       at which time will render this function unnecessary.
+ * Manage relationship DB entries. Other modules should use 
+ * flag_friend_relationship() instead of this function. 
+ * 
+ * Uni-directional relationships are not supported yet.
+ * 
+ * TODO: Add support for relationship direction. For each uni-directional 
+ * relationships store and delete single entry.
+ * 
+ * @param $op
+ *  relationship operation
+ * @param $account
+ *  for uni-directional relationships, originating user's account.
+ *  for bi-directional ones, just first user object.
+ * @param $content_id
+ *  for uni-directional relationships, terminating user's account id.
+ *  for bi-directional ones, just second user's id.
+ * @param $flag
+ *  flag object.
+ * @return boolean
+ *  TRUE on success, FALSE otherwise.
  */
-function flag_friend_get_fcid($flag, $content_id, $account_uid) {
-  return db_result(db_query("SELECT fcid FROM {flag_content} WHERE fid = %d AND content_type = '%s' AND content_id = %d AND uid = %d", $flag->fid, $flag->content_type, $content_id, $account_uid));
-}
-
-function flag_friend_message_email($status, $flag, $recipient_uid, $sender) {
-  $recipient = user_load(array('uid' => $recipient_uid));
-  // if the user can receive notifications
-  if (user_access('receive friend email notification')) {
-    // and they've expressed they want them
-    if ((isset($recipient->friend_notification) && $recipient->friend_notification !== -1) || !isset($recipient->friend_notification)) {
-      $email = theme('flag_friend_message_email', $status, $flag, $recipient, $sender);
-      if (isset($email['body'])) {
-        if (function_exists('messaging_message_send_user')) {
-          messaging_message_send_user($recipient, $email, NULL, 1);
-        }
-        else {
-          $language = user_preferred_language($recipient);
-          drupal_mail('flag_friend', $email['type'], $recipient->mail, $language, $email);
-        }
-      }
-    }
+function _flag_friend_relationship_db($op, $account, $content_id = NULL, $flag = NULL) {
+  switch ($op) {
+    case 'create':
+      $q1 = db_query("INSERT INTO {flag_friend} VALUES(%d, %d, %d, %d)", $account->uid, $content_id, $_SERVER['REQUEST_TIME'], $flag->fid);
+      $q2 = db_query("INSERT INTO {flag_friend} VALUES(%d, %d, %d, %d)", $content_id, $account->uid, $_SERVER['REQUEST_TIME'], $flag->fid);
+      return ($q1 !== FALSE && $q2 !== FALSE);
+      
+    // Delete 2 entries of single relationship between the users.
+    case 'delete':
+      $q = db_query('DELETE FROM {flag_friend} WHERE (uid = %d AND friend_uid = %d AND fid = %d) OR (uid = %d AND friend_uid = %d AND fid = %d)', $account->uid, $content_id, $flag->fid, $content_id, $account->uid, $flag->fid);
+      return ($q !== FALSE);
+      
+    // Delete all relationships of the user.
+    case 'delete_user':
+      $q = db_query("DELETE FROM {flag_friend} WHERE uid = %d OR friend_uid = %d", $account->uid, $account->uid);
+      return ($q !== FALSE);      
   }
 }
 
 /**
- * Implementation of hook_mail().
+ * Helper function to return Flag Friend operation based on Flag action and
+ * current relationship status. 
  */
-function flag_friend_mail($key, &$message, $params) {
-  $message['subject'] = $params['subject'];
-  $message['body'][] = $params['body'];
+function _flag_friend_get_op($action, $status) {
+  if ($action == 'flag' && $status == FLAG_FRIEND_UNFLAGGED) {
+    return 'request';
+  }
+  if ($action == 'unflag' && $status == FLAG_FRIEND_PENDING) {
+    return 'cancel'; 
+  }
+  if ($action == 'deny' && $status == FLAG_FRIEND_APPROVAL) {
+    return 'deny'; // special "deny" flag action  
+  }
+  if ($action == 'flag' && $status == FLAG_FRIEND_APPROVAL) {
+    return 'approve';
+  }
+  if ($action == 'unflag' && $status == FLAG_FRIEND_RELATIONSHIP) {
+    return 'remove';
+  }
+  return FALSE;
 }
 
 /**
- * Theme the outgoing email message.
- *
- * @param $status
- *   Status of the friendship.
- * @param $flag
- *   The flag object.
- * @param $recipient
- *   The user object of the person receiving the email.
- * @param $sender
- *   The user object of the person sending the email.
- * @return
- *   An array containing the email [type] (mailkey), [subject] and [body].
+ * Helper function to return Flag action based on Flag Friend operation and
+ * current relationship status.
  */
-function theme_flag_friend_message_email($status, $flag, $recipient, $sender) {
-  $email = array();
-  $email['type'] = 'flag-friend';
-
-  switch ($status) {
-    case FLAG_FRIEND_FLAGGED:
-      // sender confirmed you as a friend
-      $email['subject'] = t('!username confirmed you as a friend on !site', array(
-        '!username' => $sender->name,
-        '!site' => variable_get('site_name', ''),
-        ));
-      $email['body'] = t('!firstname confirmed you as a friend on !site.
-
-      To view !firstname\'s profile, follow this link,
-      !link
-
-      !message
-
-      Thanks,
-
-      The !site Team', array(
-        '!firstname' => isset($sender->firstname) ? $sender->firstname : $sender->name,
-        '!site' => variable_get('site_name', ''),
-        '!message' => $flag->friend_message ? t('Message:'). $flag->friend_message : '',
-        '!link' => url('user/'. $sender->uid, array('absolute' => TRUE)),
-        ));
-      break;
-
-    case FLAG_FRIEND_PENDING:
-      // sender added you as a friend
-      $email['subject'] = t('!username added you as a friend on !site', array('!username' => $sender->name, '!site' => variable_get('site_name', '')));
-      $email['body'] = t('!firstname added you as a friend on !site. We need to confirm that you know !firstname in order for you to be friends on !site.
-
-      To confirm this friend request, follow the link below:
-      !link
-
-      !message
-
-      Thanks,
-      The !site Team', array(
-        '!firstname' => isset($sender->firstname) ? $sender->firstname : $sender->name,
-        '!site' => variable_get('site_name', ''),
-        '!message' => $flag->friend_message ? t('Message:'). $flag->friend_message : '',
-        '!link' => url('user/'. $recipient->uid .'/friends', array('absolute' => TRUE)),
-        ));
-      break;
+function _flag_friend_get_action($op, $status) {
+  if ($op == 'request' && $status == FLAG_FRIEND_UNFLAGGED) {
+    return 'flag';
+  }
+  if ($op == 'cancel' && $status == FLAG_FRIEND_PENDING) {
+    return 'unflag'; 
   }
-  return $email;
+  if ($op == 'deny' && $status == FLAG_FRIEND_APPROVAL) {
+    // This is special part: "deny" action turns into "deny" operation to 
+    // properly theme "Deny" link. But when we turn "deny" operation into 
+    // an action, we make it "unflag" because that's what we pass to the
+    // $flag->flag().
+    return 'unflag';  
+  }
+  if ($op == 'approve' && $status == FLAG_FRIEND_APPROVAL) {
+    return 'flag';
+  }
+  if ($op == 'remove' && $status == FLAG_FRIEND_RELATIONSHIP) {
+    return 'unflag';
+  }
+  return FALSE;
 }
 
 /**
- * Retrieve our flag's message.
+ * Access callback for confirm form menu item.
  */
-function flag_friend_get_message($fcid) {
-  $flag_friend = FALSE;
-  $result = db_result(db_query("SELECT message FROM {flag_friend_message} WHERE fcid = %d", $fcid));
-  if ($result) {
-    $flag_friend = $result;
+function _flag_friend_menu_access($link_type, $op, $flag_name, $content_id) {
+  // Initial sanity checks.
+  if (empty($link_type) || empty($op) || empty($flag_name) || !is_numeric($content_id)) {
+    return FALSE;
+  }
+  // Check if link type is supported.
+  if ($link_type != 'msg_confirm') {
+    return FALSE;
+  }
+  // Load and check flag.
+  $flag = flag_get_flag($flag_name);
+  if (!$flag) {
+    return FALSE;
   }
-  return $flag_friend;
+  // Get current status.
+  $status = flag_friend_relationship_status($flag, $GLOBALS['user']->uid, $content_id);
+  // Check if operation is applicable.
+  $action = _flag_friend_get_action($op, $status);
+  if (!$action) {
+    return FALSE;
+  }
+  // "deny" is simulated action to deny incoming request. Flag with deny
+  // action points to the requesting user and we unflag receiver on behalf 
+  // of requester.
+  // Thus we must check if the requester can "unflag" the receiver
+  if ($op == 'deny') {
+    $account = user_load(array('uid' => $content_id));
+    $content_id = $GLOBALS['user']->uid;
+  }
+  else {
+    $account =& $GLOBALS['user'];
+  }
+  return $flag->access($content_id, $action, $account);
 }
 
-/**
- * Theme function for the message form.
- */
-function theme_flag_friend_message_form($form) {
-  return drupal_render($form);
-}
+
 
 /**
- * Theme function for the unfriending action.
+ * 
+ * Flag hooks.
+ * 
  */
-function theme_flag_friend_unfriend_form($form) {
-  return drupal_render($form);
-}
 
 /**
- * Register theme functions.
- */
-function flag_friend_theme() {
-  return array(
-    'flag_friend_message_email' => array(
-      'arguments' => array('status', 'flag', 'recipient', 'sender'),
-    ),
-     'flag_friend_message_form' => array(
-      'arguments' => array('form'),
-    ),
-     'flag_friend_unfriend_form' => array(
-      'arguments' => array('form'),
-    ),
-  );
+ * Implementation of hook_flag().
+ * 
+ * Most of our magic happens here. We work here with Flag's actions and not our
+ * operations since Flag doesn't process custom actions.
+ * Using $flag_friend_no_action_required semaphore when flagging to not call
+ * ourselves.
+ * Using $flag_friend_rollback flag when non-atomic operation fails.
+ * 
+ * 
+ */
+function flag_friend_flag($event, $flag, $content_id, $account, $fcid) {
+  global $user, $flag_friend_no_action_required, $flag_friend_rollback;
+  // Check semaphore to not call ourselves.
+  if ($flag_friend_no_action_required) {
+    return;
+  }
+  // We only operate on user flags that have "msg_confirm" link type.  
+  if ($flag->content_type != 'user' || $flag->link_type != 'msg_confirm') {
+    return;
+  }
+  // See the status of the relationship. Note that we clear statically cached
+  // status so it certainly contains value AFTER operation.
+  $status = flag_friend_relationship_status($flag, $account->uid, $content_id, TRUE);
+  $target_account = user_load(array('uid' => $content_id));
+  
+  if ($event == 'flag') {
+    // If both are now flagged, record the relationship.
+    if ($status == FLAG_FRIEND_BOTH) { 
+      if (_flag_friend_relationship_db('create', $account, $content_id, $flag)) {
+        // fire trigger
+        module_invoke_all('flag_friend', 'approve', $target_account, $account, $flag);
+      }
+      else {
+        $flag_friend_rollback == TRUE;
+      }
+    }
+    else {
+      // Save request message.
+      if (isset($GLOBALS['flag_friend_request_message'])) {
+        $message = $GLOBALS['flag_friend_request_message'];
+        flag_friend_save_message($fcid, $message);
+      }
+      // fire trigger
+      module_invoke_all('flag_friend', 'request', $target_account, $account, $flag);
+    }
+  }
+  elseif ($event == 'unflag') {
+    switch ($status) {
+      case FLAG_FRIEND_BREAKING:
+        // $account unflagged $target_account.
+        // First, unflag $account on behalf of $target_account. Use semaphore 
+        // so we don't call ourselves.
+        $flag_friend_no_action_required = TRUE;
+        $result = $flag->flag('unflag', $account->uid, $target_account);
+        unset($flag_friend_no_action_required);
+        // Then delete relationship.
+        if ($result && _flag_friend_relationship_db('delete', $account, $content_id, $flag)) {
+          module_invoke_all('flag_friend', 'remove', $target_account, $account, $flag);
+        }
+        else {
+          // Use global rollback flag as the only way to return information 
+          // back to our submit callback. 
+          $flag_friend_rollback = TRUE;  
+        }
+        break;
+                
+      case FLAG_FRIEND_UNFLAGGED:
+        // Final status is same for denied and canceled request. Need 
+        // additional info to know flag operation.
+        if ($content_id == $user->uid && $account->uid != $user->uid) {
+          // User unflags himself on behalf of $account, i.e. denies incoming 
+          // request.
+          module_invoke_all('flag_friend', 'deny', $account, $target_account, $flag);
+        }
+        elseif ($account->uid == $user->uid && $account->uid != $content_id) {
+          // User cancels own request. 
+          module_invoke_all('flag_friend', 'cancel', $target_account, $account, $flag);
+        }
+    }
+  }
 }
 
 /**
@@ -621,244 +591,169 @@ function flag_friend_theme() {
  */
 function flag_friend_flag_default_flags() {
   $flags = array();
-  $flags[] = array(
+  // Exported flag: "Friend".
+  $flags[] = array (
     'content_type' => 'user',
     'name' => 'friend',
     'title' => 'Friend',
-    'roles' => array(
-      0 => '2',
-    ),
-    'global' => FALSE,
+    'global' => false,
+    'types' => array (),
     'flag_short' => 'Add friend',
     'flag_long' => 'Add this user to your list of friends.',
-    'flag_confirmation' => 'Are you sure you want to add [user] to your list of friends?',
+    'flag_message' => '',
     'unflag_short' => 'Remove friend',
     'unflag_long' => 'Remove this user from your list of friends.',
-    'unflag_confirmation' => 'Are you sure you want to remove [user] from your list of friends?',
-    'status' => FALSE,
-    'link_type' => 'confirm',
-    'locked' => array('name', 'global', 'link_type'),
+    'unflag_message' => '',
+    'unflag_denied_text' => '',
+    'link_type' => 'msg_confirm',
+    'roles' => array (
+      'flag' => array (0 => '2'),
+      'unflag' => array (0 => '2'),
+    ),
+    'show_on_profile' => true,
+    'access_uid' => '',
+    'status' => false,
+    'locked' => array (
+      'name' => 'name',
+      'global' => 'global',
+    ),
+    'module' => 'flag_friend',
+    'api_version' => 2,
   );
   return $flags;
 }
 
 /**
- * Implementation of hook_popups().
+ * Implementation of hook_flag_link().
+ * 
+ * Routes flag actions to custom callback and provides custom operations to it.
+ * Actions are ones supported by Flag plus "deny" action that allows us
+ * to distinguish "deny" and "approve" operations.
  */
-function flag_friend_popups() {
-  return array(
-    'user/*' => array( // any user page
-      'span.flag-friend a' => array(
-        'afterSubmit' => 'Drupal.flagFriendPopupsAfterSubmit',
-      ),
-    ),
-    'user/*/friends/*' => array( // friend views
-      'span.friend a' => array(
-        'afterSubmit' => 'Drupal.flagFriendPopupsAfterSubmit',
-      ),
-    ),
-  );
+function flag_friend_flag_link($flag, $action, $content_id) {
+  global $user; 
+  $link = array('query' => drupal_get_destination());
+    
+  // Determine what the status in the friend process is.
+  $status = flag_friend_relationship_status($flag, $user->uid, $content_id);
+  // Transform Flag action to a Flag Friend operation.
+  $op = _flag_friend_get_op($action, $status);
+  if (!$op) {
+    return array(); // invalid status.
+  }
+  $link['title'] = $flag->get_label("${op}_short", $content_id);
+  $link['attributes']['title'] = $flag->get_label("${op}_long", $content_id);
+  $link['href'] = "ff/msg_confirm/${op}/$flag->name/$content_id";
+  return $link;
 }
 
 /**
- * Implementation of hook_hook_info().
- *
- * Provide some triggers so that actions can be performed at various stages.
+ * Implementation of hook_flag_link_types().
  */
-function flag_friend_hook_info() {
+function flag_friend_flag_link_types() {
+  $options = _flag_friend_default_link_options();
+  // Let modules alter our link options. Need to alter them here rather than
+  // in hook_flag_options_alter() so Flag module renders additions as dependant
+  // fields too.
+  drupal_alter('flag_friend_link_options', $options);
   return array(
-    'flag_friend' => array(
-      'flag_friend' => array(
-        'approve' => array(
-          'runs when' => t("A user approves another's friendship request."),
-        ),
-        'request' => array(
-          'runs when' => t("A user requested another's friendship."),
-        ),
-        'deny' => array(
-          'runs when' => t("A user denies another's friendship request."),
-        ),
-        'remove' => array(
-          'runs when' => t("A user removes another user as a friend."),
-        ),
-      ),
+    'msg_confirm' => array(
+      'title' => t('Relationship confirmation form'),
+      'description' => t('Flag Friend: the user will be taken to a confirmation form with optional message on a separate page to confirm the relationship.'),
+      'options' => $options,
     ),
   );
 }
 
+
+
+
+
 /**
- * Implementation of hook_trigger_name().
+ * 
+ * All other hooks.
+ * 
  */
-function flag_friend_flag_friend($op, $friend, $user) {
-  if (function_exists('_trigger_get_hook_aids')) {
-    $aids = _trigger_get_hook_aids('flag_friend', $op);
-  
-    switch ($op) {
-      // in these cases, the users performing the operations are flipped
-      case 'approve':
-      case 'deny':
-        $user->friend = $friend;
-        $context = array(
-          'hook' => 'flag_friend',
-          'op' => $op,
-          'user' => $friend,
-          'flag_friend' => $user,
-        );
-        break;
-      // these are normal
-      case 'request':
-      case 'remove':
-        $friend->friend = $user;
-        $context = array(
-          'hook' => 'flag_friend',
-          'op' => $op,
-          'user' => $user,
-          'flag_friend' => $friend,
-        );
-        break;
-    }
-    if ($aids) {
-      actions_do(array_keys($aids), $friend, $context);
-    }
-  }
-}
 
 /**
- * Implementation of hook_activity_info().
+ * Implementation of hook_user().
  */
-function flag_friend_activity_info() {
-  $flag = flag_get_flag('friend');
-  $info = new stdClass();
-  $info->api = 2;
-  $info->name = 'flag_friend';
-  $info->object_type = 'flag_friend';
-  $info->objects = array('requestor' => 'user', 'requestee' => 'flag_friend'); // array keys are the labels
-  $info->hooks = array('flag_friend' => array('approve', 'request', 'deny', 'remove'));
-  $info->realms = array('flag_friend' => $flag->title);
-  return $info;
+function flag_friend_user($op, &$edit, &$account, $category = NULL) {
+  if ($op == 'delete') {
+    // Remove any relationship DB entries if an account is removed. I believe 
+    // flags are handled by Flag itself.
+    _flag_friend_relationship_db('delete_user', $account); 
+  }
 }
 
 /**
- * Implementation of hook_activity_grants().
+ * Implementation of hook_menu().
  */
-function flag_friend_activity_grants($activity) {
-  return array(
-    'flag_friend' => array($activity->uid), // the id that will be used
+function flag_friend_menu() {
+  $items = array();
+  $items['ff/%/%/%/%'] = array(
+    'title' => 'Flag friend confirm',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('flag_friend_confirm', 1, 2, 3, 4),
+    'access callback' => '_flag_friend_menu_access',
+    'access arguments' => array(1, 2, 3, 4),
+    'type' => MENU_CALLBACK,
+    'file' => 'includes/flag_friend.forms.inc',
   );
+  return $items;
 }
 
 /**
- * Implementation of hook_activity_access_grants().
+ * Implementation of hook_form_FORMID_alter().
+ * 
+ * Insert Flag Friend link options into flag add/edit form.
  */
-function flag_friend_activity_access_grants($account) {
-  $friends = flag_friend_get_friends($account->uid);
-  $realm_ids = array();
-  if (!empty($friends)) {
-    $realm_ids['flag_friend'] = array_keys($friends);
-  }
-  return $realm_ids;
+function flag_friend_form_flag_form_alter(&$form, &$form_state) {
+  module_load_include('inc', 'flag_friend', 'includes/flag_friend.forms');
+  _flag_friend_form_flag_form_alter($form, $form_state);
 }
 
 /**
- * Token integration.
- */
-
-/**
- * Implementation of hook_token_list().
+ * Register theme functions.
  */
-function flag_friend_token_list($type = 'all') {
-  if ($type == 'flag_friend') {
-    $tokens = array();
-    $tokens['flag_friend'] = array(
-      'requestor' => t('The name of the user who originally made the request.'),
-      'requestee' => t('The name of the user who originally received the request.'),
-      'requestor-uid' => t("Requestor's ID."),
-      'requestee-uid' => t("Requestee's ID."),
-      'requestor-url' => t("The URL of the requestor's profile page."),
-      'requestee-url' => t("The URL of the requestee's profile page.")
-    );
-    return $tokens;
-  }
+function flag_friend_theme() {
+  return array(
+    'flag_friend_confirm_form' => array(
+      'arguments' => array('form'),
+      'file' => 'includes/flag_friend.forms.inc',
+    ),    
+  );
 }
 
 /**
- * Implementation of hook_token_values().
+ * Implementation of hook_init().
  */
-function flag_friend_token_values($type, $object = NULL, $options = array()) {
-  if (($type == 'flag_friend') && !empty($object)) {
-    $data = array();
-    $data['requestor'] = $object->friend->name;
-    $data['requestee'] = $object->name;
-    $data['requestor-uid'] = $object->friend->uid;
-    $data['requestee-uid'] = $object->uid;
-    $data['requestor-url'] = base_path().drupal_get_path_alias('user/'.$object->friend->uid);
-    $data['requestee-url'] = base_path().drupal_get_path_alias('user/'.$object->uid);
-    return $data;
+function flag_friend_init() {
+  // Include modules integrations.
+  $contrib = array('activity', 'author_pane', 'popups', 'token', 'trigger');
+  $path = drupal_get_path('module', 'flag_friend');
+  foreach ($contrib as $module) {
+    if (module_exists($module)) {
+      include_once $path ."/contrib/flag_friend.$module.inc";
+    }
   }
 }
 
 /**
- * Implementation of hook_preprocess_author_pane().
+ * Implementation of hook_views_api().
  */
-function flag_friend_preprocess_author_pane(&$variables) {
-  global $user;
-  $account_id = $variables['account']->uid;
-  $image_path = $variables['image_path'];
-
-  // Accessing the user profile is the only way to be able to see the friend
-  // flag out-of-the-box so I feel it's pretty safe to use this permisssion.
-  if ($account_id != 0 && user_access('access user profiles') && $user->uid != $account_id) {
-    $flag = flag_get_flag('friend');
-    $flag_status = flag_friend_determine_friend_status($flag, $user->uid, $account_id);
-
-    switch ($flag_status) {
-      case (FLAG_FRIEND_FLAGGED):
-        // Remove friend
-        $variables['flag_friend_link'] = flag_friend_create_link('unfriend', $account_id);
-        $variables['flag_friend'] =
-          l(theme('image', "$image_path/buddy-remove.png", t('Remove friend'), t('Remove friend'), NULL, FALSE),
-            "flag/confirm/unfriend/friend/$account_id",
-            array('query' => drupal_get_destination(),
-              'html' => TRUE,
-              'attributes'  => array('title' => $flag->unflag_short),
-            ));
-        break;
-
-      case (FLAG_FRIEND_APPROVAL):
-      case (FLAG_FRIEND_UNFLAGGED):
-        // Add friend
-        $variables['flag_friend_link'] = $flag->theme($flag->is_flagged($account_id) ? 'unflag' : 'flag', $account_id);
-        $variables['flag_friend'] =
-          l(theme('image', "$image_path/buddy-add.png", t('Add friend'), t('Add friend'), NULL, FALSE),
-            "flag/confirm/flag/friend/$account_id",
-            array('query' => drupal_get_destination(),
-              'html' => TRUE,
-              'attributes'  => array('title' => $flag->flag_short),
-            ));
-        break;
-
-      case (FLAG_FRIEND_PENDING):
-        // Pending friend
-        $variables['flag_friend_link'] = $flag->theme($flag->is_flagged($account_id) ? 'unflag' : 'flag', $account_id);
-        $variables['flag_friend'] =
-        l(theme('image', "$image_path/buddy-remove.png", t(' Friend Requested. Cancel?'), t(' Friend Requested. Cancel?'), NULL, FALSE),
-          "flag/confirm/unflag/friend/$account_id",
-          array('query' => drupal_get_destination(),
-            'html' => TRUE,
-            'attributes'  => array('title' => t(' Friend Requested. Cancel?')),
-          ));
-
-        break;
-    }
-  }
+function flag_friend_views_api() {
+  return array(
+    'api' => 2.0,
+    'path' => drupal_get_path('module', 'flag_friend') .'/includes',
+  );
 }
 
-
 /**
  * Implementation of hook_ctools_plugin_directory().
  */
 function flag_friend_ctools_plugin_directory($module, $plugin) {
-  if ($module == 'ctools') {
-    return 'plugins/'. $plugin;
-  }  
+  if ($module == 'ctools' && $plugin = 'content_types') {
+    return $plugin;
+  }
 }
diff --git flag_friend_access/flag_friend_access.info flag_friend_access/flag_friend_access.info
index 433d290..1b2bbea 100644
--- flag_friend_access/flag_friend_access.info
+++ flag_friend_access/flag_friend_access.info
@@ -2,10 +2,3 @@ name = Flag friend access control
 description = Allows users to specify that only their friends can view this piece of content
 package = Flags
 dependencies[] = flag_friend
-core = 6.x
-; Information added by drupal.org packaging script on 2010-02-20
-version = "6.x-2.x-dev"
-core = "6.x"
-project = "flag_friend"
-datestamp = "1266624362"
-
diff --git includes/flag_friend.forms.inc includes/flag_friend.forms.inc
new file mode 100644
index 0000000..ec4e542
--- /dev/null
+++ includes/flag_friend.forms.inc
@@ -0,0 +1,423 @@
+<?php
+
+/**
+ * Form for confirming the flag_friend operations.
+ * 
+ * We perform most checks in menu access callback so can have less logics here.
+ */
+function flag_friend_confirm(&$form_state, $link_type, $op, $flag_name, $content_id) {
+  global $user;
+  $flag = flag_get_flag($flag_name);
+  $status = flag_friend_relationship_status($flag, $user->uid, $content_id);
+  $action = _flag_friend_get_action($op, $status);
+  $form = array();
+  $form['#submit'] = array('flag_friend_confirm_submit');
+  
+  // Store data in the form.
+  $form['link_type'] = array(
+    '#type' => 'value',
+    '#value' => $link_type,
+  );
+  // Not "op" cause that's used by form itself.
+  $form['ff_op'] = array(
+    '#type' => 'value',
+    '#value' => $op,
+  );
+  $form['action'] = array(
+    '#type' => 'value',
+    '#value' => $action,
+  );
+  $form['flag_name'] = array(
+    '#type' => 'value',
+    '#value' => $flag_name,
+  );
+  $form['flag'] = array(
+    '#type' => 'value',
+    '#value' => &$flag,
+  );  
+  $form['content_id'] = array(
+    '#type' => 'value',
+    '#value' => $content_id,
+  );
+    
+  if ($op == 'request') {
+    $form['relationship_request_message'] = array(
+      '#type' => 'textarea',
+      '#title' => $flag->get_label('request_msg_title', $content_id),
+      '#description' => $flag->get_label('request_msg_desc', $content_id),
+      '#cols' => 60,
+      '#rows' => 5,
+      '#default_value' => $flag->get_label('request_msg', $content_id),
+    );
+  }
+  
+  $path = isset($_GET['destination']) ? $_GET['destination'] : '<front>';
+  $question    = $flag->get_label("${op}_question", $content_id);
+  $yes         = $flag->get_label("${op}_yes", $content_id);
+  $no          = $flag->get_label("${op}_no", $content_id);
+  $description = '';
+  $name        = 'confirm';
+  $form = confirm_form($form, $question, $path, $description, $yes, $no, $name);
+  $form['#theme'] = "flag_friend_confirm_form";
+  return $form;
+}
+
+/**
+ * Submit handler. Similar to flag_confirm_submit() but saves some additional
+ * info such as message.
+ * 
+ * Using transactions because the whole operation is not atomic and 
+ * DB could end up in an inconsistent state.
+ */
+function flag_friend_confirm_submit($form, &$form_state) {
+  global $user, $flag_friend_request_message, $flag_friend_rollback;
+  $op = $form_state['values']['ff_op'];
+  $action = $form_state['values']['action'];
+  $flag  = $form_state['values']['flag'];
+  $content_id = $form_state['values']['content_id'];
+  $token_context_id = $content_id;
+  
+  // Swap users incase this is deny
+  if ($op == 'deny') {
+    $account = user_load(array('uid' => $content_id));
+    $content_id = $GLOBALS['user']->uid;
+  }
+  else {
+    $account =& $GLOBALS['user'];
+  }
+  
+  // Store message in global variable so we can access it in hook_flag().
+  if (isset($form_state['values']['relationship_request_message'])) {
+    $flag_friend_request_message = $form_state['values']['relationship_request_message'];
+  }
+
+  // Flag/unflag.
+  _flag_friend_transaction('BEGIN');
+  if (!$flag->flag($action, $content_id, $account) || isset($flag_friend_rollback)) {
+    _flag_friend_transaction('ROLLBACK');
+    drupal_set_message($flag->get_label("${op}_failed_message", $token_context_id));
+  }
+  else {
+    _flag_friend_transaction('COMMIT');
+    drupal_set_message($flag->get_label("${op}_success_message", $token_context_id));      
+  }
+}
+
+
+/**
+ * Private version of flag_friend_form_flag_form_alter() for convenience.
+ */
+function _flag_friend_form_flag_form_alter(&$form, &$form_state) {
+  $flag = $form['#flag'];
+  if ($flag->content_type != 'user') {
+    // Remove our link type manually in case it's not applicable and terminate
+    // early.
+    // TODO: This may become unneeded. See http://drupal.org/node/721474
+    unset($form['display']['link_type']['#options']['msg_confirm']);
+    return;
+  }
+  
+  // We need to apply link options as default values manually in case this is
+  // new Flag. Need to be careful to not overwrite saved values.
+  foreach (_flag_friend_default_link_options() as $key => $value) {
+    if (!isset($flag->$key)) {
+      $flag->$key = $value;
+    }
+  }
+  // Insert warning.
+  $warning  = t('<strong>Note that message settings have no effect with Flag Friend link types. Flag Friend has own messages configured in <em>Link options</em> below.</strong>');
+  $warning .= '<br/><br/>';
+  $form['messages']['flag_friend_description'] = array(
+    '#value' => $warning,
+    '#weight' => -10,
+  );
+  // We could remove "required" validation but that would break Flag UX for 
+  // other user flags. Thus this is most simple we can do.
+  $note = t(' For Flag Friend flags insert random garbage here.');
+  $form['messages']['flag_short']['#description'] .= $note;
+  $form['messages']['unflag_short']['#description'] .= $note;
+  
+  // Request
+  $form['link_options']['request_short'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Request: link title.'),
+    '#default_value' => $flag->request_short,
+    '#description' => t(''),
+    '#access' => empty($flag->locked['request_short']),
+  );
+  $form['link_options']['request_long'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Request: link description'),
+    '#default_value' => $flag->request_long,
+    '#description' => t(''),
+    '#access' => empty($flag->locked['request_long']),
+  );
+  $form['link_options']['request_question'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Request: question'),
+    '#default_value' => $flag->request_question,
+    '#description' => t(''),
+    '#access' => empty($flag->locked['request_question']),
+  );
+  $form['link_options']['request_yes'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Request: <em>yes</em> answer text'),
+    '#default_value' => $flag->request_yes,
+    '#description' => t(''),
+    '#access' => empty($flag->locked['request_yes']),
+  );
+  $form['link_options']['request_no'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Request: <em>no</em> answer text'),
+    '#default_value' => $flag->request_no,
+    '#description' => t(''),
+    '#access' => empty($flag->locked['request_no']),
+  );
+  $form['link_options']['request_msg'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Request: default message text'),
+    '#default_value' => $flag->request_msg,
+    '#description' => t('Default text displayed inside message textarea in the confirmation form if the user has requested relationship.'),
+    '#access' => empty($flag->locked['request_msg']),
+  );
+  $form['link_options']['request_msg_title'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Request: message title'),
+    '#default_value' => $flag->request_msg_title,
+    '#description' => t('Text displayed as title of message textarea in the confirmation form if the user has requested relationship.'),
+    '#access' => empty($flag->locked['request_msg_title']),
+  );
+  $form['link_options']['request_msg_desc'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Request: message description'),
+    '#default_value' => $flag->request_msg_desc,
+    '#description' => t('Text displayed as description of message textarea in the confirmation form if the user has requested relationship.'),
+    '#access' => empty($flag->locked['request_msg_desc']),
+  );
+  $form['link_options']['request_success_message'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Request: success message'),
+    '#default_value' => $flag->request_success_message,
+    '#description' => t('Text displayed on success of relationship request operation.'),
+    '#access' => empty($flag->locked['request_success_message']),
+  );
+  $form['link_options']['request_failed_message'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Request: failure message'),
+    '#default_value' => $flag->request_failed_message,
+    '#description' => t('Text displayed on failure of relationship request operation.'),
+    '#access' => empty($flag->locked['request_failed_message']),
+  ); 
+  
+  // Cancel pending
+  $form['link_options']['cancel_short'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Cancel: link title.'),
+    '#default_value' => $flag->cancel_short,
+    '#description' => t(''),
+    '#access' => empty($flag->locked['cancel_short']),
+  );
+  $form['link_options']['cancel_long'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Cancel: link description'),
+    '#default_value' => $flag->cancel_long,
+    '#description' => t(''),
+    '#access' => empty($flag->locked['cancel_long']),
+  );
+  $form['link_options']['cancel_question'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Cancel: question'),
+    '#default_value' => $flag->cancel_question,
+    '#description' => t(''),
+    '#access' => empty($flag->locked['cancel_question']),
+  );
+  $form['link_options']['cancel_yes'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Cancel: <em>yes</em> answer text'),
+    '#default_value' => $flag->cancel_yes,
+    '#description' => t(''),
+    '#access' => empty($flag->locked['cancel_yes']),
+  );
+  $form['link_options']['cancel_no'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Cancel: <em>no</em> answer text'),
+    '#default_value' => $flag->cancel_no,
+    '#description' => t(''),
+    '#access' => empty($flag->locked['cancel_no']),
+  );
+  $form['link_options']['cancel_success_message'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Cancel: success message'),
+    '#default_value' => $flag->cancel_success_message,
+    '#description' => t('Text displayed on success of cancellation of relationship request.'),
+    '#access' => empty($flag->locked['cancel_success_message']),
+  );
+  $form['link_options']['cancel_failed_message'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Cancel: failure message'),
+    '#default_value' => $flag->cancel_failed_message,
+    '#description' => t('Text displayed on failure of cancellation of relationship request.'),
+    '#access' => empty($flag->locked['cancel_failed_message']),
+  );
+  
+  // Approve request
+  $form['link_options']['approve_short'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Approve: link title.'),
+    '#default_value' => $flag->approve_short,
+    '#description' => t(''),
+    '#access' => empty($flag->locked['approve_short']),
+  );
+  $form['link_options']['approve_long'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Approve: link description'),
+    '#default_value' => $flag->approve_long,
+    '#description' => t(''),
+    '#access' => empty($flag->locked['approve_long']),
+  );
+  $form['link_options']['approve_question'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Approve: question'),
+    '#default_value' => $flag->approve_question,
+    '#description' => t(''),
+    '#access' => empty($flag->locked['approve_question']),
+  );
+  $form['link_options']['approve_yes'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Approve: <em>yes</em> answer text'),
+    '#default_value' => $flag->approve_yes,
+    '#description' => t(''),
+    '#access' => empty($flag->locked['approve_yes']),
+  );
+  $form['link_options']['approve_no'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Approve: <em>no</em> answer text'),
+    '#default_value' => $flag->approve_no,
+    '#description' => t(''),
+    '#access' => empty($flag->locked['approve_no']),
+  );
+  $form['link_options']['approve_success_message'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Approve: success message'),
+    '#default_value' => $flag->approve_success_message,
+    '#description' => t('Text displayed on success of approvement of relationship request.'),
+    '#access' => empty($flag->locked['approve_success_message']),
+  );
+  $form['link_options']['approve_failed_message'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Approve: failure message'),
+    '#default_value' => $flag->approve_failed_message,
+    '#description' => t('Text displayed on failure of approvement of relationship request.'),
+    '#access' => empty($flag->locked['approve_failed_message']),
+  );
+  
+  // Deny request
+  $form['link_options']['deny_short'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Deny: link title.'),
+    '#default_value' => $flag->deny_short,
+    '#description' => t(''),
+    '#access' => empty($flag->locked['deny_short']),
+  );
+  $form['link_options']['deny_long'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Deny: link description'),
+    '#default_value' => $flag->deny_long,
+    '#description' => t(''),
+    '#access' => empty($flag->locked['deny_long']),
+  );
+  $form['link_options']['deny_question'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Deny: question'),
+    '#default_value' => $flag->deny_question,
+    '#description' => t(''),
+    '#access' => empty($flag->locked['deny_question']),
+  );
+  $form['link_options']['deny_yes'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Deny: <em>yes</em> answer text'),
+    '#default_value' => $flag->deny_yes,
+    '#description' => t(''),
+    '#access' => empty($flag->locked['deny_yes']),
+  );
+  $form['link_options']['deny_no'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Deny: <em>no</em> answer text'),
+    '#default_value' => $flag->deny_no,
+    '#description' => t(''),
+    '#access' => empty($flag->locked['deny_no']),
+  );
+  $form['link_options']['deny_success_message'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Deny: success message'),
+    '#default_value' => $flag->deny_success_message,
+    '#description' => t('Text displayed on success of denial of relationship request.'),
+    '#access' => empty($flag->locked['deny_success_message']),
+  );
+  $form['link_options']['deny_failed_message'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Deny: failure message'),
+    '#default_value' => $flag->deny_failed_message,
+    '#description' => t('Text displayed on failure of denial of relationship request.'),
+    '#access' => empty($flag->locked['deny_failed_message']),
+  );
+  
+  // Remove
+  $form['link_options']['remove_short'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Remove: link title.'),
+    '#default_value' => $flag->remove_short,
+    '#description' => t(''),
+    '#access' => empty($flag->locked['remove_short']),
+  );
+  $form['link_options']['remove_long'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Remove: link description'),
+    '#default_value' => $flag->remove_long,
+    '#description' => t(''),
+    '#access' => empty($flag->locked['remove_long']),
+  );
+  $form['link_options']['remove_question'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Remove: question'),
+    '#default_value' => $flag->remove_question,
+    '#description' => t(''),
+    '#access' => empty($flag->locked['remove_question']),
+  );
+  $form['link_options']['remove_yes'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Remove: <em>yes</em> answer text'),
+    '#default_value' => $flag->remove_yes,
+    '#description' => t(''),
+    '#access' => empty($flag->locked['remove_yes']),
+  );
+  $form['link_options']['remove_no'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Remove: <em>no</em> answer text'),
+    '#default_value' => $flag->remove_no,
+    '#description' => t(''),
+    '#access' => empty($flag->locked['remove_no']),
+  );
+  $form['link_options']['remove_success_message'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Remove: success message'),
+    '#default_value' => $flag->remove_success_message,
+    '#description' => t('Text displayed on success of relationship removal.'),
+    '#access' => empty($flag->locked['remove_success_message']),
+  );
+  $form['link_options']['remove_failed_message'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Remove: failure message'),
+    '#default_value' => $flag->remove_failed_message,
+    '#description' => t('Text displayed on failure of relationship removal.'),
+    '#access' => empty($flag->locked['remove_failed_message']),
+  );
+  
+}
+
+/**
+ * Theme function for the remove relationship confirmation form.
+ */
+function theme_flag_friend_confirm_form($form) {
+  return drupal_render($form);
+}
diff --git includes/flag_friend.views.inc includes/flag_friend.views.inc
index db28ee1..4ad52fe 100644
--- includes/flag_friend.views.inc
+++ includes/flag_friend.views.inc
@@ -16,53 +16,95 @@ function flag_friend_views_handlers() {
       'path' => drupal_get_path('module', 'flag_friend') .'/includes',
     ),
     'handlers' => array(
-      'flag_friend_handler_argument_numeric' => array(
-        'parent' => 'views_handler_argument_numeric',
-      ),
       'flag_friend_handler_argument_apachesolr_friend' => array(
         'parent' => 'apachesolr_views_handler_argument',
       ),
       'flag_friend_handler_field_links' => array(
         'parent' => 'views_handler_field',
       ),
+      'flag_friend_handler_filter_flag' => array(
+        'parent' => 'views_handler_filter_many_to_one',
+        'file' => 'flag_friend_handler_filters.inc',
+      ),
     ),
   );
 }
 
 /**
- * Implementation of hook_views_data().
+ * Implementation of hook_views_plugins().
  */
+function flag_friend_views_plugins() {
+  return array(
+    'argument validator' => array(
+      'flag_friend_user_current' => array(
+        'title' => t('User is current'),
+        'handler' => 'flag_friend_plugin_argument_validate_user_current',
+        'path' => drupal_get_path('module', 'flag_friend') . '/includes',
+      ),
+      'flag_friend_user_current_admin' => array(
+        'title' => t('User is current or admin'),
+        'handler' => 'flag_friend_plugin_argument_validate_user_current_admin',
+        'path' => drupal_get_path('module', 'flag_friend') . '/includes',
+      ),
+    ),
+  );
+}
+
+/**
+ * Implementation of hook_views_data().
+ * 
+ * To find users in a relationship, *always* JOIN flag_friend to the users 
+ * table on "friend_uid" and provide "uid" argument.
+ * 
+ * Note that we always store 2 entries for each bi-directional relationship
+ * so we only need to select one column.
+ * If Flag Friend is going to support uni-directional relationships, 
+ * we will use: 
+ *   - "uid" as "source user id" or "originating user id"
+ *   - "friend_uid" as "target user uid" or "terminating user uid".
+ *   
+ * With uni-directional relationships we will:
+ * - JOIN on "friend_uid" and provide "uid" to find "users that 
+ *   are my relationship targets"
+ * - JOIN on "uid" and provide "friend_uid" to find "users that 
+ *   target me in relationship".
+ *
+ **/
 function flag_friend_views_data() {
   $data = array();
-  
-  // flag_friend table
+
+  // flag_friend table. .
+  // We are not joining on uid or friend_uid automatically to let user decide
+  // how to join exactly by selecting proper relationship. 
   $data['flag_friend']['table']['group'] = t('Flag friend');
-  $data['flag_friend']['table']['join'] = array(
-    'users' => array(
-      'left_field' => 'uid',
-      'field' => 'uid',
-    ),
-  );
-  
+  $data['flag_friend']['table']['join'] = array();
+  // Arguments.
+  // Provide terminating user to a view.  
   $data['flag_friend']['uid'] = array(
-    'group' => t('Flag friend'),
-    'title' => t('Flag friend links'),
-    'help' => t('Remove/Deny links'),
-    'real field' => 'uid', 
-    'field' => array(
-      'handler' => 'flag_friend_handler_field_links',
+    'title' => t('Users originating a relationship'),
+    'help' => t('Users that are on <em>originating</em> side of a relationship'),
+    'argument' => array(
+      'handler' => 'views_handler_argument_numeric',
     ),
-  );
+  );  
   
-  // argument
+  // Provide originating user to a view.
   $data['flag_friend']['friend_uid'] = array(
-    'title' => t('Friends of'),
-    'help' => t('Retrieve the friends of the user id given.'),
+    'title' => t('Users terminating a relationship'),
+    'help' => t('Users that are on <em>receiving</em> side of a relationship'),
     'argument' => array(
-      'handler' => 'flag_friend_handler_argument_numeric',
+      'handler' => 'views_handler_argument_numeric',
+    ),
+  );
+  // Filter for relationship type.
+  $data['flag_friend']['fid'] = array(     
+    'title' => t('Relationship'),
+    'help' => t('Filter using specific combination of user flags (relationships).'),
+    'filter' => array(
+      'handler' => 'flag_friend_handler_filter_flag',
+      'numeric' => TRUE,
     ),
   );
-  
   // field, sort, filter, argument
   $data['flag_friend']['created'] = array(
     'title' => t('Relationship created time'),
@@ -81,7 +123,7 @@ function flag_friend_views_data() {
       'handler' => 'views_handler_argument_date',
     ),
   );
-  
+
   // flag_friend_message table
   $data['flag_friend_message']['table']['group'] = t('Flag friend');
   $data['flag_friend_message']['table']['join'] = array(
@@ -90,8 +132,7 @@ function flag_friend_views_data() {
       'field' => 'fcid',
     ),
   );
-  
-  // field
+  // message field
   $data['flag_friend_message']['message'] = array(
     'title' => t('Message'),
     'help' => t('Display the message for any friend flags. (Only useful for a list of pending friend requests.)'),
@@ -99,26 +140,7 @@ function flag_friend_views_data() {
       'handler' => 'views_handler_field',
       'click sortable' => FALSE,
     ),
-  );
-  
-  // Add the flag relationship.
-  // This basically just changes the 'base field' while reusing Flag's 
-  // relationship handler. In effect, we can display the user who flagged
-  // the content we specify, instead of the user who is flagged.
-  $data['users']['flag_friend_content_rel'] = array(
-    'group' => t('Flag Friend'),
-    'title' => t('User flag'),
-    'help' => t('Limit results to only those users flagged by a certain flag; Displays the user who flagged this content.'),
-    'relationship' => array(
-      'flag type' => 'user',
-      'handler' => 'flag_handler_relationship_content',
-      'label' => t('flag friend'),
-      'base' => 'flag_content',
-      'base field' => 'uid',
-      'relationship field' => 'uid',
-    ),
-  );
-  
+  );    
   return $data;
 }
 
@@ -136,4 +158,55 @@ function flag_friend_views_data_alter(&$data) {
       ),
     );
   }
-}
\ No newline at end of file
+  
+  // Attach argument to the Flag module table. We could move this to the Flag 
+  // module's own Views integration, since it could benefit to all Flag users.
+  $data['flag_content']['flag_uid'] = array(
+    'group' => t('Flag friend'),
+    'title' => t('Users flagged by'),
+    'help' => t('Users flagged by argument'),
+    'real field' => 'uid',
+    'argument' => array(
+      'handler' => 'views_handler_argument_numeric',
+    ),
+  );
+  // Attach deny link to the Flag module table so it's available without joining
+  // the flag_friend table. 
+  $data['flag_content']['deny_user'] = array(
+    'group' => t('Flag friend'),
+    'title' => t('Deny link'),
+    'help' => t('"Deny incoming relationship request" link'),
+    'real field' => 'uid', 
+    'field' => array(
+      'handler' => 'flag_friend_handler_field_links',
+    ),
+  );
+  
+  // Flag friend relationships. For 2-way relationship (e.g. "friend") they  
+  // work same way. Difference is for 1-way relationships.
+  
+  // "my relationship targets" for 1-way relationships.  
+  $data['users']['flag_friend_terminating'] = array(
+    'group' => t('Flag friend'),
+    'title' => t('users terminating a relationship'),
+    'help' => t('Limits users to <em>terminating</em> 1 way relationship, or participating in 2-way one.'),
+    'relationship' => array(
+      'label' => t('ff relationship'),
+      'base' => 'flag_friend',
+      'base field' => 'friend_uid',
+      'relationship field' => 'uid',
+    ),
+  );
+  // "users who are sources of my relationships" for 1-way relationships. 
+  $data['users']['flag_friend_originating'] = array(
+    'group' => t('Flag friend'),
+    'title' => t('users originating a relationship'),
+    'help' => t('Limits users to <em>originating</em> 1 way relationship, or participating in 2-way one.'),
+    'relationship' => array(
+      'label' => t('ff relationship'),
+      'base' => 'flag_friend',
+      'base field' => 'uid',
+      'relationship field' => 'uid',
+    ),
+  );
+}
diff --git includes/flag_friend.views_default.inc includes/flag_friend.views_default.inc
index 4d423b3..ffe15ec 100644
--- includes/flag_friend.views_default.inc
+++ includes/flag_friend.views_default.inc
@@ -23,83 +23,181 @@ function flag_friend_views_default_views() {
   $view->disabled = FALSE; /* Edit this to true to make a default view disabled initially */
   $handler = $view->new_display('default', 'Defaults', 'default');
   $handler->override_option('relationships', array(
-    'flag_friend_content_rel' => array(
-      'label' => 'flag friend',
-      'required' => 1,
-      'flag' => 'friend',
-      'user_scope' => 'any',
-      'id' => 'flag_friend_content_rel',
-      'table' => 'users',
-      'field' => 'flag_friend_content_rel',
-      'override' => array(
-        'button' => 'Override',
-      ),
-      'relationship' => 'none',
-    ),
+  'flag_content_rel' => array(
+    'label' => 'flag',
+    'required' => 1,
+    'flag' => 'friend',
+    'user_scope' => 'any',
+    'id' => 'flag_content_rel',
+    'table' => 'users',
+    'field' => 'flag_content_rel',
+    'relationship' => 'none',
+  ),
+  'flag_friend_terminating' => array(
+    'label' => 'ff relationship targets',
+    'required' => 1,
+    'id' => 'flag_friend_terminating',
+    'table' => 'users',
+    'field' => 'flag_friend_terminating',
+    'relationship' => 'none',
+  ),
   ));
   $handler->override_option('fields', array(
-    'name' => array(
-      'label' => 'Name',
-      'link_to_user' => 1,
-      'exclude' => 0,
-      'id' => 'name',
-      'table' => 'users',
-      'field' => 'name',
-      'override' => array(
-        'button' => 'Override',
-      ),
-      'relationship' => 'none',
-    ),
-    'ops' => array(
-      'label' => 'Flag link',
-      'link_type' => '',
-      'exclude' => 0,
-      'id' => 'ops',
-      'table' => 'flag_content',
-      'field' => 'ops',
-      'relationship' => 'flag_friend_content_rel',
-      'override' => array(
-        'button' => 'Override',
-      ),
-    ),
-    'uid' => array(
-      'label' => 'Flag friend links',
-      'exclude' => 0,
-      'id' => 'uid',
-      'table' => 'flag_friend',
-      'field' => 'uid',
-      'relationship' => 'none',
-    ),
+  'name' => array(
+    'label' => 'Name',
+    'link_to_user' => 1,
+    'exclude' => 0,
+    'id' => 'name',
+    'table' => 'users',
+    'field' => 'name',
+    'override' => array(
+      'button' => 'Override',
+  ),
+    'relationship' => 'none',
+  ),
+  'ops' => array(
+    'label' => 'Flag link',
+    'alter' => array(
+      'alter_text' => 0,
+      'text' => '',
+      'make_link' => 0,
+      'path' => '',
+      'link_class' => '',
+      'alt' => '',
+      'prefix' => '',
+      'suffix' => '',
+      'target' => '',
+      'help' => '',
+      'trim' => 0,
+      'max_length' => '',
+      'word_boundary' => 1,
+      'ellipsis' => 1,
+      'strip_tags' => 0,
+      'html' => 0,
+  ),
+    'empty' => '',
+    'hide_empty' => 0,
+    'empty_zero' => 0,
+    'link_type' => '',
+    'exclude' => 0,
+    'id' => 'ops',
+    'table' => 'flag_content',
+    'field' => 'ops',
+    'relationship' => 'flag_content_rel',
+    'override' => array(
+      'button' => 'Override',
+  ),
+  ),
   ));
   $handler->override_option('arguments', array(
-    'friend_uid' => array(
-      'id' => 'friend_uid',
-      'table' => 'flag_friend',
-      'field' => 'friend_uid',
-    ),
+  'uid' => array(
+    'default_action' => 'default',
+    'style_plugin' => 'default_summary',
+    'style_options' => array(),
+    'wildcard' => 'all',
+    'wildcard_substitution' => 'All',
+    'title' => '',
+    'breadcrumb' => '',
+    'default_argument_type' => 'user',
+    'default_argument' => '',
+    'validate_type' => 'flag_friend_user_current_admin',
+    'validate_fail' => 'not found',
+    'break_phrase' => 0,
+    'not' => 0,
+    'id' => 'uid',
+    'table' => 'flag_friend',
+    'field' => 'uid',
+    'relationship' => 'flag_friend_terminating',
+    'validate_user_argument_type' => 'uid',
+    'validate_user_roles' => array(
+      '2' => 0,
+      '3' => 0,
+      '4' => 0,
+  ),
+    'default_options_div_prefix' => '',
+    'default_argument_user' => 0,
+    'default_argument_fixed' => '',
+    'default_argument_php' => '',
+    'validate_argument_node_type' => array(
+      'forum' => 0,
+      'blogpost' => 0,
+      'comment' => 0,
+      'discussion' => 0,
+      'discussion_reply' => 0,
+      'help' => 0,
+      'page' => 0,
+      'profile' => 0,
+      'site_group' => 0,
+      'specialist' => 0,
+  ),
+    'validate_argument_node_access' => 0,
+    'validate_argument_nid_type' => 'nid',
+    'validate_argument_vocabulary' => array(
+      '1' => 0,
+      '7' => 0,
+      '6' => 0,
+      '8' => 0,
+      '9' => 0,
+      '10' => 0,
+      '11' => 0,
+      '14' => 0,
+      '12' => 0,
+      '13' => 0,
+      '17' => 0,
+      '16' => 0,
+      '15' => 0,
+  ),
+    'validate_argument_type' => 'tid',
+    'validate_argument_transform' => 0,
+    'validate_user_restrict_roles' => 0,
+    'validate_argument_node_flag_name' => '*relationship*',
+    'validate_argument_node_flag_test' => 'flaggable',
+    'validate_argument_node_flag_id_type' => 'id',
+    'validate_argument_user_flag_name' => '*relationship*',
+    'validate_argument_user_flag_test' => 'flaggable',
+    'validate_argument_user_flag_id_type' => 'id',
+    'validate_argument_is_member' => 0,
+    'validate_argument_php' => '',
+  ),
   ));
   $handler->override_option('filters', array(
-    'status' => array(
-      'operator' => '=',
-      'value' => '1',
-      'group' => '0',
-      'exposed' => FALSE,
-      'expose' => array(
-        'operator' => FALSE,
-        'label' => '',
-      ),
-      'id' => 'status',
-      'table' => 'users',
-      'field' => 'status',
-      'relationship' => 'none',
-    ),
+  'status' => array(
+    'operator' => '=',
+    'value' => '1',
+    'group' => '0',
+    'exposed' => FALSE,
+    'expose' => array(
+      'operator' => FALSE,
+      'label' => '',
+  ),
+    'id' => 'status',
+    'table' => 'users',
+    'field' => 'status',
+    'relationship' => 'none',
+  ),
+  'fid' => array(
+    'operator' => 'or',
+    'value' => array(
+      '6' => '6',
+  ),
+    'group' => '0',
+    'exposed' => FALSE,
+    'expose' => array(
+      'operator' => FALSE,
+      'label' => '',
+  ),
+    'id' => 'fid',
+    'table' => 'flag_friend',
+    'field' => 'fid',
+    'relationship' => 'flag_friend_terminating',
+    'reduce_duplicates' => 0,
+  ),
   ));
   $handler->override_option('access', array(
-    'type' => 'perm',
-    'perm' => 'access content',
+  'type' => 'none',
   ));
   $handler->override_option('cache', array(
-    'type' => 'none',
+  'type' => 'none',
   ));
   $handler->override_option('empty', 'No Friends have been added.');
   $handler->override_option('empty_format', '1');
@@ -107,373 +205,744 @@ function flag_friend_views_default_views() {
   $handler->override_option('distinct', 1);
   $handler->override_option('style_plugin', 'table');
   $handler->override_option('style_options', array(
-    'grouping' => '',
-    'override' => 1,
-    'sticky' => 0,
-    'order' => 'asc',
-    'columns' => array(
-      'picture' => 'picture',
-      'name' => 'picture',
-      'message' => 'message',
-      'ops' => 'ops',
-      'uid' => 'ops',
-    ),
-    'info' => array(
-      'picture' => array(
-        'sortable' => 0,
-        'separator' => '',
-      ),
-      'name' => array(
-        'sortable' => 0,
-        'separator' => '',
-      ),
-      'message' => array(
-        'separator' => '',
-      ),
-      'ops' => array(
-        'separator' => '',
-      ),
-      'uid' => array(
-        'separator' => '',
-      ),
-    ),
-    'default' => '-1',
-  ));
-  $handler = $view->new_display('page', 'Page (friends)', 'page_1');
-  $handler->override_option('relationships', array());
-  $handler->override_option('fields', array(
+  'grouping' => '',
+  'override' => 1,
+  'sticky' => 0,
+  'order' => 'asc',
+  'columns' => array(
+    'picture' => 'picture',
+    'name' => 'picture',
+    'message' => 'message',
+    'ops' => 'ops',
+    'uid' => 'ops',
+  ),
+  'info' => array(
     'picture' => array(
-      'label' => 'Friend',
-      'exclude' => 0,
-      'id' => 'picture',
-      'table' => 'users',
-      'field' => 'picture',
-      'override' => array(
-        'button' => 'Use default',
-      ),
-      'relationship' => 'none',
-    ),
+      'sortable' => 0,
+      'separator' => '',
+  ),
     'name' => array(
-      'label' => 'Name',
-      'link_to_user' => 1,
-      'exclude' => 0,
-      'id' => 'name',
-      'table' => 'users',
-      'field' => 'name',
-      'override' => array(
-        'button' => 'Use default',
-      ),
-      'relationship' => 'none',
-    ),
+      'sortable' => 0,
+      'separator' => '',
+  ),
+    'message' => array(
+      'separator' => '',
+  ),
+    'ops' => array(
+      'separator' => '',
+  ),
     'uid' => array(
-      'label' => 'Actions',
-      'exclude' => 0,
-      'id' => 'uid',
-      'table' => 'flag_friend',
-      'field' => 'uid',
-      'override' => array(
-        'button' => 'Use default',
-      ),
-      'relationship' => 'none',
-    ),
+      'separator' => '',
+  ),
+  ),
+  'default' => '-1',
+  ));
+  $handler = $view->new_display('page', 'Page (friends)', 'page_1');
+  $handler->override_option('relationships', array(
+  'flag_content_rel' => array(
+    'label' => 'flag',
+    'required' => 1,
+    'flag' => 'friend',
+    'user_scope' => 'any',
+    'id' => 'flag_content_rel',
+    'table' => 'users',
+    'field' => 'flag_content_rel',
+    'override' => array(
+      'button' => 'Use default',
+  ),
+    'relationship' => 'none',
+  ),
+  'flag_friend_terminating' => array(
+    'id' => 'flag_friend_terminating',
+    'table' => 'users',
+    'field' => 'flag_friend_terminating',
+  ),
+  ));
+  $handler->override_option('fields', array(
+  'picture' => array(
+    'label' => 'Friend',
+    'exclude' => 0,
+    'id' => 'picture',
+    'table' => 'users',
+    'field' => 'picture',
+    'override' => array(
+      'button' => 'Use default',
+  ),
+    'relationship' => 'none',
+  ),
+  'name' => array(
+    'label' => 'Name',
+    'link_to_user' => 1,
+    'exclude' => 0,
+    'id' => 'name',
+    'table' => 'users',
+    'field' => 'name',
+    'override' => array(
+      'button' => 'Use default',
+  ),
+    'relationship' => 'none',
+  ),
+  'ops' => array(
+    'label' => 'Actions',
+    'alter' => array(
+      'alter_text' => 0,
+      'text' => '',
+      'make_link' => 0,
+      'path' => '',
+      'link_class' => '',
+      'alt' => '',
+      'prefix' => '',
+      'suffix' => '',
+      'target' => '',
+      'help' => '',
+      'trim' => 0,
+      'max_length' => '',
+      'word_boundary' => 1,
+      'ellipsis' => 1,
+      'strip_tags' => 0,
+      'html' => 0,
+  ),
+    'empty' => '',
+    'hide_empty' => 0,
+    'empty_zero' => 0,
+    'link_type' => '',
+    'exclude' => 0,
+    'id' => 'ops',
+    'table' => 'flag_content',
+    'field' => 'ops',
+    'relationship' => 'flag_content_rel',
+    'override' => array(
+      'button' => 'Use default',
+  ),
+  ),
   ));
   $handler->override_option('arguments', array(
-    'friend_uid' => array(
-      'default_action' => 'default',
-      'style_plugin' => 'default_summary',
-      'style_options' => array(),
-      'wildcard' => 'all',
-      'wildcard_substitution' => 'All',
-      'title' => '',
-      'default_argument_type' => 'user',
-      'default_argument' => '',
-      'validate_type' => 'none',
-      'validate_fail' => 'not found',
-      'break_phrase' => 0,
-      'not' => 0,
-      'id' => 'friend_uid',
-      'table' => 'flag_friend',
-      'field' => 'friend_uid',
-      'override' => array(
-        'button' => 'Use default',
-      ),
-      'relationship' => 'none',
-      'default_options_div_prefix' => '',
-      'default_argument_user' => 0,
-      'default_argument_fixed' => '',
-      'default_argument_php' => '',
-      'validate_argument_node_access' => 0,
-      'validate_argument_nid_type' => 'nid',
-      'validate_argument_vocabulary' => array(),
-      'validate_argument_type' => 'tid',
-      'validate_argument_node_flag_name' => '*relationship*',
-      'validate_argument_node_flag_test' => 'flaggable',
-      'validate_argument_node_flag_id_type' => 'id',
-      'validate_argument_user_flag_name' => '*relationship*',
-      'validate_argument_user_flag_test' => 'flaggable',
-      'validate_argument_user_flag_id_type' => 'id',
-      'validate_argument_php' => '',
-    ),
+  'uid' => array(
+    'default_action' => 'default',
+    'style_plugin' => 'default_summary',
+    'style_options' => array(),
+    'wildcard' => '',
+    'wildcard_substitution' => '',
+    'title' => '',
+    'breadcrumb' => '',
+    'default_argument_type' => 'user',
+    'default_argument' => '',
+    'validate_type' => 'flag_friend_user_current_admin',
+    'validate_fail' => 'not found',
+    'break_phrase' => 0,
+    'not' => 0,
+    'id' => 'uid',
+    'table' => 'flag_friend',
+    'field' => 'uid',
+    'relationship' => 'flag_friend_terminating',
+    'validate_user_argument_type' => 'uid',
+    'validate_user_roles' => array(
+      '2' => 0,
+      '3' => 0,
+      '4' => 0,
+  ),
+    'override' => array(
+      'button' => 'Use default',
+  ),
+    'default_options_div_prefix' => '',
+    'default_argument_user' => 0,
+    'default_argument_fixed' => '',
+    'default_argument_php' => '',
+    'validate_argument_node_type' => array(
+      'forum' => 0,
+      'blogpost' => 0,
+      'comment' => 0,
+      'discussion' => 0,
+      'discussion_reply' => 0,
+      'help' => 0,
+      'page' => 0,
+      'profile' => 0,
+      'site_group' => 0,
+      'specialist' => 0,
+  ),
+    'validate_argument_node_access' => 0,
+    'validate_argument_nid_type' => 'nid',
+    'validate_argument_vocabulary' => array(
+      '1' => 0,
+      '7' => 0,
+      '6' => 0,
+      '8' => 0,
+      '9' => 0,
+      '10' => 0,
+      '11' => 0,
+      '14' => 0,
+      '12' => 0,
+      '13' => 0,
+      '17' => 0,
+      '16' => 0,
+      '15' => 0,
+  ),
+    'validate_argument_type' => 'tid',
+    'validate_argument_transform' => 0,
+    'validate_user_restrict_roles' => 0,
+    'validate_argument_node_flag_name' => '*relationship*',
+    'validate_argument_node_flag_test' => 'flaggable',
+    'validate_argument_node_flag_id_type' => 'id',
+    'validate_argument_user_flag_name' => '*relationship*',
+    'validate_argument_user_flag_test' => 'flaggable',
+    'validate_argument_user_flag_id_type' => 'id',
+    'validate_argument_is_member' => 0,
+    'validate_argument_php' => 'if ($argument !== $GLOBALS[\'user\']->uid && !user_access(\'administer users\')) {
+                                    return FALSE;
+                                  }
+                                  return TRUE;',
+  ),
   ));
   $handler->override_option('title', 'Friends');
   $handler->override_option('path', 'user/%/friends/all');
   $handler->override_option('menu', array(
-    'type' => 'default tab',
-    'title' => 'View All Friends',
-    'description' => '',
-    'weight' => '-10',
-    'name' => 'navigation',
+  'type' => 'default tab',
+  'title' => 'View All Friends',
+  'description' => '',
+  'weight' => '-10',
+  'name' => 'navigation',
   ));
   $handler->override_option('tab_options', array(
-    'type' => 'tab',
-    'title' => 'Friends',
-    'description' => '',
-    'weight' => '0',
+  'type' => 'tab',
+  'title' => 'Friends',
+  'description' => '',
+  'weight' => '0',
   ));
   $handler = $view->new_display('page', 'Page (pending)', 'page_2');
+  $handler->override_option('relationships', array(
+  'flag_user_content_rel' => array(
+    'label' => 'user flagged content',
+    'required' => 1,
+    'flag' => 'friend',
+    'id' => 'flag_user_content_rel',
+    'table' => 'users',
+    'field' => 'flag_user_content_rel',
+    'override' => array(
+      'button' => 'Use default',
+  ),
+    'relationship' => 'none',
+  ),
+  'flag_friend_terminating' => array(
+    'id' => 'flag_friend_terminating',
+    'table' => 'users',
+    'field' => 'flag_friend_terminating',
+  ),
+  ));
   $handler->override_option('fields', array(
-    'picture' => array(
-      'label' => 'User',
-      'exclude' => 0,
-      'id' => 'picture',
-      'table' => 'users',
-      'field' => 'picture',
-      'override' => array(
-        'button' => 'Use default',
-      ),
-      'relationship' => 'none',
-    ),
-    'name' => array(
-      'label' => 'Name',
-      'link_to_user' => 1,
-      'exclude' => 0,
-      'id' => 'name',
-      'table' => 'users',
-      'field' => 'name',
-      'override' => array(
-        'button' => 'Use default',
-      ),
-      'relationship' => 'none',
-    ),
-    'message' => array(
-      'label' => 'Message',
-      'exclude' => 0,
-      'id' => 'message',
-      'table' => 'flag_friend_message',
-      'field' => 'message',
-      'relationship' => 'flag_friend_content_rel',
-      'override' => array(
-        'button' => 'Use default',
-      ),
-    ),
-    'ops' => array(
-      'label' => 'Actions',
-      'link_type' => '',
-      'exclude' => 0,
-      'id' => 'ops',
-      'table' => 'flag_content',
-      'field' => 'ops',
-      'relationship' => 'flag_friend_content_rel',
-      'override' => array(
-        'button' => 'Use default',
-      ),
-    ),
-    'uid' => array(
-      'label' => 'Flag friend links',
-      'exclude' => 0,
-      'id' => 'uid',
-      'table' => 'flag_friend',
-      'field' => 'uid',
-      'override' => array(
-        'button' => 'Use default',
-      ),
-      'relationship' => 'none',
-    ),
+  'picture' => array(
+    'label' => 'User',
+    'exclude' => 0,
+    'id' => 'picture',
+    'table' => 'users',
+    'field' => 'picture',
+    'override' => array(
+      'button' => 'Use default',
+  ),
+    'relationship' => 'none',
+  ),
+  'name' => array(
+    'label' => 'Name',
+    'link_to_user' => 1,
+    'exclude' => 0,
+    'id' => 'name',
+    'table' => 'users',
+    'field' => 'name',
+    'override' => array(
+      'button' => 'Use default',
+  ),
+    'relationship' => 'none',
+  ),
+  'message' => array(
+    'label' => 'Message',
+    'alter' => array(
+      'alter_text' => 0,
+      'text' => '',
+      'make_link' => 0,
+      'path' => '',
+      'link_class' => '',
+      'alt' => '',
+      'prefix' => '',
+      'suffix' => '',
+      'target' => '',
+      'help' => '',
+      'trim' => 0,
+      'max_length' => '',
+      'word_boundary' => 1,
+      'ellipsis' => 1,
+      'strip_tags' => 0,
+      'html' => 0,
+  ),
+    'empty' => '',
+    'hide_empty' => 0,
+    'empty_zero' => 0,
+    'exclude' => 0,
+    'id' => 'message',
+    'table' => 'flag_friend_message',
+    'field' => 'message',
+    'relationship' => 'flag_user_content_rel',
+    'override' => array(
+      'button' => 'Use default',
+  ),
+  ),
+  'ops' => array(
+    'label' => 'Actions',
+    'alter' => array(
+      'alter_text' => 0,
+      'text' => '',
+      'make_link' => 0,
+      'path' => '',
+      'link_class' => '',
+      'alt' => '',
+      'prefix' => '',
+      'suffix' => '',
+      'target' => '',
+      'help' => '',
+      'trim' => 0,
+      'max_length' => '',
+      'word_boundary' => 1,
+      'ellipsis' => 1,
+      'strip_tags' => 0,
+      'html' => 0,
+  ),
+    'empty' => '',
+    'hide_empty' => 0,
+    'empty_zero' => 0,
+    'link_type' => '',
+    'exclude' => 0,
+    'id' => 'ops',
+    'table' => 'flag_content',
+    'field' => 'ops',
+    'relationship' => 'flag_user_content_rel',
+    'override' => array(
+      'button' => 'Use default',
+  ),
+  ),
+  'deny_user' => array(
+    'label' => 'Deny link',
+    'alter' => array(
+      'alter_text' => 0,
+      'text' => '',
+      'make_link' => 0,
+      'path' => '',
+      'link_class' => '',
+      'alt' => '',
+      'prefix' => '',
+      'suffix' => '',
+      'target' => '',
+      'help' => '',
+      'trim' => 0,
+      'max_length' => '',
+      'word_boundary' => 1,
+      'ellipsis' => 1,
+      'strip_tags' => 0,
+      'html' => 0,
+  ),
+    'empty' => '',
+    'hide_empty' => 0,
+    'empty_zero' => 0,
+    'link_type' => '',
+    'exclude' => 0,
+    'id' => 'deny_user',
+    'table' => 'flag_content',
+    'field' => 'deny_user',
+    'relationship' => 'flag_user_content_rel',
+    'override' => array(
+      'button' => 'Use default',
+  ),
+  ),
   ));
   $handler->override_option('arguments', array(
-    'content_id' => array(
-      'default_action' => 'default',
-      'style_plugin' => 'default_summary',
-      'style_options' => array(),
-      'wildcard' => 'all',
-      'wildcard_substitution' => 'All',
-      'title' => '',
-      'default_argument_type' => 'user',
-      'default_argument' => '',
-      'validate_type' => 'php',
-      'validate_fail' => 'not found',
-      'break_phrase' => 0,
-      'not' => 0,
-      'id' => 'content_id',
-      'table' => 'flag_content',
-      'field' => 'content_id',
-      'relationship' => 'flag_friend_content_rel',
-      'override' => array(
-        'button' => 'Use default',
-      ),
-      'default_options_div_prefix' => '',
-      'default_argument_user' => 0,
-      'default_argument_fixed' => '',
-      'default_argument_php' => '',
-      'validate_argument_node_access' => 0,
-      'validate_argument_nid_type' => 'nid',
-      'validate_argument_vocabulary' => array(),
-      'validate_argument_type' => 'tid',
-      'validate_argument_node_flag_name' => '*relationship*',
-      'validate_argument_node_flag_test' => 'flaggable',
-      'validate_argument_node_flag_id_type' => 'id',
-      'validate_argument_user_flag_name' => '*relationship*',
-      'validate_argument_user_flag_test' => 'flaggable',
-      'validate_argument_user_flag_id_type' => 'id',
-      'validate_argument_php' => 'if ($argument !== $GLOBALS[\'user\']->uid && !user_access(\'administer users\')) {
+  'content_id' => array(
+    'default_action' => 'default',
+    'style_plugin' => 'default_summary',
+    'style_options' => array(),
+    'wildcard' => '',
+    'wildcard_substitution' => '',
+    'title' => '',
+    'breadcrumb' => '',
+    'default_argument_type' => 'user',
+    'default_argument' => '',
+    'validate_type' => 'flag_friend_user_current_admin',
+    'validate_fail' => 'not found',
+    'break_phrase' => 0,
+    'not' => 0,
+    'id' => 'content_id',
+    'table' => 'flag_content',
+    'field' => 'content_id',
+    'relationship' => 'flag_user_content_rel',
+    'override' => array(
+      'button' => 'Use default',
+  ),
+    'default_options_div_prefix' => '',
+    'default_argument_user' => 0,
+    'default_argument_fixed' => '',
+    'default_argument_php' => '',
+    'validate_argument_node_access' => 0,
+    'validate_argument_nid_type' => 'nid',
+    'validate_argument_vocabulary' => array(
+      '1' => 0,
+      '7' => 0,
+      '6' => 0,
+      '8' => 0,
+      '9' => 0,
+      '10' => 0,
+      '11' => 0,
+      '14' => 0,
+      '12' => 0,
+      '13' => 0,
+      '17' => 0,
+      '16' => 0,
+      '15' => 0,
+  ),
+    'validate_argument_type' => 'tid',
+    'validate_argument_node_flag_name' => '*relationship*',
+    'validate_argument_node_flag_test' => 'flaggable',
+    'validate_argument_node_flag_id_type' => 'id',
+    'validate_argument_user_flag_name' => '*relationship*',
+    'validate_argument_user_flag_test' => 'flaggable',
+    'validate_argument_user_flag_id_type' => 'id',
+    'validate_argument_php' => 'if ($argument !== $GLOBALS[\'user\']->uid && !user_access(\'administer users\')) {
                                     return FALSE;
                                   }
                                   return TRUE;',
-    ),
+    'validate_user_argument_type' => 'uid',
+    'validate_user_roles' => array(
+      '2' => 0,
+      '3' => 0,
+      '4' => 0,
+  ),
+    'validate_argument_node_type' => array(
+      'forum' => 0,
+      'blogpost' => 0,
+      'comment' => 0,
+      'discussion' => 0,
+      'discussion_reply' => 0,
+      'help' => 0,
+      'page' => 0,
+      'profile' => 0,
+      'site_group' => 0,
+      'specialist' => 0,
+  ),
+    'validate_argument_transform' => 0,
+    'validate_user_restrict_roles' => 0,
+    'validate_argument_is_member' => 0,
+  ),
+  ));
+  $handler->override_option('filters', array(
+  'status' => array(
+    'operator' => '=',
+    'value' => '1',
+    'group' => '0',
+    'exposed' => FALSE,
+    'expose' => array(
+      'operator' => FALSE,
+      'label' => '',
+  ),
+    'id' => 'status',
+    'table' => 'users',
+    'field' => 'status',
+    'relationship' => 'none',
+  ),
+  'fid' => array(
+    'operator' => 'empty',
+    'value' => array(
+      '5' => '5',
+  ),
+    'group' => '0',
+    'exposed' => FALSE,
+    'expose' => array(
+      'operator' => FALSE,
+      'label' => '',
+  ),
+    'id' => 'fid',
+    'table' => 'flag_friend',
+    'field' => 'fid',
+    'relationship' => 'flag_friend_terminating',
+    'override' => array(
+      'button' => 'Use default',
+  ),
+    'reduce_duplicates' => 0,
+  ),
   ));
   $handler->override_option('title', 'Friend Requests');
   $handler->override_option('header', 'These are users who would like to be your friend.');
   $handler->override_option('header_format', '1');
-  $handler->override_option('header_empty', 0);
+  $handler->override_option('header_empty', 1);
   $handler->override_option('empty', 'No Friend Requests.');
+  $handler->override_option('style_options', array(
+  'grouping' => '',
+  'override' => 1,
+  'sticky' => 0,
+  'order' => 'asc',
+  'columns' => array(
+    'picture' => 'picture',
+    'name' => 'picture',
+    'message' => 'message',
+    'ops' => 'ops',
+    'deny_user' => 'ops',
+  ),
+  'info' => array(
+    'picture' => array(
+      'sortable' => 0,
+      'separator' => '',
+  ),
+    'name' => array(
+      'sortable' => 0,
+      'separator' => '',
+  ),
+    'message' => array(
+      'separator' => '',
+  ),
+    'ops' => array(
+      'separator' => '',
+  ),
+    'deny_user' => array(
+      'separator' => '',
+  ),
+  ),
+  'default' => '-1',
+  ));
   $handler->override_option('path', 'user/%/friends/pending');
   $handler->override_option('menu', array(
-    'type' => 'tab',
-    'title' => 'Friend Requests',
-    'description' => '',
-    'weight' => '0',
-    'name' => 'navigation',
+  'type' => 'tab',
+  'title' => 'Friend Requests',
+  'description' => '',
+  'weight' => '0',
+  'name' => 'navigation',
   ));
   $handler->override_option('tab_options', array(
-    'type' => 'none',
-    'title' => '',
-    'description' => '',
-    'weight' => 0,
+  'type' => 'none',
+  'title' => '',
+  'description' => '',
+  'weight' => 0,
   ));
   $handler = $view->new_display('page', 'Page (flagged)', 'page_3');
   $handler->override_option('relationships', array(
-    'flag_content_rel' => array(
-      'label' => 'flag',
-      'required' => 1,
-      'flag' => 'friend',
-      'user_scope' => 'any',
-      'id' => 'flag_content_rel',
-      'table' => 'users',
-      'field' => 'flag_content_rel',
-      'override' => array(
-        'button' => 'Use default',
-      ),
-      'relationship' => 'none',
-    ),
-    'uid' => array(
-      'label' => 'Flag user',
-      'required' => 0,
-      'id' => 'uid',
-      'table' => 'flag_content',
-      'field' => 'uid',
-      'relationship' => 'flag_content_rel',
-      'override' => array(
-        'button' => 'Use default',
-      ),
-    ),
+  'flag_content_rel_1' => array(
+    'label' => 'flag',
+    'required' => 1,
+    'flag' => 'friend',
+    'user_scope' => 'any',
+    'id' => 'flag_content_rel_1',
+    'table' => 'users',
+    'field' => 'flag_content_rel',
+    'override' => array(
+      'button' => 'Use default',
+  ),
+    'relationship' => 'none',
+  ),
+  'flag_friend_terminating' => array(
+    'label' => 'ff relationship targets',
+    'required' => 0,
+    'id' => 'flag_friend_terminating',
+    'table' => 'users',
+    'field' => 'flag_friend_terminating',
+    'override' => array(
+      'button' => 'Use default',
+  ),
+    'relationship' => 'none',
+  ),
   ));
   $handler->override_option('fields', array(
-    'picture' => array(
-      'label' => 'User',
-      'exclude' => 0,
-      'id' => 'picture',
-      'table' => 'users',
-      'field' => 'picture',
-      'override' => array(
-        'button' => 'Use default',
-      ),
-      'relationship' => 'none',
-    ),
-    'name' => array(
-      'label' => 'Name',
-      'link_to_user' => 1,
-      'exclude' => 0,
-      'id' => 'name',
-      'table' => 'users',
-      'field' => 'name',
-      'override' => array(
-        'button' => 'Use default',
-      ),
-      'relationship' => 'none',
-    ),
-    'message' => array(
-      'label' => 'Message',
-      'exclude' => 0,
-      'id' => 'message',
-      'table' => 'flag_friend_message',
-      'field' => 'message',
-      'relationship' => 'flag_content_rel',
-      'override' => array(
-        'button' => 'Use default',
-      ),
-    ),
-    'ops' => array(
-      'label' => 'Actions',
-      'link_type' => '',
-      'exclude' => 0,
-      'id' => 'ops',
-      'table' => 'flag_content',
-      'field' => 'ops',
-      'relationship' => 'flag_content_rel',
-      'override' => array(
-        'button' => 'Use default',
-      ),
-    ),
+  'picture' => array(
+    'label' => 'User',
+    'exclude' => 0,
+    'id' => 'picture',
+    'table' => 'users',
+    'field' => 'picture',
+    'override' => array(
+      'button' => 'Use default',
+  ),
+    'relationship' => 'none',
+  ),
+  'name' => array(
+    'label' => 'Name',
+    'link_to_user' => 1,
+    'exclude' => 0,
+    'id' => 'name',
+    'table' => 'users',
+    'field' => 'name',
+    'override' => array(
+      'button' => 'Use default',
+  ),
+    'relationship' => 'none',
+  ),
+  'message' => array(
+    'label' => 'Message',
+    'alter' => array(
+      'alter_text' => 0,
+      'text' => '',
+      'make_link' => 0,
+      'path' => '',
+      'link_class' => '',
+      'alt' => '',
+      'prefix' => '',
+      'suffix' => '',
+      'target' => '',
+      'help' => '',
+      'trim' => 0,
+      'max_length' => '',
+      'word_boundary' => 1,
+      'ellipsis' => 1,
+      'strip_tags' => 0,
+      'html' => 0,
+  ),
+    'empty' => '',
+    'hide_empty' => 0,
+    'empty_zero' => 0,
+    'exclude' => 0,
+    'id' => 'message',
+    'table' => 'flag_friend_message',
+    'field' => 'message',
+    'relationship' => 'flag_content_rel_1',
+    'override' => array(
+      'button' => 'Use default',
+  ),
+  ),
+  'ops' => array(
+    'label' => 'Actions',
+    'alter' => array(
+      'alter_text' => 0,
+      'text' => '',
+      'make_link' => 0,
+      'path' => '',
+      'link_class' => '',
+      'alt' => '',
+      'prefix' => '',
+      'suffix' => '',
+      'target' => '',
+      'help' => '',
+      'trim' => 0,
+      'max_length' => '',
+      'word_boundary' => 1,
+      'ellipsis' => 1,
+      'strip_tags' => 0,
+      'html' => 0,
+  ),
+    'empty' => '',
+    'hide_empty' => 0,
+    'empty_zero' => 0,
+    'link_type' => '',
+    'exclude' => 0,
+    'id' => 'ops',
+    'table' => 'flag_content',
+    'field' => 'ops',
+    'relationship' => 'flag_content_rel_1',
+    'override' => array(
+      'button' => 'Use default',
+  ),
+  ),
   ));
   $handler->override_option('arguments', array(
-    'uid' => array(
-      'default_action' => 'default',
-      'style_plugin' => 'default_summary',
-      'style_options' => array(),
-      'wildcard' => 'all',
-      'wildcard_substitution' => 'All',
-      'title' => '',
-      'breadcrumb' => '',
-      'default_argument_type' => 'user',
-      'default_argument' => '',
-      'validate_type' => 'none',
-      'validate_fail' => 'not found',
-      'break_phrase' => 0,
-      'not' => 0,
-      'id' => 'uid',
-      'table' => 'users',
-      'field' => 'uid',
-      'validate_user_argument_type' => 'uid',
-      'validate_user_roles' => array(
-        '2' => 0,
-      ),
-      'override' => array(
-        'button' => 'Use default',
-      ),
-      'relationship' => 'uid',
-      'default_options_div_prefix' => '',
-      'default_argument_user' => 0,
-      'default_argument_fixed' => '',
-      'default_argument_php' => '',
-      'validate_argument_node_type' => array(
-        'page' => 0,
-        'smackdown' => 0,
-        'story' => 0,
-      ),
-      'validate_argument_node_access' => 0,
-      'validate_argument_nid_type' => 'nid',
-      'validate_argument_vocabulary' => array(),
-      'validate_argument_type' => 'tid',
-      'validate_argument_transform' => 0,
-      'validate_user_restrict_roles' => 0,
-      'validate_argument_node_flag_name' => '*relationship*',
-      'validate_argument_node_flag_test' => 'flaggable',
-      'validate_argument_node_flag_id_type' => 'id',
-      'validate_argument_user_flag_name' => '*relationship*',
-      'validate_argument_user_flag_test' => 'flaggable',
-      'validate_argument_user_flag_id_type' => 'id',
-      'validate_argument_php' => '',
-    ),
+  'flag_uid' => array(
+    'default_action' => 'default',
+    'style_plugin' => 'default_summary',
+    'style_options' => array(),
+    'wildcard' => '',
+    'wildcard_substitution' => '',
+    'title' => '',
+    'breadcrumb' => '',
+    'default_argument_type' => 'user',
+    'default_argument' => '',
+    'validate_type' => 'flag_friend_user_current_admin',
+    'validate_fail' => 'not found',
+    'break_phrase' => 0,
+    'not' => 0,
+    'id' => 'flag_uid',
+    'table' => 'flag_content',
+    'field' => 'flag_uid',
+    'relationship' => 'flag_content_rel_1',
+    'validate_user_argument_type' => 'uid',
+    'validate_user_roles' => array(
+      '2' => 0,
+      '3' => 0,
+      '4' => 0,
+  ),
+    'override' => array(
+      'button' => 'Use default',
+  ),
+    'default_options_div_prefix' => '',
+    'default_argument_user' => 0,
+    'default_argument_fixed' => '',
+    'default_argument_php' => '',
+    'validate_argument_node_type' => array(
+      'forum' => 0,
+      'blogpost' => 0,
+      'comment' => 0,
+      'discussion' => 0,
+      'discussion_reply' => 0,
+      'help' => 0,
+      'page' => 0,
+      'profile' => 0,
+      'site_group' => 0,
+      'specialist' => 0,
+  ),
+    'validate_argument_node_access' => 0,
+    'validate_argument_nid_type' => 'nid',
+    'validate_argument_vocabulary' => array(
+      '1' => 0,
+      '7' => 0,
+      '6' => 0,
+      '8' => 0,
+      '9' => 0,
+      '10' => 0,
+      '11' => 0,
+      '14' => 0,
+      '12' => 0,
+      '13' => 0,
+      '17' => 0,
+      '16' => 0,
+      '15' => 0,
+  ),
+    'validate_argument_type' => 'tid',
+    'validate_argument_transform' => 0,
+    'validate_user_restrict_roles' => 0,
+    'validate_argument_node_flag_name' => '*relationship*',
+    'validate_argument_node_flag_test' => 'flaggable',
+    'validate_argument_node_flag_id_type' => 'id',
+    'validate_argument_user_flag_name' => '*relationship*',
+    'validate_argument_user_flag_test' => 'flaggable',
+    'validate_argument_user_flag_id_type' => 'id',
+    'validate_argument_is_member' => 0,
+    'validate_argument_php' => 'if ($argument !== $GLOBALS[\'user\']->uid && !user_access(\'administer users\')) {
+                                    return FALSE;
+                                  }
+                                  return TRUE;',
+  ),
+  ));
+  $handler->override_option('filters', array(
+  'status' => array(
+    'operator' => '=',
+    'value' => '1',
+    'group' => '0',
+    'exposed' => FALSE,
+    'expose' => array(
+      'operator' => FALSE,
+      'label' => '',
+  ),
+    'id' => 'status',
+    'table' => 'users',
+    'field' => 'status',
+    'relationship' => 'none',
+  ),
+  'fid' => array(
+    'operator' => 'empty',
+    'value' => array(),
+    'group' => '0',
+    'exposed' => FALSE,
+    'expose' => array(
+      'operator' => FALSE,
+      'label' => '',
+  ),
+    'id' => 'fid',
+    'table' => 'flag_friend',
+    'field' => 'fid',
+    'relationship' => 'flag_friend_terminating',
+    'override' => array(
+      'button' => 'Use default',
+  ),
+    'reduce_duplicates' => 0,
+  ),
   ));
   $handler->override_option('title', 'Awaiting Friend Approvals');
   $handler->override_option('header', 'These are users who you have requested to be friends with.');
@@ -482,83 +951,22 @@ function flag_friend_views_default_views() {
   $handler->override_option('empty', 'No Friend Requests.');
   $handler->override_option('path', 'user/%/friends/flagged');
   $handler->override_option('menu', array(
-    'type' => 'tab',
-    'title' => 'Awaiting Friend Approvals',
-    'description' => '',
-    'weight' => '0',
-    'name' => 'navigation',
+  'type' => 'tab',
+  'title' => 'Awaiting Friend Approvals',
+  'description' => '',
+  'weight' => '0',
+  'name' => 'navigation',
   ));
   $handler->override_option('tab_options', array(
-    'type' => 'none',
-    'title' => '',
-    'description' => '',
-    'weight' => 0,
-  ));
-  $handler = $view->new_display('block', 'Current user\'s Friends block', 'block_1');
-  $handler->override_option('relationships', array());
-  $handler->override_option('fields', array(
-    'name' => array(
-      'label' => 'Name',
-      'link_to_user' => 1,
-      'exclude' => 0,
-      'id' => 'name',
-      'table' => 'users',
-      'field' => 'name',
-      'override' => array(
-        'button' => 'Override',
-      ),
-      'relationship' => 'none',
-    ),
-    'uid' => array(
-      'label' => 'Flag friend links',
-      'exclude' => 0,
-      'id' => 'uid',
-      'table' => 'flag_friend',
-      'field' => 'uid',
-      'relationship' => 'none',
-    ),
-  ));
-  $handler->override_option('arguments', array(
-    'friend_uid' => array(
-      'default_action' => 'default',
-      'style_plugin' => 'default_summary',
-      'style_options' => array(),
-      'wildcard' => 'all',
-      'wildcard_substitution' => 'All',
-      'title' => '',
-      'default_argument_type' => 'current_user',
-      'default_argument' => '',
-      'validate_type' => 'none',
-      'validate_fail' => 'not found',
-      'break_phrase' => 0,
-      'not' => 0,
-      'id' => 'friend_uid',
-      'table' => 'flag_friend',
-      'field' => 'friend_uid',
-      'override' => array(
-        'button' => 'Use default',
-      ),
-      'relationship' => 'none',
-      'default_options_div_prefix' => '',
-      'default_argument_user' => 0,
-      'default_argument_fixed' => '',
-      'default_argument_php' => '',
-      'validate_argument_node_access' => 0,
-      'validate_argument_nid_type' => 'nid',
-      'validate_argument_node_flag_name' => '*relationship*',
-      'validate_argument_node_flag_test' => 'flaggable',
-      'validate_argument_node_flag_id_type' => 'id',
-      'validate_argument_user_flag_name' => '*relationship*',
-      'validate_argument_user_flag_test' => 'flaggable',
-      'validate_argument_user_flag_id_type' => 'id',
-      'validate_argument_php' => '',
-    ),
+  'type' => 'none',
+  'title' => '',
+  'description' => '',
+  'weight' => 0,
   ));
-  $handler->override_option('items_per_page', 6);
-  $handler->override_option('use_pager', '0');
-  $handler->override_option('use_more', 1);
+  $handler = $view->new_display('block', 'User\'s friends block', 'block_1');
+  $handler->override_option('title', 'User\'s friends');
   $handler->override_option('block_description', '');
   $handler->override_option('block_caching', -1);
   $views[$view->name] = $view;
   return $views;
-}
\ No newline at end of file
+}
diff --git includes/flag_friend_handler_argument_numeric.inc includes/flag_friend_handler_argument_numeric.inc
index bde3c90..ec7c6d2 100644
--- includes/flag_friend_handler_argument_numeric.inc
+++ includes/flag_friend_handler_argument_numeric.inc
@@ -4,29 +4,5 @@
 /**
  * @file flag_friend_handler_argument_numeric.inc
  *
- * Contains the custom argument handler for the flag_friend table.
+ * Contained custom argument handler which we don't need anymore.
  */
-class flag_friend_handler_argument_numeric extends views_handler_argument_numeric {
-  function query() {
-    $this->ensure_my_table();
-
-    if (!empty($this->options['break_phrase'])) {
-      views_break_phrase($this->argument, $this);
-    }
-    else {
-      $this->value = array($this->argument);
-    }
-    $group = $this->query->set_where_group('OR', 'friends');
-    if (count($this->value) > 1) {
-      $operator = empty($this->options['not']) ? 'IN' : 'NOT IN';
-      $placeholders = implode(', ', array_fill(0, sizeof($this->value), '%d'));
-      $this->query->add_where($group, "users.uid IN (SELECT f.friend_uid FROM {flag_friend} f WHERE f.uid $operator ($placeholders))", $this->value);
-      $this->query->add_where($group, "users.uid IN (SELECT f.uid FROM {flag_friend} f WHERE f.friend_uid $operator ($placeholders))", $this->value);
-    }
-    else {
-      $operator = empty($this->options['not']) ? '=' : '!=';
-      $this->query->add_where($group, "users.uid IN (SELECT f.friend_uid FROM {flag_friend} f WHERE f.uid $operator %d)", $this->argument);
-      $this->query->add_where($group, "users.uid IN (SELECT f.uid FROM {flag_friend} f WHERE f.friend_uid $operator %d)", $this->argument);
-    }
-  }
-}
\ No newline at end of file
diff --git includes/flag_friend_handler_field_links.inc includes/flag_friend_handler_field_links.inc
index 9f41a50..3c0e52a 100644
--- includes/flag_friend_handler_field_links.inc
+++ includes/flag_friend_handler_field_links.inc
@@ -7,20 +7,70 @@
  */
 
 /**
- * Views field handler for the Flag friend operations links (remove/pending/approve/deny).
+ * Views field handler for the Flag friend "deny" operations link.
  *
  * @ingroup views
  */
 class flag_friend_handler_field_links extends views_handler_field {
+  /**
+   * Returns the flag object associated with our field.
+   *
+   * A field is in some relationship. This function reaches out for this
+   * relationship and reads its 'flag' option, which holds the flag name.
+   */
+  function get_flag() {
+    $flag_name = $this->view->relationship[$this->options['relationship']]->options['flag'];
+    return flag_get_flag($flag_name);
+  }
+
+  /**
+   * Return the the relationship we're linked to. That is, the alias for its
+   * table (which is suitbale for use with the various methods of the 'query'
+   * object).
+   */
+  function get_parent_relationship() {
+    $parent = $this->view->relationship[$this->options['relationship']]->options['relationship'];
+    if (!$parent || $parent == 'none') {
+      return NULL; // Base query table.
+    }
+    else {
+      return $this->view->relationship[$parent]->alias;
+    }
+  }
+
+  function option_definition() {
+    $options = parent::option_definition();
+    $options['link_type'] = array('default' => '');
+    return $options;
+  }
+
+  function options_form(&$form, &$form_state) {
+    parent::options_form($form, $form_state);
+
+    $form['link_type'] = array(
+      '#type' => 'radios',
+      '#title' => t('Link type'),
+      '#options' => array('' => t('Use flag link settings')) + _flag_link_type_options(),
+      '#default_value' => $this->options['link_type'],
+    );
+  }
+  
+  
+  /**
+   * Render "deny incoming relationship request" link.
+   * 
+   * TODO: Add access check in pre_render() like Flag's module "ops" field.
+   */   
   function render($values) {
     global $user;
-    $flag = flag_get_flag('friend');
-    $content_id = $values->uid;
-    // what's the status?
-    $status = flag_friend_determine_friend_status($flag, $user->uid, $content_id);
-    $link_type = ($status == FLAG_FRIEND_APPROVAL) ? 'unflag' : 'unfriend';
     if ($this->view->args[0] == $user->uid) {
-      return flag_friend_create_link($link_type, $content_id);
+      $flag = $this->get_flag();
+      $content_id = $values->uid;
+      // what's the status?
+      $status = flag_friend_relationship_status($flag, $user->uid, $content_id);
+      if ($status == FLAG_FRIEND_APPROVAL) {
+        return $flag->theme('deny', $content_id);
+      }
     }
   }
 }
diff --git includes/flag_friend_handler_filters.inc includes/flag_friend_handler_filters.inc
new file mode 100644
index 0000000..0ed1ecc
--- /dev/null
+++ includes/flag_friend_handler_filters.inc
@@ -0,0 +1,20 @@
+<?php
+// $Id$
+
+/**
+ * Filter handler allowing to filter by flags (Flag Friend relationship types).
+ */
+
+class flag_friend_handler_filter_flag extends views_handler_filter_many_to_one {
+  function construct() {
+    parent::construct();
+    $this->value_title = t('Options');
+    
+    $flags = flag_get_flags('user');
+    $options = array();
+    foreach ($flags as $flag) {
+      $options[$flag->fid] = $flag->get_title();
+    }
+    $this->value_options = $options;
+  }
+}
diff --git includes/flag_friend_plugin_argument_validate_user_current.inc includes/flag_friend_plugin_argument_validate_user_current.inc
new file mode 100644
index 0000000..ef4dd79
--- /dev/null
+++ includes/flag_friend_plugin_argument_validate_user_current.inc
@@ -0,0 +1,19 @@
+<?php
+// $Id$
+
+/**
+ * @file
+ * Contains the "User: current user" argument validator plugin.
+ */
+
+
+/**
+ * Checks that user provided in argument is the current one.  
+ *
+ * @ingroup views_argument_validate_plugins
+ */
+class flag_friend_plugin_argument_validate_user_current extends views_plugin_argument_validate {
+  function validate_argument($arg) {
+    return ($arg === $GLOBALS['user']->uid); 
+  }
+}
diff --git includes/flag_friend_plugin_argument_validate_user_current_admin.inc includes/flag_friend_plugin_argument_validate_user_current_admin.inc
new file mode 100644
index 0000000..6254ca9
--- /dev/null
+++ includes/flag_friend_plugin_argument_validate_user_current_admin.inc
@@ -0,0 +1,18 @@
+<?php
+// $Id$
+
+/**
+ * @file
+ * Contains the "User: current user" argument validator plugin.
+ */
+
+/**
+ * Checks that user provided in argument is the current one or is admin.  
+ *
+ * @ingroup views_argument_validate_plugins
+ */
+class flag_friend_plugin_argument_validate_user_current_admin extends views_plugin_argument_validate {
+  function validate_argument($arg) {
+    return ($arg === $GLOBALS['user']->uid || user_access('administer users'));
+  }
+}
