Index: wp-includes/canonical.php
===================================================================
--- wp-includes/canonical.php	(revision 18542)
+++ wp-includes/canonical.php	(working copy)
@@ -66,6 +66,8 @@
 	if ( !isset($redirect['query']) )
 		$redirect['query'] = '';
 
+	$qv_remove = array();
+
 	if ( is_singular() && 1 > $wp_query->post_count && ($id = get_query_var('p')) ) {
 
 		$vars = $wpdb->get_results( $wpdb->prepare("SELECT post_type, post_parent FROM $wpdb->posts WHERE ID = %d", $id) );
@@ -75,135 +77,171 @@
 				$id = $vars->post_parent;
 
 			if ( $redirect_url = get_permalink($id) )
-				$redirect['query'] = remove_query_arg(array('p', 'page_id', 'attachment_id', 'post_type'), $redirect['query']);
+				$qv_remove = array_merge($qv_remove, array('p', 'page_id', 'attachment_id', 'post_type') );
 		}
-	}
-
-	// These tests give us a WP-generated permalink
-	if ( is_404() ) {
-
+	} elseif ( is_404() ) {
 		// Redirect ?page_id, ?p=, ?attachment_id= to their respective url's
 		$id = max( get_query_var('p'), get_query_var('page_id'), get_query_var('attachment_id') );
 		if ( $id && $redirect_post = get_post($id) ) {
-			$post_type_obj = get_post_type_object($redirect_post->post_type);
-			if ( $post_type_obj->public ) {
+			if ( get_post_type_object($redirect_post->post_type)->public ) {
 				$redirect_url = get_permalink($redirect_post);
-				$redirect['query'] = remove_query_arg(array('p', 'page_id', 'attachment_id', 'post_type'), $redirect['query']);
+				$qv_remove = array_merge($qv_remove, array('p', 'page_id', 'attachment_id', 'post_type') );
 			}
 		}
 
-		if ( ! $redirect_url )
+		if ( ! $redirect_url ) {
 			$redirect_url = redirect_guess_404_permalink();
-
-	} elseif ( is_object($wp_rewrite) && $wp_rewrite->using_permalinks() ) {
-		// rewriting of old ?p=X, ?m=2004, ?m=200401, ?m=20040101
-		if ( is_attachment() && !empty($_GET['attachment_id']) && ! $redirect_url ) {
-			if ( $redirect_url = get_attachment_link(get_query_var('attachment_id')) )
-				$redirect['query'] = remove_query_arg('attachment_id', $redirect['query']);
-		} elseif ( is_single() && !empty($_GET['p']) && ! $redirect_url ) {
-			if ( $redirect_url = get_permalink(get_query_var('p')) )
-				$redirect['query'] = remove_query_arg(array('p', 'post_type'), $redirect['query']);
-		} elseif ( is_single() && !empty($_GET['name'])  && ! $redirect_url ) {
-			if ( $redirect_url = get_permalink( $wp_query->get_queried_object_id() ) )
-				$redirect['query'] = remove_query_arg('name', $redirect['query']);
-		} elseif ( is_page() && !empty($_GET['page_id']) && ! $redirect_url ) {
-			if ( $redirect_url = get_permalink(get_query_var('page_id')) )
-				$redirect['query'] = remove_query_arg('page_id', $redirect['query']);
-		} elseif ( is_page() && !is_feed() && isset($wp_query->queried_object) && 'page' == get_option('show_on_front') && $wp_query->queried_object->ID == get_option('page_on_front')  && ! $redirect_url ) {
+			if ( $redirect_url )
+				$qv_remove = array_merge($qv_remove, array('pagename', 'name') );
+		}
+	} elseif ( is_attachment() ) {
+		if ( $redirect_url = get_attachment_link(get_query_var('attachment_id')) ) {
+			$qv_remove[] = 'attachment_id';
+			$qv_remove[] = 'attachment';
+		}
+	} elseif ( is_single() ) {
+		if ( $redirect_url = get_permalink( $wp_query->get_queried_object_id() ) ) {
+			$qv_remove[] = 'p';
+			$qv_remove[] = 'post_type';
+			$qv_remove[] = 'name';
+			$qv_remove[] = 'pagename';
+		}
+	} elseif ( is_page() ) {
+		if ( !is_feed() && isset($wp_query->queried_object) && 'page' == get_option('show_on_front') && $wp_query->queried_object->ID == get_option('page_on_front')  && ! $redirect_url )
 			$redirect_url = home_url('/');
-		} elseif ( is_home() && !empty($_GET['page_id']) && 'page' == get_option('show_on_front') && get_query_var('page_id') == get_option('page_for_posts')  && ! $redirect_url ) {
-			if ( $redirect_url = get_permalink(get_option('page_for_posts')) )
-				$redirect['query'] = remove_query_arg('page_id', $redirect['query']);
-		} elseif ( !empty($_GET['m']) && ( is_year() || is_month() || is_day() ) ) {
-			$m = get_query_var('m');
-			switch ( strlen($m) ) {
-				case 4: // Yearly
-					$redirect_url = get_year_link($m);
-					break;
-				case 6: // Monthly
-					$redirect_url = get_month_link( substr($m, 0, 4), substr($m, 4, 2) );
-					break;
-				case 8: // Daily
-					$redirect_url = get_day_link(substr($m, 0, 4), substr($m, 4, 2), substr($m, 6, 2));
-					break;
-			}
-			if ( $redirect_url )
-				$redirect['query'] = remove_query_arg('m', $redirect['query']);
-		// now moving on to non ?m=X year/month/day links
-		} elseif ( is_day() && get_query_var('year') && get_query_var('monthnum') && !empty($_GET['day']) ) {
-			if ( $redirect_url = get_day_link(get_query_var('year'), get_query_var('monthnum'), get_query_var('day')) )
-				$redirect['query'] = remove_query_arg(array('year', 'monthnum', 'day'), $redirect['query']);
-		} elseif ( is_month() && get_query_var('year') && !empty($_GET['monthnum']) ) {
-			if ( $redirect_url = get_month_link(get_query_var('year'), get_query_var('monthnum')) )
-				$redirect['query'] = remove_query_arg(array('year', 'monthnum'), $redirect['query']);
-		} elseif ( is_year() && !empty($_GET['year']) ) {
-			if ( $redirect_url = get_year_link(get_query_var('year')) )
-				$redirect['query'] = remove_query_arg('year', $redirect['query']);
-		} elseif ( is_author() && !empty($_GET['author']) && preg_match( '|^[0-9]+$|', $_GET['author'] ) ) {
-			$author = get_userdata(get_query_var('author'));
-			if ( ( false !== $author ) && $wpdb->get_var( $wpdb->prepare( "SELECT ID FROM $wpdb->posts WHERE $wpdb->posts.post_author = %d AND $wpdb->posts.post_status = 'publish' LIMIT 1", $author->ID ) ) ) {
-				if ( $redirect_url = get_author_posts_url($author->ID, $author->user_nicename) )
-					$redirect['query'] = remove_query_arg('author', $redirect['query']);
-			}
-		} elseif ( is_category() || is_tag() || is_tax() ) { // Terms (Tags/categories)
+		else
+			$redirect_url = get_permalink(get_query_var('page_id'));
+		if ( $redirect_url ) {
+			$qv_remove[] = 'page_id';
+			$qv_remove[] = 'pagename';
+		}
+	} elseif ( is_category() || is_tag() || is_tax() ) { // Terms (Tags/categories/Custom Taxonomies)
 
-			$term_count = 0;
-			foreach ( $wp_query->tax_query->queries as $tax_query )
-				$term_count += count( $tax_query['terms'] );
+		// @TODO: Buggy, Doesnt account for the fact that categories include child cats in the count.
+		$term_count = 0;
+		$term_taxonomies = array_unique(wp_list_pluck($wp_query->tax_query->queries, 'taxonomy'));
+		foreach ( $wp_query->tax_query->queries as $tax_query )
+			$term_count += count( $tax_query['terms'] );
 
-			$obj = $wp_query->get_queried_object();
-			if ( $term_count <= 1 && !empty($obj->term_id) && ( $tax_url = get_term_link((int)$obj->term_id, $obj->taxonomy) ) && !is_wp_error($tax_url) ) {
-				if ( !empty($redirect['query']) ) {
-					// Strip taxonomy query vars off the url.
-					$qv_remove = array( 'term', 'taxonomy');
-					if ( is_category() ) {
-						$qv_remove[] = 'category_name';
-						$qv_remove[] = 'cat';
-					} elseif ( is_tag() ) {
-						$qv_remove[] = 'tag';
-						$qv_remove[] = 'tag_id';
-					} else { // Custom taxonomies will have a custom query var, remove those too:
-						$tax_obj = get_taxonomy( $obj->taxonomy );
-						if ( false !== $tax_obj->query_var )
-							$qv_remove[] = $tax_obj->query_var;
-					}
+		$obj = $wp_query->get_queried_object();
+		if ( $term_count <= 1 && !empty($obj->term_id) ) 
+			$redirect_url = get_term_link((int)$obj->term_id, $obj->taxonomy);
 
-					$rewrite_vars = array_diff( array_keys($wp_query->query), array_keys($_GET) );
+		elseif ( $term_count > 1 && 1 == count($term_taxonomies) )
+			$redirect_url = false; // Booyakasha? Build the merged array and win the world?
 
-					if ( !array_diff($rewrite_vars, array_keys($_GET))  ) { // Check to see if all the Query vars are coming from the rewrite, none are set via $_GET
-						$redirect['query'] = remove_query_arg($qv_remove, $redirect['query']); //Remove all of the per-tax qv's
+		if ( $term_count == 1 ) {
+			// Strip taxonomy query vars off the url.
+			$qv_remove[] = 'term';
+			$qv_remove[] = 'taxonomy';
+		}
 
-						// Create the destination url for this taxonomy
-						$tax_url = parse_url($tax_url);
-						if ( ! empty($tax_url['query']) ) { // Taxonomy accessable via ?taxonomy=..&term=.. or any custom qv..
-							parse_str($tax_url['query'], $query_vars);
-							$redirect['query'] = add_query_arg($query_vars, $redirect['query']);
-						} else { // Taxonomy is accessable via a "pretty-URL"
-							$redirect['path'] = $tax_url['path'];
-						}
-
-					} else { // Some query vars are set via $_GET. Unset those from $_GET that exist via the rewrite
-						foreach ( $qv_remove as $_qv ) {
-							if ( isset($rewrite_vars[$_qv]) )
-								$redirect['query'] = remove_query_arg($_qv, $redirect['query']);
-						}
-					}
-				}
-
+		if ( is_category() ) {
+			$qv_remove[] = 'category_name';
+			$qv_remove[] = 'cat';
+		} elseif ( is_tag() ) {
+			$qv_remove[] = 'tag';
+			$qv_remove[] = 'tag_id';
+		} else { // Custom taxonomies will have a custom query var, remove those too:
+			$tax_obj = get_taxonomy( $obj->taxonomy );
+			if ( false !== $tax_obj->query_var )
+				$qv_remove[] = $tax_obj->query_var;
+		}
+	} elseif ( is_author() ) {
+		$author = get_userdata( get_query_var('author') );
+		if ( false !== $author && $wpdb->get_var( $wpdb->prepare( "SELECT ID FROM $wpdb->posts WHERE $wpdb->posts.post_author = %d AND $wpdb->posts.post_status = 'publish' LIMIT 1", $author->ID ) ) ) {
+			if ( $redirect_url = get_author_posts_url($author->ID, $author->user_nicename) ) {
+				$qv_remove[] = 'author';
+				$qv_remove[] = 'author_name';
 			}
-		} elseif ( is_single() && strpos($wp_rewrite->permalink_structure, '%category%') !== false ) {
-			$category = get_category_by_path(get_query_var('category_name'));
-			$post_terms = wp_get_object_terms($wp_query->get_queried_object_id(), 'category', array('fields' => 'tt_ids'));
-			if ( (!$category || is_wp_error($category)) || ( !is_wp_error($post_terms) && !empty($post_terms) && !in_array($category->term_taxonomy_id, $post_terms) ) )
-				$redirect_url = get_permalink($wp_query->get_queried_object_id());
 		}
+	} elseif ( is_year() || is_month() || is_day() ) {
+		if ( '' != get_query_var('m') ) {
+			$m = get_query_var('m');
+			if ( strlen($m) > 6 )
+				$redirect_url = get_day_link(substr($m, 0, 4), substr($m, 4, 2), substr($m, 6, 2));
+			elseif ( strlen($m) > 4 )
+				$redirect_url = get_month_link( substr($m, 0, 4), substr($m, 4, 2) );
+			else
+				$redirect_url = get_year_link($m);
+			if ( $redirect_url )
+				$qv_remove[] = 'm';
+		} elseif ( is_day() ) {
+			if ( get_query_var('year') && get_query_var('monthnum') )
+				$redirect_url = get_day_link(get_query_var('year'), get_query_var('monthnum'), get_query_var('day'));
+			$qv_remove = array_merge($qv_remove, array('year', 'monthnum', 'day'));
+		} elseif ( is_month() ) {
+			if ( get_query_var('year') )
+				if ( $redirect_url = get_month_link(get_query_var('year'), get_query_var('monthnum')) )
+					$qv_remove = array_merge($qv_remove, array('year', 'monthnum'));
+		} elseif ( is_year() ) {
+			if ( $redirect_url = get_year_link(get_query_var('year')) )
+				$qv_remove[] = 'year';
+		}
+	} elseif ( is_single() && strpos($wp_rewrite->permalink_structure, '%category%') !== false ) {
+		$category = get_category_by_path(get_query_var('category_name'));
+		$post_terms = wp_get_object_terms($wp_query->get_queried_object_id(), 'category', array('fields' => 'tt_ids'));
+		if ( (!$category || is_wp_error($category)) || ( !is_wp_error($post_terms) && !empty($post_terms) && !in_array($category->term_taxonomy_id, $post_terms) ) )
+			$redirect_url = get_permalink($wp_query->get_queried_object_id());
+	} elseif ( is_singular() ) {
+		$redirect_url = get_permalink( $wp_query->get_queried_object_id() );
+	} else {
+		$redirect_url = home_url();
+	}
+	
+	if ( is_object($wp_rewrite) && $wp_rewrite->using_permalinks() ) {
+		// Feeds
+		if ( is_feed() ) {
+			$feed = get_query_var('feed');
+			$redirect_url = trailingslashit( $redirect_url );
+			if ( is_comment_feed() ) {
+				$feed = str_replace('comments-', '', $feed);
+				$redirect_url .= 'comments/';
+			}
+			$redirect_url .= 'feed';
+			if ( $feed != get_default_feed() )
+				$redirect_url .= '/' . $feed;
+			$redirect_url = user_trailingslashit( $redirect_url, 'single_single' );
+			$qv_remove[] = 'feed';
+		}
 
+		// Comment Paging
+		if ( get_query_var('cpage') ) {
+			if ( !is_feed() && get_query_var('cpage') > 0 )
+				$redirect_url = trailingslashit($redirect_url) . user_trailingslashit( 'comment-page-' . intval(get_query_var('cpage')),  'commentpaged' );
+			$qv_remove[] = 'cpage';
+		}
+
 		// Post Paging
-		if ( is_singular() && get_query_var('page') && $redirect_url ) {
-			$redirect_url = trailingslashit( $redirect_url ) . user_trailingslashit( get_query_var( 'page' ), 'single_paged' );
-			$redirect['query'] = remove_query_arg( 'page', $redirect['query'] );
+		if ( get_query_var('page') && ( is_singular() || (is_404() && $redirect_url) ) ) {
+			$page = get_query_var('page');
+			if ( is_singular() ) {
+				setup_postdata(get_queried_object());
+				global $numpages;
+				$page = min($page, $numpages);
+			}
+			if ( !is_feed() ) // Feeds don't support paging
+				$redirect_url = trailingslashit( $redirect_url ) . user_trailingslashit( $page, 'single_paged' );
+			$qv_remove[] = 'page';
 		}
-
+		
+		// Archive Paging
+		if ( get_query_var('paged') > 0 ) {
+			if ( !is_feed() ) // Feeds don't support paging
+				$redirect_url = trailingslashit( $redirect_url ) . user_trailingslashit( "$wp_rewrite->pagination_base/" . get_query_var( 'paged' ), 'paged' );
+			$qv_remove[] = 'paged';
+		}
+	
+		if ( !empty($redirect_url) && ( is_singular() || is_404() ) ) {
+			// Get the query vars in the current permastruct
+			if ( preg_match_all('/(%.+?%)/', $wp_rewrite->permalink_structure, $tokens) ) {
+				foreach ( $tokens[0] as $token )
+					$qv_remove[] = trim($wp_rewrite->queryreplace[ array_search($token, $wp_rewrite->rewritecode) ], '=');
+			}
+		}
+	}
+	
+/* 
 		// paging and feeds
 		if ( get_query_var('paged') || is_feed() || get_query_var('cpage') ) {
 			while ( preg_match( "#/$wp_rewrite->pagination_base/?[0-9]+?(/+)?$#", $redirect['path'] ) || preg_match( '#/(comments/?)?(feed|rss|rdf|atom|rss2)(/+)?$#', $redirect['path'] ) || preg_match( '#/comment-page-[0-9]+(/+)?$#', $redirect['path'] ) ) {
@@ -265,27 +303,26 @@
 				$redirect['path'] = trailingslashit($redirect['path']) . $addl_path;
 			$redirect_url = $redirect['scheme'] . '://' . $redirect['host'] . $redirect['path'];
 		}
-	}
+	}*/
 
+	if ( empty($redirect_url) )
+		$redirect_url = $requested_url;
+
+	$redirect = @parse_url($redirect_url);
+	if ( empty($redirect['query']) )
+		$redirect['query'] = '';
+
 	// tack on any additional query vars
 	$redirect['query'] = preg_replace( '#^\??&*?#', '', $redirect['query'] );
-	if ( $redirect_url && !empty($redirect['query']) ) {
-		parse_str( $redirect['query'], $_parsed_query );
-		$redirect = @parse_url($redirect_url);
+	global $wp;
 
-		if ( ! empty( $_parsed_query['name'] ) && ! empty( $redirect['query'] ) ) {
-			parse_str( $redirect['query'], $_parsed_redirect_query );
+	$vars = array_merge($wp->query_vars, $_GET);
+	$vars = array_filter($vars); //remove empty
+	foreach ( $qv_remove as $qv )
+		unset($vars[ $qv ]);
 
-			if ( empty( $_parsed_redirect_query['name'] ) )
-				unset( $_parsed_query['name'] );
-		}
+	$redirect['query'] = add_query_arg($vars, $redirect['query']);
 
-		$redirect_url = add_query_arg( $_parsed_query, $redirect_url );
-	}
-
-	if ( $redirect_url )
-		$redirect = @parse_url($redirect_url);
-
 	// www.example.com vs example.com
 	$user_home = @parse_url(home_url());
 	if ( !empty($user_home['host']) )
@@ -317,6 +354,9 @@
 
 		// Remove redundant leading ampersands
 		$redirect['query'] = preg_replace( '#^\??&*?#', '', $redirect['query'] );
+
+		// %2c => ,
+		$redirect['query'] = urldecode($redirect['query']);
 	}
 
 	// strip /index.php/ when we're not using PATHINFO permalinks
@@ -349,7 +389,7 @@
 	// Always trailing slash the Front Page URL
 	if ( trailingslashit( $redirect['path'] ) == trailingslashit( $user_home['path'] ) )
 		$redirect['path'] = trailingslashit($redirect['path']);
-
+/*
 	// Ignore differences in host capitalization, as this can lead to infinite redirects
 	// Only redirect no-www <=> yes-www
 	if ( strtolower($original['host']) == strtolower($redirect['host']) ||
@@ -371,18 +411,19 @@
 
 	if ( !empty( $redirect['query'] ) )
 		$compare_redirect[] = $redirect['query'];
+*/
+//	if ( $compare_original !== $compare_redirect ) {
 
-	if ( $compare_original !== $compare_redirect ) {
 		$redirect_url = $redirect['scheme'] . '://' . $redirect['host'];
 		if ( !empty($redirect['port']) )
 			$redirect_url .= ':' . $redirect['port'];
 		$redirect_url .= $redirect['path'];
 		if ( !empty($redirect['query']) )
 			$redirect_url .= '?' . $redirect['query'];
-	}
+//	}
 
-	if ( !$redirect_url || $redirect_url == $requested_url )
-		return false;
+//	if ( !$redirect_url || $redirect_url == $requested_url )
+//		return false;
 
 	// Hex encoded octets are case-insensitive.
 	if ( false !== strpos($requested_url, '%') ) {
@@ -397,7 +438,7 @@
 	// Note that you can use the "redirect_canonical" filter to cancel a canonical redirect for whatever reason by returning FALSE
 	$redirect_url = apply_filters('redirect_canonical', $redirect_url, $requested_url);
 
-	if ( !$redirect_url || $redirect_url == $requested_url ) // yes, again -- in case the filter aborted the request
+	if ( !$redirect_url  || $redirect_url == $requested_url ) // yes, again -- in case the filter aborted the request
 		return false;
 
 	if ( $do_redirect ) {
