diff --git a/editors/js/yui.js b/editors/js/yui.js
index 364921c..a1bc7be 100644
--- a/editors/js/yui.js
+++ b/editors/js/yui.js
@@ -8,6 +8,9 @@ Drupal.wysiwyg.editor.attach.yui = function(context, params, settings) {
   $('#' + params.field).parent().addClass('yui-skin-' + settings.theme);
   // Attach editor.
   var editor = new YAHOO.widget.Editor(params.field, settings);
+  if (Drupal.settings.wysiwyg.upload_files_allowed == true) {
+      Drupal.wysiwyg.editor.yuiImgUploader(editor, params.field, Drupal.settings.basePath +'?q=/wysiwyg_upload/yui', 'files[yui_upload]');
+  }
   editor.render();
 };
 
@@ -36,3 +39,97 @@ Drupal.wysiwyg.editor.detach.yui = function(context, params) {
   }
 };
 
+
+/*
+yuiImgUploader
+variables: 
+ rte: The YAHOO.widget.Editor instance
+ upload_url: the url to post the file to
+ upload_image_name: the name of the post parameter to send the file as
+
+Your server must handle the posted image.  You must return a JSON object
+with the result url that the image can be viewed at on your server.  If 
+the upload fails, you can return an error message.  For successful
+uploads, the status must be set to UPLOADED.  All other status messages,
+or the lack of a status message is interpreted as an error.  IE will 
+try to open a new document window when the response is returned if your
+content-type header on your response is not set to 'text/javascript'
+
+Example Success:
+{status:'UPLOADED', image_url:'/somedirectory/filename'}
+Example Failure:
+{status:'We only allow JPEG Images.'}
+
+*/
+
+Drupal.wysiwyg.editor.yuiImgUploader = function(rte, editor_name, upload_url, upload_image_name) {
+   // customize the editor img button 
+
+
+   YAHOO.log( "Adding Click Listener" ,'debug');
+   rte.addListener('toolbarLoaded',function() {
+       rte.toolbar.addListener ( 'insertimageClick', function(o) {
+           try {
+               var imgPanel=new YAHOO.util.Element(editor_name + '-panel');
+               imgPanel.on ( 'contentReady', function() {
+                   try {
+                       var Dom=YAHOO.util.Dom;
+
+                       if (! Dom.get(editor_name + '_insertimage_upload'))
+                       {
+                           var label=document.createElement('label');
+                          label.innerHTML='<strong>Upload:</strong>'+
+			         '<input type="file" id="' +
+				  editor_name + '_insertimage_upload" name="'+upload_image_name+
+			         '" size="10" style="width: 300px" />'+
+			         '</label>';
+
+                           var img_elem=Dom.get(editor_name + '_insertimage_url');
+                           Dom.getAncestorByTagName(img_elem, 'form').encoding = 'multipart/form-data';
+
+                           Dom.insertAfter(
+                               label,
+                               img_elem.parentNode);
+                           YAHOO.util.Event.on ( editor_name + '_insertimage_upload', 'change', function(ev) {
+                               YAHOO.util.Event.stopEvent(ev); // no default click action
+                               YAHOO.util.Connect.setForm ( img_elem.form, true, true );
+                               var c=YAHOO.util.Connect.asyncRequest(
+                               'POST', upload_url, {
+                                   upload:function(r){
+                                       try {
+                                           // strip pre tags if they got added somehow
+                                           resp=r.responseText.replace( /<pre>/i, '').replace ( /<\/pre>/i, '');
+                                           var o=eval('('+resp+')');
+                                           if (o.status=='UPLOADED') {
+                                               Dom.get(editor_name + '_insertimage_upload').value='';
+                                               Dom.get(editor_name + '_insertimage_url').value=o.image_url;
+                                               // tell the image panel the url changed
+                                               // hack instead of fireEvent('blur')
+                                               // which for some reason isn't working
+                                               Dom.get(editor_name + '_insertimage_url').focus();
+                                               Dom.get(editor_name + '_insertimage_upload').focus();
+                                           } else {
+                                               alert ( "Upload Failed: "+o.status );
+                                           }
+
+                                       } catch ( eee ) {
+                                           YAHOO.log( eee.message, 'error' );
+                                       }
+                                   }
+                               }
+                               );
+                               return false;
+                           });
+                       }
+                   }
+			catch ( ee ) { YAHOO.log( ee.message, 'error' ); }
+		   
+               });
+           } catch ( e ) {
+               YAHOO.log( e.message, 'error' );
+           }
+       });
+   });
+
+}
+
diff --git a/editors/yui.inc b/editors/yui.inc
index 3c155e9..77615bc 100644
--- a/editors/yui.inc
+++ b/editors/yui.inc
@@ -26,6 +26,7 @@ function wysiwyg_yui_editor() {
           'menu/menu-min.js',
           'button/button-min.js',
           'editor/editor-min.js',
+	  'connection/connection-min.js',
         ),
       ),
       'src' => array(
@@ -38,6 +39,7 @@ function wysiwyg_yui_editor() {
           'menu/menu.js',
           'button/button.js',
           'editor/editor.js',
+	  'connection/connection.js',
         ),
       ),
     ),
@@ -46,6 +48,7 @@ function wysiwyg_yui_editor() {
     'load callback' => 'wysiwyg_yui_load',
     'settings callback' => 'wysiwyg_yui_settings',
     'plugin callback' => 'wysiwyg_yui_plugins',
+    'upload callback' => 'wysiwyg_yui_upload',
     'versions' => array(
       '2.7.0' => array(
         'js files' => array('yui.js'),
@@ -292,3 +295,83 @@ function wysiwyg_yui_plugins($editor) {
   );
 }
 
+// FIXME: perhaps some of the generic checking here in
+// wysiwyg_yui_upload could be factored out and moved into
+// wysiwyg_upload  (in wysiwyg.upload.inc)
+
+function wysiwyg_yui_upload() {
+  global $user;
+  global $base_path; 
+
+  header('content-type: text/html'); // the return type must be text/html
+  $response = NULL;
+  $path = file_directory_path();
+
+  // FIXME: we should probably validate the form tokens here to
+  // protect against CSRF.
+
+  // Append trailing slash to path if not there
+  if (!(substr($path, -1) == '/')) {
+    $path .= '/';
+  }
+  $path .= 'images';
+
+  if ($_FILES['files']['error']['yui_upload'] != UPLOAD_ERR_OK) {
+    switch ($_FILES['files']['error']['yui_upload']) {
+    case UPLOAD_ERR_INI_SIZE:
+    case UPLOAD_ERR_FORM_SIZE:
+      $response->status = t('File was too large');
+      break;
+    case UPLOAD_ERR_NO_FILE:
+      $response->status = t('No file was uploaded');
+      break;
+    default:
+      $response->status = t('Error reading uploaded file')."\n".'(Guru Meditation $_FILES error#: '.$_FILES['files']['error']['yui_upload'].')';
+    }
+    print drupal_to_js($response);
+    exit;
+  }
+
+
+  // FIXME: it sucks to have to call an internal function from upload.module
+  $limits = _upload_file_limits($user);
+  // FIXME: maybe log something if _upload_file_limits doesn't exist
+  // or returns some garbage
+  $validators = array(
+    'file_validate_extensions' => array($limits['extensions']),
+    'file_validate_image_resolution' => array($limits['resolution']),
+    'file_validate_size' => array($limits['file_size'], $limits['user_size']),
+  );
+
+  $file = file_save_upload('yui_upload', $validators, $path);
+
+  if (!$file) {
+    // this will clear the message queue.  FIXME: seems like trouble
+    // or a race condition during ajax.  :(
+    $msgsout="";
+    $msgtypes = drupal_get_messages();
+    foreach ($msgtypes as $type => $msgs) {
+      foreach ($msgs as $msg) {
+        $msgsout .= "\n".$type.': '.strip_tags(str_replace('<li>', "\n", $msg));
+      }
+    }
+    
+    $response->status = t('Trouble saving file').$msgsout;
+  } else {
+
+    // FIXME: it might also be nice to associate this upload with a
+    // given node; however, this is in the generic WYSIWYG context, and
+    // might be associated with a block or something else, so i don't
+    // know how to do that.
+
+    $response->status = 'UPLOADED';
+    $response->image_url = $base_path .$file->filepath;
+
+    // Set it to permanent so it doesn't get wiped on the next cron run!
+    file_set_status($file, FILE_STATUS_PERMANENT);
+  }
+
+  print drupal_to_js($response);
+  exit;
+}
+
diff --git a/wysiwyg.module b/wysiwyg.module
index fe526a5..75b0d2a 100644
--- a/wysiwyg.module
+++ b/wysiwyg.module
@@ -50,6 +50,14 @@ function wysiwyg_menu() {
     'type' => MENU_CALLBACK,
     'file' => 'wysiwyg.dialog.inc',
   );
+  $items['wysiwyg_upload/%'] = array(
+    'page callback' => 'wysiwyg_upload',
+    'page arguments' => array(1),
+    'access arguments' => array('upload files'),
+    'type' => MENU_CALLBACK,
+    'file' => 'wysiwyg.upload.inc',
+  );
+   
   return $items;
 }
 
@@ -305,6 +313,7 @@ function wysiwyg_load_editor($profile) {
       'configs' => array(),
       'disable' => t('Disable rich-text'),
       'enable' => t('Enable rich-text'),
+      'upload_files_allowed' => array_key_exists('upload', module_list()) && user_access('upload files'),
     )), 'setting');
 
     $path = drupal_get_path('module', 'wysiwyg');
@@ -688,6 +697,7 @@ function wysiwyg_get_all_editors() {
       'settings callback' => NULL,
       'plugin callback' => NULL,
       'plugin settings callback' => NULL,
+      'upload callback' => NULL,
       'versions' => array(),
       'js path' => $editors[$editor]['path'] . '/js',
       'css path' => $editors[$editor]['path'] . '/css',
diff --git a/wysiwyg.upload.inc b/wysiwyg.upload.inc
new file mode 100644
index 0000000..452c52a
--- /dev/null
+++ b/wysiwyg.upload.inc
@@ -0,0 +1,35 @@
+<?php
+// $Id$
+
+/**
+ * @file
+ * Wysiwyg upload handling functions.
+ */
+
+/**
+ * Menu callback; Return well structured response from image upload in
+ * the form that the associated editor can accept.
+ */
+
+// FIXME: perhaps some of the generic file upload checking in
+// wysiwyg_yui_upload (in editors/yui/yui.inc) could be factored out
+// and moved into this function.
+
+function wysiwyg_upload($editor_name) {
+  //  print_r(debug_backtrace());
+  if (!array_key_exists('upload', module_list()))
+    return drupal_not_found();
+
+    $editor = wysiwyg_get_editor($editor_name);
+    if (!isset($editor['upload callback'])) {
+	return drupal_not_found();
+      }
+    $callback = $editor['upload callback']; 
+
+    if (!function_exists($callback)) {
+      return drupal_not_found();
+    }
+
+    $callback();
+}
+
