--- modules/poll.module	21 Feb 2006 18:46:54 -0000	1.188
+++ modules/poll.module	27 Feb 2006 13:30:19 -0000
@@ -189,6 +189,7 @@ function poll_insert($node) {
  */
 function poll_menu($may_cache) {
   $items = array();
+  global $user;
 
   if ($may_cache) {
     $items[] = array('path' => 'node/add/poll', 'title' => t('poll'),
@@ -203,11 +204,24 @@ function poll_menu($may_cache) {
       'callback' => 'poll_vote',
       'access' => user_access('vote on polls'),
       'type' => MENU_CALLBACK);
+
+    $items[] = array('path' => 'poll/cancel',
+      'title' => t('cancel'),
+      'callback' => 'poll_cancel',
+      'access' => user_access('vote on polls'),
+      'type' => MENU_CALLBACK);
   }
   else {
     if (arg(0) == 'node' && is_numeric(arg(1))) {
       $node = node_load(arg(1));
-
+      if ($node->type == 'poll') {
+        $items[] = array('path' => 'node/'. arg(1) .'/votes',
+          'title' => t('votes'),
+          'callback' => 'poll_votes',
+          'access' => user_access('view poll votes'),
+          'weight' => 3,
+          'type' => MENU_LOCAL_TASK);
+      }
       if ($node->type == 'poll' && $node->allowvotes) {
         $items[] = array('path' => 'node/'. arg(1) .'/results',
           'title' => t('results'),
@@ -239,10 +253,15 @@ function poll_load($node) {
   // Determine whether or not this user is allowed to vote
   $poll->allowvotes = FALSE;
   if (user_access('vote on polls') && $poll->active) {
-    if ($user->uid && db_num_rows(db_query('SELECT uid FROM {poll_votes} WHERE nid = %d AND uid = %d', $node->nid, $user->uid)) == 0) {
-      $poll->allowvotes = TRUE;
+    if ($user->uid) {
+      $result = db_fetch_object(db_query('SELECT chorder FROM {poll_votes} WHERE nid = %d AND uid = %d', $node->nid, $user->uid));
+    } else if ($user->uid == 0) {
+      $result = db_fetch_object(db_query("SELECT chorder FROM {poll_votes} WHERE nid = %d AND hostname = '%s'", $node->nid, $_SERVER['REMOTE_ADDR']));
     }
-    else if ($user->uid == 0 && db_num_rows(db_query("SELECT hostname FROM {poll_votes} WHERE nid = %d AND hostname = '%s'", $node->nid, $_SERVER['REMOTE_ADDR'])) == 0) {
+    if (isset($result->chorder)) {
+      $poll->vote = $result->chorder;
+    } else {
+      $poll->vote = -1;
       $poll->allowvotes = TRUE;
     }
   }
@@ -274,7 +293,7 @@ function poll_page() {
  * Implementation of hook_perm().
  */
 function poll_perm() {
-  return array('create polls', 'vote on polls');
+  return array('create polls', 'vote on polls', 'view poll votes');
 }
 
 /**
@@ -344,12 +363,12 @@ function poll_view_results(&$node, $teas
     }
   }
 
-  $output .= theme('poll_results', check_plain($node->title), $poll_results, $total_votes, $node->links, $block);
+  $output .= theme('poll_results', check_plain($node->title), $poll_results, $total_votes, $node->links, $block, $node->nid, $node->vote, $node->choice[$node->vote]['chtext']);
 
   return $output;
 }
 
-function theme_poll_results($title, $results, $votes, $links, $block) {
+function theme_poll_results($title, $results, $votes, $links, $block, $nid, $vote, $vote_str) {
   if ($block) {
     $output .= '<div class="poll">';
     $output .= '<div class="title">'. $title .'</div>';
@@ -362,12 +381,21 @@ function theme_poll_results($title, $res
     $output .= '<div class="poll">';
     $output .= $results;
     $output .= '<div class="total">'. t('Total votes: %votes', array('%votes' => $votes)) .'</div>';
+    if (isset($vote)) {
+      $form['#action'] = url('poll/cancel/'. $nid);
+      $form['choice'] = array('#type' => 'hidden', '#value' => $vote);
+      $form['submit'] = array('#type' => 'submit', '#value' => t('Cancel vote'));
+      $output .= '<div class="total">'. t('Your vote') .": $vote_str ";
+      $output .= drupal_get_form('poll_cancel_form', $form);
+      $output .= '</div>';
+    }
     $output .= '</div>';
   }
 
   return $output;
 }
 
+
 function theme_poll_bar($title, $percentage, $votes, $block) {
   if ($block) {
     $output  = '<div class="text">'. $title .'</div>';
@@ -397,6 +425,38 @@ function poll_results() {
 }
 
 /**
+ * Callback for the 'votes' tab for polls you can see other votes on
+ */
+function poll_votes() {
+  if ($node = node_load(arg(1))) {
+    drupal_set_title(check_plain($node->title));
+    $output = t("This table lists all the recorded votes for this poll.  If anonymous users are allowed to vote, they will be identified by the IP address of the computer they used when they voted (which is the method used to prevent anonymous users from voting multiple times at once).  For a summary of the results, use the ");
+    $output .= l(t('view'),"node/$node->nid");
+    $output .= " tab.<br/><br/>\n";
+
+    $result = db_query("SELECT pv.chorder, pv.uid, pv.hostname, u.name FROM {poll_votes} pv LEFT JOIN {users} u ON pv.uid = u.uid WHERE pv.nid = %d ORDER BY pv.chorder, u.name", $node->nid );
+    $header = array( "Identifier", "Vote" );
+    $rows = array();
+    while ($vote = db_fetch_object($result)) {
+      $row = array();
+      if ($vote->name) {
+        $row[] = l(check_plain($vote->name),"user/$vote->uid");
+      } else {
+        $row[] = $vote->hostname;
+      }
+      $row[] = $node->choice[$vote->chorder]['chtext'];
+      $rows[] = $row;
+    }    
+    $output .= theme('table', $header, $rows);
+    print theme('page', $output);
+  }
+  else {
+    drupal_not_found();
+  }
+}
+
+
+/**
  * Callback for processing a vote
  */
 function poll_vote(&$node) {
@@ -412,10 +472,10 @@ function poll_vote(&$node) {
       if ($node->allowvotes) {
         // Mark the user or host as having voted.
         if ($user->uid) {
-          db_query('INSERT INTO {poll_votes} (nid, uid) VALUES (%d, %d)', $node->nid, $user->uid);
+          db_query('INSERT INTO {poll_votes} (nid, chorder, uid) VALUES (%d, %d, %d)', $node->nid, $choice, $user->uid);
         }
         else {
-          db_query("INSERT INTO {poll_votes} (nid, hostname) VALUES (%d, '%s')", $node->nid, $_SERVER['REMOTE_ADDR']);
+          db_query("INSERT INTO {poll_votes} (nid, chorder, hostname) VALUES (%d, %d, '%s')", $node->nid, $choice, $_SERVER['REMOTE_ADDR']);
         }
 
         // Add one to the votes.
@@ -440,6 +500,43 @@ function poll_vote(&$node) {
   }
 }
 
+
+/**
+ * Callback for canceling a vote
+ */
+function poll_cancel(&$node) {
+  global $user;
+
+  $nid = arg(2);
+  if ($node = node_load(array('nid' => $nid))) {
+    $edit = $_POST['edit'];
+    $choice = $edit['choice'];
+    $cancel = $_POST['cancel'];
+
+    if (isset($choice) && isset($node->choice[$choice])) {
+      if ($user->uid) { 
+        db_query('DELETE FROM {poll_votes} WHERE nid = %d and uid = %d', $node->nid, $user->uid);
+      } else {
+        db_query("DELETE FROM {poll_votes} WHERE nid = %d and hostname = '%s'", $node->nid, $_SERVER['REMOTE_ADDR']);
+      }
+
+      // Subtract from the votes.
+      db_query("UPDATE {poll_choices} SET chvotes = chvotes - 1 WHERE nid = %d AND chorder = %d", $node->nid, $choice);
+      $node->allowvotes = true;
+      $node->choice[$choice]['chvotes']--;
+      drupal_set_message(t('Your vote was canceled.'));
+    }
+    else {
+      drupal_set_message(t("You're not allowed to cancel an invalid poll choice."), 'error');
+    }
+    drupal_goto('node/'. $nid);
+  }
+  else {
+    drupal_not_found();
+  }
+}
+
+
 /**
  * Implementation of hook_view().
  *
--- database/database.mysql	27 Feb 2006 13:22:29 -0000	1.226
+++ database/database.mysql	27 Feb 2006 13:30:19 -0000
@@ -569,6 +569,7 @@
 CREATE TABLE poll_votes (
   nid int(10) unsigned NOT NULL,
   uid int(10) unsigned NOT NULL default 0,
+  chorder int(10) NOT NULL default -1,
   hostname varchar(128) NOT NULL default '',
   INDEX (nid),
   INDEX (uid),
--- database/database.pgsql	22 Feb 2006 10:06:46 -0000	1.169
+++ database/database.pgsql	27 Feb 2006 13:30:19 -0000
@@ -535,6 +535,7 @@
 CREATE TABLE poll_votes (
   nid int NOT NULL,
   uid int NOT NULL default 0,
+  chorder int NOT NULL default -1,
   hostname varchar(128) NOT NULL default ''
 );
 CREATE INDEX poll_votes_nid_idx ON poll_votes (nid);
--- database/updates.inc	27 Feb 2006 13:22:29 -0000	1.201
+++ database/updates.inc	27 Feb 2006 13:30:19 -0000
@@ -1698,3 +1698,23 @@ function system_update_174() {
   }
   return array();
 }
+
+function system_update_175() {
+  // change DB schema for better poll support
+  $ret = array();
+
+  switch ($GLOBALS['db_type']) {
+    case 'mysqli':
+    case 'mysql':
+      // alter poll_votes table
+      $ret[] = update_sql("ALTER TABLE {poll_votes} ADD COLUMN chorder int(10) NOT NULL default -1 AFTER uid");
+      break;
+
+    case 'pgsql':
+      db_add_column($ret, 'poll_votes', 'chorder', 'int', array('not null' => TRUE, 'default' => "'-1'"));
+      break;
+  }
+
+  return $ret;
+}
+
