Browse Source

more module updates

Bachir Soussi Chiadmi 9 years ago
parent
commit
2121a356b3
51 changed files with 1639 additions and 852 deletions
  1. 7 4
      sites/all/modules/contrib/dev/prod_check/README.txt
  2. 1 1
      sites/all/modules/contrib/dev/prod_check/css/prod-check.css
  3. 300 26
      sites/all/modules/contrib/dev/prod_check/includes/prod_check.admin.inc
  4. 102 77
      sites/all/modules/contrib/dev/prod_check/includes/prod_check.apc.inc
  5. 35 0
      sites/all/modules/contrib/dev/prod_check/includes/prod_check.theme.inc
  6. 3 3
      sites/all/modules/contrib/dev/prod_check/prod_check.info
  7. 139 40
      sites/all/modules/contrib/dev/prod_check/prod_check.module
  8. 3 3
      sites/all/modules/contrib/dev/prod_check/prod_monitor/js/prod-monitor.performance.js
  9. 3 3
      sites/all/modules/contrib/dev/prod_check/prod_monitor/prod_monitor.info
  10. 1 1
      sites/all/modules/contrib/dev/prod_check/prod_monitor/prod_monitor.module
  11. 0 28
      sites/all/modules/contrib/mail/smtp/smtp-base64-1741082-16.patch
  12. 32 0
      sites/all/modules/contrib/mail/smtp/smtp.admin.inc
  13. 3 3
      sites/all/modules/contrib/mail/smtp/smtp.info
  14. 13 9
      sites/all/modules/contrib/mail/smtp/smtp.install
  15. 47 33
      sites/all/modules/contrib/mail/smtp/smtp.mail.inc
  16. 41 0
      sites/all/modules/contrib/mail/smtp/smtp.module
  17. 26 12
      sites/all/modules/contrib/mail/smtp/smtp.phpmailer.inc
  18. 8 2
      sites/all/modules/contrib/messages/better_messages/better_messages.inc
  19. 4 3
      sites/all/modules/contrib/messages/better_messages/better_messages.info
  20. 3 2
      sites/all/modules/contrib/messages/better_messages/better_messages.install
  21. 1 1
      sites/all/modules/contrib/messages/better_messages/better_messages.js
  22. 65 25
      sites/all/modules/contrib/messages/better_messages/better_messages.module
  23. 11 12
      sites/all/modules/contrib/responsive/browscap/browscap.admin.inc
  24. 3 3
      sites/all/modules/contrib/responsive/browscap/browscap.info
  25. 10 3
      sites/all/modules/contrib/responsive/browscap/browscap.install
  26. 24 22
      sites/all/modules/contrib/responsive/browscap/browscap.module
  27. 69 41
      sites/all/modules/contrib/responsive/browscap/import.inc
  28. 3 0
      sites/all/modules/contrib/taxonomy/synonyms/README.txt
  29. 15 11
      sites/all/modules/contrib/taxonomy/synonyms/includes/AbstractSynonymsExtractor.class.inc
  30. 6 7
      sites/all/modules/contrib/taxonomy/synonyms/includes/EntityReferenceSynonymsExtractor.class.inc
  31. 4 4
      sites/all/modules/contrib/taxonomy/synonyms/includes/SynonymsSynonymsExtractor.class.inc
  32. 4 4
      sites/all/modules/contrib/taxonomy/synonyms/includes/TaxonomySynonymsExtractor.class.inc
  33. 2 2
      sites/all/modules/contrib/taxonomy/synonyms/synonyms.api.php
  34. 5 3
      sites/all/modules/contrib/taxonomy/synonyms/synonyms.info
  35. 213 287
      sites/all/modules/contrib/taxonomy/synonyms/synonyms.module
  36. 263 103
      sites/all/modules/contrib/taxonomy/synonyms/synonyms.test
  37. 7 9
      sites/all/modules/contrib/theming/colorbox/README.txt
  38. 9 3
      sites/all/modules/contrib/theming/colorbox/colorbox-insert-image.tpl.php
  39. 20 1
      sites/all/modules/contrib/theming/colorbox/colorbox.admin.inc
  40. 3 3
      sites/all/modules/contrib/theming/colorbox/colorbox.info
  41. 5 3
      sites/all/modules/contrib/theming/colorbox/colorbox.install
  42. 0 9
      sites/all/modules/contrib/theming/colorbox/colorbox.make.example
  43. 46 17
      sites/all/modules/contrib/theming/colorbox/colorbox.module
  44. 54 13
      sites/all/modules/contrib/theming/colorbox/colorbox.theme.inc
  45. 13 6
      sites/all/modules/contrib/theming/colorbox/js/colorbox.js
  46. 1 1
      sites/all/modules/contrib/theming/colorbox/styles/default/colorbox_style.js
  47. 1 1
      sites/all/modules/contrib/theming/colorbox/styles/plain/colorbox_style.css
  48. 2 2
      sites/all/modules/contrib/theming/colorbox/styles/plain/colorbox_style.js
  49. 2 1
      sites/all/modules/contrib/theming/colorbox/styles/stockholmsyndrome/colorbox_style.css
  50. 3 3
      sites/all/modules/contrib/theming/colorbox/styles/stockholmsyndrome/colorbox_style.js
  51. 4 2
      sites/all/modules/contrib/theming/colorbox/views/colorbox_handler_field_colorbox.inc

+ 7 - 4
sites/all/modules/contrib/dev/prod_check/README.txt

@@ -232,11 +232,14 @@ Cron is NOT used to do this, since we want to keep the transfer to a minimum.
 
 Hidden link
 ===========
-Production check adds a 'hidden link' to the site where you can check the APC
-status of your site. This page can be found on /admin/reports/status/apc.
-This is in analogy with the system module that adds these 'hidden pages':
+Production check adds some 'hidden links' to the site where you can check the
+APC, Memcache and DB status of your site. These pages can be found on:
+  /admin/reports/status/apc
+  /admin/reports/status/memcache
+  /admin/reports/status/database
+
+This is in analogy with the system module that adds this 'hidden page':
  /admin/reports/status/php
- /admin/reports/status/sql
 
 Truely unmissable when setting up your site on a production server to check if
 all is well!

+ 1 - 1
sites/all/modules/contrib/dev/prod_check/css/prod-check.css

@@ -1,5 +1,5 @@
 
-/* Prod monitor settings page styling */
+/* Prod check settings page styling */
 
 .prod-check-settings{float:left;padding:0 5px;}
 .prod-check-settings.odd{background-color:#f8f8f8;}

+ 300 - 26
sites/all/modules/contrib/dev/prod_check/includes/prod_check.admin.inc

@@ -395,9 +395,9 @@ function prod_check_settings_form_validate($form, &$form_state) {
   // seem logical...
   $base = drupal_get_path('module', 'prod_check');
   drupal_add_css($base . '/css/prod-check.css');
-  drupal_add_js($base . '/js/jquery.equalheights.js', 'module', 'header');
-  drupal_add_js($base . '/js/jquery.maskedinput.min.js', 'module', 'header');
-  drupal_add_js($base . '/js/prod-check.js', 'module', 'header');
+  drupal_add_js($base . '/js/jquery.equalheights.js');
+  drupal_add_js($base . '/js/jquery.maskedinput.min.js');
+  drupal_add_js($base . '/js/prod-check.js');
 
   if (module_exists('dblog')) {
     if (!is_numeric($form_state['values']['prod_check_dblog_php_threshold'])) {
@@ -737,6 +737,297 @@ function prod_check_prod_mode_modules($options) {
   return $modules;
 }
 
+/**
+ * Generate default key if none is present.
+ */
+function prod_check_generate_key($length = 25) {
+  $chars = 'abcdefghijklmnopqrstuxyvwzABCDEFGHIJKLMNOPQRSTUXYVWZ+-*#&@!?';
+  $size = strlen($chars);
+  $key = '';
+  for ($i = 0; $i < $length; $i++) {
+    $key .= $chars[rand(0, $size - 1)];
+  }
+
+  return $key;
+}
+
+/**
+ * Database status page.
+ */
+function prod_check_dbstatus() {
+  // Get active connection.
+  $pdo = Database::getConnection();
+  // Get database driver.
+  $db_type = $pdo->getAttribute(PDO::ATTR_DRIVER_NAME);
+
+  $details = array(
+    'status' => array(),
+    'tables' => array(),
+    'databases' => array(),
+  );
+
+  $add_js = FALSE;
+
+  $title = '';
+  $db = $db_type;
+  switch($db_type) {
+    case 'pgsql':
+      // Set title & version.
+      $server = db_query('SELECT version()')->fetchField();
+      $title = t('Running @version', array('@version' => $server));
+      // Get detailed status.
+      $details = _prod_check_dbstatus_pgsql($details);
+      break;
+    case 'mysql':
+      $db = 'MySQL';
+      // Get detailed status.
+      $details = _prod_check_dbstatus_mysql($details);
+      // NO break here!
+    default:
+      // Set title & version.
+      $server = $pdo->getAttribute(PDO::ATTR_SERVER_VERSION);
+      $title = t('Running @db @version', array('@db' => $db, '@version' => $server));
+      break;
+  }
+
+  // Get basic status.
+  $status = '';
+  try {
+    $status = $pdo->getAttribute(PDO::ATTR_SERVER_INFO);
+    if (is_array($status)) {
+      $status = implode("<br />\n", $status);
+    }
+    else {
+      $status = str_replace('  ', "<br />\n", $status);
+    }
+  } catch(Exception $e) {}
+
+  // Get additional status.
+  $additional = '';
+  $attributes = array(
+    'AUTOCOMMIT' => 'Auto commit',
+    'PREFETCH' => 'Prefetch',
+    'TIMEOUT' => 'Timeout',
+    'ERRMODE' => 'Error mode',
+    'CLIENT_VERSION' => 'Client version',
+    'CONNECTION_STATUS' => 'Connection status',
+    'CASE' => 'Case',
+    'CURSOR_NAME' => 'Cursor name',
+    'CURSOR' => 'Cursor',
+    'ORACLE_NULLS' => 'Oracle nulls',
+    'PERSISTENT' => 'Persistent',
+    'STATEMENT_CLASS' => 'Statement class',
+    'FETCH_CATALOG_NAMES' => 'Fatch catalog names',
+    'FETCH_TABLE_NAMES' => 'Fetch table names',
+    'STRINGIFY_FETCHES' => 'Stringify fetches',
+    'MAX_COLUMN_LEN' => 'Max column length',
+    'DEFAULT_FETCH_MODE' => 'Default fetch mode',
+    'EMULATE_PREPARES' => 'Emulate prepares',
+  );
+  foreach ($attributes as $constant => $name) {
+    try {
+      $result = $pdo->getAttribute(constant("PDO::ATTR_$constant"));
+      if (is_bool($result)) {
+        $result = $result ? 'TRUE' : 'FALSE';
+      }
+      elseif (is_array($result) || is_object($result)) {
+        $add_js = TRUE;
+        include_once DRUPAL_ROOT . '/includes/utility.inc';
+
+        $class = strtolower(str_replace('_', '-', $constant));
+
+        $link = l(
+          t('Show details'),
+          'admin/reports/status/database',
+          array(
+            'attributes' => array(
+              'class' => array('show-more'),
+              'data-details' => $class
+            )
+          )
+        );
+
+        // Seemed a bit overkill to create a css file only for this display:none
+        // thingy.
+        $result = $link . '<pre class="' . $class . '" style="display:none;">' . drupal_var_export($result) . '</pre>';
+      }
+      $additional .= $name . ': ' . $result . "<br />\n";
+    } catch (Exception $e) {}
+  }
+  $status = "$additional<br />\n$status";
+
+  if ($add_js) {
+    $base = drupal_get_path('module', 'prod_check');
+    drupal_add_js($base . '/js/prod-check-database.js');
+  }
+
+  return theme('prod_check_dbstatus', array('title' => $title, 'status' => $status, 'details' => $details));
+}
+
+/**
+ * Helper function to return MySQL detailed status info.
+ */
+function _prod_check_dbstatus_mysql($details) {
+  $db_name = '';
+  // Feels like there should be a better way of getting the current database
+  // name.
+  $db_setting = Database::getConnectionInfo();
+  foreach($db_setting as $params) {
+    if(isset($params['database'])) {
+      // We get the first name we find.
+      $db_name = $params['database'];
+      break;
+    }
+  }
+
+  // Get detailed status.
+  $rows = array();
+  try {
+    $result = db_query('SHOW STATUS');
+    foreach ($result as $row) {
+      $rows[] = array($row->Variable_name, $row->Value);
+    }
+  } catch (Exception $e) {}
+  if ($rows) {
+    $details['status'] = array(
+      'title' => t('Detailed status'),
+      'header' => array(
+        t('Variable'),
+        t('Value'),
+      ),
+      'rows' => $rows,
+    );
+  }
+
+  // Get all tables.
+  $rows = array();
+  try {
+    // We cannot use the standard db_query with arguments here as the argument
+    // should NOT be enclosed in quotes.
+    $result = db_query(sprintf('SHOW TABLES FROM %s', $db_name));
+    $property = 'Tables_in_' . $db_name;
+    foreach ($result as $row) {
+      $rows[] = array($row->$property);
+    }
+  } catch (Exception $e) {}
+  if ($rows) {
+    $details['tables'] = array(
+      'title' => t('Tables for active database %name', array('%name' => $db_name)),
+      'header' => array(
+        t('Table'),
+      ),
+      'rows' => $rows,
+    );
+  }
+
+  // Get all databases.
+  $rows = array();
+  try {
+    $result = db_query('SHOW DATABASES');
+    foreach ($result as $row) {
+      $rows[] = array($row->Database);
+    }
+  } catch (Exception $e) {}
+  if ($rows) {
+    $details['databases'] = array(
+      'title' => t('Available databases'),
+      'header' => array(
+        t('Database'),
+      ),
+      'rows' => $rows,
+    );
+  }
+
+  return $details;
+}
+
+/**
+ * Helper function to return PostgreSQL status info.
+ *
+ * Useful links for possible expansion:
+ *  http://www.php.net/manual/en/book.pgsql.php
+ *  http://www.alberton.info/postgresql_meta_info.html#.UbXmAFQW3eU
+ *  http://www.postgresql.org/docs/devel/static/catalog-pg-statistic.html
+ *  http://www.postgresql.org/docs/9.0/static/functions-info.html
+ *  http://www.postgresql.org/docs/9.0/static/functions-admin.html
+ */
+function _prod_check_dbstatus_pgsql($db_name, $details) {
+  // Get detailed status.
+  $rows = array();
+  try {
+    // See http://www.postgresql.org/docs/9.0/static/view-pg-settings.html
+    $result = db_query('SELECT * FROM pg_settings');
+    foreach ($result as $row) {
+    /* TODO: add some more detail here? This is available:
+
+         Column   | Type | Modifiers | Storage  | Description
+      ------------+------+-----------+----------+-------------
+       name       | text |           | extended |
+       setting    | text |           | extended |
+       unit       | text |           | extended |
+       category   | text |           | extended |
+       short_desc | text |           | extended |
+       extra_desc | text |           | extended |
+       context    | text |           | extended |
+       vartype    | text |           | extended |
+       source     | text |           | extended |
+       min_val    | text |           | extended |
+       max_val    | text |           | extended | */
+      $rows[] = array($row->name, $row->setting);
+    }
+  } catch (Exception $e) {}
+  if ($rows) {
+    $details['status'] = array(
+      'title' => t('Detailed status'),
+      'header' => array(
+        t('Name'),
+        t('Setting'),
+      ),
+      'rows' => $rows,
+    );
+  }
+
+  // Get all tables.
+  $rows = array();
+  try {
+    // See http://www.postgresql.org/docs/9.0/static/catalog-pg-class.html
+    // relclass: r = ordinary table, i = index, S = sequence, v = view, c = composite type, t = TOAST table
+    $result = db_query("SELECT relname FROM pg_class WHERE relname !~ '^(pg_|sql_)' AND relkind = 'r'");
+    foreach ($result as $row) {
+      $rows[] = array($row->relname);
+    }
+  } catch (Exception $e) {}
+  if ($rows) {
+    $details['tables'] = array(
+      'title' => t('Tables for active database %name', array('%name' => $db_name)),
+      'header' => array(
+        t('Table'),
+      ),
+      'rows' => $rows,
+    );
+  }
+
+  // Get all databases.
+  $rows = array();
+  try {
+    $result = db_query('SELECT datname FROM pg_database');
+    foreach ($result as $row) {
+      $rows[] = array($row->datname);
+    }
+  } catch (Exception $e) {}
+  if ($rows) {
+    $details['databases'] = array(
+      'title' => t('Available databases'),
+      'header' => array(
+        t('Database'),
+      ),
+      'rows' => $rows,
+    );
+  }
+
+  return $details;
+}
+
 /**
  * Integration of the APC status page.
  */
@@ -751,29 +1042,12 @@ function prod_check_apc() {
  * Integration of the Memcache status page.
  */
 function prod_check_memcache() {
-  global $conf;
-
-  if (isset($conf['memcache_servers'])) {
-    global $MEMCACHE_SERVERS;
-    $MEMCACHE_SERVERS = array_keys($conf['memcache_servers']);
-    include(drupal_get_path('module', 'prod_check') . '/includes/prod_check.memcache.inc');
-  }
-  else {
-    print 'No memcache servers found in settings.php.';
-  }
-  exit;
-}
+  // Memcache module defaults to 127.0.0.1:11211
+  $memcache_servers = variable_get('memcache_servers', array('127.0.0.1:11211' => 'default'));
 
-/**
- * Generate default key if none is present.
- */
-function prod_check_generate_key($length = 25) {
-  $chars = 'abcdefghijklmnopqrstuxyvwzABCDEFGHIJKLMNOPQRSTUXYVWZ+-*#&@!?';
-  $size = strlen($chars);
-  $key = '';
-  for ($i = 0; $i < $length; $i++) {
-    $key .= $chars[rand(0, $size - 1)];
-  }
+  global $MEMCACHE_SERVERS;
+  $MEMCACHE_SERVERS = array_keys($memcache_servers);
+  include(drupal_get_path('module', 'prod_check') . '/includes/prod_check.memcache.inc');
 
-  return $key;
+  exit;
 }

+ 102 - 77
sites/all/modules/contrib/dev/prod_check/includes/prod_check.apc.inc

@@ -1,10 +1,9 @@
 <?php
-
 /*
   +----------------------------------------------------------------------+
   | APC                                                                  |
   +----------------------------------------------------------------------+
-  | Copyright (c) 2008 The PHP Group                                     |
+  | Copyright (c) 2006-2011 The PHP Group                                |
   +----------------------------------------------------------------------+
   | This source file is subject to version 3.01 of the PHP license,      |
   | that is bundled with this package in the file LICENSE, and is        |
@@ -23,7 +22,7 @@
 
  */
 
-$VERSION='$Id$';
+$VERSION='$Id: apc.php 325483 2012-05-01 00:34:04Z rasmus $';
 
 ////////// READ OPTIONAL CONFIGURATION FILE ////////////
 if (file_exists("apc.conf.php")) include("apc.conf.php");
@@ -31,18 +30,19 @@ if (file_exists("apc.conf.php")) include("apc.conf.php");
 
 ////////// BEGIN OF DEFAULT CONFIG AREA ///////////////////////////////////////////////////////////
 
-defaults('USE_AUTHENTICATION',1);			// Use (internal) authentication - best choice if 
+defaults('USE_AUTHENTICATION',1);			// Use (internal) authentication - best choice if
 											// no other authentication is available
 											// If set to 0:
-											//  There will be no further authentication. You 
+											//  There will be no further authentication. You
 											//  will have to handle this by yourself!
 											// If set to 1:
 											//  You need to change ADMIN_PASSWORD to make
 											//  this work!
+// Removed these lines for prod_check compatibility
 //defaults('ADMIN_USERNAME','apc'); 			// Admin Username
 //defaults('ADMIN_PASSWORD','password');  	// Admin Password - CHANGE THIS TO ENABLE!!!
 
-// (beckerr) I'm using a clear text password here, because I've no good idea how to let 
+// (beckerr) I'm using a clear text password here, because I've no good idea how to let
 //           users generate a md5 or crypt password in a easy way to fill it in above
 
 //defaults('DATE_FORMAT', "d.m.Y H:i:s");	// German
@@ -50,6 +50,8 @@ defaults('DATE_FORMAT', 'Y/m/d H:i:s'); 	// US
 
 defaults('GRAPH_SIZE',200);					// Image size
 
+//defaults('PROXY', 'tcp://127.0.0.1:8080');
+
 ////////// END OF DEFAULT CONFIG AREA /////////////////////////////////////////////////////////////
 
 
@@ -60,12 +62,15 @@ function defaults($d,$v) {
 
 // rewrite $PHP_SELF to block XSS attacks
 //
-//$PHP_SELF= isset($_SERVER['PHP_SELF']) ? htmlentities(strip_tags($_SERVER['PHP_SELF'],''), ENT_QUOTES) : '';
-//Line above modified to make this work for the Drupal 'Prod check' module
-$PHP_SELF= isset($_GET['q']) ? base_path() . htmlentities(strip_tags($_GET['q'],''), ENT_QUOTES) : '';
-$time = REQUEST_TIME;
-$host = getenv('HOSTNAME');
+//$PHP_SELF= isset($_SERVER['PHP_SELF']) ? htmlentities(strip_tags($_SERVER['PHP_SELF'],''), ENT_QUOTES, 'UTF-8') : '';
+//Line above modified to make this work for the prod_check module
+$PHP_SELF= isset($_GET['q']) ? base_path() . htmlentities(strip_tags($_GET['q'],''), ENT_QUOTES, 'UTF-8') : '';
+$time = time();
+$host = php_uname('n');
 if($host) { $host = '('.$host.')'; }
+if (isset($_SERVER['SERVER_ADDR'])) {
+  $host .= ' ('.$_SERVER['SERVER_ADDR'].')';
+}
 
 // operation constants
 define('OB_HOST_STATS',1);
@@ -89,7 +94,7 @@ $vardom=array(
 	'SORT1'	=> '/^[AHSMCDTZ]$/',	// first sort key
 	'SORT2'	=> '/^[DA]$/',			// second sort key
 	'AGGR'	=> '/^\d+$/',			// aggregation by dir level
-	'SEARCH'	=> '~^[a-zA-Z0-1/_.-]*$~'			// aggregation by dir level
+	'SEARCH'	=> '~^[a-zA-Z0-9/_.-]*$~'			// aggregation by dir level
 );
 
 // default cache mode
@@ -132,6 +137,7 @@ if (empty($MYREQUEST['SORT2'])) $MYREQUEST['SORT2']="D";
 if (empty($MYREQUEST['OB']))	$MYREQUEST['OB']=OB_HOST_STATS;
 if (!isset($MYREQUEST['COUNT'])) $MYREQUEST['COUNT']=20;
 if (!isset($scope_list[$MYREQUEST['SCOPE']])) $MYREQUEST['SCOPE']='A';
+
 // added for prod_check support
 global $MY_SELF;
 // end prod_check
@@ -172,13 +178,13 @@ if (!USE_AUTHENTICATION) {
 				</body></html>
 EOB;
 			exit;
-			
+
 		} else {
 			$AUTHENTICATED=1;
 		}
 	}
 }
-	
+
 // select cache mode
 if ($AUTHENTICATED && $MYREQUEST['OB'] == OB_USER_CACHE) {
 	$cache_mode='user';
@@ -197,7 +203,7 @@ if(!function_exists('apc_cache_info') || !($cache=@apc_cache_info($cache_mode)))
   exit;
 }
 
-$cache_user = apc_cache_info('user', 1);  
+$cache_user = apc_cache_info('user', 1);
 $mem=apc_sma_info();
 if(!$cache['num_hits']) { $cache['num_hits']=1; $time++; }  // Avoid division by 0 errors on a cache clear
 
@@ -244,7 +250,7 @@ if (isset($MYREQUEST['IMG']))
 		$r=$diameter/2;
 		$w=deg2rad((360+$start+($end-$start)/2)%360);
 
-		
+
 		if (function_exists("imagefilledarc")) {
 			// exists only if GD 2.0.1 is avaliable
 			imagefilledarc($im, $centerX+1, $centerY+1, $diameter, $diameter, $start, $end, $color1, IMG_ARC_PIE);
@@ -261,13 +267,13 @@ if (isset($MYREQUEST['IMG']))
 		if ($text) {
 			if ($placeindex>0) {
 				imageline($im,$centerX + $r*cos($w)/2, $centerY + $r*sin($w)/2,$diameter, $placeindex*12,$color1);
-				imagestring($im,4,$diameter, $placeindex*12,$text,$color1);	
-				
+				imagestring($im,4,$diameter, $placeindex*12,$text,$color1);
+
 			} else {
 				imagestring($im,4,$centerX + $r*cos($w)/2, $centerY + $r*sin($w)/2,$text,$color1);
 			}
 		}
-	} 
+	}
 
 	function text_arc($im, $centerX, $centerY, $diameter, $start, $end, $color1,$text,$placeindex=0) {
 		$r=$diameter/2;
@@ -275,13 +281,13 @@ if (isset($MYREQUEST['IMG']))
 
 		if ($placeindex>0) {
 			imageline($im,$centerX + $r*cos($w)/2, $centerY + $r*sin($w)/2,$diameter, $placeindex*12,$color1);
-			imagestring($im,4,$diameter, $placeindex*12,$text,$color1);	
-				
+			imagestring($im,4,$diameter, $placeindex*12,$text,$color1);
+
 		} else {
 			imagestring($im,4,$centerX + $r*cos($w)/2, $centerY + $r*sin($w)/2,$text,$color1);
 		}
-	} 
-	
+	}
+
 	function fill_box($im, $x, $y, $w, $h, $color1, $color2,$text='',$placeindex='') {
 		global $col_black;
 		$x1=$x+$w-1;
@@ -293,15 +299,15 @@ if (isset($MYREQUEST['IMG']))
 		imagerectangle($im, $x, $y1, $x1, $y, $color1);
 		if ($text) {
 			if ($placeindex>0) {
-			
+
 				if ($placeindex<16)
 				{
 					$px=5;
 					$py=$placeindex*12+6;
 					imagefilledrectangle($im, $px+90, $py+3, $px+90-4, $py-3, $color2);
 					imageline($im,$x,$y+$h/2,$px+90,$py,$color2);
-					imagestring($im,2,$px,$py-6,$text,$color1);	
-					
+					imagestring($im,2,$px,$py-6,$text,$color1);
+
 				} else {
 					if ($placeindex<31) {
 						$px=$x+40*2;
@@ -312,7 +318,7 @@ if (isset($MYREQUEST['IMG']))
 					}
 					imagefilledrectangle($im, $px, $py+3, $px-4, $py-3, $color2);
 					imageline($im,$x+$w,$y+$h/2,$px,$py,$color2);
-					imagestring($im,2,$px+2,$py-6,$text,$color1);	
+					imagestring($im,2,$px+2,$py-6,$text,$color1);
 				}
 			} else {
 				imagestring($im,4,$x+5,$y1-16,$text,$color1);
@@ -334,7 +340,7 @@ if (isset($MYREQUEST['IMG']))
 	imagecolortransparent($image,$col_white);
 
 	switch ($MYREQUEST['IMG']) {
-	
+
 	case 1:
 		$s=$mem['num_seg']*$mem['seg_size'];
 		$a=$mem['avail_mem'];
@@ -345,9 +351,10 @@ if (isset($MYREQUEST['IMG']))
 		// would expect because we try to visualize any memory fragmentation as well.
 		$angle_from = 0;
 		$string_placement=array();
-		for($i=0; $i<$mem['num_seg']; $i++) {	
+		for($i=0; $i<$mem['num_seg']; $i++) {
 			$ptr = 0;
 			$free = $mem['block_lists'][$i];
+			uasort($free, 'block_sort');
 			foreach($free as $block) {
 				if($block['offset']!=$ptr) {       // Used block
 					$angle_to = $angle_from+($block['offset']-$ptr)/$s;
@@ -371,7 +378,7 @@ if (isset($MYREQUEST['IMG']))
 				$angle_from = $angle_to;
 				$ptr = $block['offset']+$block['size'];
 			}
-			if ($ptr < $mem['seg_size']) { // memory at the end 
+			if ($ptr < $mem['seg_size']) { // memory at the end
 				$angle_to = $angle_from + ($mem['seg_size'] - $ptr)/$s;
 				if(($angle_to+$fuzz)>1) $angle_to = 1;
 				fill_arc($image,$x,$y,$size,$angle_from*360,$angle_to*360,$col_black,$col_red);
@@ -384,15 +391,15 @@ if (isset($MYREQUEST['IMG']))
 			text_arc($image,$x,$y,$size,$angle[0]*360,$angle[1]*360,$col_black,bsize($s*($angle[1]-$angle[0])));
 		}
 		break;
-		
-	case 2: 
+
+	case 2:
 		$s=$cache['num_hits']+$cache['num_misses'];
 		$a=$cache['num_hits'];
-		
+
 		fill_box($image, 30,$size,50,-$a*($size-21)/$s,$col_black,$col_green,sprintf("%.1f%%",$cache['num_hits']*100/$s));
 		fill_box($image,130,$size,50,-max(4,($s-$a)*($size-21)/$s),$col_black,$col_red,sprintf("%.1f%%",$cache['num_misses']*100/$s));
 		break;
-		
+
 	case 3:
 		$s=$mem['num_seg']*$mem['seg_size'];
 		$a=$mem['avail_mem'];
@@ -402,9 +409,10 @@ if (isset($MYREQUEST['IMG']))
 
 		// This block of code creates the bar chart.  It is a lot more complex than you
 		// would expect because we try to visualize any memory fragmentation as well.
-		for($i=0; $i<$mem['num_seg']; $i++) {	
+		for($i=0; $i<$mem['num_seg']; $i++) {
 			$ptr = 0;
 			$free = $mem['block_lists'][$i];
+			uasort($free, 'block_sort');
 			foreach($free as $block) {
 				if($block['offset']!=$ptr) {       // Used block
 					$h=(GRAPH_SIZE-5)*($block['offset']-$ptr)/$s;
@@ -424,7 +432,7 @@ if (isset($MYREQUEST['IMG']))
 				$y+=$h;
 				$ptr = $block['offset']+$block['size'];
 			}
-			if ($ptr < $mem['seg_size']) { // memory at the end 
+			if ($ptr < $mem['seg_size']) { // memory at the end
 				$h = (GRAPH_SIZE-5) * ($mem['seg_size'] - $ptr) / $s;
 				if ($h > 0) {
 					fill_box($image,$x,$y,50,$h,$col_black,$col_red,bsize($mem['seg_size']-$ptr),$j++);
@@ -432,14 +440,14 @@ if (isset($MYREQUEST['IMG']))
 			}
 		}
 		break;
-	case 4: 
+	case 4:
 		$s=$cache['num_hits']+$cache['num_misses'];
 		$a=$cache['num_hits'];
-	        	
+
 		fill_box($image, 30,$size,50,-$a*($size-21)/$s,$col_black,$col_green,sprintf("%.1f%%",$cache['num_hits']*100/$s));
 		fill_box($image,130,$size,50,-max(4,($s-$a)*($size-21)/$s),$col_black,$col_red,sprintf("%.1f%%",$cache['num_misses']*100/$s));
 		break;
-	
+
 	}
 	header("Content-type: image/png");
 	imagepng($image);
@@ -459,7 +467,7 @@ function bsize($s) {
 // sortable table header in "scripts for this host" view
 function sortheader($key,$name,$extra='') {
 	global $MYREQUEST, $MY_SELF_WO_SORT;
-	
+
 	if ($MYREQUEST['SORT1']==$key) {
 		$MYREQUEST['SORT2'] = $MYREQUEST['SORT2']=='A' ? 'D' : 'A';
 	}
@@ -467,7 +475,7 @@ function sortheader($key,$name,$extra='') {
 
 }
 
-// create menu entry 
+// create menu entry
 function menu_entry($ob,$title) {
 	global $MYREQUEST,$MY_SELF;
 	if ($MYREQUEST['OB']!=$ob) {
@@ -475,7 +483,7 @@ function menu_entry($ob,$title) {
 	} else if (empty($MYREQUEST['SH'])) {
 		return "<li><span class=active>$title</span></li>";
 	} else {
-		return "<li><a class=\"child_active\" href=\"$MY_SELF&OB=$ob\">$title</a></li>";	
+		return "<li><a class=\"child_active\" href=\"$MY_SELF&OB=$ob\">$title</a></li>";
 	}
 }
 
@@ -488,8 +496,11 @@ function put_login_link($s="Login")
 		return;
 	} else if (ADMIN_PASSWORD=='password')
 	{
+		// Message below changed to avoid prod_check integration confusion. It used
+		// to be:
+		// You need to set a password at the top of apc.php before this will work!
 		print <<<EOB
-			<a href="#" onClick="javascript:alert('You need to set a password at the top of apc.php before this will work!');return false";>$s</a>
+			<a href="#" onClick="javascript:alert('You need to set a password in the Production Check settings before this will work!');return false";>$s</a>
 EOB;
 	} else if ($AUTHENTICATED) {
 		print <<<EOB
@@ -502,6 +513,15 @@ EOB;
 	}
 }
 
+function block_sort($array1, $array2)
+{
+	if ($array1['offset'] > $array2['offset']) {
+		return 1;
+	} else {
+		return -1;
+	}
+}
+
 
 ?>
 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
@@ -618,8 +638,8 @@ ol.menu a:hover {
 	background:rgb(193,193,244);
 	text-decoration:none;
 	}
-	
-	
+
+
 div.info {
 	background:rgb(204,204,204);
 	border:solid rgb(204,204,204) 1px;
@@ -692,7 +712,7 @@ div.authneeded {
 	padding:2em;
 	text-align:center;
 	}
-	
+
 input {
 	background:rgb(153,153,204);
 	border:solid rgb(102,102,153) 2px;
@@ -732,10 +752,10 @@ if ($AUTHENTICATED) {
 echo
 	menu_entry(3,'User Cache Entries'),
 	menu_entry(9,'Version Check');
-	
+
 if ($AUTHENTICATED) {
 	echo <<<EOB
-		<li><a class="aright" href="$MY_SELF&CC=1&OB={$MYREQUEST['OB']}" onClick="javascipt:return confirm('Are you sure?');">Clear $cache_mode Cache</a></li>
+		<li><a class="aright" href="$MY_SELF&CC=1&OB={$MYREQUEST['OB']}" onClick="javascript:return confirm('Are you sure?');">Clear $cache_mode Cache</a></li>
 EOB;
 }
 echo <<<EOB
@@ -748,7 +768,7 @@ echo <<<EOB
 	<div class=content>
 EOB;
 
-// MAIN SWITCH STATEMENT 
+// MAIN SWITCH STATEMENT
 
 switch ($MYREQUEST['OB']) {
 
@@ -774,7 +794,7 @@ case OB_HOST_STATS:
 	$insert_rate_user = sprintf("%.2f",($cache_user['num_inserts'])/($time-$cache_user['start_time']));
 	$apcversion = phpversion('apc');
 	$phpversion = phpversion();
-	$number_files = $cache['num_entries']; 
+	$number_files = $cache['num_entries'];
     $size_files = bsize($cache['mem_size']);
 	$number_vars = $cache_user['num_entries'];
     $size_vars = bsize($cache_user['mem_size']);
@@ -792,7 +812,7 @@ EOB;
 		echo "<tr class=tr-1><td class=td-0>Server Software</td><td>{$_SERVER['SERVER_SOFTWARE']}</td></tr>\n";
 
 	echo <<<EOB
-		<tr class=tr-0><td class=td-0>Shared Memory</td><td>{$mem['num_seg']} Segment(s) with $seg_size 
+		<tr class=tr-0><td class=td-0>Shared Memory</td><td>{$mem['num_seg']} Segment(s) with $seg_size
     <br/> ({$cache['memory_type']} memory, {$cache['locking_type']} locking)
     </td></tr>
 EOB;
@@ -860,7 +880,7 @@ EOB;
 EOB;
 
 	echo
-		graphics_avail() ? 
+		graphics_avail() ?
 			  '<tr>'.
 			  "<td class=td-0><img alt=\"\" $size src=\"$PHP_SELF?IMG=1&$time\"></td>".
 			  "<td class=td-1><img alt=\"\" $size src=\"$PHP_SELF?IMG=2&$time\"></td></tr>\n"
@@ -898,7 +918,7 @@ EOB;
 		}
 		$freeseg += count($mem['block_lists'][$i]);
 	}
-	
+
 	if ($freeseg > 1) {
 		$frag = sprintf("%.2f%% (%s out of %s in %d fragments)", ($fragsize/$freetotal)*100,bsize($fragsize),bsize($freetotal),$freeseg);
 	} else {
@@ -928,7 +948,7 @@ EOB;
 		</tbody></table>
 		</div>
 EOB;
-		
+
 	break;
 
 
@@ -947,15 +967,15 @@ case OB_USER_CACHE:
 	$fieldkey='info';
 
 // -----------------------------------------------
-// System Cache Entries		
+// System Cache Entries
 // -----------------------------------------------
-case OB_SYS_CACHE:	
+case OB_SYS_CACHE:
 	if (!isset($fieldname))
 	{
 		$fieldname='filename';
 		$fieldheading='Script Filename';
 		if(ini_get("apc.stat")) $fieldkey='inode';
-		else $fieldkey='filename'; 
+		else $fieldkey='filename';
 	}
 	if (!empty($MYREQUEST['SH']))
 	{
@@ -983,14 +1003,14 @@ EOB;
 					echo
 						"<tr class=tr-$m>",
 						"<td class=td-0>",ucwords(preg_replace("/_/"," ",$k)),"</td>",
-						"<td class=td-last>",(preg_match("/time/",$k) && $value!='None') ? date(DATE_FORMAT,$value) : $value,"</td>",
+						"<td class=td-last>",(preg_match("/time/",$k) && $value!='None') ? date(DATE_FORMAT,$value) : htmlspecialchars($value, ENT_QUOTES, 'UTF-8'),"</td>",
 						"</tr>";
 					$m=1-$m;
 				}
 				if($fieldkey=='info') {
 					echo "<tr class=tr-$m><td class=td-0>Stored Value</td><td class=td-last><pre>";
 					$output = var_export(apc_fetch($entry[$fieldkey]),true);
-					echo htmlspecialchars($output);
+					echo htmlspecialchars($output, ENT_QUOTES, 'UTF-8');
 					echo "</pre></td></tr>\n";
 				}
 				break;
@@ -1010,7 +1030,7 @@ EOB;
 		<input type=hidden name=OB value={$MYREQUEST['OB']}>
 		<select name=SCOPE>
 EOB;
-	echo 
+	echo
 		"<option value=A",$MYREQUEST['SCOPE']=='A' ? " selected":"",">Active</option>",
 		"<option value=D",$MYREQUEST['SCOPE']=='D' ? " selected":"",">Deleted</option>",
 		"</select>",
@@ -1024,7 +1044,7 @@ EOB;
 		"<option value=D",$MYREQUEST['SORT1']=='D' ? " selected":"",">Deleted at</option>";
 	if($fieldname=='info') echo
 		"<option value=D",$MYREQUEST['SORT1']=='T' ? " selected":"",">Timeout</option>";
-	echo 
+	echo
 		'</select>',
 		'<select name=SORT2>',
 		'<option value=D',$MYREQUEST['SORT2']=='D' ? ' selected':'','>DESC</option>',
@@ -1086,28 +1106,29 @@ EOB;
 		}
 		if (!$AUTHENTICATED) {
 			// hide all path entries if not logged in
-			$list[$k.$entry[$fieldname]]=preg_replace('/^.*(\\/|\\\\)/','<i>&lt;hidden&gt;</i>/',$entry);
+			$list[$k.$entry[$fieldname]]=preg_replace('/^.*(\\/|\\\\)/','*hidden*/',$entry);
 		} else {
 			$list[$k.$entry[$fieldname]]=$entry;
 		}
 	}
 
 	if ($list) {
-		
+
 		// sort list
 		//
 		switch ($MYREQUEST['SORT2']) {
 			case "A":	krsort($list);	break;
 			case "D":	ksort($list);	break;
 		}
-		
+
 		// output list
 		$i=0;
 		foreach($list as $k => $entry) {
-      if(!$MYREQUEST['SEARCH'] || preg_match($MYREQUEST['SEARCH'], $entry[$fieldname]) != 0) {  
+      if(!$MYREQUEST['SEARCH'] || preg_match($MYREQUEST['SEARCH'], $entry[$fieldname]) != 0) {
+        $field_value = htmlentities(strip_tags($entry[$fieldname],''), ENT_QUOTES, 'UTF-8');
         echo
           '<tr class=tr-',$i%2,'>',
-          "<td class=td-0><a href=\"$MY_SELF&OB=",$MYREQUEST['OB'],"&SH=",md5($entry[$fieldkey]),"\">",$entry[$fieldname],'</a></td>',
+          "<td class=td-0><a href=\"$MY_SELF&OB=",$MYREQUEST['OB'],"&SH=",md5($entry[$fieldkey]),"\">",$field_value,'</a></td>',
           '<td class="td-n center">',$entry['num_hits'],'</td>',
           '<td class="td-n right">',$entry['mem_size'],'</td>',
           '<td class="td-n center">',date(DATE_FORMAT,$entry['access_time']),'</td>',
@@ -1137,7 +1158,7 @@ EOB;
           break;
       }
 		}
-		
+
 	} else {
 		echo '<tr class=tr-0><td class="center" colspan=',$cols,'><i>No data</i></td></tr>';
 	}
@@ -1158,7 +1179,7 @@ EOB;
 // -----------------------------------------------
 // Per-Directory System Cache Entries
 // -----------------------------------------------
-case OB_SYS_CACHE_DIR:	
+case OB_SYS_CACHE_DIR:
 	if (!$AUTHENTICATED) {
 		break;
 	}
@@ -1168,7 +1189,7 @@ case OB_SYS_CACHE_DIR:
 		<input type=hidden name=OB value={$MYREQUEST['OB']}>
 		<select name=SCOPE>
 EOB;
-	echo 
+	echo
 		"<option value=A",$MYREQUEST['SCOPE']=='A' ? " selected":"",">Active</option>",
 		"<option value=D",$MYREQUEST['SCOPE']=='D' ? " selected":"",">Deleted</option>",
 		"</select>",
@@ -1241,14 +1262,14 @@ EOB;
 	}
 
 	if ($list) {
-		
+
 		// sort list
 		//
 		switch ($MYREQUEST['SORT2']) {
 			case "A":	krsort($list);	break;
 			case "D":	ksort($list);	break;
 		}
-		
+
 		// output list
 		$i = 0;
 		foreach($list as $entry) {
@@ -1264,7 +1285,7 @@ EOB;
 
 			if (++$i == $MYREQUEST['COUNT']) break;
 		}
-		
+
 	} else {
 		echo '<tr class=tr-0><td class="center" colspan=6><i>No data</i></td></tr>';
 	}
@@ -1292,8 +1313,12 @@ case OB_VERSION_CHECK:
 		<th></th>
 		</tr>
 EOB;
-
-	$rss = @file_get_contents("http://pecl.php.net/feeds/pkg_apc.rss");
+  if (defined('PROXY')) {
+    $ctxt = stream_context_create( array( 'http' => array( 'proxy' => PROXY, 'request_fulluri' => True ) ) );
+    $rss = @file_get_contents("http://pecl.php.net/feeds/pkg_apc.rss", False, $ctxt);
+  } else {
+    $rss = @file_get_contents("http://pecl.php.net/feeds/pkg_apc.rss");
+  }
 	if (!$rss) {
 		echo '<tr class="td-last center"><td>Unable to fetch version information.</td></tr>';
 	} else {
@@ -1305,7 +1330,7 @@ EOB;
 			echo '<div class="ok">You are running the latest version of APC ('.$apcversion.')</div>';
 			$i = 3;
 		} else {
-			echo '<div class="failed">You are running an older version of APC ('.$apcversion.'), 
+			echo '<div class="failed">You are running an older version of APC ('.$apcversion.'),
 				newer version '.$match[1].' is available at <a href="http://pecl.php.net/package/APC/'.$match[1].'">
 				http://pecl.php.net/package/APC/'.$match[1].'</a>
 				</div>';
@@ -1324,8 +1349,8 @@ EOB;
 			} else if (!$i--) {
 				break;
 			}
-			echo "<b><a href=\"http://pecl.php.net/package/APC/$ver\">".htmlspecialchars($v)."</a></b><br><blockquote>";
-			echo nl2br(htmlspecialchars(current($match[2])))."</blockquote>";
+			echo "<b><a href=\"http://pecl.php.net/package/APC/$ver\">".htmlspecialchars($v, ENT_QUOTES, 'UTF-8')."</a></b><br><blockquote>";
+			echo nl2br(htmlspecialchars(current($match[2]), ENT_QUOTES, 'UTF-8'))."</blockquote>";
 			next($match[2]);
 		}
 		echo '</td></tr>';

+ 35 - 0
sites/all/modules/contrib/dev/prod_check/includes/prod_check.theme.inc

@@ -51,3 +51,38 @@ function theme_prod_check_status_report($variables) {
   $output .= '</table>';
   return $output;
 }
+
+/**
+ * Theme database status page.
+ *
+ * @param $variables
+ *   An associative array containing:
+ *   - title: title string to display.
+ *   - status: string with status summary.
+ *   - details: associative array of associative arrays containing detailed
+ *     status info.
+ *
+ * @ingroup themeable
+ */
+function theme_prod_check_dbstatus($variables) {
+  $title = $variables['title'];
+  $status = $variables['status'];
+  $details = $variables['details'];
+
+  $output = '';
+
+  // DB system and version.
+  $output .= '<h2>' . $title . '</h2>';
+  // Basic status info.
+  $output .= '<div>' . $status . '</div><p>&nbsp;</p>';
+
+  // Add detailed statuses.
+  foreach ($details as $type) {
+    if ($type) {
+      $caption = '<h2>' . $type['title'] . '</h2>';
+      $output .= theme('table', array('header' => $type['header'], 'rows' => $type['rows'], 'caption' => $caption));
+    }
+  }
+
+  return $output;
+}

+ 3 - 3
sites/all/modules/contrib/dev/prod_check/prod_check.info

@@ -4,9 +4,9 @@ package = Monitoring
 core = 7.x
 configure = admin/config/system/prod-check
 
-; Information added by drupal.org packaging script on 2013-10-01
-version = "7.x-1.7+0-dev"
+; Information added by  packaging script on 2013-11-25
+version = "7.x-1.8"
 core = "7.x"
 project = "prod_check"
-datestamp = "1380623918"
+datestamp = "1385405033"
 

+ 139 - 40
sites/all/modules/contrib/dev/prod_check/prod_check.module

@@ -67,7 +67,6 @@ function prod_check_help($path, $arg) {
  * Implementation of hook_permission()
  */
 function prod_check_permission() {
-
   return array(
     'administer production check' => array(
       'title' => t('Administer Production Check'),
@@ -90,6 +89,12 @@ function prod_check_permission() {
 function prod_check_menu() {
   $items = array();
 
+  $admin_defaults = array(
+    'access arguments' => array('access production check'),
+    'type' => MENU_CALLBACK,
+    'file' => 'includes/prod_check.admin.inc',
+  );
+
   $items['admin/reports/prod-check'] = array(
     'title' => 'Production check',
     'description' => 'View the Production check report page.',
@@ -130,23 +135,22 @@ function prod_check_menu() {
     'file' => 'includes/prod_check.admin.inc',
   );
 
+  $items['admin/reports/status/database'] = array(
+    'title' => 'Database',
+    'page callback' => 'prod_check_dbstatus',
+  ) + $admin_defaults;
+
   $items['admin/reports/status/apc'] = array(
     'title' => 'APC',
     'page callback' => 'prod_check_apc',
     'access callback' => 'user_access',
-    'access arguments' => array('access production check'),
-    'type' => MENU_CALLBACK,
-    'file' => 'includes/prod_check.admin.inc',
-  );
+  ) + $admin_defaults;
 
   $items['admin/reports/status/memcache'] = array(
     'title' => 'Memcache',
     'page callback' => 'prod_check_memcache',
     'access callback' => 'user_access',
-    'access arguments' => array('access production check'),
-    'type' => MENU_CALLBACK,
-    'file' => 'includes/prod_check.admin.inc',
-  );
+  ) + $admin_defaults;
 
   return $items;
 }
@@ -173,6 +177,10 @@ function prod_check_theme($existing, $type, $theme, $path) {
       'variables' => array('requirements' => NULL),
       'file' => 'includes/prod_check.theme.inc',
     ),
+    'prod_check_dbstatus' => array(
+      'variables' => array('title' => NULL, 'status' => NULL, 'details' => NULL),
+      'file' => 'includes/prod_check.theme.inc',
+    ),
   );
 }
 
@@ -565,6 +573,7 @@ function _prod_check_functions() {
       '_prod_check_error_reporting' =>  'Error reporting',
       '_prod_check_user_register' => 'User registration',
       '_prod_check_site_mail' => 'Site e-mail',
+      '_prod_check_poormanscron' => 'Cron',
     ),
   );
 
@@ -753,6 +762,52 @@ function _prod_check_site_mail($caller = 'internal') {
   return prod_check_execute_check($check, $caller);
 }
 
+// Cron check
+function _prod_check_poormanscron($caller = 'internal') {
+  $check = array();
+
+  $title = 'Cron';
+  $path = 'admin/config/system/cron';
+  if ($caller != 'internal') {
+    $path = PRODCHECK_BASEURL . $path;
+  }
+
+  $cron_interval = variable_get('cron_safe_threshold', DRUPAL_CRON_DEFAULT_THRESHOLD);
+
+  // TODO: add some form of cron interval checking here so we can check if the
+  // cron is running regularly AND the poormanscron is disabled?
+  // We could use the data from dblog, but this might not always be enabled so
+  // it will be similar to _prod_check_dblog_php...
+
+  /*$cron_interval_regularity = FALSE;
+  if (module_exists('dblog')) {
+    $result = db_query("SELECT timestamp FROM {watchdog} where type = 'cron' ORDER BY timestamp DESC LIMIT 10");
+    $prev = -1;
+    $diff = array();
+    foreach ($result as $row) {
+      if($prev == -1) {
+        $prev = $row->timestamp;
+        continue;
+      }
+      $diff[] = $prev - $row->timestamp;
+    }
+  }*/
+
+  $check['prod_check_poormanscron'] = array(
+    '#title' => t($title),
+    '#state' => $cron_interval == 0 /*&& $cron_interval_regularity*/,
+    '#severity' => ($caller == 'nagios') ? NAGIOS_STATUS_WARNING : PROD_CHECK_REQUIREMENT_WARNING,
+    '#value_ok'  => t("Drupal's built in cron mechanism is disabled."),
+    '#value_nok'  => t("Drupal's built in cron mechanism is set to run every %interval.", array('%interval' => format_interval($cron_interval))),
+    '#description_ok'  => prod_check_ok_title($title, $path),
+    '#description_nok' => t('The !link interval should be disabled if you have also setup a crontab or scheduled task for this to avoid running the cron more often than you have planned to!', prod_check_link_array($title, $path)),
+    '#nagios_key' => 'CRON',
+    '#nagios_type' => 'state',
+  );
+
+  return prod_check_execute_check($check, $caller);
+}
+
 // --- SERVER ---
 
 // APC check
@@ -999,16 +1054,19 @@ function _prod_check_boost($caller = 'internal') {
   if (module_exists('boost')) {
     $check = array();
 
-    $path = 'admin/config/development/performance/boost';
+    $path = 'admin/config/system/boost';
     if ($caller != 'internal') {
       $path = PRODCHECK_BASEURL . $path;
     }
+    $path_htaccess = $path . '/htaccess';
+    $path_crawler = $path . '/crawler';
+    $path_expire = $path . '/expiration';
 
     $title = 'Boost: ';
 
     // Cache lifetime check
-    $subtitle = 'HTML max. cache lifetime ';
-    $var = variable_get('boost_cache_lifetime', 3600);
+    $subtitle = 'text/html - Maximum Cache Lifetime';
+    $var = variable_get('boost_lifetime_max_text/html', 3600);
     $check['prod_check_boost_cache_lifetime'] = array(
       '#title' => t($title.$subtitle),
       '#state' => $var <= 3600,
@@ -1022,53 +1080,78 @@ function _prod_check_boost($caller = 'internal') {
     );
 
     // Clear pages check
-    $subtitle = 'Clear expired pages on cron runs';
-    $var = variable_get('boost_expire_cron', TRUE);
+    $subtitle = 'Remove old cache files on cron';
+    $var = variable_get('boost_expire_cron', BOOST_EXPIRE_CRON);
     $check['prod_check_boost_expire_cron'] = array(
       '#title' => t($title.$subtitle),
       '#state' => $var,
       '#severity' => ($caller == 'nagios') ? NAGIOS_STATUS_WARNING : PROD_CHECK_REQUIREMENT_WARNING,
       '#value_ok'  => t('Enabled'),
       '#value_nok'  => t('Disabled'),
-      '#description_ok'  => prod_check_ok_title($subtitle, $path),
-      '#description_nok' => t('!link is disabled! You should enable this to ensure that expired pages get flushed when the cron runs. This is imperative if you wish to keep view blocks up to date!', prod_check_link_array($subtitle, $path)),
+      '#description_ok'  => prod_check_ok_title($subtitle, $path_expire),
+      '#description_nok' => t('!link is disabled! You should enable this to ensure that expired pages get flushed when the cron runs. This is imperative if you wish to keep view blocks up to date!', prod_check_link_array($subtitle, $path_expire)),
       '#nagios_key' => 'BCLPG',
       '#nagios_type' => 'state',
     );
 
-    /*
     // Crawl on cron check
+    $subtitle = 'Crawl on cron';
+    $var = module_exists('boost_crawler') && variable_get('boost_crawl_on_cron', FALSE);
+    $check['prod_check_boost_crawl_on_cron'] = array(
+      '#title' => t($title.$subtitle),
+      '#state' => $var,
+      '#severity' => ($caller == 'nagios') ? NAGIOS_STATUS_WARNING : PROD_CHECK_REQUIREMENT_WARNING,
+      '#value_ok'  => t('Enabled'),
+      '#value_nok'  => t('Disabled'),
+      '#description_ok'  => prod_check_ok_title($subtitle, $path_crawler),
+      '#description_nok' => t('!link is disabled! You should enable this to ensure that the users are served cached pages all the time. The crawler caches pages before anyone can access them.', prod_check_link_array($subtitle, $path_crawler)),
+      '#nagios_key' => 'BCRCR',
+      '#nagios_type' => 'state',
+    );
+
+    // Boost nagios page check
+    if (module_exists('nagios')) {
+      $subtitle = 'Nagios page';
+
+      $visibility = variable_get('boost_cacheability_option', BOOST_VISIBILITY_NOTLISTED);
+      $pages_setting = variable_get('boost_cacheability_pages', BOOST_CACHEABILITY_PAGES);
 
-    // The Boost module is in development atm, as soon as it is released we'll fix this.
-
-        $subtitle = 'Crawl on cron';
-        $var = variable_get('boost_crawl_on_cron', FALSE);
-        $check['prod_check_boost_crawl_on_cron'] = array(
-          '#title' => t($title.$subtitle),
-          '#state' => $var,
-          '#severity' => ($caller == 'nagios') ? NAGIOS_STATUS_WARNING : PROD_CHECK_REQUIREMENT_WARNING,
-          '#value_ok'  => t('Enabled'),
-          '#value_nok'  => t('Disabled'),
-          '#description_ok'  => prod_check_ok_title($subtitle, $path),
-          '#description_nok' => t('!link is disabled! You should enable this to ensure that the users are served cached pages all the time. The crawler caches pages before anyone can access them.', prod_check_link_array($subtitle, $path)),
-          '#nagios_key' => 'BCRCR',
-          '#nagios_type' => 'state',
-        );
-     */
+      $pages_array = explode("\n", str_replace(array("\n", "\r\n"), "\n", strtolower($pages_setting)));
+
+      $var = ($visibility && in_array('nagios', $pages_array)) || (!$visibility && !in_array('nagios', $pages_array));
+      if($visibility) {
+        $advise = "You should remove 'nagios' from the listed pages.";
+      }
+      else {
+        $advise = "You should add 'nagios' to the listed pages.";
+      }
+
+      $check['prod_check_boost_apache_nagios_page'] = array(
+        '#title' => t($title.$subtitle),
+        '#state' => !$var,
+        '#severity' => ($caller == 'nagios') ? NAGIOS_STATUS_WARNING : PROD_CHECK_REQUIREMENT_WARNING,
+        '#value_ok'  => t('Enabled'),
+        '#value_nok'  => t('Not properly configured.'),
+        '#description_ok'  => prod_check_ok_title($subtitle, $path),
+        '#description_nok' => t('The !link is being cached by Boost. '.$advise, prod_check_link_array($subtitle, $path)),
+        '#nagios_key' => 'BNAPA',
+        '#nagios_type' => 'state',
+      );
+    }
 
     // Apache etag check
     $subtitle = 'ETag';
-    $var = variable_get('boost_apache_etag', 0);
+    $var = variable_get('boost_apache_etag', BOOST_APACHE_ETAG);
     $check['prod_check_boost_apache_etag'] = array(
       '#title' => t($title.$subtitle),
       '#state' => $var >= 2,
       '#severity' => ($caller == 'nagios') ? NAGIOS_STATUS_WARNING : PROD_CHECK_REQUIREMENT_WARNING,
       '#value_ok'  => t('Enabled'),
       '#value_nok'  => t('Not properly configured.'),
-      '#description_ok'  => prod_check_ok_title($subtitle, $path),
+      '#description_ok'  => prod_check_ok_title($subtitle, $path_htaccess),
       '#description_nok' => t('Your !link settings are not ok! You should enable entity tags (!etag) in Boost so that user side caching and bandwith usage will be optimal! You do need to enable !mod for this to work.',
         array(
-          '!link' => '<em>'.l(t($subtitle), $path, array('attributes' => array('title' => t($subtitle)), 'query' => drupal_get_destination())).'</em>',
+          '!link' => '<em>'.l(t($subtitle), $path_htaccess, array('attributes' => array('title' => t($subtitle)), 'query' => drupal_get_destination())).'</em>',
           '!etag' => '<em>'.l(t('ETags'), 'http://en.wikipedia.org/wiki/HTTP_ETag', array('attributes' => array('title' => t('Etags')))).'</em>',
           '!mod' => '<em>'.l(t('mod_headers'), 'http://httpd.apache.org/docs/2.0/mod/mod_headers.html', array('attributes' => array('title' => t('mod_headers')))).'</em>',
         )
@@ -1076,6 +1159,7 @@ function _prod_check_boost($caller = 'internal') {
       '#nagios_key' => 'BETAG',
       '#nagios_type' => 'state',
     );
+
     $result = prod_check_execute_check($check, $caller);
   }
   return $result;
@@ -1769,6 +1853,10 @@ function _prod_check_redirect($caller = 'internal') {
 // XML sitemap
 function _prod_check_xmlsitemap($caller = 'internal') {
   $check = array();
+  $error = FALSE;
+  $xml_base_url = variable_get('xmlsitemap_base_url', $GLOBALS['base_url']);
+  $value_nok = $msg_nok = '';
+
   $title_ok = 'settings';
   $text_ok = 'Check the !link to verify if they are as you expect.';
 
@@ -1778,14 +1866,25 @@ function _prod_check_xmlsitemap($caller = 'internal') {
     $path = PRODCHECK_BASEURL . $path;
   }
 
-  $check['prod_check_sitemap'] = array(
+  if(!module_exists('xmlsitemap')) {
+    $error = TRUE;
+    $value_nok = t('Disabled');
+    $msg_nok = t('You have not enabled the !link module. This module generates an XML sitemap which can be submitted to search engines, guaranteeing optimal indexation of all urls within the site.', prod_check_link_array($title, 'http://drupal.org/project/xmlsitemap'));
+  }
+  elseif (strtolower($xml_base_url) != strtolower($GLOBALS['base_url'])) {
+    $error = TRUE;
+    $value_nok = t('Not properly configured.');
+    $msg_nok = t('Your sitemap.xml !link is not the same as the current base URL you are viewing the site from.', prod_check_link_array('default base URL', $path));
+  }
+
+  $check['prod_check_xmlsitemap'] = array(
     '#title' => t($title),
-    '#state' => module_exists('xmlsitemap'),
+    '#state' => !$error,
     '#severity' => ($caller == 'nagios') ? NAGIOS_STATUS_WARNING : PROD_CHECK_REQUIREMENT_WARNING,
     '#value_ok'  => t('Enabled'),
-    '#value_nok'  => t('Disabled'),
+    '#value_nok'  => $value_nok,
     '#description_ok'  => prod_check_ok_title($title_ok, $path, $text_ok),
-    '#description_nok' => t('You have not enabled the !link module. This module generates an XML sitemap which can be submitted to search engines, guaranteeing optimal indexation of all urls within the site.', prod_check_link_array($title, 'http://drupal.org/project/xmlsitemap')),
+    '#description_nok' => $msg_nok,
     '#nagios_key' => 'XMLS',
     '#nagios_type' => 'state',
   );

+ 3 - 3
sites/all/modules/contrib/dev/prod_check/prod_monitor/js/prod-monitor.performance.js

@@ -4,7 +4,7 @@
   Drupal.behaviors.prod_monitor_init = {
     attach: function(context, settings) {
       var script = document.createElement('script');
-      script.src = 'http://www.google.com/jsapi?callback=Drupal.behaviors.prod_monitor_performance.initGoogleDependencies';
+      script.src = document.location.protocol + '//www.google.com/jsapi?callback=Drupal.behaviors.prod_monitor_performance.initGoogleDependencies';
       script.type = 'text/javascript';
       $('head').append(script);
     }
@@ -14,12 +14,12 @@
   Drupal.behaviors.prod_monitor_performance = {
     initGoogleDependencies: function() {
       google.load('visualization', '1', {
-        'callback':Drupal.behaviors.prod_monitor_performance.initGraphs, 
+        'callback':Drupal.behaviors.prod_monitor_performance.initGraphs,
         'packages':['annotatedtimeline']
       })
     },
 
-    initGraphs: function() {  
+    initGraphs: function() {
       $('.performance-data').each(function() {
         var callback = $(this).attr('id').replace('-', '_');
         //console.log(Drupal.behaviors.prod_monitor_performance[callback]);

+ 3 - 3
sites/all/modules/contrib/dev/prod_check/prod_monitor/prod_monitor.info

@@ -4,9 +4,9 @@ package = Monitoring
 core = 7.x
 configure = admin/reports/prod-monitor
 
-; Information added by drupal.org packaging script on 2013-10-01
-version = "7.x-1.7+0-dev"
+; Information added by  packaging script on 2013-11-25
+version = "7.x-1.8"
 core = "7.x"
 project = "prod_check"
-datestamp = "1380623918"
+datestamp = "1385405033"
 

+ 1 - 1
sites/all/modules/contrib/dev/prod_check/prod_monitor/prod_monitor.module

@@ -328,7 +328,7 @@ function prod_monitor_cron() {
   $elapsed = $process = 0;
 
   foreach ($sites as $id => $site_info) {
-    $elapsed = REQUEST_TIME - $cron_start;
+    $elapsed = time() - $cron_start;
     if ($elapsed < $time_limit) {
       //TODO: add module status update check here.
       _prod_monitor_retrieve_data($id, $site_info);

+ 0 - 28
sites/all/modules/contrib/mail/smtp/smtp-base64-1741082-16.patch

@@ -1,28 +0,0 @@
-diff --git a/smtp.mail.inc b/smtp.mail.inc
-index 2cf0841..b228e45 100644
---- a/smtp.mail.inc
-+++ b/smtp.mail.inc
-@@ -367,10 +367,21 @@ class SmtpMailSystem implements MailSystemInterface {
-               }
-               // If plain/html within the body part, add it to $mailer->Body.
-               elseif (strpos($body_part2, 'text/html')) {
-+                // Get the encoding.
-+                $body_part2_encoding = $this->_get_substring($body_part2, 'Content-Transfer-Encoding', ' ', "\n");
-                 // Clean up the text.
-                 $body_part2 = trim($this->_remove_headers(trim($body_part2)));
--                // Include it as part of the mail object.
--                $mailer->Body = $body_part2;
-+                // Check whether the encoding is base64, and if so, decode it.
-+                if (drupal_strtolower($body_part2_encoding) == 'base64') {
-+                  // Include it as part of the mail object.
-+                  $mailer->Body = base64_decode($body_part2);
-+                  // Ensure the whole message is recoded in the base64 format.
-+                  $mailer->Encoding = 'base64';
-+                }
-+                else {
-+                  // Include it as part of the mail object.
-+                  $mailer->Body = $body_part2;
-+                }
-                 $mailer->ContentType = 'multipart/mixed';
-               }
-             }

+ 32 - 0
sites/all/modules/contrib/mail/smtp/smtp.admin.inc

@@ -49,6 +49,12 @@ function smtp_admin_settings() {
     '#options'       => array(1 => t('On'), 0 => t('Off')),
     '#description'   => t('To uninstall this module you must turn it off here first.'),
   );
+  $form['onoff']['smtp_queue'] = array(
+    '#type'  => 'checkbox',
+    '#title' => t('Send mail by queue'),
+    '#default_value' => variable_get('smtp_queue', FALSE),
+    '#description'   => t('Mails will be sent by drupal queue api.'),
+  );
 
   $form['server'] = array(
     '#type'  => 'fieldset',
@@ -167,6 +173,8 @@ function smtp_admin_settings() {
     '#description'   => t('Checking this box will print SMTP messages from the server for every e-mail that is sent.'),
   );
 
+  $form['#submit'][] = 'smtp_admin_settings_form_submit';
+
   return system_settings_form($form);
 }  //  End of smtp_admin_settings().
 
@@ -205,3 +213,27 @@ function smtp_admin_settings_validate($form, &$form_state) {
   }
 }  //  End of smtp_admin_settings_validate().
 
+/**
+ * Submit handler().
+ */
+function smtp_admin_settings_form_submit($form, &$form_state) {
+  // Check if SMTP status has been changed.
+  if (
+    (!variable_get('smtp_on', FALSE) && $form_state['values']['smtp_on']) ||
+    (variable_get('smtp_on', FALSE) && !$form_state['values']['smtp_on'])
+  ) {
+    $mail_modes = variable_get('mail_system', array('default-system' => 'DefaultMailSystem'));
+
+    // Turning on.
+    if ($form_state['values']['smtp_on']) {
+      variable_set('smtp_previous_mail_system', $mail_modes['default-system']);
+      $mail_modes['default-system'] = 'SmtpMailSystem';
+    }
+    // Turning off.
+    else {
+      $mail_modes['default-system'] = variable_get('smtp_previous_mail_system', 'DefaultMailSystem');
+    }
+
+    variable_set('mail_system', $mail_modes);
+  }
+}

+ 3 - 3
sites/all/modules/contrib/mail/smtp/smtp.info

@@ -7,9 +7,9 @@ files[] = smtp.mail.inc
 files[] = smtp.phpmailer.inc
 files[] = smtp.transport.inc
 
-; Information added by drupal.org packaging script on 2013-02-17
-version = "7.x-1.0"
+; Information added by Drupal.org packaging script on 2015-01-07
+version = "7.x-1.2"
 core = "7.x"
 project = "smtp"
-datestamp = "1361062292"
+datestamp = "1420662781"
 

+ 13 - 9
sites/all/modules/contrib/mail/smtp/smtp.install

@@ -32,15 +32,6 @@ function smtp_uninstall() {
   }
 }
 
-/**
- * Implements hook_enable().
- */
-function smtp_enable() {
-  $mail_modes = variable_get('mail_system', array('default-system' => 'DefaultMailSystem'));
-  $mail_modes['default-system'] = 'SmtpMailSystem';
-  variable_set('mail_system', $mail_modes);
-}
-
 /**
  * Implements hook_disable().
  */
@@ -59,3 +50,16 @@ function smtp_update_7000() {
     variable_set('mail_system', array('default-system' => 'SmtpMailSystem'));
   }
 }
+
+/**
+ * Implements hook_update_N().
+ *
+ * Back to default mail system if the status flag is off.
+ */
+function smtp_update_7100() {
+  $mail_modes = variable_get('mail_system', array('default-system' => 'DefaultMailSystem'));
+  if ($mail_modes['default-system'] == 'SmtpMailSystem' && !variable_get('smtp_on', FALSE)) {
+    $mail_modes['default-system'] = 'DefaultMailSystem';
+    variable_set('mail_system', $mail_modes);
+  }
+}

+ 47 - 33
sites/all/modules/contrib/mail/smtp/smtp.mail.inc

@@ -230,6 +230,16 @@ class SmtpMailSystem implements MailSystemInterface {
           break;
 
         case 'return-path':
+          if (strpos($value, '<') !== FALSE) {
+            $returnPathParts = explode('<', $value);
+            $returnPathAddr = rtrim($returnPathParts[1], '>');
+            $mailer->Sender = $returnPathAddr;
+          }
+          else {
+            $mailer->Sender = $value;
+          }
+          break;
+
         case 'mime-version':
         case 'x-mailer':
           // Let PHPMailer specify these.
@@ -271,27 +281,31 @@ class SmtpMailSystem implements MailSystemInterface {
           }
           break;
 
+        case 'message-id':
+          $mailer->MessageID = $value;
+          break;
+
         default:
           // The header key is not special - add it as is.
           $mailer->AddCustomHeader($key . ': ' . $value);
       }
     }
 
-/**
- * TODO
- * Need to figure out the following.
- *
- * Add one last header item, but not if it has already been added.
- * $errors_to = FALSE;
- * foreach ($mailer->CustomHeader as $custom_header) {
- *   if ($custom_header[0] = '') {
- *     $errors_to = TRUE;
- *   }
- * }
- * if ($errors_to) {
- *   $mailer->AddCustomHeader('Errors-To: '. $from);
- * }
- */
+    /**
+     * TODO
+     * Need to figure out the following.
+     *
+     * Add one last header item, but not if it has already been added.
+     * $errors_to = FALSE;
+     * foreach ($mailer->CustomHeader as $custom_header) {
+     *   if ($custom_header[0] = '') {
+     *     $errors_to = TRUE;
+     *   }
+     * }
+     * if ($errors_to) {
+     *   $mailer->AddCustomHeader('Errors-To: '. $from);
+     * }
+     */
     // Add the message's subject.
     $mailer->Subject = $subject;
 
@@ -299,12 +313,7 @@ class SmtpMailSystem implements MailSystemInterface {
     switch ($content_type) {
       case 'multipart/related':
         $mailer->Body = $body;
-
-  /**
-   * TODO
-   * Firgure out if there is anything more to handling this type.
-   */
-
+        // TODO: Figure out if there is anything more to handling this type.
         break;
 
       case 'multipart/alternative':
@@ -368,7 +377,7 @@ class SmtpMailSystem implements MailSystemInterface {
               // If plain/html within the body part, add it to $mailer->Body.
               elseif (strpos($body_part2, 'text/html')) {
                 // Get the encoding.
-                $body_part2_encoding = $this->_get_substring($body_part2, 'Content-Transfer-Encoding', ' ', "\n");
+                $body_part2_encoding = $this->_get_substring($body_part2, 'Content-Transfer-Encoding', ':', "\n");
                 // Clean up the text.
                 $body_part2 = trim($this->_remove_headers(trim($body_part2)));
                 // Check whether the encoding is base64, and if so, decode it.
@@ -412,7 +421,7 @@ class SmtpMailSystem implements MailSystemInterface {
             $mailer->ContentType = 'multipart/mixed';
           }
           // Add the attachment.
-          elseif (strpos($body_part, 'Content-Disposition: attachment;')) {
+          elseif (strpos($body_part, 'Content-Disposition: attachment;') && !isset($message['params']['attachments'])) {
             $file_path     = $this->_get_substring($body_part, 'filename=', '"', '"');
             $file_name     = $this->_get_substring($body_part, ' name=', '"', '"');
             $file_encoding = $this->_get_substring($body_part, 'Content-Transfer-Encoding', ' ', "\n");
@@ -454,14 +463,16 @@ class SmtpMailSystem implements MailSystemInterface {
         break;
     }
 
-    // Process mimemail attachments
+    // Process mimemail attachments, which are prepared in mimemail_mail().
     if (isset($message['params']['attachments'])) {
       foreach ($message['params']['attachments'] as $attachment) {
         if (isset($attachment['filecontent'])) {
           $mailer->AddStringAttachment($attachment['filecontent'], $attachment['filename'], 'base64', $attachment['filemime']);
         }
         if (isset($attachment['filepath'])) {
-          $mailer->AddAttachment($attachment['filepath'], $attachment['filename'], 'base64', $attachment['filemime']);
+          $filename = isset($attachment['filename']) ? $attachment['filename'] : basename($attachment['filepath']);
+          $filemime = isset($attachment['filemime']) ? $attachment['filemime'] : file_get_mimetype($attachment['filepath']);
+          $mailer->AddAttachment($attachment['filepath'], $filename, 'base64', $filemime);
         }
       }
     }
@@ -498,16 +509,19 @@ class SmtpMailSystem implements MailSystemInterface {
     $mailer->Port = variable_get('smtp_port', '25');
     $mailer->Mailer = 'smtp';
 
-    // Let the people know what is going on.
-    watchdog('smtp', 'Sending mail to: @to', array('@to' => $to));
-
-    // Try to send e-mail. If it fails, set watchdog entry.
-    if (!$mailer->Send()) {
-      watchdog('smtp', 'Error sending e-mail from @from to @to : !error_message', array('@from' => $from, '@to' => $to, '!error_message' => $mailer->ErrorInfo), WATCHDOG_ERROR);
-      return FALSE;
+    $mailerArr = array(
+      'mailer' => $mailer,
+      'to' => $to,
+      'from' => $from,
+    );
+    if (variable_get('smtp_queue', FALSE)) {
+      watchdog('smtp', 'Queue sending mail to: @to', array('@to' => $to));
+      smtp_send_queue($mailerArr);
+    }
+    else {
+      return _smtp_mailer_send($mailerArr);
     }
 
-    $mailer->SmtpClose();
     return TRUE;
   }
 

+ 41 - 0
sites/all/modules/contrib/mail/smtp/smtp.module

@@ -61,3 +61,44 @@ function smtp_mail($key, &$message, $params) {
     $message['body'] = $params['body'];
   }
 }
+
+/**
+ * Implementation of hook_cron_queue_info().
+ */
+function smtp_cron_queue_info() {
+  $queues['smtp_send_queue'] = array(
+    'worker callback' => 'smtp_send_queue_runner',
+    'time' => 60, // This is the max run time per cron run in seconds.
+  );
+  return $queues;
+}
+
+/**
+ * smtp_send_queue queuer.
+ */
+function smtp_send_queue($mailerObj) {
+  $queue = DrupalQueue::get('smtp_send_queue');
+  $queue->createItem($mailerObj);
+}
+
+function smtp_send_queue_runner($variables) {
+  _smtp_mailer_send($variables);
+}
+
+function _smtp_mailer_send($variables) {
+  $mailer = $variables['mailer'];
+  $to = $variables['to'];
+  $from = $variables['from'];
+
+  // Let the people know what is going on.
+  watchdog('smtp', 'Sending mail to: @to', array('@to' => $to));
+
+  // Try to send e-mail. If it fails, set watchdog entry.
+  if (!$mailer->Send()) {
+    watchdog('smtp', 'Error sending e-mail from @from to @to : !error_message', array('@from' => $from, '@to' => $to, '!error_message' => $mailer->ErrorInfo), WATCHDOG_ERROR);
+    return FALSE;
+  }
+
+  $mailer->SmtpClose();
+  return TRUE;
+}

+ 26 - 12
sites/all/modules/contrib/mail/smtp/smtp.phpmailer.inc

@@ -1741,27 +1741,41 @@ class PHPMailer {
    */
   public function EncodeQ($str, $position = 'text') {
     // There should not be any EOL in the string
-    $encoded = preg_replace('/[\r\n]*/', '', $str);
-
+    $pattern = '';
+    $encoded = str_replace(array("\r", "\n"), '', $str);
     switch (strtolower($position)) {
       case 'phrase':
-        $encoded = preg_replace("/([^A-Za-z0-9!*+\/ -])/e", "'='.sprintf('%02X', ord('\\1'))", $encoded);
+        // RFC 2047 section 5.3
+        $pattern = '^A-Za-z0-9!*+\/ -';
         break;
+      /** @noinspection PhpMissingBreakStatementInspection */
       case 'comment':
-        $encoded = preg_replace("/([\(\)\"])/e", "'='.sprintf('%02X', ord('\\1'))", $encoded);
+        // RFC 2047 section 5.2
+        $pattern = '\(\)"';
+        // intentional fall-through
+        // for this reason we build the $pattern without including delimiters and []
       case 'text':
       default:
-        // Replace every high ascii, control =, ? and _ characters
-        //TODO using /e (equivalent to eval()) is probably not a good idea
-        $encoded = preg_replace('/([\000-\011\013\014\016-\037\075\077\137\177-\377])/e',
-              "'='.sprintf('%02X', ord('\\1'))", $encoded);
+        // RFC 2047 section 5.1
+        // Replace every high ascii, control, =, ? and _ characters
+        $pattern = '\000-\011\013\014\016-\037\075\077\137\177-\377' . $pattern;
         break;
     }
-
+    $matches = array();
+    if (preg_match_all("/[{$pattern}]/", $encoded, $matches)) {
+      // If the string contains an '=', make sure it's the first thing we replace
+      // so as to avoid double-encoding
+      $s = array_search('=', $matches[0]);
+      if ($s !== false) {
+        unset($matches[0][$s]);
+        array_unshift($matches[0], '=');
+      }
+      foreach (array_unique($matches[0]) as $char) {
+        $encoded = str_replace($char, '=' . sprintf('%02X', ord($char)), $encoded);
+      }
+    }
     // Replace every spaces to _ (more readable than =20)
-    $encoded = str_replace(' ', '_', $encoded);
-
-    return $encoded;
+    return str_replace(' ', '_', $encoded);
   }
 
   /**

+ 8 - 2
sites/all/modules/contrib/messages/better_messages/better_messages.inc

@@ -171,7 +171,13 @@ function better_messages_admin() {
     '#default_value' => $settings['extra']['pages'],
     '#description' => $description,
   );
-  
+
+  $form['vis_settings']['admin'] = array(
+    '#type' => 'checkbox',
+    '#title' => t('Use Better Messages popup for the admin user (UID 1)'),
+    '#default_value' => $settings['extra']['admin'],
+  );
+
   $form['jquery_ui'] = array(
     '#type' => 'fieldset',
     '#title' => t('jQuery UI enhancements'),
@@ -218,7 +224,7 @@ function better_messages_admin_submit($form, &$form_state) {
     'popin' => array('effect' => $form_state['values']['popin_effect'], 'duration' => $form_state['values']['popin_duration']),
     'popout' => array('effect' => $form_state['values']['popout_effect'], 'duration' => $form_state['values']['popout_duration']),
     'jquery_ui' => array('draggable' => $form_state['values']['draggable'], 'resizable' => $form_state['values']['resizable']),
-    'extra' => array('pages' => $form_state['values']['pages'], 'visibility' => $form_state['values']['visibility'],
+    'extra' => array('pages' => $form_state['values']['pages'], 'visibility' => $form_state['values']['visibility'], 'admin' =>  $form_state['values']['admin']
     )
   );
   variable_set('better_messages', $settings);

+ 4 - 3
sites/all/modules/contrib/messages/better_messages/better_messages.info

@@ -2,10 +2,11 @@ name = Better Messages
 description = This module adds simple functions to make Drupal messages look and act better.
 core = 7.x
 package = User interface
+configure = admin/config/user-interface/better-messages
 
-; Information added by drupal.org packaging script on 2012-03-25
-version = "7.x-1.x-dev"
+; Information added by Drupal.org packaging script on 2014-12-11
+version = "7.x-1.0-alpha1"
 core = "7.x"
 project = "better_messages"
-datestamp = "1332677109"
+datestamp = "1418319316"
 

+ 3 - 2
sites/all/modules/contrib/messages/better_messages/better_messages.install

@@ -4,7 +4,7 @@
  * Implementaton of hook_install
  */
 function better_messages_install() {
-  drupal_set_message(t("Better Messages is installed successfully.<br />Click here to visit the <a href=@href>settings page</a>!", array('@href' => base_path() . 'admin/settings/better-messages')));
+  drupal_set_message(t("Better Messages is installed successfully.<br />Click here to visit the <a href=@href>settings page</a>!", array('@href' => base_path() . 'admin/config/user-interface/better-messages')));
 }
 
 /**
@@ -12,6 +12,7 @@ function better_messages_install() {
  */
 function better_messages_uninstall() {
   db_query("DELETE FROM {variable} WHERE name LIKE 'better_messages_%'");
+  db_query("DELETE FROM {variable} WHERE name = 'better_messages'");
   db_query("DELETE FROM {system} WHERE name = 'better_messages'");
 }
 
@@ -32,4 +33,4 @@ function better_messages_update_6000() {
   db_query("DELETE FROM {variable} WHERE name LIKE 'better_messages_%'");
   variable_set('better_messages', $settings_new);
   return array();
-}
+}

+ 1 - 1
sites/all/modules/contrib/messages/better_messages/better_messages.js

@@ -39,7 +39,7 @@
 					if(seconds > 0) {
 						seconds--;
 						if (betterMessages.show_countdown == '1') {
-							$('.message-timer').text(Drupal.t('Closing in' + ' ' + seconds + ' ' + Drupal.t('seconds')));
+              $('.message-timer').text(Drupal.t('Closing in !seconds seconds', {'!seconds': seconds}));
 						}
 			      if(seconds > 0) {
 			      	betterMessages.countDown = setTimeout( function() {betterMessages.countDownClose(seconds);}, 1000 );

+ 65 - 25
sites/all/modules/contrib/messages/better_messages/better_messages.module

@@ -5,6 +5,7 @@ Implementation of hook_init
 */
 function better_messages_init() {
   drupal_add_css(drupal_get_path('module', 'better_messages') . '/better_messages_admin.css');
+  drupal_add_css(drupal_get_path('module', 'better_messages') . '/skins/default/better_messages.css');
 }
 
 /*
@@ -29,11 +30,11 @@ function better_messages_menu() {
 function better_messages_permission() {
 	return array(
     'access better messages' => array(
-      'title' => t('access better messages'), 
+      'title' => t('access better messages'),
       'description' => t('access better messages.'),
     ),
 		'administer better messages' => array(
-      'title' => t('administer better messages'), 
+      'title' => t('administer better messages'),
       'description' => t('administer better messages.'),
     ),
   );
@@ -45,11 +46,11 @@ Implementation of hook_theme
 function better_messages_theme($existing, $type, $theme, $path) {
   return array(
     'better_messages_content' => array(
-    	'arguments' => array('display' => NULL),
+    	'variables' => array('messages_drupal' => array()),
     ),
     'better_messages' => array(
     	'template'	=> 'better_messages',
-    	'arguments' => array('content' => NULL),
+    	'variables' => array('content' => NULL),
     ),
   );
 }
@@ -65,26 +66,29 @@ function theme_better_messages($display = NULL) {
 	$output = '';
 	$better_messages = better_messages_process_visibility();
  	$access = user_access('access better messages');
-	$message = drupal_get_messages($display['display'], FALSE);
+	$message = drupal_get_messages($display['display']);
 	if ($better_messages && $access && !empty($message)) {
-		$disable_autoclose = array_key_exists('error', $message);
+		$disable_autoclose = better_messages_process_autoclose($message);
 		better_messages_add_files($disable_autoclose);
-		$message = theme('better_messages_content', $display['display']);
-		// We save the intial output to SESSION so we can put it in <noscript> on page_preprocess
+		$message = theme('better_messages_content', array('messages_drupal' => $message));
+		// We save the initial output to SESSION so we can put it in <noscript> on page_preprocess
 		$_SESSION['original_messages'] = $message;
 		$message_skin = theme('better_messages', array('content' => $message));
 		// We add a special ID so that JavaScript knows what to handle. Changing the ID will break JavaScript handling code.
-		$output = "<div id=\"better-messages-wrapper\" style=\"display:none;overflow:visible;position:absolute;z-index:9999;\">\n". 
+		$output = "<div id=\"better-messages-wrapper\" style=\"display:none;overflow:visible;position:absolute;z-index:9999;\">\n".
 					$message_skin ."\n</div>\n";
 	}
-	else { $output = theme('better_messages_content', $display['display']);}
+	else {
+  	$output = theme('better_messages_content', array('messages_drupal' => $message));
+  }
 	return $output;
 }
 
-function theme_better_messages_content($display = NULL) {
+function theme_better_messages_content($variables) {
+  $messages_drupal = $variables['messages_drupal'];
 	$output = '';
 	$first = TRUE;
-	foreach (drupal_get_messages($display) as $type => $messages) {
+	foreach ($messages_drupal as $type => $messages) {
 		$class = $first ? 'first' : '';
 		$first = FALSE;
 		$output .= "<h2 class=\"messages-label $type\">" . t(drupal_ucfirst($type)) . "</h2>\n";
@@ -92,24 +96,31 @@ function theme_better_messages_content($display = NULL) {
 		if (count($messages) > 1) {
 			$output .= " <ul>\n";
 			foreach ($messages as $k => $message) {
-		        if ($k == 0) { $output .= "<li class='message-item first'>$message</li>"; }
-		        else if ($k == count($messages) - 1) { $output .= "<li class='message-item last'>$message</li>"; }
-		        else { $output .= "<li class='message-item'>$message</li>"; }
+		      if ($k == 0) {
+  		      $output .= "<li class='message-item first'>$message</li>";
+  		    }
+		      elseif ($k == count($messages) - 1) {
+  		      $output .= "<li class='message-item last'>$message</li>";
+  		    }
+		      else {
+  		      $output .= "<li class='message-item'>$message</li>";
+  		    }
 		    }
 			$output .= " </ul>\n";
 		}
-		else { $output .= $messages[0];	}
+		else {
+  		$output .= $messages[0];
+    }
 		$output .= "</div>\n";
 	}
 	return $output;
 }
-	
+
 /*
 Preprocess the default status_messages so we add our template file here
 */
 function better_messages_preprocess_page(&$vars) {
 	if (isset($vars['messages'])) {
-		$settings = better_messages_get_settings();
 		// Check if path Better Messages is enabled for this path
 		$better_messages = better_messages_process_visibility();
 		$access = user_access('access better messages');
@@ -137,6 +148,7 @@ function better_messages_get_settings() {
 		'extra' => array(
 			'pages' => '',
 			'visibility' => 0,
+      'admin' => TRUE,
 		)
 	);
 	return variable_get('better_messages', $settings);
@@ -147,6 +159,12 @@ Helper function to check where to popup Better Messages relative to path
 */
 function better_messages_process_visibility() {
 	$settings = better_messages_get_settings();
+
+  global $user;
+  if (!$settings['extra']['admin'] && $user->uid == 1) {
+    return FALSE;
+  }
+
 	if ($settings['extra']['pages']) {
 		$path = drupal_get_path_alias($_GET['q']);
 		$page_match = drupal_match_path($path, $settings['extra']['pages']);
@@ -155,26 +173,48 @@ function better_messages_process_visibility() {
 		}
 		$page_match = !($settings['extra']['visibility'] xor $page_match);
 	}
-	else { $page_match = TRUE; }	
+	else {
+  	$page_match = TRUE;
+  }
 	return $page_match;
 }
 
-/*
-Helper function to add required JS and CSS only when required
+/**
+ * Helper function to process auto close
+ * @return bool
+ */
+
+function better_messages_process_autoclose($message){
+  $settings = better_messages_get_settings();
+  if (array_key_exists('error', $message) ){
+    if ($settings['disable_autoclose']) {
+      return true;
+    }
+    else {
+      return false;
+    }
+  }
+  else {
+    return false;
+  }
+
+}
+
+/**
+ * Helper function to add required JS and CSS only when required
 */
 function better_messages_add_files($disable_autoclose){
 	$settings = better_messages_get_settings();
-	drupal_add_css(drupal_get_path('module', 'better_messages') . '/skins/default/better_messages.css');
 	drupal_add_js(drupal_get_path('module', 'better_messages') . '/better_messages.js');
 	// Remove extra info from JS
-	if (!module_exists('jquery_ui')) { 
-		unset($settings['jquery_ui']); 
+	if (!module_exists('jquery_ui')) {
+		unset($settings['jquery_ui']);
 	}
 	else {
 		foreach ($settings['jquery_ui'] as $jquery_ui_setting => $value) {
 			if ($value == 1) {
 				jquery_ui_add(array('ui.' . $jquery_ui_setting));
-			} 
+			}
 		}
 	}
 	unset($settings['extra']);

+ 11 - 12
sites/all/modules/contrib/responsive/browscap/browscap.admin.inc

@@ -8,32 +8,31 @@
  * Implements hook_form().
  */
 function browscap_settings_form($form, &$form_state) {
-  // Check the local browscap data version number
+  // Check the local browscap data version number.
   $version = variable_get('browscap_version', 0);
 
-  // If the version number is 0 then browscap data has never been fetched
+  // If the version number is 0 then browscap data has never been fetched.
   if ($version == 0) {
     $version = t('Never fetched');
   }
 
-  $form['data'] = array(
-    '#type' => 'fieldset',
-    '#title' => t('User agent detection settings'),
-  );
-  $form['data']['browscap_data_version'] = array(
+  $form['browscap_data_version'] = array(
     '#markup' => '<p>' . t('Current browscap data version: %fileversion.', array('%fileversion' => $version)) . '</p>',
   );
-  $form['data']['browscap_enable_automatic_updates'] = array(
+  $form['browscap_enable_automatic_updates'] = array(
     '#type' => 'checkbox',
     '#title' => t('Enable automatic updates'),
     '#default_value' => variable_get('browscap_enable_automatic_updates', TRUE),
     '#description' => t('Automatically update the user agent detection information.'),
   );
-  $form['data']['browscap_automatic_updates_timer'] = array(
+  $form['browscap_automatic_updates_timer'] = array(
     '#type' => 'select',
     '#title' => t('Check for new user agent detection information every'),
     '#default_value' => variable_get('browscap_automatic_updates_timer', 604800),
-    '#options' => drupal_map_assoc(array(3600, 10800, 21600, 32400, 43200, 86400, 172800, 259200, 604800, 1209600, 2419200, 4838400, 9676800), 'format_interval'),
+    '#options' => drupal_map_assoc(array(
+        3600, 10800, 21600, 32400, 43200, 86400, 172800,
+        259200, 604800, 1209600, 2419200, 4838400, 9676800),
+        'format_interval'),
     '#description' => t('Newer user agent detection information will be automatically downloaded and installed. (Requires a correctly configured <a href="@cron">cron maintenance task</a>.)', array('@cron' => url('admin/reports/status'))),
     '#states' => array(
       'visible' => array(
@@ -55,9 +54,9 @@ function browscap_settings_form($form, &$form_state) {
  * Submit handler for the refresh browscap button.
  */
 function browscap_refresh_submit($form, &$form_state) {
-  // Update the browscap information
+  // Update the browscap information.
   _browscap_import(FALSE);
 
-  // Record when the browscap information was updated
+  // Record when the browscap information was updated.
   variable_set('browscap_imported', REQUEST_TIME);
 }

+ 3 - 3
sites/all/modules/contrib/responsive/browscap/browscap.info

@@ -3,9 +3,9 @@ description = Provides a replacement for PHPs get_browser() function.
 core = 7.x
 configure = admin/config/system/browscap
 
-; Information added by drupal.org packaging script on 2012-11-22
-version = "7.x-2.0"
+; Information added by Drupal.org packaging script on 2014-07-09
+version = "7.x-2.2"
 core = "7.x"
 project = "browscap"
-datestamp = "1353586510"
+datestamp = "1404915228"
 

+ 10 - 3
sites/all/modules/contrib/responsive/browscap/browscap.install

@@ -5,7 +5,7 @@
  */
 
 /**
- * Implements hook_install().
+ * Implements hook_schema().
  */
 function browscap_schema() {
   $schema['browscap'] = array(
@@ -32,10 +32,10 @@ function browscap_schema() {
  * Implements hook_install().
  */
 function browscap_install() {
-  // Update the browscap information
+  // Update the browscap information.
   _browscap_import();
 
-  // Record when the browscap information was updated
+  // Record when the browscap information was updated.
   variable_set('browscap_imported', REQUEST_TIME);
 }
 
@@ -48,3 +48,10 @@ function browscap_uninstall() {
   variable_del('browscap_enable_automatic_updates');
   variable_del('browscap_automatic_updates_timer');
 }
+
+/**
+ * Drop the unused Browscap 1.x statistics table.
+ */
+function browscap_update_7200() {
+  db_drop_table('browscap_statistics');
+}

+ 24 - 22
sites/all/modules/contrib/responsive/browscap/browscap.module

@@ -4,8 +4,8 @@
  * Replacement for PHP's get_browser() function.
  */
 
-// Include browscap data import and user agent recording functions
-include_once('import.inc');
+// Include browscap data import and user agent recording functions.
+include_once 'import.inc';
 
 /**
  * Implements hook_permission().
@@ -24,7 +24,7 @@ function browscap_permission() {
 function browscap_menu() {
   $items['admin/config/system/browscap'] = array(
     'title' => 'Browscap',
-    'description' => 'Configure user agent monitoring and browscap information settings.',
+    'description' => 'View the current browscap data version and configure automatic update settings.',
     'page callback' => 'drupal_get_form',
     'page arguments' => array('browscap_settings_form'),
     'access arguments' => array('administer browscap'),
@@ -40,7 +40,7 @@ function browscap_menu() {
 function browscap_help($path, $arg) {
   switch ($path) {
     case 'admin/config/system/browscap':
-      return '<p>' . t('Settings for user agent detection and the log that Browscap will keep about user agents that visit the site. See <a href="@statistics">user agent statistics</a> for the actual information.', array('@statistics' => url('admin/reports/browscap'))) . '</p>';
+      return '<p>' . t('View the current browscap data version and configure automatic update settings.') . '</p>';
   }
 }
 
@@ -49,19 +49,19 @@ function browscap_help($path, $arg) {
  */
 function browscap_cron() {
   if (variable_get('browscap_enable_automatic_updates', TRUE) == TRUE) {
-    // Check the current update timer
+    // Check the current update timer.
     $automatic_update_timer = variable_get('browscap_automatic_updates_timer', 604800);
 
-    // Check when the last update occurred
+    // Check when the last update occurred.
     $last_imported = variable_get('browscap_imported', REQUEST_TIME);
 
     // Update the browscap data if the amount of time specified by the update
-    // timer has passed
+    // timer has passed.
     if (($last_imported + $automatic_update_timer) < REQUEST_TIME) {
-      // Update the browscap information
+      // Update the browscap information.
       _browscap_import();
 
-      // Record when the browscap information was updated
+      // Record when the browscap information was updated.
       variable_set('browscap_imported', REQUEST_TIME);
     }
   }
@@ -71,12 +71,14 @@ function browscap_cron() {
  * Provide data about a user agent string or the current user agent.
  *
  * @param string $user_agent
- *   Optional user agent string to test. If empty, use the value from the current request.
+ *   Optional user agent string to test. If empty, use the value from the
+ *   current request.
+ *
  * @return array
  *   An array of information about the user agent.
  */
 function browscap_get_browser($user_agent = NULL) {
-  // Determine the current user agent if a user agent was not specified
+  // Determine the current user agent if a user agent was not specified.
   if ($user_agent != NULL) {
     $user_agent = check_plain(trim($user_agent));
   }
@@ -87,40 +89,40 @@ function browscap_get_browser($user_agent = NULL) {
     $user_agent = 'Default Browser';
   }
 
-  // Check the cache for user agent data
+  // Check the cache for user agent data.
   $cache = cache_get($user_agent, 'cache_browscap');
 
-  // Attempt to find a cached user agent
-  // Otherwise store the user agent data in the cache
+  // Attempt to find a cached user agent.
+  // Otherwise store the user agent data in the cache.
   if (!empty($cache) && ($cache->created > REQUEST_TIME - 60 * 60 * 24)) {
     $user_agent_properties = $cache->data;
   }
   else {
-    // Find the user agent's properties
+    // Find the user agent's properties.
     // The useragent column contains the wildcarded pattern to match against our
     // full-length string while the ORDER BY chooses the most-specific matching
-    // pattern
+    // pattern.
     $user_agent_properties = db_query("SELECT * FROM {browscap} WHERE :useragent LIKE useragent ORDER BY LENGTH(useragent) DESC", array(':useragent' => $user_agent))
       ->fetchObject();
 
-    // Store user agent data in the cache
+    // Store user agent data in the cache.
     cache_set($user_agent, $user_agent_properties, 'cache_browscap');
   }
 
-  // Create an array to hold the user agent's properties
+  // Create an array to hold the user agent's properties.
   $properties = array();
 
-  // Return an array of user agent properties
+  // Return an array of user agent properties.
   if (isset($user_agent_properties) && isset($user_agent_properties->data)) {
-    // Unserialize the user agent data found in the cache or the database
+    // Unserialize the user agent data found in the cache or the database.
     $properties = unserialize($user_agent_properties->data);
 
-    // Set the user agent name and name pattern
+    // Set the user agent name and name pattern.
     $properties['useragent'] = $user_agent;
     $properties['browser_name_pattern'] = strtr($user_agent_properties->useragent, '%_', '*?');
   }
   else {
-    // Set the user agent name and name pattern to 'unrecognized'
+    // Set the user agent name and name pattern to 'unrecognized'.
     $properties['useragent'] = 'unrecognized';
     $properties['browser_name_pattern'] = strtr('unrecognized', '%_', '*?');
   }

+ 69 - 41
sites/all/modules/contrib/responsive/browscap/import.inc

@@ -7,22 +7,23 @@
 /**
  * Helper function to update the browscap data.
  *
- * @param boolean $cron
- *   Optional import environment. If false, display status messages to the user in addition to logging information with the watchdog.
+ * @param bool $cron
+ *   Optional import environment. If false, display status messages to the user
+ *   in addition to logging information with the watchdog.
  */
 function _browscap_import($cron = TRUE) {
-  // Check the local browscap data version number
+  // Check the local browscap data version number.
   $local_version = variable_get('browscap_version', 0);
 
-  // Retrieve the current browscap data version number using HTTP
-  $current_version = drupal_http_request('http://tempdownloads.browserscap.com/versions/version-number.php');
+  // Retrieve the current browscap data version number using HTTP.
+  $current_version = drupal_http_request('http://www.browscap.org/version-number');
 
-  // Log an error if the browscap version number could not be retrieved
+  // Log an error if the browscap version number could not be retrieved.
   if (isset($current_version->error)) {
-    // Log a message with the watchdog
+    // Log a message with the watchdog.
     watchdog('browscap', "Couldn't check version: %error", array('%error' => $current_version->error), WATCHDOG_ERROR);
 
-    // Display a message to the user if the update process was triggered manually
+    // Display a message to user if the update process was triggered manually.
     if ($cron == FALSE) {
       drupal_set_message(t("Couldn't check version: %error", array('%error' => $current_version->error)), 'error');
     }
@@ -30,16 +31,16 @@ function _browscap_import($cron = TRUE) {
     return;
   }
 
-  // Sanitize the returned version number
+  // Sanitize the returned version number.
   $current_version = check_plain(trim($current_version->data));
 
   // Compare the current and local version numbers to determine if the browscap
-  // data requires updating
+  // data requires updating.
   if ($current_version == $local_version) {
-    // Log a message with the watchdog
+    // Log a message with the watchdog.
     watchdog('browscap', 'No new version of browscap to import');
 
-    // Display a message to the user if the update process was triggered manually
+    // Display a message to user if the update process was triggered manually.
     if ($cron == FALSE) {
       drupal_set_message(t('No new version of browscap to import'));
     }
@@ -47,15 +48,27 @@ function _browscap_import($cron = TRUE) {
     return;
   }
 
-  // Retrieve the browscap data using HTTP
-  $browscap_data = drupal_http_request('http://tempdownloads.browserscap.com/stream.php?BrowsCapINI');
+  // Set options for downloading data with or without compression.
+  if (function_exists('gzdecode')) {
+    $options = array(
+      'headers' => array('Accept-Encoding' => 'gzip'),
+    );
+  }
+  else {
+    // The download takes over ten times longer without gzip, and may exceed
+    // the default timeout of 30 seconds, so we increase the timeout.
+    $options = array('timeout' => 600);
+  }
+
+  // Retrieve the browscap data using HTTP.
+  $browscap_data = drupal_http_request('http://www.browscap.org/stream?q=PHP_BrowsCapINI', $options);
 
-  // Log an error if the browscap data could not be retrieved
+  // Log an error if the browscap data could not be retrieved.
   if (isset($browscap_data->error) || empty($browscap_data)) {
-    // Log a message with the watchdog
+    // Log a message with the watchdog.
     watchdog('browscap', "Couldn't retrieve updated browscap: %error", array('%error' => $browscap_data->error), WATCHDOG_ERROR);
 
-    // Display a message to the user if the update process was triggered manually
+    // Display a message to user if the update process was triggered manually.
     if ($cron == FALSE) {
       drupal_set_message(t("Couldn't retrieve updated browscap: %error", array('%error' => $browscap_data->error)), 'error');
     }
@@ -63,83 +76,98 @@ function _browscap_import($cron = TRUE) {
     return;
   }
 
-  // Parse the returned browscap data
-  // The parse_ini_string function is preferred but only available in PHP 5.3.0
+  // Decompress the downloaded data if it is compressed.
+  if (function_exists('gzdecode')) {
+    $browscap_data->data = gzdecode($browscap_data->data);
+  }
+
+  // Parse the returned browscap data.
+  // The parse_ini_string function is preferred but only available in PHP 5.3.0.
   if (version_compare(PHP_VERSION, '5.3.0', '>=')) {
-    // Retrieve the browscap data
+    // Retrieve the browscap data.
     $browscap_data = $browscap_data->data;
 
     // Replace 'true' and 'false' with '1' and '0'
-    $browscap_data = strtr($browscap_data, array("=true\r" => "=1\r", "=false\r" => "=0\r"));
-
-    // Parse the browscap data as a string
+    $browscap_data = preg_replace(
+      array(
+        "/=\s*true\s*\n/",
+        "/=\s*false\s*\n/",
+      ),
+      array(
+        "=1\n",
+        "=0\n",
+      ),
+      $browscap_data
+    );
+
+    // Parse the browscap data as a string.
     $browscap_data = parse_ini_string($browscap_data, TRUE, INI_SCANNER_RAW);
   }
   else {
-    // Create a path and filename
+    // Create a path and filename.
     $server = $_SERVER['SERVER_NAME'];
     $path = variable_get('file_temporary_path', '/tmp');
     $file = "$path/browscap_$server.ini";
 
-    // Write the browscap data to a file
+    // Write the browscap data to a file.
     $browscap_file = fopen($file, "w");
     fwrite($browscap_file, $browscap_data->data);
     fclose($browscap_file);
 
-    // Parse the browscap data as a file
+    // Parse the browscap data as a file.
     $browscap_data = parse_ini_file($file, TRUE);
   }
 
   if ($browscap_data) {
-    // Find the version information
-    // The version information is the first entry in the array
+    // Find the version information.
+    // The version information is the first entry in the array.
     $version = array_shift($browscap_data);
 
-    // Store the data available for each user agent
+    // Store the data available for each user agent.
     foreach ($browscap_data as $key => $values) {
-      // Store the current value
+      // Store the current value.
       $e = $values;
 
-      // Create an array to hold the last parent
+      // Create an array to hold the last parent.
       $last_parent = array();
 
-      // Recurse through the available user agent information
+      // Recurse through the available user agent information.
       while (isset($values['Parent']) && $values['Parent'] !== $last_parent) {
         $values = isset($browscap_data[$values['Parent']]) ? $browscap_data[$values['Parent']] : array();
         $e = array_merge($values, $e);
         $last_parent = $values;
       }
 
-      // Replace '*?' with '%_'
+      // Replace '*?' with '%_'.
       $user_agent = strtr($key, '*?', '%_');
 
-      // Change all array keys to lowercase
+      // Change all array keys to lowercase.
       $e = array_change_key_case($e);
 
-      // Delete all data about the current user agent from the database
+      // Delete all data about the current user agent from the database.
       db_delete('browscap')
         ->condition('useragent', $user_agent)
         ->execute();
 
-      // Insert all data about the current user agent into the database
+      // Insert all data about the current user agent into the database.
       db_insert('browscap')
         ->fields(array(
          'useragent' => $user_agent,
-         'data' => serialize($e)
+         'data' => serialize($e),
         ))
         ->execute();
     }
 
-    // Clear the browscap data cache
+    // Clear the browscap data cache.
     cache_clear_all('*', 'cache_browscap', TRUE);
 
-    // Update the browscap version
+    // Update the browscap version.
     variable_set('browscap_version', $current_version);
 
-    // Log a message with the watchdog
+    // Log a message with the watchdog.
     watchdog('browscap', 'New version of browscap imported: %version', array('%version' => $current_version));
 
-    // Display a message to the user if the update process was triggered manually
+    // Display a message to user if the update process was triggered manually.
     if ($cron == FALSE) {
       drupal_set_message(t('New version of browscap imported: %version', array('%version' => $current_version)));
     }

+ 3 - 0
sites/all/modules/contrib/taxonomy/synonyms/README.txt

@@ -8,6 +8,9 @@ the module provides this additional functionality:
 * synonym-friendly autocomplete widget for taxonomy_term_reference fields
 * integration with Drupal search functionality enabling searching content by
    synonyms of the terms that the content references
+* integration with Search API. If you include synonyms of a term into your
+   Search API search index, your clients will be able to find content with
+   search keywords that contain synonyms and not actual names of terms.
 
 -- REQUIREMENTS --
 

+ 15 - 11
sites/all/modules/contrib/taxonomy/synonyms/includes/AbstractSynonymsExtractor.class.inc

@@ -14,7 +14,9 @@ abstract class AbstractSynonymsExtractor {
    *   Array of Field API field types from which this class is able to extract
    *   synonyms
    */
-  static public abstract function fieldTypesSupported();
+  public static function fieldTypesSupported() {
+    return array();
+  }
 
   /**
    * Extract synonyms from a field attached to an entity.
@@ -38,7 +40,9 @@ abstract class AbstractSynonymsExtractor {
    * @return array
    *   Array of synonyms extracted from $items
    */
-  static public abstract function synonymsExtract($items, $field, $instance, $entity, $entity_type);
+  public static function synonymsExtract($items, $field, $instance, $entity, $entity_type) {
+    return array();
+  }
 
   /**
    * Allow you to hook in during autocomplete suggestions generation.
@@ -58,7 +62,7 @@ abstract class AbstractSynonymsExtractor {
    * @param array $instance
    *   Array of instance definition according to Field API
    */
-  static public abstract function processEntityFieldQuery($tag, EntityFieldQuery $query, $field, $instance);
+  public static function processEntityFieldQuery($tag, EntityFieldQuery $query, $field, $instance) {}
 
   /**
    * Add an entity as a synonym into a field of another entity.
@@ -91,22 +95,22 @@ abstract class AbstractSynonymsExtractor {
    *   Array of extra items to be merged into the items that already exist in
    *   field values
    */
-  static public abstract function mergeEntityAsSynonym($items, $field, $instance, $synonym_entity, $synonym_entity_type);
+  public static function mergeEntityAsSynonym($items, $field, $instance, $synonym_entity, $synonym_entity_type) {
+    return array();
+  }
 
   /**
    * Supportive method.
    *
    * Set such a condition on $query that it will always yield no results. Should
-   *   be called from $this->processEntityFieldQuery() when for whatever reason
-   *   the object can't alter $query to include matched synonyms. As a fallback
-   *   it should call this method to make sure it filtered everything out.
+   * be called from $this->processEntityFieldQuery() when for whatever reason
+   * the object can't alter $query to include matched synonyms. As a fallback it
+   * should call this method to make sure it filtered everything out.
    *
    * @param EntityFieldQuery $query
    *   Query object passed to $this->processEntityFieldQuery() method
-   * @param array $field
-   *   Field array passed to $this->processEntityFieldQuery() method
    */
-  static protected function emptyResultsCondition(EntityFieldQuery $query) {
-    $query->entityCondition('entity_id', -1);
+  protected static function emptyResultsCondition(EntityFieldQuery $query) {
+    $query->range(0, 0);
   }
 }

+ 6 - 7
sites/all/modules/contrib/taxonomy/synonyms/includes/EntityReferenceSynonymsExtractor.class.inc

@@ -7,11 +7,11 @@
 
 class EntityReferenceSynonymsExtractor extends AbstractSynonymsExtractor {
 
-  static public function fieldTypesSupported() {
+  public static function fieldTypesSupported() {
     return array('entityreference');
   }
 
-  static public function synonymsExtract($items, $field, $instance, $entity, $entity_type) {
+  public static function synonymsExtract($items, $field, $instance, $entity, $entity_type) {
     $synonyms = array();
 
     // For speading up loading all the entities at once.
@@ -27,7 +27,7 @@ class EntityReferenceSynonymsExtractor extends AbstractSynonymsExtractor {
     return $synonyms;
   }
 
-  static public function processEntityFieldQuery($tag, EntityFieldQuery $query, $field, $instance) {
+  public static function processEntityFieldQuery($tag, EntityFieldQuery $query, $field, $instance) {
     // Unfortunately EntityFieldQuery does not currently support INNER JOINing
     // referenced entities via any field type.
     // Thus, we use an ugly solution -- going through all entities that exist
@@ -55,9 +55,9 @@ class EntityReferenceSynonymsExtractor extends AbstractSynonymsExtractor {
     $query->fieldCondition($field, 'target_id', array_keys($result));
   }
 
-  static public function mergeEntityAsSynonym($items, $field, $instance, $synonym_entity, $synonym_entity_type) {
-    // Firstly validating that this entity refernce is able to reference to that
-    // type of entity.
+  public static function mergeEntityAsSynonym($items, $field, $instance, $synonym_entity, $synonym_entity_type) {
+    // Firstly validating that this entity reference is able to reference to
+    // that type of entity.
     $expected_synonym_entity_type = $field['settings']['target_type'];
     if ($expected_synonym_entity_type != $synonym_entity_type) {
       return array();
@@ -67,5 +67,4 @@ class EntityReferenceSynonymsExtractor extends AbstractSynonymsExtractor {
       'target_id' => $synonym_entity_id,
     ));
   }
-
 }

+ 4 - 4
sites/all/modules/contrib/taxonomy/synonyms/includes/SynonymsSynonymsExtractor.class.inc

@@ -7,11 +7,11 @@
 
 class SynonymsSynonymsExtractor extends AbstractSynonymsExtractor {
 
-  static public function fieldTypesSupported() {
+  public static function fieldTypesSupported() {
     return array('text', 'number_integer', 'number_float', 'number_decimal');
   }
 
-  static public function synonymsExtract($items, $field, $instance, $entity, $entity_type) {
+  public static function synonymsExtract($items, $field, $instance, $entity, $entity_type) {
     $synonyms = array();
 
     foreach ($items as $item) {
@@ -21,11 +21,11 @@ class SynonymsSynonymsExtractor extends AbstractSynonymsExtractor {
     return $synonyms;
   }
 
-  static public function processEntityFieldQuery($tag, EntityFieldQuery $query, $field, $instance) {
+  public static function processEntityFieldQuery($tag, EntityFieldQuery $query, $field, $instance) {
     $query->fieldCondition($field, 'value', '%' . $tag . '%', 'LIKE');
   }
 
-  static public function mergeEntityAsSynonym($items, $field, $instance, $synonym_entity, $synonym_entity_type) {
+  public static function mergeEntityAsSynonym($items, $field, $instance, $synonym_entity, $synonym_entity_type) {
     $synonym = entity_label($synonym_entity_type, $synonym_entity);
     switch ($field['type']) {
       case 'text':

+ 4 - 4
sites/all/modules/contrib/taxonomy/synonyms/includes/TaxonomySynonymsExtractor.class.inc

@@ -7,11 +7,11 @@
 
 class TaxonomySynonymsExtractor extends AbstractSynonymsExtractor {
 
-  static public function fieldTypesSupported() {
+  public static function fieldTypesSupported() {
     return array('taxonomy_term_reference');
   }
 
-  static public function synonymsExtract($items, $field, $instance, $entity, $entity_type) {
+  public static function synonymsExtract($items, $field, $instance, $entity, $entity_type) {
     $synonyms = array();
 
     $terms = array();
@@ -25,7 +25,7 @@ class TaxonomySynonymsExtractor extends AbstractSynonymsExtractor {
     return $synonyms;
   }
 
-  static public function processEntityFieldQuery($tag, EntityFieldQuery $query, $field, $instance) {
+  public static function processEntityFieldQuery($tag, EntityFieldQuery $query, $field, $instance) {
     // Unfortunately EntityFieldQuery does not currently support INNER JOINing
     // term entity that is referenced via taxonomy_term_reference field type.
     // Thus, we use an ugly solution -- going through all terms that exist in
@@ -56,7 +56,7 @@ class TaxonomySynonymsExtractor extends AbstractSynonymsExtractor {
     $query->fieldCondition($field, 'tid', $tids);
   }
 
-  static public function mergeEntityAsSynonym($items, $field, $instance, $synonym_entity, $synonym_entity_type) {
+  public static function mergeEntityAsSynonym($items, $field, $instance, $synonym_entity, $synonym_entity_type) {
     // Taxonomy term reference supports only referencing of entity types
     // 'taxonomy_term'.. duh.
     if ($synonym_entity_type != 'taxonomy_term') {

+ 2 - 2
sites/all/modules/contrib/taxonomy/synonyms/synonyms.api.php

@@ -17,7 +17,7 @@
  */
 function hook_synonyms_extractor_info() {
   return array(
-    // Please see below the defintion of ApiSynonymsSynonymsExtractor class
+    // Please see below the definition of ApiSynonymsSynonymsExtractor class
     // for your reference.
     'ApiSynonymsSynonymsExtractor',
   );
@@ -28,7 +28,7 @@ function hook_synonyms_extractor_info() {
  *
  * This is a copy of SynonymsSynonymsExtractor class providing an example of
  * how to write your own synonyms extractor class. See the definition of
- * AbstractSynonymsExtractor for reference and incode comments. For more
+ * AbstractSynonymsExtractor for reference and in code comments. For more
  * complicated examples take a look at EntityReferenceSynonymsExtractor class.
  */
 class ApiSynonymsSynonymsExtractor extends AbstractSynonymsExtractor {

+ 5 - 3
sites/all/modules/contrib/taxonomy/synonyms/synonyms.info

@@ -10,10 +10,12 @@ files[] = includes/AbstractSynonymsExtractor.class.inc
 files[] = includes/SynonymsSynonymsExtractor.class.inc
 files[] = includes/TaxonomySynonymsExtractor.class.inc
 files[] = includes/EntityReferenceSynonymsExtractor.class.inc
+files[] = views/synonyms.views.inc
+files[] = views/synonyms_views_plugin_argument_validate_taxonomy_term.inc
 
-; Information added by drupal.org packaging script on 2013-01-15
-version = "7.x-1.1"
+; Information added by Drupal.org packaging script on 2014-09-15
+version = "7.x-1.2"
 core = "7.x"
 project = "synonyms"
-datestamp = "1358220389"
+datestamp = "1410753528"
 

+ 213 - 287
sites/all/modules/contrib/taxonomy/synonyms/synonyms.module

@@ -16,16 +16,95 @@ define('SYNONYMS_DEFAULT_FIELD_NAME', 'synonyms_synonyms');
 function synonyms_menu() {
   $items = array();
 
-  $items['synonyms/autocomplete'] = array(
+  $items['synonyms/autocomplete/%/%/%'] = array(
     'title' => 'Autocomplete Synonyms',
     'page callback' => 'synonyms_autocomplete',
+    'page arguments' => array(2, 3, 4),
     'access arguments' => array('access content'),
+    'file' => 'synonyms.pages.inc',
     'type' => MENU_CALLBACK,
   );
 
   return $items;
 }
 
+/**
+ * Implements hook_taxonomy_term_update().
+ */
+function synonyms_taxonomy_term_update($term) {
+  // If we notice at least some change in synonyms of this term, we want to
+  // trigger search re-indexing of nodes, where this term is referenced, since
+  // change in term synonyms affects nodes ranking in the search.
+  if (isset($term->original)) {
+    $current_synonyms = synonyms_get_raw($term);
+    $previous_synonyms = synonyms_get_raw($term->original);
+    if (count($current_synonyms) != count($previous_synonyms)) {
+      // Schedule re-indexing, because amount of synonyms has changed.
+      module_load_include('inc', 'synonyms', 'synonyms.pages');
+      synonyms_reindex_nodes_by_terms(array($term->tid));
+    }
+    else {
+      foreach ($current_synonyms as $k => $current_synonym) {
+        if ($current_synonyms[$k] != $previous_synonyms[$k]) {
+          // Schedule re-indexing, because some synonym has changed.
+          module_load_include('inc', 'synonyms', 'synonyms.pages');
+          synonyms_reindex_nodes_by_terms(array($term->tid));
+          break;
+        }
+      }
+    }
+  }
+}
+
+/**
+ * Implements hook_entity_property_info().
+ */
+function synonyms_entity_property_info() {
+  $info = array();
+  $properties = &$info['taxonomy_term']['properties'];
+  $properties['synonyms'] = array(
+    'label' => t('Synonyms'),
+    'description' => t('Synonyms of entity.'),
+    'type' => 'list<text>',
+    'getter callback' => 'synonyms_get_sanitized',
+    'computed' => TRUE,
+    'sanitized' => TRUE,
+    'raw getter callback' => 'synonyms_get_raw',
+  );
+  return $info;
+}
+
+/**
+ * Implements hook_node_update_index().
+ */
+function synonyms_node_update_index($node) {
+  $output = '';
+  foreach (field_info_instances('node', $node->type) as $instance) {
+    // We go a field by field looking for taxonomy term reference and
+    // if that vocabulary has enabled synonyms, we add term's synonyms
+    // to the search index.
+    $field_info = field_info_field($instance['field_name']);
+    if ($field_info['type'] == 'taxonomy_term_reference') {
+      // For each term referenced in this node we have to add synonyms.
+      $_terms = field_get_items('node', $node, $instance['field_name']);
+      if (is_array($_terms) && !empty($_terms)) {
+        $terms = array();
+        foreach ($_terms as $v) {
+          $terms[] = $v['tid'];
+        }
+        $terms = taxonomy_term_load_multiple($terms);
+        foreach ($terms as $term) {
+          $synonyms = synonyms_get_sanitized($term);
+          if (!empty($synonyms)) {
+            $output .= '<strong>' . implode(', ', $synonyms) . '</strong>';
+          }
+        }
+      }
+    }
+  }
+  return $output;
+}
+
 /**
  * Implements hook_synonyms_extractor_info().
  */
@@ -53,7 +132,7 @@ function synonyms_synonyms_extractor_info() {
  *   Whether collect all the info again from hooks, or cached info is fine
  *
  * @return array
- *   Key of this array denote the field type while value of the array denotes
+ *   Key of this array denotes the field type while value of the array denotes
  *   which class reports ability to extract synonyms from such field type.
  */
 function synonyms_extractor_info($field_type = NULL, $reset = FALSE) {
@@ -72,10 +151,8 @@ function synonyms_extractor_info($field_type = NULL, $reset = FALSE) {
 
       if (is_array($extractor_classes)) {
         foreach ($extractor_classes as $class) {
-          if (class_exists($class) && is_subclass_of($class, 'AbstractSynonymsExtractor')) {
-            foreach ($class::fieldTypesSupported() as $_field_type) {
-              $info[$_field_type] = $class;
-            }
+          foreach (call_user_func(array($class, 'fieldTypesSupported')) as $_field_type) {
+            $info[$_field_type] = $class;
           }
         }
       }
@@ -84,13 +161,6 @@ function synonyms_extractor_info($field_type = NULL, $reset = FALSE) {
       // data.
       drupal_alter('synonyms_extractor_info', $info);
 
-      // Validating that any changes made to $info do not break class hierarchy.
-      foreach ($info as $k => $v) {
-        if (!class_exists($v) || !is_subclass_of($v, 'AbstractSynonymsExtractor')) {
-          unset($info[$k]);
-        }
-      }
-
       $cache = $info;
       cache_set($cid, $cache, 'cache', CACHE_TEMPORARY);
     }
@@ -106,41 +176,6 @@ function synonyms_extractor_info($field_type = NULL, $reset = FALSE) {
   return $cache;
 }
 
-/**
- * Implements hook_node_update_index().
- */
-function synonyms_node_update_index($node) {
-  $output = '';
-  foreach (field_info_instances('node', $node->type) as $instance) {
-    // We go a field by field looking for taxonomy term reference and
-    // if that vocabulary has enabled synonyms, we add term's synonyms
-    // to the search index.
-    $field_info = field_info_field($instance['field_name']);
-    if ($field_info['type'] == 'taxonomy_term_reference') {
-      // For each term referenced in this node we have to add synonyms.
-      $_terms = field_get_items('node', $node, $instance['field_name']);
-      if (is_array($_terms) && !empty($_terms)) {
-        $terms = array();
-        foreach ($_terms as $v) {
-          $terms[] = $v['tid'];
-        }
-        $terms = taxonomy_term_load_multiple($terms);
-        foreach ($terms as $term) {
-          $synonyms = synonyms_get_term_synonyms($term);
-          if (!empty($synonyms)) {
-            $safe_synonyms = array();
-            foreach ($synonyms as $synonym) {
-              $safe_synonyms[] = $synonym['safe_value'];
-            }
-            $output .= '<strong>' . implode(', ', $safe_synonyms) . '</strong>';
-          }
-        }
-      }
-    }
-  }
-  return $output;
-}
-
 /**
  * Implements hook_form_FORM_ID_alter().
  */
@@ -149,6 +184,8 @@ function synonyms_form_taxonomy_form_vocabulary_alter(&$form, &$form_state) {
     return;
   }
 
+  module_load_include('inc', 'synonyms', 'synonyms.pages');
+
   $form['synonyms'] = array(
     '#type' => 'fieldset',
     '#title' => t('Synonyms'),
@@ -160,7 +197,7 @@ function synonyms_form_taxonomy_form_vocabulary_alter(&$form, &$form_state) {
     SYNONYMS_DEFAULT_FIELD_NAME => t('Default synonyms field'),
   );
   if (isset($form['#vocabulary']->vid)) {
-    $instances = synonyms_instances_extract_applicapable($form['#vocabulary']);
+    $instances = synonyms_instances_extract_applicable($form['#vocabulary']);
     foreach ($instances as $instance) {
       // Here we prefer some informative text for the default synonyms field
       // rather its label.
@@ -178,7 +215,7 @@ function synonyms_form_taxonomy_form_vocabulary_alter(&$form, &$form_state) {
     '#default_value' => synonyms_synonyms_fields($form['#vocabulary']),
   );
 
-  // Adding out own submit handler.
+  // Adding our own submit handler.
   $form['#submit'][] = 'synonyms_taxonomy_form_vocabulary_submit';
 }
 
@@ -193,6 +230,9 @@ function synonyms_field_widget_info() {
       'settings' => array(
         'size' => 60,
         'autocomplete_path' => 'synonyms/autocomplete',
+        'suggestion_size' => 10,
+        'suggest_only_unique' => FALSE,
+        'auto_creation' => 1,
       ),
       'behaviors' => array(
         'multiple values' => FIELD_BEHAVIOR_CUSTOM,
@@ -214,7 +254,23 @@ function synonyms_field_widget_settings_form($field, $instance) {
     '#type' => 'checkbox',
     '#title' => t('Allow auto-creation?'),
     '#description' => t('Whether users may create a new term by typing in a non-existing name into this field.'),
-    '#default_value' => isset($settings['auto_creation']) ? $settings['auto_creation'] : 0,
+    '#default_value' => $settings['auto_creation'],
+  );
+
+  $form['suggestion_size'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Suggestions Size'),
+    '#description' => t('Please, enter how many suggested entities to show in the autocomplete textfield.'),
+    '#required' => TRUE,
+    '#element_validate' => array('element_validate_integer_positive'),
+    '#default_value' => $settings['suggestion_size'],
+  );
+
+  $form['suggest_only_unique'] = array(
+    '#type' => 'checkbox',
+    '#title' => t('Suggest only one entry per term'),
+    '#description' => t('If you want to include only term name or a single synonym, suggesting a particular term, while disregarding all ongoing ones, please, tick this checkbox on.'),
+    '#default_value' => $settings['suggest_only_unique'],
   );
 
   return $form;
@@ -232,11 +288,11 @@ function synonyms_field_widget_form(&$form, &$form_state, $field, $instance, $la
   $element += array(
     '#type' => 'textfield',
     '#default_value' => taxonomy_implode_tags($tags),
-    '#autocomplete_path' => $instance['widget']['settings']['autocomplete_path'] . '/' . $field['field_name'],
+    '#autocomplete_path' => $instance['widget']['settings']['autocomplete_path'] . '/' . $field['field_name'] . '/' . $instance['entity_type'] . '/' . $instance['bundle'],
     '#size' => $instance['widget']['settings']['size'],
     '#maxlength' => 1024,
     '#element_validate' => array('taxonomy_autocomplete_validate', 'synonyms_autocomplete_validate'),
-    '#auto_creation' => isset($instance['widget']['settings']['auto_creation']) ? $instance['widget']['settings']['auto_creation'] : 0,
+    '#auto_creation' => $instance['widget']['settings']['auto_creation'],
   );
 
   return $element;
@@ -255,226 +311,43 @@ function synonyms_field_widget_error($element, $error, $form, &$form_state) {
  * Handle validation for taxonomy term synonym-friendly autocomplete element.
  */
 function synonyms_autocomplete_validate($element, &$form_state) {
-  // After taxonomy_autocomplete_validate() has finished its job
-  // it might left terms in the format for autocreation. Since our field
-  // supports auto creation as a configurable option, we have to make sure
-  // auto creation terms are allowed.
+  // After taxonomy_autocomplete_validate() has finished its job any terms it
+  // didn't find have been set for autocreation. We need to:
+  // (a) Double-check that those terms are not synonyms.
+  // (b) Check that synonyms' configurable auto-creation option is enabled.
   $value = drupal_array_get_nested_value($form_state['values'], $element['#parents']);
-  if (!$element['#auto_creation']) {
-    // Deleting all the terms meant to be auto-created.
-    foreach ($value as $delta => $term) {
-      if ($term['tid'] == 'autocreate') {
+  foreach ($value as $delta => $term) {
+    if ($term['tid'] == 'autocreate') {
+      $vocabulary = taxonomy_vocabulary_load($term['vid']);
+      $synonym_tid = synonyms_get_term_by_synonym($term['name'], $vocabulary);
+      if ($synonym_tid != 0) {
+        $value[$delta]['tid'] = $synonym_tid;
+      }
+      elseif (empty($element['#auto_creation'])) {
         unset($value[$delta]);
       }
     }
-    $value = array_values($value);
   }
-
+  $value = array_values($value);
   form_set_value($element, $value, $form_state);
 }
 
-/**
- * Submit hanlder for Taxonomy vocabulary edit form.
- *
- * Store extra values attached to form in this module.
- */
-function synonyms_taxonomy_form_vocabulary_submit($form, &$form_state) {
-  $values = $form_state['values'];
-
-  if ($values['op'] == $form['actions']['submit']['#value']) {
-    if (isset($form['#vocabulary']->vid)) {
-      $vocabulary = taxonomy_vocabulary_load($form['#vocabulary']->vid);
-    }
-    else {
-      // As a fallback, if this is a just created vocabulary, we try to pull it
-      // up by the just submitted machine name.
-      $vocabulary = taxonomy_vocabulary_machine_name_load($values['machine_name']);
-    }
-
-    // Preprocessing values keeping only field names of the checked fields.
-    foreach ($values['synonyms']['synonyms'] as $k => $v) {
-      if (!$v) {
-        unset($values['synonyms']['synonyms'][$k]);
-      }
-    }
-    $values['synonyms']['synonyms'] = array_values($values['synonyms']['synonyms']);
-    $settings = synonyms_vocabulary_settings($vocabulary);
-    $settings = $values['synonyms'] + $settings;
-    synonyms_vocabulary_settings_save($vocabulary, $settings);
-  }
-}
-
-/**
- * Page callback: Outputs JSON for taxonomy autocomplete suggestions.
- *
- * This callback outputs term name suggestions in response to Ajax requests
- * made by the synonyms autocomplete widget for taxonomy term reference
- * fields. The output is a JSON object of plain-text term suggestions,
- * keyed by the user-entered value with the completed term name appended.
- * Term names containing commas are wrapped in quotes. The search is made
- * with consideration of synonyms.
- *
- * @param string $field_name
- *   The name of the term reference field.
- * @param string $tags_typed
- *   (optional) A comma-separated list of term names entered in the
- *   autocomplete form element. Only the last term is used for autocompletion.
- *   Defaults to '' (an empty string).
- */
-function synonyms_autocomplete($field_name, $tags_typed = '') {
-  // How many suggestions maximum we are able to output.
-  $max_suggestions = 10;
-
-  // If the request has a '/' in the search text, then the menu system will have
-  // split it into multiple arguments, recover the intended $tags_typed.
-  $args = func_get_args();
-  // Shift off the $field_name argument.
-  array_shift($args);
-  $tags_typed = implode('/', $args);
-
-  // Make sure the field exists and is a taxonomy field.
-  if (!($field = field_info_field($field_name)) || $field['type'] != 'taxonomy_term_reference') {
-    // Error string. The JavaScript handler will realize this is not JSON and
-    // will display it as debugging information.
-    print t('Taxonomy field @field_name not found.', array('@field_name' => $field_name));
-    exit;
-  }
-
-  // The user enters a comma-separated list of tags. We only autocomplete the
-  // last tag.
-  $tags_typed = drupal_explode_tags($tags_typed);
-  $tag_last = drupal_strtolower(array_pop($tags_typed));
-
-  $term_matches = array();
-  if ($tag_last != '') {
-    // Part of the criteria for the query come from the field's own settings.
-    $vocabularies = array();
-    $tmp = taxonomy_vocabulary_get_names();
-    foreach ($field['settings']['allowed_values'] as $tree) {
-      $vocabularies[$tmp[$tree['vocabulary']]->vid] = $tree['vocabulary'];
-    }
-    $vocabularies = taxonomy_vocabulary_load_multiple(array_keys($vocabularies));
-
-    // Firstly getting a list of tids that match by $term->name.
-    $query = db_select('taxonomy_term_data', 't');
-    $query->addTag('translatable');
-    $query->addTag('term_access');
-
-    // Do not select already entered terms.
-    if (!empty($tags_typed)) {
-      $query->condition('t.name', $tags_typed, 'NOT IN');
-    }
-    // Select rows that match by term name.
-    $tags_return = $query
-      ->fields('t', array('tid', 'name'))
-      ->condition('t.vid', array_keys($vocabularies))
-      ->condition('t.name', '%' . db_like($tag_last) . '%', 'LIKE')
-      ->range(0, $max_suggestions)
-      ->execute()
-      ->fetchAllKeyed();
-
-    // Converting results into another format.
-    foreach ($tags_return as $tid => $name) {
-      $tags_return[$tid] = array('name' => $name);
-    }
-
-    $synonym_tids = array();
-    // Now we go vocabulary by vocabulary looking through synonym fields.
-    foreach ($vocabularies as $vocabulary) {
-      // Now we go a synonym field by synonym field gathering suggestions.
-      // Since officially EntityFieldQuery doesn't support OR conditions
-      // we are enforced to go a field by field querying multiple times the DB.
-      $bundle = field_extract_bundle('taxonomy_term', $vocabulary);
-      foreach (synonyms_synonyms_fields($vocabulary) as $field) {
-        $field = field_info_field($field);
-        $instance = field_info_instance('taxonomy_term', $field['field_name'], $bundle);
-        if (count($tags_return) + count($synonym_tids) > $max_suggestions) {
-          // We have collected enough suggestions and the ongoing queries
-          // will be just a waste of time.
-          break;
-        }
-        $query = new EntityFieldQuery();
-        $query->entityCondition('entity_type', 'taxonomy_term')
-            ->entityCondition('bundle', $vocabulary->machine_name);
-
-        // We let the class that defines this field type as a source of synonyms
-        // filter our and provide its suggestions based on this field.
-        $class = synonyms_extractor_info($field['type']);
-        $class::processEntityFieldQuery($tag_last, $query, $field, $instance);
-
-        if (!empty($tags_typed)) {
-          $query->propertyCondition('name', $tags_typed, 'NOT IN');
-        }
-        if (!empty($tags_return)) {
-          // We don't want to search among the terms already found by term name.
-          $query->entityCondition('entity_id', array_keys($tags_return), 'NOT IN');
-        }
-        if (!empty($synonym_tids)) {
-          // Nor we want to search among the terms already mached by previous
-          // synonym fields.
-          $query->entityCondition('entity_id', $synonym_tids, 'NOT IN');
-        }
-        $tmp = $query->execute();
-        if (!empty($tmp)) {
-          // Merging the results.
-          $tmp = array_keys($tmp['taxonomy_term']);
-          $synonym_tids = array_merge($synonym_tids, $tmp);
-        }
-      }
-    }
-    if (!empty($synonym_tids)) {
-      $synonym_tids = array_slice($synonym_tids, 0, $max_suggestions - count($tags_return));
-      foreach (taxonomy_term_load_multiple($synonym_tids) as $synonym_term) {
-        $tags_return[$synonym_term->tid] = array('name' => $synonym_term->name);
-        // Additionally we have to find out which synonym triggered inclusion
-        // of this term.
-        $synonyms = synonyms_get_term_synonyms($synonym_term);
-        foreach ($synonyms as $item) {
-          if (strpos(mb_strtoupper($item['value'], 'UTF-8'), mb_strtoupper($tag_last, 'UTF-8')) !== FALSE) {
-            $tags_return[$synonym_term->tid]['synonym'] = $item['value'];
-            break;
-          }
-        }
-      }
-    }
-    $prefix = count($tags_typed) ? drupal_implode_tags($tags_typed) . ', ' : '';
-
-    // Now formatting the results.
-    foreach ($tags_return as $tid => $info) {
-      $n = $info['name'];
-      // Term names containing commas or quotes must be wrapped in quotes.
-      if (strpos($info['name'], ',') !== FALSE || strpos($info['name'], '"') !== FALSE) {
-        $n = '"' . str_replace('"', '""', $info['name']) . '"';
-      }
-
-      if (isset($info['synonym'])) {
-        $display_name = t('@synonym, synonym of %term', array('@synonym' => $info['synonym'], '%term' => $info['name']));
-      }
-      else {
-        $display_name = check_plain($info['name']);
-      }
-      $term_matches[$prefix . $n] = $display_name;
-    }
-  }
-  drupal_json_output($term_matches);
-}
-
 /**
  * Try to find a term by its name or synonym.
  *
- * To maximize the match trimming and case-insensetive comparison is used.
+ * To maximize the match trimming and case-insensitive comparison is used.
  *
  * @param string $name
- *   The string to be searched for its {taxonomy_term}.tid
+ *   The string to be searched for its {taxonomy_term_data}.tid
  * @param object $vocabulary
  *   Fully loaded vocabulary object in which you wish to search
  * @param int $parent
  *   Optional. In case you want to narrow your search scope, this parameter
- *   takes in the {taxonomy_term}.tid of the parent term, letting you search
- *   only among its children
+ *   takes in the {taxonomy_term_data}.tid of the parent term, letting you
+ *   search only among its children
  *
  * @return int
- *   If the look up was successfull returns the {taxonomy_term}.tid of the
+ *   If the look up was successful returns the {taxonomy_term_data}.tid of the
  *   found term, otherwise returns 0
  */
 function synonyms_get_term_by_synonym($name, $vocabulary, $parent = 0) {
@@ -487,9 +360,9 @@ function synonyms_get_term_by_synonym($name, $vocabulary, $parent = 0) {
     }
 
     // We additionally scan through the synonyms.
-    $synonyms = synonyms_get_term_synonyms($term);
+    $synonyms = synonyms_get_sanitized($term);
     foreach ($synonyms as $item) {
-      if (mb_strtoupper($item['safe_value'], 'UTF-8') == $name) {
+      if (mb_strtoupper($item, 'UTF-8') == $name) {
         return $term->tid;
       }
     }
@@ -503,21 +376,21 @@ function synonyms_get_term_by_synonym($name, $vocabulary, $parent = 0) {
 /**
  * Look up a term considering synonyms and if nothing found add one.
  *
- * This function is useful for automated creation of new terms
- * as it won't generate the same terms over and over again.
+ * This function is useful for automated creation of new terms as it won't
+ * generate the same terms over and over again.
  *
  * @param string $name
- *   The string to be searched for its {taxonomy_term}.tid
+ *   The string to be searched for its {taxonomy_term_data}.tid
  * @param object $vocabulary
  *   Fully loaded vocabulary object in which you wish to search
  * @param int $parent
  *   Optional. In case you want to narrow your search scope, this parameter
- *   takes in the {taxonomy_term}.tid of the parent term, letting you search
- *   only among its children
+ *   takes in the {taxonomy_term_data}.tid of the parent term, letting you
+ *   search only among its children
  *
  * @return int
- *   If a term already exists, its {taxonomy_term}.tid is returned,
- *   otherwise it creates a new term and returns its {taxonomy_term}.tid
+ *   If a term already exists, its {taxonomy_term_data}.tid is returned,
+ *   otherwise it creates a new term and returns its {taxonomy_term_data}.tid
  */
 function synonyms_add_term_by_synonym($name, $vocabulary, $parent = 0) {
   $tid = synonyms_get_term_by_synonym($name, $vocabulary, $parent);
@@ -544,6 +417,40 @@ function synonyms_add_term_by_synonym($name, $vocabulary, $parent = 0) {
   return 0;
 }
 
+/**
+ * Retrieve a list of sanitized synonyms of a taxonomy term.
+ *
+ * @param $item object
+ *   Fully loaded taxonomy term
+ *
+ * @return array
+ *   List of sanitized synonyms of a taxonomy term
+ */
+function synonyms_get_sanitized($item) {
+  $synonyms = array();
+  foreach (synonyms_get_term_synonyms($item) as $synonym) {
+    $synonyms[] = $synonym['safe_value'];
+  }
+  return $synonyms;
+}
+
+/**
+ * Retrieve a list of raw synonyms of a taxonomy term.
+ *
+ * @param $item object
+ *   Fully loaded taxonomy term
+ *
+ * @return array
+ *   List of raw synonyms of a taxonomy term
+ */
+function synonyms_get_raw($item) {
+  $synonyms = array();
+  foreach (synonyms_get_term_synonyms($item) as $synonym) {
+    $synonyms[] = $synonym['value'];
+  }
+  return $synonyms;
+}
+
 /**
  * Public function for retrieving synonyms of a taxonomy term.
  *
@@ -552,10 +459,10 @@ function synonyms_add_term_by_synonym($name, $vocabulary, $parent = 0) {
  *
  * @return array
  *   Array of synonyms, if synonyms are disabled for the taxonomy term's
- *   vocabulary, an empty array is returned. Each synonyms array consists of the
- *   following keys:
- *     value - the value of a synonym as it was input by user
- *     safe_value - a sanitized value of a synonym
+ *   vocabulary, an empty array is returned. Each synonym subarray consists of
+ *   the following keys:
+ *   - value: (string) the value of a synonym as it was input by user
+ *   - safe_value: (string) a sanitized value of a synonym
  */
 function synonyms_get_term_synonyms($term) {
   $synonyms = array();
@@ -568,18 +475,15 @@ function synonyms_get_term_synonyms($term) {
 
     if (is_array($items) && !empty($items)) {
       $class = synonyms_extractor_info($field['type']);
-      $synonyms = array_merge($synonyms, $class::synonymsExtract($items, $field, $instance, $term, 'taxonomy_term'));
+      foreach (call_user_func(array($class, 'synonymsExtract'), $items, $field, $instance, $term, 'taxonomy_term') as $synonym) {
+        $synonyms[] = array(
+          'value' => $synonym,
+          'safe_value' => check_plain($synonym),
+        );
+      }
     }
   }
 
-  // Applying sanitization to the extracted synonyms.
-  foreach ($synonyms as $k => $v) {
-    $synonyms[$k] = array(
-      'value' => $v,
-      'safe_value' => check_plain($v),
-    );
-  }
-
   return $synonyms;
 }
 
@@ -626,7 +530,7 @@ function synonyms_add_entity_as_synonym($trunk_entity, $trunk_entity_type, $fiel
   $trunk_entity_ids = entity_extract_ids($trunk_entity_type, $trunk_entity);
   $instance = field_info_instance($trunk_entity_type, $field['field_name'], $trunk_entity_ids[2]);
 
-  $extra_items = $extractor::mergeEntityAsSynonym($items, $field, $instance, $synonym_entity, $synonym_entity_type);
+  $extra_items = call_user_func(array($extractor, 'mergeEntityAsSynonym'), $items, $field, $instance, $synonym_entity, $synonym_entity_type);
 
   // Merging extracted synonym items into the values of the field that already
   // exist.
@@ -655,7 +559,7 @@ function synonyms_add_entity_as_synonym($trunk_entity, $trunk_entity_type, $fiel
 function synonyms_synonyms_fields($vocabulary) {
   $settings = synonyms_vocabulary_settings($vocabulary);
   if (!isset($settings['synonyms']) || !is_array($settings['synonyms'])) {
-    // Wierd as normally we expect to see here at least an empty array but
+    // Weird as normally we expect to see here at least an empty array but
     // no problem. We simply initialize it.
     $settings['synonyms'] = array();
   }
@@ -717,13 +621,16 @@ function synonyms_synonyms_enforce($vocabulary, $fields) {
  * @return array
  *   Array of current synonyms settings for the supplied vocabulary.
  *   Should include the following keys:
- *     synonyms - array of field names that are enabled as source of synonyms
+ *   - synonyms: (array) array of field names that are enabled as source of
+ *     synonyms
  */
 function synonyms_vocabulary_settings($vocabulary) {
   $settings = array();
 
   if (isset($vocabulary->vid)) {
-    $settings = variable_get('synonyms_settings_' . $vocabulary->vid, array());
+    $settings = variable_get('synonyms_settings_' . $vocabulary->vid, array(
+      'synonyms' => array(),
+    ));
   }
 
   return $settings;
@@ -740,6 +647,15 @@ function synonyms_vocabulary_settings($vocabulary) {
  *   synonyms_vocabulary_settings()
  */
 function synonyms_vocabulary_settings_save($vocabulary, $settings) {
+  // If source of synonyms has changed for this vocabulary, we have to trigger
+  // search re-indexing on all the nodes that reference at least 1 term from
+  // this vocabulary.
+  $previous_settings = synonyms_vocabulary_settings($vocabulary);
+  if (implode('', $settings['synonyms']) != implode('', $previous_settings['synonyms'])) {
+    module_load_include('inc', 'synonyms', 'synonyms.pages');
+    synonyms_reindex_nodes_by_vocabulary($vocabulary);
+  }
+
   variable_set('synonyms_settings_' . $vocabulary->vid, $settings);
 
   // Now enforcing each setting.
@@ -772,7 +688,7 @@ function synonyms_default_field_ensure() {
 }
 
 /**
- * Extract instances that are applicapable for being source of synonyms.
+ * Extract instances that are applicable for being source of synonyms.
  *
  * Walk through all instances of a vocabulary and extract only valid candidates
  * for becoming a source of synonyms for the vocabulary terms.
@@ -783,15 +699,25 @@ function synonyms_default_field_ensure() {
  * @return array
  *   Array of instance arrays
  */
-function synonyms_instances_extract_applicapable($vocabulary) {
-  $applicapable_field_types = array_keys(synonyms_extractor_info());
-  $applicapable = array();
+function synonyms_instances_extract_applicable($vocabulary) {
+  $applicable_field_types = array_keys(synonyms_extractor_info());
+  $applicable = array();
   $bundle = field_extract_bundle('taxonomy_term', $vocabulary);
   foreach (field_info_instances('taxonomy_term', $bundle) as $instance) {
     $field = field_info_field($instance['field_name']);
-    if (in_array($field['type'], $applicapable_field_types)) {
-      $applicapable[] = $instance;
+    if (in_array($field['type'], $applicable_field_types)) {
+      $applicable[] = $instance;
     }
   }
-  return $applicapable;
+  return $applicable;
+}
+
+/**
+ * Implements hook_views_api().
+ */
+function synonyms_views_api() {
+  return array(
+    'api' => 3,
+    'path' => drupal_get_path('module', 'synonyms') . '/views',
+  );
 }

+ 263 - 103
sites/all/modules/contrib/taxonomy/synonyms/synonyms.test

@@ -38,7 +38,7 @@ abstract class SynonymsWebTestCase extends DrupalWebTestCase {
    *   Fully loaded taxonomy vocabulary object
    *
    * @return object
-   *   Fully loaded taxonomy term object of the last interted term into
+   *   Fully loaded taxonomy term object of the last inserted term into
    *   the specified vocabulary
    */
   protected function getLastTerm($vocabulary) {
@@ -175,28 +175,28 @@ class SynonymsSynonymsWebTestCase extends SynonymsWebTestCase {
     // Asserting the presence of synonym string.
     $this->assertText($synonym, 'The synonym string is present on taxonomy term view page');
 
-    // Testing the function synonyms_get_term_synonyms().
-    $synonyms = synonyms_get_term_synonyms($no_synonyms_term);
-    $this->assertTrue(empty($synonyms), 'Successfully called synonyms_get_term_synonyms() for a term without synonyms.');
-    $synonyms = synonyms_get_term_synonyms($one_synonym_term);
-    $this->assertTrue(count($synonyms) == 1 && $synonyms[0]['value'] == $synonym1, 'Sucessfully called synonyms_get_term_synonyms for a term with single synonym.');
-    $synonyms = synonyms_get_term_synonyms($two_synonyms_term);
-    $this->assertTrue(count($synonyms) == 2 && $synonyms[0]['value'] == $synonym1 && $synonyms[1]['value'] == $synonym2, 'Sucessfully called synonyms_get_term_synonyms for a term with 2 synonyms.');
+    // Testing the 'synonyms' property of 'taxonomy_term' entity.
+    $synonyms = synonyms_get_sanitized($no_synonyms_term);
+    $this->assertTrue(empty($synonyms), 'Successfully retrieved synonyms_get_sanitized() for a term without synonyms.');
+    $synonyms = synonyms_get_sanitized($one_synonym_term);
+    $this->assertTrue(count($synonyms) == 1 && $synonyms[0] == $synonym1, 'Successfully retrieved synonyms_get_sanitized() for a term with a single synonym.');
+    $synonyms = synonyms_get_sanitized($two_synonyms_term);
+    $this->assertTrue(count($synonyms) == 2 && $synonyms[0] == $synonym1 && $synonyms[1] == $synonym2, 'Successfully retrieved synonyms_get_sanitized() for a term with 2 synonyms.');
 
     // Testing the function synonyms_get_term_by_synonym().
     $tid = synonyms_get_term_by_synonym(drupal_strtoupper($synonym), $this->vocabularies['enabled'], $term_parent->tid);
-    $this->assertEqual($tid, $term->tid, 'Sucessfully looked up term by its synonym.');
+    $this->assertEqual($tid, $term->tid, 'Successfully looked up term by its synonym.');
     $tid = synonyms_get_term_by_synonym(drupal_strtoupper($name), $this->vocabularies['enabled'], $term_parent->tid);
-    $this->assertEqual($tid, $term->tid, 'Sucessfully looked up term by its name.');
+    $this->assertEqual($tid, $term->tid, 'Successfully looked up term by its name.');
     // Now submitting a non-existing name.
     $tid = synonyms_get_term_by_synonym($parent_synonym, $this->vocabularies['enabled'], $term_parent->tid);
     $this->assertEqual($tid, 0, 'synonyms_get_term_by_synonym() returns 0 if the term is not found (considering $parent parameter).');
 
     // Testing the function synonyms_add_term_by_synonym().
     $tid = synonyms_add_term_by_synonym(drupal_strtolower($name), $this->vocabularies['enabled'], $term_parent->tid);
-    $this->assertEqual($tid, $term->tid, 'Sucessfully called synonyms_add_term_by_synonym() on an existing title and no new term was created.');
+    $this->assertEqual($tid, $term->tid, 'Successfully called synonyms_add_term_by_synonym() on an existing title and no new term was created.');
     $tid = synonyms_add_term_by_synonym(drupal_strtolower($synonym), $this->vocabularies['enabled'], $term_parent->tid);
-    $this->assertEqual($tid, $term->tid, 'Sucessfully called synonyms_add_term_by_synonym() on an existing synonym and no new term was created.');
+    $this->assertEqual($tid, $term->tid, 'Successfully called synonyms_add_term_by_synonym() on an existing synonym and no new term was created.');
     drupal_static_reset();
     $tid = synonyms_add_term_by_synonym($parent_synonym, $this->vocabularies['enabled'], $term_parent->tid);
     $new_term = taxonomy_term_load($tid);
@@ -217,13 +217,13 @@ class SynonymsSynonymsWebTestCase extends SynonymsWebTestCase {
     $term = array_pop(entity_load('taxonomy_term', array($term->tid), array(), TRUE));
     $this->assertFalse(isset($term->{SYNONYMS_DEFAULT_FIELD_NAME}), 'The term no longer has synonyms field after disabling "synonyms" feature for a vocabulary');
 
-    // Testing synonyms_get_term_synonums() function.
-    $synonyms = synonyms_get_term_synonyms($no_synonyms_term);
-    $this->assertTrue(empty($synonyms), 'Successfully called synonyms_get_term_synonyms() on a term without synonyms after disabling "synonyms" feature');
-    $synonyms = synonyms_get_term_synonyms($one_synonym_term);
-    $this->assertTrue(empty($synonyms), 'Successfully called synonyms_get_term_synonyms() on a term with single synonym after disabling "synonyms" feature');
-    $synonyms = synonyms_get_term_synonyms($two_synonyms_term);
-    $this->assertTrue(empty($synonyms), 'Successfully called synonyms_get_term_synonyms() on a term with 2 synonyms after disabling "synonyms" feature');
+    // Testing the 'synonyms' property of 'taxonomy_term' entity.
+    $synonyms = synonyms_get_sanitized($no_synonyms_term);
+    $this->assertTrue(empty($synonyms), 'Successfully retrieved synonyms_get_sanitized() on a term without synonyms after disabling "synonyms" feature');
+    $synonyms = synonyms_get_sanitized($one_synonym_term);
+    $this->assertTrue(empty($synonyms), 'Successfully retrieved synonyms_get_sanitized() on a term with a single synonym after disabling "synonyms" feature');
+    $synonyms = synonyms_get_sanitized($two_synonyms_term);
+    $this->assertTrue(empty($synonyms), 'Successfully retrieved synonyms_get_sanitized() on a term with 2 synonyms after disabling "synonyms" feature');
 
     $tid = synonyms_get_term_by_synonym(drupal_strtoupper($synonym), $this->vocabularies['enabled']);
     $this->assertEqual($tid, 0, 'synonyms_get_term_by_synonym() returns 0 after disabling "synonyms" feature for a vocabulary');
@@ -247,19 +247,49 @@ class SynonymsSynonymsWebTestCase extends SynonymsWebTestCase {
 }
 
 /**
- * Test "Synonym friednly autocomplete" widget of Synonyms module.
+ * Test "Synonyms friendly autocomplete" widget of Synonyms module.
  */
 class AutocompleteSynonymsWebTestCase extends SynonymsWebTestCase {
+
+  /**
+   * Array of fully loaded vocabulary entities to be used in this test.
+   *
+   * Array is keyed by the corresponding vocabulary's machine name.
+   *
+   * @var array
+   */
   protected $vocabularies = array(
     'enabled' => TRUE,
     'disabled' => FALSE,
   );
 
+  /**
+   * Array of fully loaded taxonomy term entities to be used in this test.
+   *
+   * Term entities are grouped by machine name of the vocabulary to which they
+   * belong.
+   *
+   * @var array
+   */
   protected $terms = array(
     'enabled' => array(),
     'disabled' => array(),
   );
 
+  /**
+   * Entity type to which a term reference field with tested widget is attached.
+   *
+   * @var string
+   */
+  protected $entity_type = 'node';
+
+  /**
+   * Bundle to which a term reference field with tested widget is attached.
+   *
+   * @var string
+   */
+  protected $bundle = 'synonyms_test_content';
+
   /**
    * GetInfo method.
    */
@@ -292,7 +322,7 @@ class AutocompleteSynonymsWebTestCase extends SynonymsWebTestCase {
     // Creating a test content type.
     $this->drupalPost('admin/structure/types/add', array(
       'name' => 'Synonyms Test Content',
-      'type' => 'synonyms_test_content',
+      'type' => $this->bundle,
     ), 'Save content type');
 
     // Attaching each vocabulary term reference field to the new content type.
@@ -313,8 +343,8 @@ class AutocompleteSynonymsWebTestCase extends SynonymsWebTestCase {
     // Flushing static cache.
     _field_info_collate_fields(TRUE);
 
-    // Now creating taxonomy tree for each vocabularies.
-    // For synonym-disbaled vocabulary just one term is good enough.
+    // Now creating taxonomy tree for each vocabulary.
+    // For synonym-disabled vocabulary just a few terms is good enough.
     $name = $this->randomName();
     $this->drupalPost('admin/structure/taxonomy/disabled/add', array(
       'name' => $name,
@@ -355,7 +385,7 @@ class AutocompleteSynonymsWebTestCase extends SynonymsWebTestCase {
       SYNONYMS_DEFAULT_FIELD_NAME . '[' . LANGUAGE_NONE . '][0][value]' => $name . $this->randomName(),
     ), 'Save');
     $this->terms['enabled']['name_similar_synonym'] = $this->getLastTerm($this->vocabularies['enabled']);
-    $name = 'simiar_synonyms_';
+    $name = 'similar_synonyms_';
     $this->drupalPost('admin/structure/taxonomy/enabled/add', array(
       'name' => $this->randomName(),
       SYNONYMS_DEFAULT_FIELD_NAME . '[' . LANGUAGE_NONE . '][0][value]' => $name . $this->randomName(),
@@ -379,8 +409,10 @@ class AutocompleteSynonymsWebTestCase extends SynonymsWebTestCase {
   /**
    * Test auto-creation functionality.
    *
-   * Test the auto-creation funcationality of the synonym friendly autocomplete
-   * widget type.
+   * Test the auto-creation functionality of the synonym friendly autocomplete
+   * widget type. Along the way it tests whether synonyms, submitted into the
+   * widget's textfield are converted into the terms, synonyms of which they
+   * are.
    */
   public function testAutoCreation() {
     // Trying enabled auto creation.
@@ -391,12 +423,13 @@ class AutocompleteSynonymsWebTestCase extends SynonymsWebTestCase {
     $new_term_name = $this->randomName();
     $this->drupalPost('node/add/synonyms-test-content', array(
       'title' => $this->randomName(),
-      'field_synonyms_term_enabled[' . LANGUAGE_NONE . ']' => $this->terms['enabled']['no_synonyms']->name . ', ' . $new_term_name,
+      'field_synonyms_term_enabled[' . LANGUAGE_NONE . ']' => $this->terms['enabled']['no_synonyms']->name . ', ' . $new_term_name . ', ' . $this->terms['enabled']['one_synonym']->{SYNONYMS_DEFAULT_FIELD_NAME}[LANGUAGE_NONE][0]['value'],
     ), 'Save');
     $this->assertText($this->terms['enabled']['no_synonyms']->name, 'Existing term was assigned to the new node');
-    $this->assertText($new_term_name, 'Auto created term was assigned to the new node');
+    $this->assertText($new_term_name, 'Auto created term was assigned to the new node when Auto creation is on.');
+    $this->assertText($this->terms['enabled']['one_synonym']->name, 'Submitting a synonym into autocomplete widget results in the term, to which the synonym belongs, being assigned to the just created entity (when Auto creation is on).');
     $term = $this->getLastTerm($this->vocabularies['enabled']);
-    $this->assertEqual($term->name, $new_term_name, 'The auto created term has been created');
+    $this->assertEqual($term->name, $new_term_name, 'The auto created term has been created when Auto creation is on.');
 
     // Trying disabled auto creation.
     $this->drupalPost('admin/structure/types/manage/synonyms-test-content/fields/field_synonyms_term_enabled', array(
@@ -406,12 +439,13 @@ class AutocompleteSynonymsWebTestCase extends SynonymsWebTestCase {
     $new_term_name = $this->randomName();
     $this->drupalPost('node/add/synonyms-test-content', array(
       'title' => $this->randomName(),
-      'field_synonyms_term_enabled[und]' => $this->terms['enabled']['no_synonyms']->name . ', ' . $new_term_name,
+      'field_synonyms_term_enabled[' . LANGUAGE_NONE . ']' => $this->terms['enabled']['no_synonyms']->name . ', ' . $new_term_name . ', ' . $this->terms['enabled']['one_synonym']->{SYNONYMS_DEFAULT_FIELD_NAME}[LANGUAGE_NONE][0]['value'],
     ), 'Save');
     $this->assertText($this->terms['enabled']['no_synonyms']->name, 'Existing term was assigned to the new node');
-    $this->assertNoText($new_term_name, 'Auto created term was not assigned to the new node');
+    $this->assertNoText($new_term_name, 'Auto created term was not assigned to the new node when Auto creation is off.');
+    $this->assertText($this->terms['enabled']['one_synonym']->name, 'Submitting a synonym into autocomplete widget results in the term, to which the synonym belongs, being assigned to the just created entity (when Auto creation is off).');
     $term = $this->getLastTerm($this->vocabularies['enabled']);
-    $this->assertNotEqual($term->name, $new_term_name, 'The auto created term has not been created');
+    $this->assertNotEqual($term->name, $new_term_name, 'The auto created term has not been created when Auto creation is off.');
   }
 
   /**
@@ -449,7 +483,7 @@ class AutocompleteSynonymsWebTestCase extends SynonymsWebTestCase {
     $assertions[] = array(
       'vocabulary' => 'disabled',
       'input' => $terms['term1']->name . ',' . drupal_strtoupper(drupal_substr($terms['term1']->name, 1, -1)),
-      'response' => array($terms['term1']->name . ', ' . $this->terms['disabled']['term1_longer_name']->name => $this->terms['disabled']['term1_longer_name']->name),
+      'response' => array($terms['term1']->name . ', ' . $terms['term1_longer_name']->name => $terms['term1_longer_name']->name),
       'message' => 'Submitting one term already chosen along with a name similar to 2 existing term names into a disabled synonyms vocabulary',
     );
     $assertions[] = array(
@@ -475,7 +509,7 @@ class AutocompleteSynonymsWebTestCase extends SynonymsWebTestCase {
     );
     $assertions[] = array(
       'vocabulary' => 'enabled',
-      'input' => $terms['one_synonym']->name . ',' . $terms['one_synonym']->synonyms_synonyms[LANGUAGE_NONE][0]['safe_value'],
+      'input' => $terms['one_synonym']->name . ',' . $terms['one_synonym']->{SYNONYMS_DEFAULT_FIELD_NAME}[LANGUAGE_NONE][0]['safe_value'],
       'response' => array(),
       'message' => 'Submitting a synonym of a term over again into an enabled synonyms vocabulary',
     );
@@ -487,42 +521,136 @@ class AutocompleteSynonymsWebTestCase extends SynonymsWebTestCase {
         'message' => 'Submitting a name similar to ' . $k . ' term into an enabled synonyms vocabulary',
       );
 
-      $synonyms = field_get_items('taxonomy_term', $terms[$k], 'synonyms_synonyms');
+      $synonyms = field_get_items('taxonomy_term', $terms[$k], SYNONYMS_DEFAULT_FIELD_NAME);
       if (is_array($synonyms)) {
         foreach ($synonyms as $delta => $item) {
           $assertions[] = array(
             'vocabulary' => 'enabled',
             'input' => drupal_strtolower(drupal_substr($item['safe_value'], 1, -1)),
             'response' => array($terms[$k]->name => $this->synonymAutocompleteResult($terms[$k], $item['safe_value'])),
-            'message' => 'Submitting a name similar to synonym#' . $delta . ' of the term ' . $k . 'into an enabled synonyms vocabulary',
+            'message' => 'Submitting a name similar to synonym#' . $delta . ' of the term ' . $k . ' into an enabled synonyms vocabulary',
           );
         }
       }
     }
     $assertions[] = array(
       'vocabulary' => 'enabled',
-      'input' => $terms['name_similar_synonym']->name,
-      'response' => array($terms['name_similar_synonym']->name => $terms['name_similar_synonym']->name),
-      'message' => 'Submitting a keyword similar to name and synonym of a term into an enabled synonyms vocabulary',
+      'input' => 'one_term_name_another_synonym_',
+      'response' => array(
+        $terms['name_another_synonym']->name => $terms['name_another_synonym']->name,
+        $terms['synonym_another_name']->name => $this->synonymAutocompleteResult($terms['synonym_another_name'], $terms['synonym_another_name']->{SYNONYMS_DEFAULT_FIELD_NAME}[LANGUAGE_NONE][0]['safe_value']),
+      ),
+      'message' => 'Submitting a keyword similar to name of one term and synonym of another into an enabled synonyms vocabulary yields both included in the results',
+    );
+
+    foreach ($assertions as $v) {
+      $this->assertAutocompleteMenuPath($v);
+    }
+  }
+
+  /**
+   * Test 'Suggestions Size' setting of synonyms-friendly autocomplete widget.
+   */
+  function testWidgetSettingsSuggestionSize() {
+    $suggestion_size = 1;
+    $this->drupalPost('admin/structure/types/manage/synonyms-test-content/fields/field_synonyms_term_disabled', array(
+      'instance[widget][settings][suggestion_size]' => $suggestion_size,
+    ), 'Save settings');
+    $this->drupalPost('admin/structure/types/manage/synonyms-test-content/fields/field_synonyms_term_enabled', array(
+      'instance[widget][settings][suggestion_size]' => $suggestion_size,
+    ), 'Save settings');
+
+    $assertions = array();
+
+    // If size was bigger than 1, we'd get suggested 2 terms: 'term1' and
+    // 'term1_longer_name'.
+    $assertions[] = array(
+      'vocabulary' => 'disabled',
+      'input' => $this->terms['disabled']['term1']->name,
+      'response' => array($this->terms['disabled']['term1']->name => $this->terms['disabled']['term1']->name),
+      'message' => 'Suggestions Size option is respected in autocomplete widget for term suggestion entries.',
+    );
+
+    $assertions[] = array(
+      'vocabulary' => 'enabled',
+      'input' => $this->terms['enabled']['name_similar_synonym']->name,
+      'response' => array($this->terms['enabled']['name_similar_synonym']->name => $this->terms['enabled']['name_similar_synonym']->name),
+      'message' => 'Suggestions Size option is respected in autocomplete widget for term and synonym suggestion entries.'
     );
+
     $assertions[] = array(
       'vocabulary' => 'enabled',
-      'input' => 'simiar_synonyms_',
-      'response' => array($terms['similar_synonyms']->name => $this->synonymAutocompleteResult($terms['similar_synonyms'], $terms['similar_synonyms']->synonyms_synonyms[LANGUAGE_NONE][0]['safe_value'])),
-      'message' => 'Submitting a keyword similar to name and synonym of a term into an enabled synonyms vocabulary',
+      'input' => drupal_substr($this->terms['enabled']['similar_synonyms']->{SYNONYMS_DEFAULT_FIELD_NAME}[LANGUAGE_NONE][0]['value'], 0, 8),
+      'response' => array($this->terms['enabled']['similar_synonyms']->name => $this->synonymAutocompleteResult($this->terms['enabled']['similar_synonyms'], $this->terms['enabled']['similar_synonyms']->{SYNONYMS_DEFAULT_FIELD_NAME}[LANGUAGE_NONE][0]['value'])),
+      'message' => 'Suggestions Size option is respected in autocomplete widget for synonyms suggestion entries.'
     );
+
+    foreach ($assertions as $assertion) {
+      $this->assertAutocompleteMenuPath($assertion);
+    }
+  }
+
+  /**
+   * Test 'Suggest only one entry per term' setting of autocomplete widget.
+   */
+  function testWidgetSettingsSuggestOnlyUnique() {
+    $assertions = array();
+
+    // Testing disabled "Suggest only one entry per term" setting.
     $assertions[] = array(
       'vocabulary' => 'enabled',
-      'input' => 'one_term_name_another_synonym_',
+      'input' => $this->terms['enabled']['name_similar_synonym']->name,
       'response' => array(
-        $terms['name_another_synonym']->name => $terms['name_another_synonym']->name,
-        $terms['synonym_another_name']->name => $this->synonymAutocompleteResult($terms['synonym_another_name'], $terms['synonym_another_name']->synonyms_synonyms[LANGUAGE_NONE][0]['safe_value']),
+        $this->terms['enabled']['name_similar_synonym']->name => $this->terms['enabled']['name_similar_synonym']->name,
+        $this->terms['enabled']['name_similar_synonym']->name . ' ' => $this->synonymAutocompleteResult($this->terms['enabled']['name_similar_synonym'], $this->terms['enabled']['name_similar_synonym']->{SYNONYMS_DEFAULT_FIELD_NAME}[LANGUAGE_NONE][0]['value']),
       ),
-      'message' => 'Submitting a keyword similar to name of one term and synonym of another into an enabled synonyms vocabulary yields both included in the results',
+      'message' => 'Both term and its synonym are shown when "Suggest only one entry per term" is off.'
     );
 
-    foreach ($assertions as $v) {
-      $this->assertAutocompleteMenuPath($v);
+    $assertions[] = array(
+      'vocabulary' => 'enabled',
+      'input' => drupal_substr($this->terms['enabled']['similar_synonyms']->{SYNONYMS_DEFAULT_FIELD_NAME}[LANGUAGE_NONE][0]['value'], 0, 8),
+      'response' => array(
+        $this->terms['enabled']['similar_synonyms']->name => $this->synonymAutocompleteResult($this->terms['enabled']['similar_synonyms'], $this->terms['enabled']['similar_synonyms']->{SYNONYMS_DEFAULT_FIELD_NAME}[LANGUAGE_NONE][0]['value']),
+        $this->terms['enabled']['similar_synonyms']->name . ' ' => $this->synonymAutocompleteResult($this->terms['enabled']['similar_synonyms'], $this->terms['enabled']['similar_synonyms']->{SYNONYMS_DEFAULT_FIELD_NAME}[LANGUAGE_NONE][1]['value']),
+      ),
+      'message' => 'Multiple synonyms are shown when "Suggest only one entry per term" is off.'
+    );
+
+    foreach ($assertions as $assertion) {
+      $this->assertAutocompleteMenuPath($assertion);
+    }
+
+    // Testing enabled "Suggest only one entry per term" setting.
+    $this->drupalPost('admin/structure/types/manage/synonyms-test-content/fields/field_synonyms_term_disabled', array(
+      'instance[widget][settings][suggest_only_unique]' => TRUE,
+    ), 'Save settings');
+    $this->drupalPost('admin/structure/types/manage/synonyms-test-content/fields/field_synonyms_term_enabled', array(
+      'instance[widget][settings][suggest_only_unique]' => TRUE,
+    ), 'Save settings');
+
+    $assertions = array();
+
+    $assertions[] = array(
+      'vocabulary' => 'enabled',
+      'input' => $this->terms['enabled']['name_similar_synonym']->name,
+      'response' => array(
+        $this->terms['enabled']['name_similar_synonym']->name => $this->terms['enabled']['name_similar_synonym']->name,
+      ),
+      'message' => 'Only term is shown and synonym is not shown when "Suggest only one entry per term" is on.'
+    );
+
+    $assertions[] = array(
+      'vocabulary' => 'enabled',
+      'input' => drupal_substr($this->terms['enabled']['similar_synonyms']->{SYNONYMS_DEFAULT_FIELD_NAME}[LANGUAGE_NONE][0]['value'], 0, 8),
+      'response' => array(
+        $this->terms['enabled']['similar_synonyms']->name => $this->synonymAutocompleteResult($this->terms['enabled']['similar_synonyms'], $this->terms['enabled']['similar_synonyms']->{SYNONYMS_DEFAULT_FIELD_NAME}[LANGUAGE_NONE][0]['value']),
+      ),
+      'message' => 'Only single synonym is shown when "Suggest only one entry per term" is on.'
+    );
+
+    foreach ($assertions as $assertion) {
+      $this->assertAutocompleteMenuPath($assertion);
     }
   }
 
@@ -530,7 +658,7 @@ class AutocompleteSynonymsWebTestCase extends SynonymsWebTestCase {
    * Assert output of synonym friendly autocomplete path.
    *
    * @param array $assertion
-   *   Specially encoded array of assertion. Should include the follwing keys:
+   *   Specially encoded array of assertion. Should include the following keys:
    *     vocabulary - machine name of vocabulary whose field is asserted
    *     input - input string to be fed to autocomplete menu path
    *     response - JSON decoded expected response of autocomplete menu path
@@ -538,7 +666,7 @@ class AutocompleteSynonymsWebTestCase extends SynonymsWebTestCase {
    *                 page
    */
   protected function assertAutocompleteMenuPath($assertion) {
-    $response = $this->drupalGet('synonyms/autocomplete/field_synonyms_term_' . $assertion['vocabulary'] . '/' . $assertion['input']);
+    $response = $this->drupalGet('synonyms/autocomplete/field_synonyms_term_' . $assertion['vocabulary'] . '/' . $this->entity_type . '/' . $this->bundle . '/' . $assertion['input']);
     if (!$response) {
       $this->fail($assertion['message'], 'Autocomplete Menu Path');
       return;
@@ -635,32 +763,46 @@ class SearchIndexSynonymsWebTestCase extends SynonymsWebTestCase {
    *
    * Since logically term and its synonyms represent the same entity, the idea
    * is that searching by a term synonym should trigger all content referencing
-   * that term to be included in search results.
+   * that term to be included in search results. Additionally we test that when
+   * a synonym is deleted/edited in a term, corresponding content is no longer
+   * encountered when searched by ex-synonym.
    */
   public function testSearchTermSynonym() {
     // Create a few terms and synonyms.
     $terms = array();
-    $this->drupalPost('admin/structure/taxonomy/enabled/add', array(
+    $term = (object) array(
+      'vid' => $this->vocabularies['enabled']->vid,
       'name' => $this->randomName(),
-    ), 'Save');
+    );
+    taxonomy_term_save($term);
     $terms['no_synonyms'] = $this->getLastTerm($this->vocabularies['enabled']);
-    $this->drupalPost('admin/structure/taxonomy/enabled/add', array(
+
+    $term = (object) array(
+      'vid' => $this->vocabularies['enabled']->vid,
       'name' => $this->randomName(),
-      SYNONYMS_DEFAULT_FIELD_NAME . '[' . LANGUAGE_NONE . '][0][value]' => $this->randomName(),
-    ), 'Save');
+      SYNONYMS_DEFAULT_FIELD_NAME => array(
+        LANGUAGE_NONE => array(
+          array('value' => $this->randomName()),
+        ),
+      )
+    );
+    taxonomy_term_save($term);
     $terms['one_synonym'] = $this->getLastTerm($this->vocabularies['enabled']);
-    $this->drupalPost('admin/structure/taxonomy/enabled/add', array(
+
+    $term = (object) array(
+      'vid' => $this->vocabularies['enabled']->vid,
       'name' => $this->randomName(),
-      SYNONYMS_DEFAULT_FIELD_NAME . '[' . LANGUAGE_NONE . '][0][value]' => $this->randomName(),
-    ), 'Add another item');
-    $this->drupalPost(NULL, array(
-      SYNONYMS_DEFAULT_FIELD_NAME . '[' . LANGUAGE_NONE . '][1][value]' => $this->randomName(),
-    ), 'Save');
+      SYNONYMS_DEFAULT_FIELD_NAME => array(
+        LANGUAGE_NONE => array(
+          array('value' => $this->randomName()),
+          array('value' => $this->randomName()),
+        ),
+      )
+    );
+    taxonomy_term_save($term);
     $terms['two_synonyms'] = $this->getLastTerm($this->vocabularies['enabled']);
 
-    $assertions = array();
-
-    // Creating a node, which refereces to all the terms we have.
+    // Creating a node, which references to all the terms we have.
     $title = $this->randomName();
     $this->drupalPost('node/add/synonyms-test-content', array(
       'title' => $title,
@@ -671,58 +813,76 @@ class SearchIndexSynonymsWebTestCase extends SynonymsWebTestCase {
     // Rebuilding Search index.
     $this->cronRun();
 
-    foreach ($terms as $k => $v) {
-      $assertions[] = array(
-        'keyword' => $v->name,
-        'results' => array($node),
-        'message' => 'Searching by name of the term ' . $k,
-      );
-      foreach (synonyms_get_term_synonyms($v) as $delta => $synonym) {
-        $assertions[] = array(
-          'keyword' => $synonym['value'],
-          'results' => array($node),
-          'message' => 'Searching by synonym #' . $delta . ' of the term ' . $k,
-        );
+    foreach ($terms as $k => $term) {
+      $this->assertSearchResults($term->name, array($node), 'Searching by name of the term ' . $k);
+      foreach (synonyms_get_sanitized($term) as $delta => $synonym) {
+        $this->assertSearchResults($synonym, array($node), 'Searching by synonym #' . $delta . ' of the term ' . $k);
       }
     }
 
-    foreach ($assertions as $assertion) {
-      $this->assertSearchResults($assertion);
+    // Removing a synonym from the term. Then asserting node got re-indexed
+    // with new values of synonyms.
+    $deleted_synonym = array_pop($terms['one_synonym']->{SYNONYMS_DEFAULT_FIELD_NAME}[LANGUAGE_NONE]);
+    taxonomy_term_save($terms['one_synonym']);
+    $this->cronRun();
+    $this->assertSearchResults($deleted_synonym['value'], array(), 'Searching by recently deleted synonym of a taxonomy term yields no results.');
+
+    // Editing a synonym in a term. Then asserting node got re-indexed with new
+    // values of synonyms.
+    $ex_synonym = $terms['two_synonyms']->{SYNONYMS_DEFAULT_FIELD_NAME}[LANGUAGE_NONE][0]['value'];
+    $terms['two_synonyms']->{SYNONYMS_DEFAULT_FIELD_NAME}[LANGUAGE_NONE][0]['value'] = $this->randomName();
+    taxonomy_term_save($terms['two_synonyms']);
+    $this->cronRun();
+    $this->assertSearchResults($ex_synonym, array(), 'Searching by recently changed synonym of a taxonomy term yields no results.');
+
+    // We disable entire field from being source of synonyms and make sure for
+    // all synonyms search results are empty.
+    $this->drupalPost('admin/structure/taxonomy/enabled/edit', array(
+      'synonyms[synonyms][' . SYNONYMS_DEFAULT_FIELD_NAME . ']' => FALSE,
+    ), 'Save');
+    $this->cronRun();
+    foreach ($terms as $k => $term) {
+      $items = field_get_items('taxonomy_term', $term, SYNONYMS_DEFAULT_FIELD_NAME);
+      if (is_array($items)) {
+        foreach ($items as $synonym) {
+          $this->assertSearchResults($synonym['value'], array(), 'Searching by ' . $k . ' term synonym, which field was recently disabled as source of synonyms in vocabulary yields no results.');
+        }
+      }
     }
   }
 
   /**
    * Assert search results.
    *
-   * @param array $assertion
-   *   Specially encoded array of assertion. Should include the follwing keys:
-   *     keyword - what keyword has to be supplied to the search mechanism
-   *     results - array of nodes that are expected to be on search results
-   *     message - Drupal assertion message to be displayed on test results
-   *                 page
+   * @param $keyword string
+   *   Keyword to supply to the search mechanism
+   * @param $results array
+   *   Array of fully loaded nodes that are expected to be on search results
+   * @param $message string
+   *   Drupal assertion message to display on test results page
    */
-  protected function assertSearchResults($assertion) {
-    $response = $this->drupalGet('search/node/' . $assertion['keyword']);
+  protected function assertSearchResults($keyword, $results, $message) {
+    $response = $this->drupalGet('search/node/' . $keyword);
     $matches = array();
     preg_match_all('#\<li[^>]+class="search-result"[^>]*\>(.*?)\</li\>#si', $response, $matches);
-    $results = $matches[1];
-    if (count($results) != count($assertion['results'])) {
-      $this->fail($assertion['message']);
+    $matches = $matches[1];
+    if (count($matches) != count($results)) {
+      $this->fail($message);
       return;
     }
-    $results = implode('', $results);
-    foreach ($assertion['results'] as $node) {
-      if (strpos($results, 'node/' . $node->nid) === FALSE) {
-        $this->fail($assertion['message']);
+    $matches = implode('', $matches);
+    foreach ($results as $node) {
+      if (strpos($matches, 'node/' . $node->nid) === FALSE) {
+        $this->fail($message);
         return;
       }
     }
-    $this->pass($assertion['message']);
+    $this->pass($message);
   }
 }
 
 /**
- * Base class for all test cases that test Synonoyms Extractor classes.
+ * Base class for all test cases that test Synonyms Extractor classes.
  */
 abstract class AbstractSynonymsExtractorWebTestCase extends DrupalWebTestCase {
 
@@ -769,7 +929,7 @@ abstract class AbstractSynonymsExtractorWebTestCase extends DrupalWebTestCase {
     parent::setUp($modules);
 
     $this->vocabulary = (object) array(
-      'name' => 'Test Synonyms Extactor',
+      'name' => 'Test Synonyms Extractor',
       'machine_name' => 'synonyms_extractor',
     );
     taxonomy_vocabulary_save($this->vocabulary);
@@ -787,7 +947,7 @@ abstract class AbstractSynonymsExtractorWebTestCase extends DrupalWebTestCase {
    * @param array $field
    *   Field definition array as expected by Field API
    * @param array $instance
-   *   Instance defintion array as expected by Field API
+   *   Instance definition array as expected by Field API
    */
   protected function addFieldInstance($field, $instance) {
     $field = field_create_field($field);
@@ -821,7 +981,7 @@ abstract class AbstractSynonymsExtractorWebTestCase extends DrupalWebTestCase {
     taxonomy_term_save($term);
     $items = field_get_items('taxonomy_term', $term, $this->field['field_name']);
 
-    $synonyms = is_array($items) ? call_user_func($this->extractor . '::synonymsExtract', $items, $this->field, $this->instance, $term, 'taxonomy_term') : array();
+    $synonyms = is_array($items) ? call_user_func(array($this->extractor, 'synonymsExtract'), $items, $this->field, $this->instance, $term, 'taxonomy_term') : array();
     $this->assertTrue(count(array_intersect($etalon, $synonyms)) == count($etalon), 'Synonyms Extractor ' . $this->extractor . ' passed synonymsExtract() method: ' . $message);
     // Cleaning up.
     taxonomy_term_delete($term->tid);
@@ -862,7 +1022,7 @@ abstract class AbstractSynonymsExtractorWebTestCase extends DrupalWebTestCase {
     $efq = new EntityFieldQuery();
     $efq->entityCondition('entity_type', 'taxonomy_term')
         ->entityCondition('bundle', $this->vocabulary->machine_name);
-    call_user_func($this->extractor . '::processEntityFieldQuery', $tag, $efq, $this->field, $this->instance);
+    call_user_func(array($this->extractor, 'processEntityFieldQuery'), $tag, $efq, $this->field, $this->instance);
     $result = $efq->execute();
     $result = isset($result['taxonomy_term']) ? array_keys($result['taxonomy_term']) : array();
     // Asserting results of EntityFieldQuery.
@@ -894,7 +1054,7 @@ abstract class AbstractSynonymsExtractorWebTestCase extends DrupalWebTestCase {
    *   SimpleTest assertion method
    */
   protected function assertMergeEntityAsSynonym($items, $synonym_entity, $synonym_entity_type, $etalon, $message = '') {
-    $extra_items = call_user_func($this->extractor . '::mergeEntityAsSynonym', $items, $this->field, $this->instance, $synonym_entity, $synonym_entity_type);
+    $extra_items = call_user_func(array($this->extractor, 'mergeEntityAsSynonym'), $items, $this->field, $this->instance, $synonym_entity, $synonym_entity_type);
     foreach ($etalon as $k => $v) {
       if (count(array_intersect($etalon[$k], $extra_items[$k])) != count($etalon[$k])) {
         $this->fail('Synonyms Extractor ' . $this->extractor . ' passed mergeEntityAsSynonym() method: ' . $message);
@@ -908,7 +1068,7 @@ abstract class AbstractSynonymsExtractorWebTestCase extends DrupalWebTestCase {
 /**
  * Test SynonymsSynonymsExtractor class.
  */
-class SynonymsSynonoymsExtractorWebTestCase extends AbstractSynonymsExtractorWebTestCase {
+class SynonymsSynonymsExtractorWebTestCase extends AbstractSynonymsExtractorWebTestCase {
 
   /**
    * GetInfo method.
@@ -995,7 +1155,7 @@ class SynonymsSynonoymsExtractorWebTestCase extends AbstractSynonymsExtractorWeb
 /**
  * Test TaxonomySynonymsExtractor class.
  */
-class TaxonomySynonoymsExtractorWebTestCase extends AbstractSynonymsExtractorWebTestCase {
+class TaxonomySynonymsExtractorWebTestCase extends AbstractSynonymsExtractorWebTestCase {
 
   /**
    * Taxonomy vocabulary object terms.

+ 7 - 9
sites/all/modules/contrib/theming/colorbox/README.txt

@@ -32,15 +32,13 @@ The Colorbox module:
 
 The Colorbox plugin:
 
-* Supports images, image groups, slideshow, ajax, inline, and
-  iframed content.
-* Appearance is controlled through CSS so users can restyle the box.
-* Preloads background images and can preload upcoming images in a
-  photo group.
-* Generates W3C valid XHTML and adds no JS global variables and
-  passes JSLint.
-* Tested in Firefox 2 & 3, Safari 3 & 4, Opera 9, Chrome,
-  Internet Explorer 6, 7, 8.
+* Supports photos, grouping, slideshow, ajax, inline, and iframed content.
+* Appearance is controlled through CSS so it can be restyled.
+* Preloads upcoming images in a photo group.
+* Completely unobtrusive, options are set in the JS and require no
+  changes to existing HTML.
+* Compatible with: jQuery 1.3.2+ in Firefox, Safari, Chrome, Opera,
+  Internet Explorer 7+.
 * Released under the MIT License.
 
 

+ 9 - 3
sites/all/modules/contrib/theming/colorbox/colorbox-insert-image.tpl.php

@@ -6,9 +6,12 @@
  *
  * Available variables:
  * - $item: The complete item being inserted.
- * - $image_path: The URL to the image.
- * - $link_path: The URL to the image that Colorbox should open.
+ * - $url: The URL to the image.
+ * - $path: The URL to the image that Colorbox should open.
  * - $class: A set of classes assigned to this image (if any).
+ * - $width: The width of the image (if known).
+ * - $height: The height of the image (if known).
+ * - $style_name: The Image style being used.
  * - $gallery_id: The ID of the Colorbox gallery.
  *
  * Note that ALT and Title fields should not be filled in here, instead they
@@ -19,6 +22,9 @@
  * - __alt__: The ALT text, intended for use in the <img> tag.
  * - __title__: The Title text, intended for use in the <img> tag.
  * - __description__: A description of the image, sometimes used as a caption.
+ * - __filename__: The file name.
+ * - __[token]_or_filename__: Any of the above tokens if available, otherwise
+ *   use the file's name. i.e. __title_or_filename__.
  */
 ?>
-<a href="<?php print $link_path; ?>" title="__title__" class="colorbox colorbox-insert-image" rel="<?php print $gallery_id; ?>"><img typeof="foaf:Image" src="<?php print $image_path; ?>" alt="__alt__" title="__title__" class="<?php print $class; ?>" /></a>
+<a href="<?php print $path; ?>" title="__title__" class="colorbox colorbox-insert-image" rel="<?php print $gallery_id; ?>"><img src="<?php print $url; ?>" <?php if ($width && $height): ?>width="<?php print $width; ?>" height="<?php print $height; ?>" <?php endif; ?>alt="__alt__" title="__title__" class="<?php print $class; ?>" /></a>

+ 20 - 1
sites/all/modules/contrib/theming/colorbox/colorbox.admin.inc

@@ -198,7 +198,7 @@ function colorbox_admin_settings() {
   $form['colorbox_custom_settings']['colorbox_scrolling'] = array(
     '#type' => 'radios',
     '#title' => t('Scrollbars'),
-    '#options' => array(0 => t('Off'), 1 => t('On')),
+    '#options' => array(1 => t('On'), 0 => t('Off')),
     '#default_value' => variable_get('colorbox_scrolling', 1),
     '#description' => t('If false, Colorbox will hide scrollbars for overflowing content. This could be used on conjunction with the resize method for a smoother transition if you are appending content to an already open instance of Colorbox.'),
   );
@@ -250,6 +250,25 @@ function colorbox_admin_settings() {
     '#collapsible' => TRUE,
     '#collapsed' => TRUE,
   );
+  $form['colorbox_advanced_settings']['colorbox_mobile_detect'] = array(
+    '#type' => 'radios',
+    '#title' => t('Mobile detection'),
+    '#options' => array(1 => t('On'), 0 => t('Off')),
+    '#default_value' => variable_get('colorbox_mobile_detect', 1),
+    '#description' => t('If on (default) Colorbox will not be active for devices with a the max width set below.'),
+  );
+  $form['colorbox_advanced_settings']['colorbox_mobile_device_width'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Device with'),
+    '#default_value' => variable_get('colorbox_mobile_device_width', '480px'),
+    '#size' => 30,
+    '#description' => t('Set the mobile device max with. Default: 480px.'),
+    '#states' => array(
+      'visible' => array(
+        ':input[name="colorbox_mobile_detect"]' => array('value' => '1'),
+      ),
+    ),
+  );
   $form['colorbox_advanced_settings']['colorbox_caption_trim'] = array(
     '#type' => 'radios',
     '#title' => t('Caption shortening'),

+ 3 - 3
sites/all/modules/contrib/theming/colorbox/colorbox.info

@@ -6,9 +6,9 @@ configure = admin/config/media/colorbox
 
 files[] = views/colorbox_handler_field_colorbox.inc
 
-; Information added by drupal.org packaging script on 2013-04-08
-version = "7.x-2.4"
+; Information added by Drupal.org packaging script on 2014-09-12
+version = "7.x-2.8"
 core = "7.x"
 project = "colorbox"
-datestamp = "1365452412"
+datestamp = "1410514129"
 

+ 5 - 3
sites/all/modules/contrib/theming/colorbox/colorbox.install

@@ -14,13 +14,15 @@ function colorbox_requirements($phase) {
   if ($phase == 'runtime') {
     $t = get_t();
     $library = libraries_detect('colorbox');
+    $error_type = isset($library['error']) ? drupal_ucfirst($library['error']) : '';
+    $error_message = isset($library['error message']) ? $library['error message'] : '';
 
     if (empty($library['installed'])) {
       $requirements['colorbox_plugin'] = array(
         'title' => $t('Colorbox plugin'),
-        'value' => $t('At least @a', array('@a' => COLORBOX_MIN_PLUGIN_VERSION)),
+        'value' => $t('@e: At least @a', array('@e' => $error_type, '@a' => COLORBOX_MIN_PLUGIN_VERSION)),
         'severity' => REQUIREMENT_ERROR,
-        'description' => $t('You need to download the !colorbox, extract the archive and place the colorbox directory in the %path directory on your server.', array('!colorbox' => l($t('Colorbox plugin'), $library['download url']), '%path' => 'sites/all/libraries')),
+        'description' => $t('!error You need to download the !colorbox, extract the archive and place the colorbox directory in the %path directory on your server.', array('!error' => $error_message, '!colorbox' => l($t('Colorbox plugin'), $library['download url']), '%path' => 'sites/all/libraries')),
       );
     }
     elseif (version_compare($library['version'], COLORBOX_MIN_PLUGIN_VERSION, '>=')) {
@@ -47,7 +49,7 @@ function colorbox_requirements($phase) {
  * Implements hook_uninstall().
  */
 function colorbox_uninstall() {
-  db_query("DELETE FROM {variable} WHERE name LIKE 'colorbox_%'");
+  db_delete('variable')->condition('name', db_like('colorbox_') . '%', 'LIKE')->execute();
 }
 
 /**

+ 0 - 9
sites/all/modules/contrib/theming/colorbox/colorbox.make.example

@@ -1,9 +0,0 @@
-; $Id$
-
-core = 7.x
-api = 2
-
-libraries[colorbox][download][type] = "get"
-libraries[colorbox][download][url] = "http://colorpowered.com/colorbox/colorbox.zip"
-libraries[colorbox][directory_name] = "colorbox"
-libraries[colorbox][destination] = "libraries"

+ 46 - 17
sites/all/modules/contrib/theming/colorbox/colorbox.module

@@ -32,6 +32,7 @@ function colorbox_theme() {
         'widget' => NULL,
       ),
       'template' => 'colorbox-insert-image',
+      'pattern' => 'colorbox_insert_image__[a-z0-9_]+',
       'file' => 'colorbox.theme.inc',
     ),
 
@@ -43,6 +44,7 @@ function colorbox_theme() {
         'node' => NULL,  // Left for legacy support.
         'field' => array(),
         'display_settings' => array(),
+        'delta' => null,
       ),
       'file' => 'colorbox.theme.inc',
     ),
@@ -77,10 +79,10 @@ function colorbox_libraries_info() {
   $libraries['colorbox'] = array(
     'name' => 'Colorbox plugin',
     'vendor url' => 'http://www.jacklmoore.com/colorbox',
-    'download url' => 'http://www.jacklmoore.com/colorbox',
+    'download url' => 'https://github.com/jackmoore/colorbox/archive/1.x.zip',
     'version arguments' => array(
       'file' => 'jquery.colorbox-min.js',
-      'pattern' => '@(?i:Colorbox) v([0-9\.a-z]+)@',
+      'pattern' => '@(?i:Colorbox)\sv?([0-9\.a-z]+)@',
       'lines' => 5,
     ),
     'files' => array(
@@ -140,7 +142,7 @@ function _colorbox_active() {
     return FALSE;
   }
 
-  // Code from the block_list funtion in block.module.
+  // Code from the block_list function in block.module.
   $path = drupal_get_path_alias($_GET['q']);
   $colorbox_pages = variable_get('colorbox_pages', "admin*\nimagebrowser*\nimg_assist*\nimce*\nnode/add/*\nnode/*/edit\nprint/*\nprintpdf/*\nsystem/ajax\nsystem/ajax/*");
   // Compare with the internal and path alias (if any).
@@ -176,10 +178,10 @@ function _colorbox_doheader() {
       'slideshowSpeed' => variable_get('colorbox_slideshowspeed', 2500),
       'slideshowStart' => variable_get('colorbox_text_start', 'start slideshow'),
       'slideshowStop' => variable_get('colorbox_text_stop', 'stop slideshow'),
-      'current' => variable_get('colorbox_text_current', '{current} of {total}'),
-      'previous' => variable_get('colorbox_text_previous', '« Prev'),
-      'next' => variable_get('colorbox_text_next', 'Next »'),
-      'close' => variable_get('colorbox_text_close', 'Close'),
+      'current' => strip_tags(variable_get('colorbox_text_current', '{current} of {total}')),
+      'previous' => strip_tags(variable_get('colorbox_text_previous', '« Prev')),
+      'next' => strip_tags(variable_get('colorbox_text_next', 'Next »')),
+      'close' => strip_tags(variable_get('colorbox_text_close', 'Close')),
       'overlayClose' => variable_get('colorbox_overlayclose', 1) ? TRUE : FALSE,
       'maxWidth' => variable_get('colorbox_maxwidth', '98%'),
       'maxHeight' => variable_get('colorbox_maxheight', '98%'),
@@ -187,6 +189,8 @@ function _colorbox_doheader() {
       'initialHeight' => variable_get('colorbox_initialheight', '250'),
       'fixed' => variable_get('colorbox_fixed', 1) ? TRUE : FALSE,
       'scrolling' => variable_get('colorbox_scrolling', 1) ? TRUE : FALSE,
+      'mobiledetect' => variable_get('colorbox_mobile_detect', 1) ? TRUE : FALSE,
+      'mobiledevicewidth' => variable_get('colorbox_mobile_device_width', '480px'),
     );
   }
   else {
@@ -199,6 +203,8 @@ function _colorbox_doheader() {
       'maxWidth' => '98%',
       'maxHeight' => '98%',
       'fixed' => TRUE,
+      'mobiledetect' => variable_get('colorbox_mobile_detect', 1) ? TRUE : FALSE,
+      'mobiledevicewidth' => variable_get('colorbox_mobile_device_width', '480px'),
     );
   }
 
@@ -213,7 +219,9 @@ function _colorbox_doheader() {
 
   // Add and initialise the Colorbox plugin.
   $variant = variable_get('colorbox_compression_type', 'minified');
-  libraries_load('colorbox', $variant);
+  if (module_exists('libraries')) {
+    libraries_load('colorbox', $variant);
+  }
   drupal_add_js($path . '/js/colorbox.js');
 
   // Add JS and CSS based on selected style.
@@ -251,6 +259,7 @@ function colorbox_field_formatter_info() {
       'field types' => array('image'),
       'settings' => array(
         'colorbox_node_style' => '',
+        'colorbox_node_style_first' => '',
         'colorbox_image_style' => '',
         'colorbox_gallery' => 'post',
         'colorbox_gallery_custom' => '',
@@ -280,6 +289,14 @@ function colorbox_field_formatter_settings_form($field, $instance, $view_mode, $
     '#options' => $image_styles_hide,
     '#description' => t('Image style to use in the content.'),
   );
+  $element['colorbox_node_style_first'] = array(
+    '#title' => t('Content image style for first image'),
+    '#type' => 'select',
+    '#default_value' => $settings['colorbox_node_style_first'],
+    '#empty_option' => t('No special style.'),
+    '#options' => $image_styles,
+    '#description' => t('Image style to use in the content for the first image.'),
+  );
   $element['colorbox_image_style'] = array(
     '#title' => t('Colorbox image style'),
     '#type' => 'select',
@@ -306,15 +323,12 @@ function colorbox_field_formatter_settings_form($field, $instance, $view_mode, $
   );
   $element['colorbox_gallery_custom'] = array(
     '#title' => t('Custom gallery'),
-    '#type' => 'machine_name',
+    '#type' => 'textfield',
     '#maxlength' => 32,
     '#default_value' => $settings['colorbox_gallery_custom'],
-    '#description' => t('All images on a page with the same gallery value (rel attribute) will be grouped together. It must only contain lowercase letters, numbers, and underscores.'),
+    '#description' => t('All images on a page with the same gallery value (rel attribute) will be grouped together. It must only contain lowercase letters, numbers, hyphen and underscores.'),
+    '#element_validate' => array('colorbox_gallery_custom_validate'),
     '#required' => FALSE,
-    '#machine_name' => array(
-      'exists' => 'colorbox_gallery_exists',
-      'error' => t('The custom gallery field must only contain lowercase letters, numbers, and underscores.'),
-    ),
     '#states' => array(
       'visible' => array(
         ':input[name$="[settings_edit_form][settings][colorbox_gallery]"]' => array('value' => 'custom'),
@@ -335,7 +349,7 @@ function colorbox_field_formatter_settings_form($field, $instance, $view_mode, $
     '#type' => 'select',
     '#default_value' => $settings['colorbox_caption'],
     '#options' => $caption,
-    '#description' => t('Automatic will use the first none empty value of the title, the alt text and the content title.'),
+    '#description' => t('Automatic will use the first non-empty value of the title, the alt text and the content title.'),
   );
   $element['colorbox_caption_custom'] = array(
     '#title' => t('Custom caption'),
@@ -380,6 +394,15 @@ function colorbox_field_formatter_settings_form($field, $instance, $view_mode, $
   return $element;
 }
 
+/**
+ * Validate function for colorbox_gallery_custom.
+ */
+function colorbox_gallery_custom_validate($element, &$form_state) {
+  if (!empty($element['#value']) && !preg_match('!^[a-z0-9_-]+$!', $element['#value'])) {
+    form_error($element, t('%name must only contain lowercase letters, numbers, hyphen and underscores.', array('%name' => $element['#title'])));
+  }
+}
+
 /**
  * Implements hook_field_formatter_settings_summary().
  */
@@ -404,6 +427,10 @@ function colorbox_field_formatter_settings_summary($field, $instance, $view_mode
     $summary[] = t('Content image style: Original image');
   }
 
+  if (isset($image_styles[$settings['colorbox_node_style_first']])) {
+    $summary[] = t('Content image style of first image: @style', array('@style' => $image_styles[$settings['colorbox_node_style_first']]));
+  }
+
   if (isset($image_styles[$settings['colorbox_image_style']])) {
     $summary[] = t('Colorbox image style: @style', array('@style' => $image_styles[$settings['colorbox_image_style']]));
   }
@@ -455,6 +482,7 @@ function colorbox_field_formatter_view($entity_type, $entity, $field, $instance,
         '#node' => $entity, // Left for legacy support.
         '#field' => $field,
         '#display_settings' => $display['settings'],
+        '#delta' => $delta,
       );
     }
   }
@@ -468,7 +496,8 @@ function colorbox_field_formatter_view($entity_type, $entity, $field, $instance,
 function colorbox_insert_styles() {
   $insert_styles = array();
   foreach (image_styles() as $key => $style) {
-    $insert_styles['colorbox__' . $key] = array('label' => t('Colorbox @style', array('@style' => $style['name'])));
+    $label = isset($style['label']) ? $style['label'] : $style['name'];
+    $insert_styles['colorbox__' . $key] = array('label' => t('Colorbox @style', array('@style' => $label)));
   }
 
   return $insert_styles;
@@ -479,7 +508,7 @@ function colorbox_insert_styles() {
  */
 function colorbox_insert_content($item, $style, $widget) {
   list($item['module_name'], $item['style_name']) = explode('__', $style['name'], 2);
-  return theme('colorbox_insert_image', array('item' => $item, 'widget' => $widget));
+  return theme(array('colorbox_insert_image__' . str_replace('-', '_', $item['style_name']), 'colorbox_insert_image'), array('item' => $item, 'widget' => $widget));
 }
 
 /**

+ 54 - 13
sites/all/modules/contrib/theming/colorbox/colorbox.theme.inc

@@ -25,16 +25,40 @@ function theme_colorbox_image_formatter($variables) {
 
   $image = array(
     'path' => $item['uri'],
-    'alt' => $item['alt'],
-    'title' => $item['title'],
+    'alt' => isset($item['alt']) ? $item['alt'] : '',
+    'title' => isset($item['title']) ? $item['title'] : '',
     'style_name' => $settings['colorbox_node_style'],
   );
 
+  if ($variables['delta'] == 0 && !empty($settings['colorbox_node_style_first'])) {
+    $image['style_name'] = $settings['colorbox_node_style_first'];
+  }
+
   if (isset($item['width']) && isset($item['height'])) {
     $image['width'] = $item['width'];
     $image['height'] = $item['height'];
   }
 
+  if (isset($item['attributes'])) {
+    $image['attributes'] = $item['attributes'];
+  }
+
+  // Allow image attributes to be overridden.
+  if (isset($variables['item']['override']['attributes'])) {
+    foreach (array('width', 'height', 'alt', 'title') as $key) {
+      if (isset($variables['item']['override']['attributes'][$key])) {
+        $image[$key] = $variables['item']['override']['attributes'][$key];
+        unset($variables['item']['override']['attributes'][$key]);
+      }
+    }
+    if (isset($image['attributes'])) {
+      $image['attributes'] = $variables['item']['override']['attributes'] + $image['attributes'];
+    }
+    else {
+      $image['attributes'] = $variables['item']['override']['attributes'];
+    }
+  }
+
   $entity_title = entity_label($entity_type, $entity);
 
   switch ($settings['colorbox_caption']) {
@@ -135,45 +159,62 @@ function theme_colorbox_imagefield($variables) {
     $image = theme('image', $variables['image']);
   }
 
-  $options = array(
+  $options = drupal_parse_url($variables['path']);
+  $options += array(
     'html' => TRUE,
     'attributes' => array(
       'title' => $variables['title'],
       'class' => $class,
       'rel' => $variables['gid'],
-    )
+    ),
+    'language' => array('language' => NULL),
   );
 
-  return l($image, $variables['path'], $options);
+  return l($image, $options['path'], $options);
 }
 
 /**
  * Preprocess variables for the colorbox-insert-image.tpl.php file.
  */
 function template_preprocess_colorbox_insert_image(&$variables) {
-  $class = array();
-  $file = file_load($variables['item']['fid']);
+  $item = $variables['item'];
+  $variables['file'] = file_load($item['fid']);
+  $variables['style_name'] = $item['style_name'];
+  $variables['width'] = isset($item['width']) ? $item['width'] : NULL;
+  $variables['height'] = isset($item['height']) ? $item['height'] : NULL;
 
+  // Determine dimensions of the image after the image style transformations.
+  image_style_transform_dimensions($variables['style_name'], $variables);
+
+  $class = array();
   if (!empty($variables['widget']['settings']['insert_class'])) {
     $class = explode(' ', $variables['widget']['settings']['insert_class']);
   }
-  $class[] = 'image-' . $variables['item']['style_name'];
+  $class[] = 'image-' . $variables['style_name'];
 
   foreach ($class as $key => $value) {
     $class[$key] = drupal_html_class($value);
   }
 
-  $variables['image_path'] = image_style_url($variables['item']['style_name'], $file->uri);
+  $variables['class'] = implode(' ', $class);
+
+  $variables['uri'] = image_style_path($variables['style_name'], $variables['file']->uri);
+  $absolute = isset($variables['widget']['settings']['insert_absolute']) ? $variables['widget']['settings']['insert_absolute'] : NULL;
+  $variables['url'] = insert_create_url($variables['uri'], $absolute, variable_get('clean_url'));
+
+  // http://drupal.org/node/1923336
+  if (function_exists('image_style_path_token')) {
+    $token_query = array(IMAGE_DERIVATIVE_TOKEN => image_style_path_token($variables['style_name'], $variables['file']->uri));
+    $variables['url'] .= (strpos($variables['url'], '?') !== FALSE ? '&' : '?') . drupal_http_build_query($token_query);
+  }
 
   if ($style_name = variable_get('colorbox_image_style', '')) {
-    $variables['link_path'] = image_style_url($style_name, $file->uri);
+    $variables['path'] = image_style_url($style_name, $variables['file']->uri);
   }
   else {
-    $variables['link_path'] = file_create_url($file->uri);
+    $variables['path'] = file_create_url($variables['file']->uri);
   }
 
-  $variables['class'] = implode(' ', $class);
-
   $variables['gallery_id'] = '';
   switch (variable_get('colorbox_insert_gallery', 0)) {
     case 0:

+ 13 - 6
sites/all/modules/contrib/theming/colorbox/js/colorbox.js

@@ -5,16 +5,23 @@ Drupal.behaviors.initColorbox = {
     if (!$.isFunction($.colorbox)) {
       return;
     }
+
+    if (settings.colorbox.mobiledetect && window.matchMedia) {
+      // Disable Colorbox for small screens.
+      var mq = window.matchMedia("(max-device-width: " + settings.colorbox.mobiledevicewidth + ")");
+      if (mq.matches) {
+        return;
+      }
+    }
+
     $('.colorbox', context)
       .once('init-colorbox')
       .colorbox(settings.colorbox);
+
+    $(context).bind('cbox_complete', function () {
+      Drupal.attachBehaviors('#cboxLoadedContent');
+    });
   }
 };
 
-{
-  $(document).bind('cbox_complete', function () {
-    Drupal.attachBehaviors('#cboxLoadedContent');
-  });
-}
-
 })(jQuery);

+ 1 - 1
sites/all/modules/contrib/theming/colorbox/styles/default/colorbox_style.js

@@ -2,7 +2,7 @@
 
 Drupal.behaviors.initColorboxDefaultStyle = {
   attach: function (context, settings) {
-    $(document).bind('cbox_complete', function () {
+    $(context).bind('cbox_complete', function () {
       // Only run if there is a title.
       if ($('#cboxTitle:empty', context).length == false) {
         $('#cboxLoadedContent img', context).bind('mouseover', function () {

+ 1 - 1
sites/all/modules/contrib/theming/colorbox/styles/plain/colorbox_style.css

@@ -126,7 +126,7 @@
       #cboxClose.cbox-close-plain {
         position: absolute;
         font-size: 20px;
-        line-height: 18px;;
+        line-height: 18px;
         text-align: center;
         color: rgba(255, 255, 255, 0.7);
         background: rgba(0, 0, 0, 0.5);

+ 2 - 2
sites/all/modules/contrib/theming/colorbox/styles/plain/colorbox_style.js

@@ -2,7 +2,7 @@
 
 Drupal.behaviors.initColorboxPlainStyle = {
   attach: function (context, settings) {
-    $(document).bind('cbox_complete', function () {
+    $(context).bind('cbox_complete', function () {
       // Make all the controls invisible.
       $('#cboxCurrent, #cboxSlideshow, #cboxPrevious, #cboxNext', context).addClass('element-invisible');
       // Replace "Close" with "×" and show.
@@ -24,7 +24,7 @@ Drupal.behaviors.initColorboxPlainStyle = {
         }
       });
     });
-    $(document).bind('cbox_closed', function () {
+    $(context).bind('cbox_closed', function () {
       $('#cboxClose', context).removeClass('cbox-close-plain');
     });
   }

+ 2 - 1
sites/all/modules/contrib/theming/colorbox/styles/stockholmsyndrome/colorbox_style.css

@@ -151,8 +151,9 @@
         height: 38px;
         color: #313131;
         padding: 0 140px 0 15px;
-        display: table-cell;
+        display: table-cell !important;
         vertical-align: middle;
+        float: none !important;
       }
       #cboxCurrent {
         position: absolute;

+ 3 - 3
sites/all/modules/contrib/theming/colorbox/styles/stockholmsyndrome/colorbox_style.js

@@ -2,15 +2,15 @@
 
 Drupal.behaviors.initColorboxStockholmsyndromeStyle = {
   attach: function (context, settings) {
-    $(document).bind('cbox_open', function () {
+    $(context).bind('cbox_open', function () {
       // Hide close button initially.
       $('#cboxClose', context).css('opacity', 0);
     });
-    $(document).bind('cbox_load', function () {
+    $(context).bind('cbox_load', function () {
       // Hide close button. (It doesn't handle the load animation well.)
       $('#cboxClose', context).css('opacity', 0);
     });
-    $(document).bind('cbox_complete', function () {
+    $(context).bind('cbox_complete', function () {
       // Show close button with a delay.
       $('#cboxClose', context).fadeTo('fast', 0, function () {$(this).css('opacity', 1)});
     });

+ 4 - 2
sites/all/modules/contrib/theming/colorbox/views/colorbox_handler_field_colorbox.inc

@@ -109,7 +109,7 @@ If you would like to have the characters %5B and %5D please use the html entity
     $form['custom_gid'] = array(
       '#type' => 'textfield',
       '#title' => t('Custom Colorbox gallery'),
-      '#description' => t('Enable Colorbox gallery with a given string as gallery. Overrides the automatically generated gallery id above.'),
+      '#description' => t('Enable Colorbox gallery with a given string as gallery. Overrides the automatically generated gallery id above. You may enter data from this view as per the "Replacement patterns" below.'),
       '#default_value' => $this->options['custom_gid'],
       '#weight' => -8,
     );
@@ -162,12 +162,14 @@ If you would like to have the characters %5B and %5D please use the html entity
     $tokens = $this->get_render_tokens($this->options['alter']);
     $popup = filter_xss_admin($this->options['popup']);
     $caption = filter_xss_admin($this->options['caption']);
+    $gallery = drupal_html_class($this->options['custom_gid']);
     $popup = strtr($popup, $tokens);
     $caption = strtr($caption, $tokens);
+    $gallery = strtr($gallery, $tokens);
 
     $width = $this->options['width'] ? $this->options['width'] : '';
     $height = $this->options['height'] ? $this->options['height'] : '';
-    $gallery_id = !empty($this->options['custom_gid']) ? $this->options['custom_gid'] : ($this->options['gid'] ? 'gallery-' . $this->view->name : '');
+    $gallery_id = !empty($gallery) ? $gallery : ($this->options['gid'] ? 'gallery-' . $this->view->name : '');
     $link_text = $tokens["[{$this->options['trigger_field']}]"];
     $link_options = array(
       'html' => TRUE,