Index: filefield_sources.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/filefield_sources/filefield_sources.module,v
retrieving revision 1.8
diff -u -r1.8 filefield_sources.module
--- filefield_sources.module	7 Aug 2010 19:28:25 -0000	1.8
+++ filefield_sources.module	9 Aug 2010 04:09:04 -0000
@@ -229,6 +229,7 @@
 function filefield_sources_info() {
   $info = module_invoke_all('filefield_sources_info');
   drupal_alter('filefield_sources_info', $info);
+  uasort($info, '_filefield_sources_sort');
   return $info;
 }
 
@@ -280,6 +281,45 @@
 }
 
 /**
+ * Clean up the file name, munging extensions and transliterating.
+ *
+ * @param $filepath
+ *   A string containing a file name or full path. Only the file name will
+ *   actually be modified.
+ * @return
+ *   A file path with a cleaned-up file name.
+ */
+function filefield_sources_clean_filename($filepath) {
+  global $user;
+
+  $filename = basename($filepath);
+
+  if (module_exists('transliteration')) {
+    module_load_include('inc', 'transliteration');
+
+    $langcode = NULL;
+    if (!empty($_POST['language'])) {
+      $languages = language_list();
+      $langcode = isset($languages[$_POST['language']]) ? $_POST['language'] : NULL;
+    }
+    $filename = transliteration_clean_filename($filename, $langcode);
+  }
+
+  // Because this transfer mechanism does not use file_save_upload(), we need
+  // to manually munge the filename to prevent dangerous extensions.
+  // See file_save_upload().
+  $extensions = '';
+  foreach ($user->roles as $rid => $name) {
+    $extensions .= ' '. variable_get("upload_extensions_$rid",
+    variable_get('upload_extensions_default', 'jpg jpeg gif png txt html doc xls pdf ppt pps odt ods odp'));
+  }
+  $filename = file_munge_filename($filename, $extensions);
+
+  $directory = dirname($filepath);
+  return ($directory ? $directory . '/' : $directory) . $filename;
+}
+
+/**
  * Theme the display of the sources list.
  */
 function theme_filefield_sources_list($element, $sources) {
@@ -340,9 +380,9 @@
 /**
  * Generate help text based on the $element['#upload_validators'] property.
  */
-function filefield_sources_element_validation_help($element) {
+function filefield_sources_element_validation_help($validators) {
   $desc = array();
-  foreach ($element['#upload_validators'] as $callback => $arguments) {
+  foreach ($validators as $callback => $arguments) {
     $help_func = $callback .'_help';
     if (function_exists($help_func)) {
       $desc[] = call_user_func_array($help_func, $arguments);
@@ -350,3 +390,12 @@
   }
   return empty($desc) ? '' : implode('<br />', $desc);
 }
+
+/**
+ * Custom sort function for ordering sources.
+ */
+function _filefield_sources_sort($a, $b) {
+  $a = (array)$a + array('weight' => 0, 'label' => '');
+  $b = (array)$b + array('weight' => 0, 'label' => '');
+  return $a['weight'] < $b['weight'] ? -1 : ($a['weight'] > $b['weight'] ? 1 : strnatcasecmp($a['label'], $b['label']));
+}
Index: filefield_sources.css
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/filefield_sources/filefield_sources.css,v
retrieving revision 1.1
diff -u -r1.1 filefield_sources.css
--- filefield_sources.css	17 Apr 2009 00:20:12 -0000	1.1
+++ filefield_sources.css	9 Aug 2010 04:09:04 -0000
@@ -2,9 +2,14 @@
 
 /* Generic display for all sources. */
 
-div.filefield-source input.form-text {
+div.filefield-source input.form-text,
+div.filefield-source select.form-select {
   display: inline;
-  width: 28em;
+  width: 20em;
+}
+
+div.filefield-source .form-item {
+  white-space: normal;
 }
 
 div.filefield-source input.hint {
Index: sources/reference.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/filefield_sources/sources/reference.inc,v
retrieving revision 1.5
diff -u -r1.5 reference.inc
--- sources/reference.inc	17 Jun 2010 00:10:20 -0000	1.5
+++ sources/reference.inc	9 Aug 2010 04:09:04 -0000
@@ -23,6 +23,7 @@
     'description' => t('Reuse an existing file by entering its file name.'),
     'process' => 'filefield_source_reference_process',
     'value' => 'filefield_source_reference_value',
+    'weight' => 1,
   );
   return $source;
 }
@@ -70,7 +71,8 @@
     $return['sources_reference'] = array(
       '#title' => t('Autocomplete reference options'),
       '#type' => 'fieldset',
-      '#collapsible' => FALSE,
+      '#collapsible' => TRUE,
+      '#collapsed' => TRUE,
     );
 
     $return['sources_reference']['filefield_source_autocomplete'] = array(
@@ -105,7 +107,7 @@
   $element['filefield_reference']['autocomplete'] = array(
     '#type' => 'textfield',
     '#autocomplete_path' => 'filefield/reference/' . $element['#type_name'] . '/' . $element['#field_name'],
-    '#description' => filefield_sources_element_validation_help($element),
+    '#description' => filefield_sources_element_validation_help($element['#upload_validators']),
   );
 
   $element['filefield_reference']['select'] = array(
Index: sources/remote.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/filefield_sources/sources/remote.inc,v
retrieving revision 1.8
diff -u -r1.8 remote.inc
--- sources/remote.inc	8 Aug 2010 22:42:29 -0000	1.8
+++ sources/remote.inc	9 Aug 2010 04:09:05 -0000
@@ -144,6 +144,7 @@
     $url_info = parse_url($url);
     $pathinfo = pathinfo($url_info['path']);
     $filename = rawurldecode(basename($url_info['path']));
+    $filename = filefield_sources_clean_filename($filename);
     $filepath = file_create_filename($filename, file_directory_temp());
 
     if (empty($pathinfo['extension'])) {
Index: sources/imce.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/filefield_sources/sources/imce.inc,v
retrieving revision 1.4
diff -u -r1.4 imce.inc
--- sources/imce.inc	2 Mar 2010 20:01:27 -0000	1.4
+++ sources/imce.inc	9 Aug 2010 04:09:04 -0000
@@ -32,6 +32,7 @@
     'description' => t('Select a file to use from a file browser.'),
     'process' => 'filefield_source_imce_process',
     'value' => 'filefield_source_imce_value',
+    'weight' => -1,
   );
   return $source;
 }
@@ -67,10 +68,10 @@
   $field = content_fields($element['#field_name'], $element['#type_name']);
 
   $element['filefield_imce'] = array(
-    '#weight' => 100.3,
+    '#weight' => 100.5,
     '#access' => empty($element['fid']['#value']),
     '#theme' => 'filefield_source_imce_element',
-    '#description' => filefield_sources_element_validation_help($element),
+    '#description' => filefield_sources_element_validation_help($element['#upload_validators']),
   );
 
   $filepath_id = $element['#id'] . '-imce-path';
Index: sources/attach.inc
===================================================================
RCS file: sources/attach.inc
diff -N sources/attach.inc
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ sources/attach.inc	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,266 @@
+<?php
+// $Id$
+
+/**
+ * @file
+ * A FileField extension to allow use of files within a server directory.
+ *
+ * The "hooks" in this file are not true hooks, they're called individually
+ * from the main filefield_sources.module in the corresponding hook by the
+ * same name. Any of these hooks could be broken out into a separate module.
+ */
+
+/**
+ * Implementation of hook_filefield_source_info().
+ */
+function filefield_source_attach_info() {
+  $source = array();
+  $source['attach'] = array(
+    'name' => t('File attach from server directory'),
+    'label' => t('File attach'),
+    'description' => t('Select a file from a directory on the server.'),
+    'process' => 'filefield_source_attach_process',
+    'value' => 'filefield_source_attach_value',
+    'weight' => 3,
+  );
+  return $source;
+}
+
+/**
+ * Implementation of hook_theme().
+ */
+function filefield_source_attach_theme() {
+  return array(
+    'filefield_source_attach_element' => array(
+      'arguments' => array('element' => NULL),
+      'file' => 'sources/attach.inc',
+    ),
+  );
+}
+
+/**
+ * Implementation of hook_filefield_source_settings().
+ */
+function filefield_source_attach_settings($op, $field) {
+  $return = array();
+
+  if ($op == 'form') {
+    $return['source_attach'] = array(
+      '#title' => t('File attach settings'),
+      '#type' => 'fieldset',
+      '#collapsible' => TRUE,
+      '#collapsed' => TRUE,
+      '#description' => t('File attach allows for selecting a file from a directory on the server, commonly used in combination with FTP.') . ' <strong>' . t('This file source will ignore file size checking when used.') . '</strong>',
+      '#element_validate' => array('_filefield_source_attach_file_path_validate'),
+      '#weight' => 3,
+    );
+    $return['source_attach']['filefield_source_attach_path'] = array(
+      '#type' => 'textfield',
+      '#title' => t('File attach path'),
+      '#default_value' => empty($field['filefield_source_attach_path']) ? 'file_attach' : $field['filefield_source_attach_path'],
+      '#size' => 60,
+      '#maxlength' => 128,
+      '#description' => t('The directory within the <em>File attach location</em> that will contain attachable files.'),
+    );
+    $return['source_attach']['filefield_source_attach_absolute'] = array(
+      '#type' => 'radios', 
+      '#title' => t('File attach location'),
+      '#options' => array(
+        0 => t('Within the files directory'),
+        1 => t('Absolute server path'),
+      ),
+      '#default_value' => isset($field['filefield_source_attach_absolute']) ? $field['filefield_source_attach_absolute'] : 0,
+      '#description' => t('The <em>File attach path</em> may be with the files directory (%file_directory) or from the root of your server. If an absolute path is used and it does not start with a "/" your path will be relative to your site directory: %realpath.', array('%file_directory' => file_directory_path(), '%realpath' => realpath('./'))),
+    );
+    $return['source_attach']['filefield_source_attach_mode'] = array(
+      '#type' => 'radios',
+      '#title' => t('Attach method'),
+      '#options' => array(
+        'move' => t('Move the file directly to the final location'),
+        'copy' => t('Leave a copy of the file in the attach directory'),
+      ),
+      '#default_value' => isset($field['filefield_source_attach_mode']) ? $field['filefield_source_attach_mode'] : 'move',
+      '#description' => t(),
+    );
+    $return['source_attach']['tokens'] = array(
+      '#type' => 'markup',
+      '#value' => theme('token_help', 'user'),
+    );
+  }
+  elseif ($op == 'save') {
+    $return[] = 'filefield_source_attach_path';
+    $return[] = 'filefield_source_attach_absolute';
+    $return[] = 'filefield_source_attach_mode';
+  }
+
+  return $return;
+}
+
+function _filefield_source_attach_file_path_validate($element, &$form_state) {
+  // Strip slashes from the end of the file path.
+  $filepath = rtrim($element['filefield_source_attach_path']['#value'], '\\/');
+  form_set_value($element['filefield_source_attach_path'], $filepath, $form_state);
+
+  $filepath = _filefield_source_attach_directory($form_state['values']);
+
+  // Check that the directory exists and is writable.
+  if (!field_file_check_directory($filepath, FILE_CREATE_DIRECTORY)) {
+    form_error($element['filefield_source_attach_path'], t('Specified file attach path must exist or be writable.'));
+  }
+}
+
+/**
+ * A #process callback to extend the filefield_widget element type.
+ */
+function filefield_source_attach_process($element, $edit, &$form_state, $form) {
+  $field = content_fields($element['#field_name'], $element['#type_name']);
+
+  $element['filefield_attach'] = array(
+    '#theme' => 'filefield_source_attach_element',
+    '#weight' => 100.5,
+    '#access' => empty($element['fid']['#value']),
+  );
+
+  $path = _filefield_source_attach_directory($field['widget']);
+  $options = _filefield_source_attach_options($path);
+
+  $description = t('This method may be used to attach files that exceed the file size limit. Files may be attached from the %directory directory on the server, usually uploaded through FTP.', array('%directory' => realpath($path)));
+
+  // Error messages.
+  if ($options === FALSE || empty($field['widget']['filefield_source_attach_path'])) {
+    $attach_message = t('A file attach directory could not be located.');
+    $attach_description = t('Please check your settings for the %field field.',  array('%field' => $field['widget']['label']));
+  }
+  elseif (!count($options)) {
+    $attach_message = t('There currently no files to attach.');
+    $attach_description = $description;
+  }
+
+  if (isset($attach_message)) {
+    $element['filefield_attach']['attach_message'] = array(
+      '#value' => $attach_message,
+    );
+    $element['filefield_attach']['#description'] = $attach_description;
+  }
+  else {
+    $validators = $element['#upload_validators'];
+    if (isset($validators['filefield_validate_size'])) {
+      unset($validators['filefield_validate_size']);
+    }
+    $description .= '<br />' . filefield_sources_element_validation_help($validators);
+    $element['filefield_attach']['filename'] = array(
+      '#type' => 'select',
+      '#options' => $options,
+    );
+    $element['filefield_attach']['#description'] = $description;
+  }
+
+  $element['filefield_attach']['attach'] = array(
+    '#type' => 'submit',
+    '#value' => $attach_message ? t('Refresh') : t('Attach'),
+    '#submit' => array('node_form_submit_build_node'),
+    '#ahah' => array(
+       'path' => 'filefield/ahah/'. $element['#type_name'] .'/'. $element['#field_name'] .'/'. $element['#delta'],
+       'wrapper' => $element['#id'] .'-ahah-wrapper',
+       'method' => 'replace',
+       'effect' => 'fade',
+    ),
+  );
+
+  return $element;
+}
+
+function _filefield_source_attach_options($path) {
+  if (!field_file_check_directory($path, FILE_CREATE_DIRECTORY)) {
+    drupal_set_message(t('Specified file attach path must exist or be writable.'), 'error');
+    return FALSE;
+  }
+
+  $options = array();
+  $file_attach = file_scan_directory($path, '.*', array('.', '..', 'CVS', '.svn'), 0, TRUE, 'filename', 0, 0);
+
+  if (count($file_attach)) {
+    $options = array('' => t('-- Select file --'));
+    foreach ($file_attach as $filename => $fileinfo) {
+      $filename = basename($filename);
+      $options[$filename] = $filename;
+    }
+  }
+
+  natcasesort($options);
+  return $options;
+}
+
+/**
+ * A #filefield_value_callback function.
+ */
+function filefield_source_attach_value($element, &$item) {
+  if (!empty($item['filefield_attach']['filename'])) {
+    $field = content_fields($element['#field_name'], $element['#type_name']);
+    $attach_path = _filefield_source_attach_directory($field['widget']);
+    $filepath = $attach_path . '/' . $item['filefield_attach']['filename'];
+
+    // Clean up the file name extensions and transliterate.
+    $original_filepath = $filepath;
+    $new_filepath = filefield_sources_clean_filename($filepath);
+    rename($filepath, $new_filepath);
+    $filepath = $new_filepath;
+
+    // Run all the normal validations, minus file size restrictions.
+    $validators = $element['#upload_validators'];
+    if (isset($validators['filefield_validate_size'])) {
+      unset($validators['filefield_validate_size']);
+    }
+
+    // Save the file to the new location.
+    if ($file = field_file_save_file($filepath, $validators, filefield_widget_file_path($field))) {
+      $item = array_merge($item, $file);
+
+      // Delete the original file if "moving" the file instead of copying.
+      if (empty($field['widget']['filefield_source_attach_mode']) || $field['widget']['filefield_source_attach_mode'] !== 'copy') {
+        @unlink($filepath);
+      }
+    }
+
+    // Restore the original file name if the file still exists.
+    if (file_exists($filepath) && $filepath != $original_filepath) {
+      rename($filepath, $original_filepath);
+    }
+  }
+
+  $item['filefield_attach']['filename'] = '';
+}
+
+/**
+ * Theme the output of the autocomplete field.
+ */
+function theme_filefield_source_attach_element($element) {
+  if (isset($element['attach_message'])) {
+    $output = $element['attach_message']['#value'];
+  }
+  else {
+    $select = '';
+    $size = $element['#size'] ? ' size="'. $element['filename']['#size'] .'"' : '';
+    _form_set_class($element['filename'], array('form-select'));
+    $multiple = $element['#multiple'];
+    $output = '<select name="'. $element['filename']['#name'] .''. ($multiple ? '[]' : '') .'"'. ($multiple ? ' multiple="multiple" ' : '') . drupal_attributes($element['filename']['#attributes']) .' id="'. $element['filename']['#id'] .'" '. $size .'>'. form_select_options($element['filename']) .'</select>';
+  }
+  $output .= theme('submit', $element['attach']);
+  $element['#type'] = 'item';
+  return '<div class="filefield-source filefield-source-attach clear-block">' . theme('form_element', $element, $output) . '</div>';
+}
+
+function _filefield_source_attach_directory($field, $account = NULL) {
+  $account = isset($account) ? $account : $GLOBALS['user'];  
+  $path = $field['filefield_source_attach_path'];
+  $absolute = !empty($field['filefield_source_attach_absolute']);
+
+  // Replace user level tokens.
+  // Node level tokens require a lot of complexity like temporary storage
+  // locations when values don't exist. See the filefield_paths module.
+  if (module_exists('token')) {
+    $path = token_replace($path, 'user', $account);
+  }
+
+  return $absolute ? $path : file_directory_path() . '/' . $path;
+}
