Index: class-wp-xmlrpc-server.php
===================================================================
--- class-wp-xmlrpc-server.php	(revision 17571)
+++ class-wp-xmlrpc-server.php	(working copy)
@@ -430,107 +430,275 @@
 		return $struct;
 	}
 
-	/**
-	 * Retrieve page.
-	 *
-	 * @since 2.2.0
-	 *
-	 * @param array $args Method parameters.
-	 * @return array
-	 */
-	function wp_getPage($args) {
-		$this->escape($args);
+    function wp_getPost($args, $mode = null) {
+        $this->escape($args);
+        
+        // Check if $args array has numeric keys
+        // Note: Deprecated since 3.1.1, use associative array with named keys instead 
+        if(array_values($args) === $args) {
+            // _deprecated_argument( __FUNCTION__, '3.1.1', __( 'Passing an numeric array of arguments is deprecated. Pass an associative array instead.' ) );
+            $args = array(
+            	'blog_id' => (int) $args[0], 
+            	'post_id' => (int) $args[1],
+            	'username' => $args[2], 
+            	'password' => $args[3]
+            );
+        }
 
-		$blog_id	= (int) $args[0];
-		$page_id	= (int) $args[1];
-		$username	= $args[2];
-		$password	= $args[3];
+        $defaults = array(
+        	'blog_id' => 1, 
+        	'post_id' => 1, 
+        	'username' => '', 
+        	'password' => '', 
+        	'post_type' => 'post',
+            'with_taxonomies' => 1
+        );
 
-		if ( !$user = $this->login($username, $password) ) {
-			return $this->error;
-		}
+        $args = wp_parse_args($args, $defaults);
+        $args = (object) $args;
+        
+        if (! $user = $this->login($args->username, $args->password)) {
+            return $this->error;
+        }
+        
+        if (! post_type_exists($args->post_type)) {
+            return new IXR_Error(401, __('Sorry, the post type ' . $args->post_type . ' does not exist.'));
+        }
+        
+        // TODO: Capability must be mapped in register_posttype function, so we can test against it here
+        // e.g.  current_user_can('edit_' . $args->post_type, $args->post_id)
+        // @see <http://justintadlock.com/archives/2010/07/10/meta-capabilities-for-custom-post-types> for mapping example
+        if (! current_user_can('edit_post', $args->post_id)) {
+            return new IXR_Error(401, __('Sorry, you cannot edit the post type _' . $args->post_type . '_.'));
+        }
+        
+        do_action('xmlrpc_call', 'wp.getPost');
+        
+        // Lookup post info.
+        $post = get_post($args->post_id);
 
-		if ( !current_user_can( 'edit_page', $page_id ) )
-			return new IXR_Error( 401, __( 'Sorry, you cannot edit this page.' ) );
+        // If we found the post then format the data.
+        if ($post->ID && $post->post_type == $args->post_type) {
+            // Format post date.
+            $post_date = mysql2date('Ymd\TH:i:s', $post->post_date, false);
+            $post_date_gmt = mysql2date('Ymd\TH:i:s', $post->post_date_gmt, false);
+            
+            // For drafts use the GMT version of the date
+            if ($post->post_status == 'draft') {
+                $post_date_gmt = get_gmt_from_date(mysql2date('Y-m-d H:i:s', $post->post_date), 'Ymd\TH:i:s');
+            }
+            
+            if($args->with_taxonomies) {
+                $tax_ids = get_object_taxonomies($post);
+                $taxonomies = array();
+                
+                foreach ($tax_ids as $tax_id) {
+            		$terms[$tax_id] = get_object_term_cache($post->ID, $tax_id);
+            		
+            		if ( empty($terms[$tax_id]) ) {
+            			$terms[$tax_id] = wp_get_object_terms($post->ID, $tax_id, $args, array('fields' => 'ids'));
+            		}
+            		
+        			foreach ($terms[$tax_id] as $term) {
+        			    $term = (object) get_term($term, $tax_id);
+        			    $taxonomies[$tax_id][] = $term->name;
+        			}
+                }
+            }
 
-		do_action('xmlrpc_call', 'wp.getPage');
-
-		// Lookup page info.
-		$page = get_page($page_id);
-
-		// If we found the page then format the data.
-		if ( $page->ID && ($page->post_type == "page") ) {
-			// Get all of the page content and link.
-			$full_page = get_extended($page->post_content);
-			$link = post_permalink($page->ID);
-
-			// Get info the page parent if there is one.
-			$parent_title = "";
-			if ( !empty($page->post_parent) ) {
-				$parent = get_page($page->post_parent);
-				$parent_title = $parent->post_title;
+            // Get post tags
+            if(!empty($taxonomies['post_tag'])) {
+                $tagnames = implode(', ', $taxonomies['post_tag']);
+            } else {
+                $tagnames = '';
+            }
+            
+            // Get categories
+            if(!empty($taxonomies['category'])) {
+                $categories = $taxonomies['category'];
+            } else {
+                $categories = array();
+            }
+            
+            // Get all of the post content and link.
+            $full_post = get_extended($post->post_content);
+            $link = post_permalink($post->ID);
+            
+            // Get info the page parent if there is one.
+            $parent_title = "";
+            if (! empty($post->post_parent)) {
+                $parent = get_post($post->post_parent);
+                $parent_title = $parent->post_title;
+            }
+            
+            // Determine comment and ping settings.
+            $allow_comments = comments_open($post->ID) ? 1 : 0;
+            $allow_pings = pings_open($post->ID) ? 1 : 0;
+            
+            // Get the author info.
+            $author = get_userdata($post->post_author);
+            
+			// Consider future posts as published
+			if ( $post->post_status === 'future' ) {
+				$post->post_status = 'publish';
 			}
+			
+			// Get post format
+			$post_format = get_post_format( $post->ID);
+			if ( empty( $post_format ) )
+				$post_format = 'standard';
+				
+            $sticky = false;
+			if ( is_sticky( $post->ID) ) {
+			    $sticky = true;
+			}
+            
+			// Get page template
+            $page_template = get_post_meta($post->ID, '_wp_page_template', true);
+            if (empty($page_template)) {
+                $page_template = 'default';
+            }
+            
+            $post_struct = array(
+            	'dateCreated' => new IXR_Date($post_date), 
+            	'userid' => $post->post_author, 
+            	'postid' => $post->ID, 
+            	'post_status' => $post->post_status, 
+            	'description' => $full_post['main'], 
+            	'title' => $post->post_title, 
+            	'link' => $link, 
+            	'permaLink' => $link, 
+            	'categories' => $categories, 
+            	'excerpt' => $post->post_excerpt, 
+            	'text_more' => $full_post['extended'], 
+            	'mt_allow_comments' => $allow_comments, 
+            	'mt_allow_pings' => $allow_pings,
+            	'mt_keywords' => $tagnames,
+            	'wp_slug' => $post->post_name, 
+            	'wp_password' => $post->post_password, 
+            	'wp_author' => $author->display_name, 
+            	'wp_page_parent_id' => $post->post_parent, 
+            	'wp_page_parent_title' => $parent_title, 
+            	'wp_page_order' => $post->menu_order, 
+            	'wp_author_id' => $author->ID, 
+            	'wp_author_display_name' => $author->display_name, 
+            	'date_created_gmt' => new IXR_Date($post_date_gmt), 
+            	'custom_fields' => $this->get_custom_fields($args->post_id), 
+            	'wp_page_template' => $page_template,
+                'wp_post_format' => $post_format,
+                'sticky' => $sticky,
+                'post_type' => $post->post_type,
+                'taxonomies' => $taxonomies
+            );
+            
+            return $post_struct;
+        } else {
+            // If the post doesn't exist indicate that.
+            return new IXR_Error(404, __('Sorry, no such post in post type _' . $args->post_type . '_.'));
+        }
+    }
+    
+    function wp_getPosts($args) {
+        $this->escape($args);
+        
+        // Check if $args array has numeric keys
+        // Note: Deprecated since 3.1.1, use associative array with named keys instead 
+        if(array_values($args) === $args) {
+            // _deprecated_argument( __FUNCTION__, '3.1.1', __( 'Passing an numeric array of arguments is deprecated. Pass an associative array instead.' ) );
+            $args = array(
+            	'blog_id' => (int) $args[0], 
+            	'username' => $args[1], 
+            	'password' => $args[2]
+            );
+        }
+        
+        $defaults = array(
+        	'blog_id' => 1,
+        	'username' => '', 
+        	'password' => '', 
+        	'post_type' => 'post', 
+        	'num_posts' => 10,
+            'post_status' => 'any',
+            'with_taxonomies' => 1
+        );
+        
+        $args = wp_parse_args($args, $defaults);
+        $args = (object) $args;
 
-			// Determine comment and ping settings.
-			$allow_comments = comments_open($page->ID) ? 1 : 0;
-			$allow_pings = pings_open($page->ID) ? 1 : 0;
+        if (! $user = $this->login($args->username, $args->password)) {
+            return $this->error;
+        }
+        
+        if (! post_type_exists($args->post_type)) {
+            return new IXR_Error(401, __('Sorry, the post type ' . $args->post_type . ' does not exist.'));
+        }
 
-			// Format page date.
-			$page_date = mysql2date("Ymd\TH:i:s", $page->post_date, false);
-			$page_date_gmt = mysql2date("Ymd\TH:i:s", $page->post_date_gmt, false);
+		do_action('xmlrpc_call', 'wp.getPosts');
 
-			// For drafts use the GMT version of the date
-			if ( $page->post_status == 'draft' )
-				$page_date_gmt = get_gmt_from_date( mysql2date( 'Y-m-d H:i:s', $page->post_date ), 'Ymd\TH:i:s' );
+		$posts = get_posts( array('post_type' => $args->post_type, 'post_status' => $args->post_status, 'numberposts' => $args->num_posts) );
+		$num_posts = count($posts);
 
-			// Pull the categories info together.
-			$categories = array();
-			foreach ( wp_get_post_categories($page->ID) as $cat_id ) {
-				$categories[] = get_cat_name($cat_id);
+		// If we have pages, put together their info.
+		if ( $num_posts >= 1 ) {
+			$posts_struct = array();
+			
+			for ( $i = 0; $i < $num_posts; $i++ ) {
+		        // TODO: Capability must be mapped in register_posttype function, so we can test against it here
+                // e.g.  current_user_can('edit_' . $args->post_type, $args->post_id)
+                // @see <http://justintadlock.com/archives/2010/07/10/meta-capabilities-for-custom-post-types> for mapping example
+                if (! current_user_can('edit_posts', $posts[$i])) {
+                    continue;
+                }
+			    
+				$post = self::wp_getPost(array(
+					'blog_id' => $args->blog_id, 
+					'post_id' => $posts[$i]->ID, 
+					'username' => $args->username, 
+					'password' => $args->password,
+				    'post_type'=> $args->post_type,
+				    'with_taxonomies' => $args->with_taxonomies
+				));
+				
+				$posts_struct[] = $post;
 			}
 
-			// Get the author info.
-			$author = get_userdata($page->post_author);
-
-			$page_template = get_post_meta( $page->ID, '_wp_page_template', true );
-			if ( empty( $page_template ) )
-				$page_template = 'default';
-
-			$page_struct = array(
-				"dateCreated"			=> new IXR_Date($page_date),
-				"userid"				=> $page->post_author,
-				"page_id"				=> $page->ID,
-				"page_status"			=> $page->post_status,
-				"description"			=> $full_page["main"],
-				"title"					=> $page->post_title,
-				"link"					=> $link,
-				"permaLink"				=> $link,
-				"categories"			=> $categories,
-				"excerpt"				=> $page->post_excerpt,
-				"text_more"				=> $full_page["extended"],
-				"mt_allow_comments"		=> $allow_comments,
-				"mt_allow_pings"		=> $allow_pings,
-				"wp_slug"				=> $page->post_name,
-				"wp_password"			=> $page->post_password,
-				"wp_author"				=> $author->display_name,
-				"wp_page_parent_id"		=> $page->post_parent,
-				"wp_page_parent_title"	=> $parent_title,
-				"wp_page_order"			=> $page->menu_order,
-				"wp_author_id"			=> $author->ID,
-				"wp_author_display_name"	=> $author->display_name,
-				"date_created_gmt"		=> new IXR_Date($page_date_gmt),
-				"custom_fields"			=> $this->get_custom_fields($page_id),
-				"wp_page_template"		=> $page_template
-			);
-
-			return($page_struct);
+			return $posts_struct;
 		}
-		// If the page doesn't exist indicate that.
+		// If no post were found return an error.
 		else {
-			return(new IXR_Error(404, __("Sorry, no such page.")));
+			return array();
 		}
-	}
+    }
+    
+    function wp_getPage($args) {
+        $this->escape($args);
+        
+        // Check if $args array has numeric keys
+        // Note: Deprecated since 3.1.1, use associative array with named keys instead 
+        if(array_values($args) === $args) {
+            // _deprecated_argument( __FUNCTION__, '3.1.1', __( 'Passing an numeric array of arguments is deprecated. Pass an associative array instead.' ) );
+            $args = array(
+            	'blog_id' => (int) $args[0], 
+            	'post_id' => (int) $args[1],
+            	'username' => $args[2], 
+            	'password' => $args[3]
+            );
+        }
 
+        $defaults = array(
+        	'blog_id' => 1, 
+        	'post_id' => 1, 
+        	'username' => '', 
+        	'password' => '', 
+        	'post_type' => 'page',
+            'with_taxonomies' => 1
+        );
+        
+        $args = wp_parse_args($args, $defaults);
+
+        return self::wp_getPost($args);
+    }
+
 	/**
 	 * Retrieve Pages.
 	 *
