Index: wp-admin/includes/ajax-actions.php
===================================================================
--- wp-admin/includes/ajax-actions.php	(revision 22730)
+++ wp-admin/includes/ajax-actions.php	(working copy)
@@ -1780,6 +1780,8 @@
  * @since 3.5.0
  */
 function wp_ajax_get_attachment() {
+	// @todo Nonce check!
+
 	if ( ! isset( $_REQUEST['id'] ) )
 		wp_send_json_error();
 
@@ -1801,6 +1803,9 @@
  * @since 3.5.0
  */
 function wp_ajax_query_attachments() {
+	// @todo upload_files cap check!
+	// @todo Nonce check!
+
 	$query = isset( $_REQUEST['query'] ) ? (array) $_REQUEST['query'] : array();
 	$query = array_intersect_key( $query, array_flip( array(
 		's', 'order', 'orderby', 'posts_per_page', 'paged', 'post_mime_type',
@@ -1907,3 +1912,139 @@
 
 	wp_send_json_success( $attachment );
 }
+
+// These filters get run:
+	// media_send_to_editor
+// And for images only:
+	// image_send_to_editor
+	// image_add_caption_shortcode (unless there is no caption, or if captions are disabled with disable_captions)
+	// get_image_tag
+	// get_image_tag_class
+// These callbacks are run by core against these filters:
+	// add_filter( 'media_send_to_editor', 'image_media_send_to_editor', 10, 3 );
+	// add_filter( 'image_send_to_editor', 'image_add_caption', 20, 8 );
+
+function do_i_need_php_to_send_images_to_the_editor() {
+	if ( 10 === has_filter( 'media_send_to_editor', 'image_media_send_to_editor' ) )
+		remove_filter( 'media_send_to_editor', 'image_media_send_to_editor', 10 );
+	else
+		return true;
+
+	$return = has_filter( 'media_send_to_editor' );
+	add_filter( 'media_send_to_editor', 'image_media_send_to_editor', 10, 3 );
+	if ( $return )
+		return true;
+
+	if ( 20 === has_filter( 'image_send_to_editor', 'image_add_caption' ) )
+		remove_filter( 'image_send_to_editor', 'image_add_caption', 20 );
+	else
+		return true;
+
+	$return = has_filter( 'image_send_to_editor' );
+	add_filter( 'image_send_to_editor', 'image_add_caption', 20, 8 );
+	if ( $return )
+		return true;
+
+	foreach ( array( 'image_add_caption_shortcode', 'get_image_tag', 'get_image_tag_class' ) as $filter ) {
+		if ( has_filter( $filter ) )
+			return true;
+	}
+
+	return false;
+}
+
+// Does media_send_to_editor have anything hooked into it except for image_media_send_to_editor?
+function do_i_need_php_to_send_non_images_to_the_editor() {
+	$priority = has_filter( 'media_send_to_editor', 'image_media_send_to_editor' );
+	if ( false !== $priority )
+		remove_filter( 'media_send_to_editor', 'image_media_send_to_editor', $priority );
+
+	$return = has_filter( 'media_send_to_editor' );
+
+	if ( false !== $priority )
+		add_filter( 'media_send_to_editor', 'image_media_send_to_editor', $priority );
+
+	return $return;
+}
+
+function wp_ajax_send_to_editor() {
+	// @todo cap check like edit_posts or upload_files
+
+	check_ajax_referer( 'media_send_to_editor' );
+
+	$attachment = stripslashes_deep( $_POST['attachment'] );
+	// keys must include 'id'
+	// keys may include 'image-align', 'image-size', 'image-alt', 'url',
+	// and 'caption' for images, 'title' for non-images
+
+	$id = intval( $attachment['id'] );
+
+	if ( ! $post = get_post( $id ) )
+		wp_send_json_error();
+
+	if ( ! current_user_can( 'edit_post', $id ) )
+		wp_send_json_error();
+
+	if ( 'attachment' != $post->post_type )
+		wp_send_json_error();
+
+	$html = isset( $attachment['title'] ) ? $attachment['title'] : '';
+	if ( ! empty( $attachment['url'] ) ) {
+		$rel = '';
+		if ( strpos($attachment['url'], 'attachment_id') || get_attachment_link( $id ) == $attachment['url'] )
+			$rel = ' rel="attachment wp-att-' . $id . '"';
+		$html = '<a href="' . esc_url( $attachment['url'] ) . '"' . $rel . '>' . $html . '</a>';
+	}
+
+	remove_filter( 'media_send_to_editor', 'image_media_send_to_editor', 10, 3 );
+
+	if ( 'image' === substr( $post->post_mime_type, 0, 5 ) ) {
+		$url = $attachment['url'];
+		$align = isset( $attachment['image-align'] ) ? $attachment['image-align'] : 'none';
+		$size = isset( $attachment['image-size'] ) ? $attachment['image-size'] : 'medium';
+		$alt = isset( $attachment['image-alt'] ) ? $attachment['image-alt'] : '';
+		$caption = isset( $attachment['caption'] ) ? $attachment['caption'] : '';
+		$title = ''; // We no longer insert title tags into <img> tags, as they are redundant.
+		$html = get_image_send_to_editor( $id, $caption, $title, $align, $url, (bool) $rel, $size, $alt );
+	}
+
+	$html = apply_filters( 'media_send_to_editor', $html, $id, $attachment );
+
+	wp_send_json_success( $html );
+}
+
+// Only needs to run for non-images inserted from Embed from URL
+// You must check disable_captions to see if captions are disabled, when handling images from JS
+//
+// Only needs to be run if the {$type}_send_to_editor_url hooks are used,
+// where $type is file, audio, or video
+
+function wp_ajax_send_to_editor_url() {
+	check_ajax_referer( 'media_send_to_editor' );
+
+	if ( ! $src = stripslashes( $_POST['src'] ) )
+		wp_send_json_error();
+
+	if ( ! strpos( $src, '://' ) )
+		$src = 'http://' . $src;
+
+	if ( ! $src = esc_url_raw( $src ) )
+		wp_send_json_error();
+
+	if ( ! $title = trim( stripslashes( $_POST['title'] ) ) )
+		$title = wp_basename( $src );
+
+	$html = '';
+	if ( $title )
+		$html = '<a href="' . esc_url( $src ) . '">' . $title . '</a>';
+
+	// Figure out what filter to run:
+	$type = 'file';
+	if ( ( $ext = preg_replace( '/^.+?\.([^.]+)$/', '$1', $src ) ) && ( $ext_type = wp_ext2type( $ext ) )
+		&& ( 'audio' == $ext_type || 'video' == $ext_type ) )
+			$type = $ext_type;
+
+	$html = apply_filters( $type . '_send_to_editor_url', $html, $src, $title );
+
+	wp_send_json_success( $html );
+}
