Browse Source

updated mailgun, mailsystem, honeypot, googleanalitycs, features, content_taxonomy

Bachir Soussi Chiadmi 5 years ago
parent
commit
e08a2639c6
54 changed files with 1860 additions and 391 deletions
  1. 3 3
      sites/all/modules/contrib/admin/features/features.admin.inc
  2. 1 1
      sites/all/modules/contrib/admin/features/features.drush.inc
  3. 13 12
      sites/all/modules/contrib/admin/features/features.export.inc
  4. 3 4
      sites/all/modules/contrib/admin/features/features.info
  5. 1 0
      sites/all/modules/contrib/admin/features/features.module
  6. 4 4
      sites/all/modules/contrib/admin/features/includes/features.field.inc
  7. 8 2
      sites/all/modules/contrib/admin/features/includes/features.image.inc
  8. 8 4
      sites/all/modules/contrib/admin/features/includes/features.menu.inc
  9. 3 0
      sites/all/modules/contrib/admin/features/tests/features.test
  10. 3 4
      sites/all/modules/contrib/admin/features/tests/features_test/features_test.info
  11. 7 7
      sites/all/modules/contrib/admin/google_analytics/README.txt
  12. 1 1
      sites/all/modules/contrib/admin/google_analytics/googleanalytics.admin.inc
  13. 3 3
      sites/all/modules/contrib/admin/google_analytics/googleanalytics.debug.js
  14. 3 4
      sites/all/modules/contrib/admin/google_analytics/googleanalytics.info
  15. 21 15
      sites/all/modules/contrib/admin/google_analytics/googleanalytics.install
  16. 3 3
      sites/all/modules/contrib/admin/google_analytics/googleanalytics.js
  17. 32 13
      sites/all/modules/contrib/admin/google_analytics/googleanalytics.module
  18. 61 13
      sites/all/modules/contrib/admin/google_analytics/googleanalytics.test
  19. 8 6
      sites/all/modules/contrib/admin/google_analytics/googleanalytics.test.js
  20. 0 0
      sites/all/modules/contrib/admin/google_analytics/googleanalytics.variable.inc
  21. 42 0
      sites/all/modules/contrib/fields/content_taxonomy/CHANGELOG.txt
  22. 42 0
      sites/all/modules/contrib/fields/content_taxonomy/content_taxonomy.api.php
  23. 3 3
      sites/all/modules/contrib/fields/content_taxonomy/content_taxonomy.info
  24. 94 0
      sites/all/modules/contrib/fields/content_taxonomy/content_taxonomy.install
  25. 49 7
      sites/all/modules/contrib/fields/content_taxonomy/content_taxonomy.module
  26. 3 3
      sites/all/modules/contrib/fields/content_taxonomy/content_taxonomy_autocomplete.info
  27. 39 8
      sites/all/modules/contrib/fields/content_taxonomy/content_taxonomy_autocomplete.module
  28. 15 0
      sites/all/modules/contrib/fields/content_taxonomy/content_taxonomy_et.info
  29. 404 0
      sites/all/modules/contrib/fields/content_taxonomy/content_taxonomy_et.module
  30. 4 6
      sites/all/modules/contrib/fields/content_taxonomy/content_taxonomy_migrate.info
  31. 79 8
      sites/all/modules/contrib/fields/content_taxonomy/content_taxonomy_migrate.module
  32. 58 0
      sites/all/modules/contrib/form/honeypot/README.md
  33. 0 43
      sites/all/modules/contrib/form/honeypot/README.txt
  34. 32 0
      sites/all/modules/contrib/form/honeypot/docker-compose.yml
  35. 20 2
      sites/all/modules/contrib/form/honeypot/honeypot.admin.inc
  36. 3 4
      sites/all/modules/contrib/form/honeypot/honeypot.info
  37. 2 2
      sites/all/modules/contrib/form/honeypot/honeypot.install
  38. 125 8
      sites/all/modules/contrib/form/honeypot/honeypot.module
  39. 55 0
      sites/all/modules/contrib/form/honeypot/honeypot.test
  40. 37 0
      sites/all/modules/contrib/form/honeypot/js/honeypot.js
  41. 3 4
      sites/all/modules/contrib/form/honeypot/tests/honeypot_test.info
  42. 1 0
      sites/all/modules/contrib/mail/mailgun/README.txt
  43. 12 0
      sites/all/modules/contrib/mail/mailgun/composer.json
  44. 112 59
      sites/all/modules/contrib/mail/mailgun/mailgun.admin.inc
  45. 8 7
      sites/all/modules/contrib/mail/mailgun/mailgun.info
  46. 38 2
      sites/all/modules/contrib/mail/mailgun/mailgun.install
  47. 77 23
      sites/all/modules/contrib/mail/mailgun/mailgun.mail.inc
  48. 188 64
      sites/all/modules/contrib/mail/mailgun/mailgun.module
  49. 28 0
      sites/all/modules/contrib/mail/mailgun/templates/mailgun-message.tpl.php
  50. 5 4
      sites/all/modules/contrib/mail/mailsystem/html_to_text.inc
  51. 9 8
      sites/all/modules/contrib/mail/mailsystem/mailsystem.admin.inc
  52. 3 5
      sites/all/modules/contrib/mail/mailsystem/mailsystem.info
  53. 35 15
      sites/all/modules/contrib/mail/mailsystem/mailsystem.module
  54. 49 7
      sites/all/modules/contrib/mail/mailsystem/mailsystem.theme.inc

+ 3 - 3
sites/all/modules/contrib/admin/features/features.admin.inc

@@ -871,7 +871,7 @@ function features_export_build_form_submit($form, &$form_state) {
   $feature = $form['#feature'];
   $feature = $form['#feature'];
   $export = _features_export_build($feature, $form_state);
   $export = _features_export_build($feature, $form_state);
   $export = _features_export_generate($export, $form_state, $feature);
   $export = _features_export_generate($export, $form_state, $feature);
-  $generate = ($form_state['values']['op'] == $form_state['values']['generate']);
+  $generate = isset($form_state['values']['generate']) && ($form_state['values']['op'] == $form_state['values']['generate']);
   $module_name = $form_state['values']['module_name'];
   $module_name = $form_state['values']['module_name'];
 
 
   if ($generate && !user_access('generate features')) {
   if ($generate && !user_access('generate features')) {
@@ -1628,9 +1628,9 @@ function _features_get_features_list() {
 
 
   $cache = cache_get('features:features_list');
   $cache = cache_get('features:features_list');
   if ($cache) {
   if ($cache) {
-    $features = $cache->data;  
+    $features = $cache->data;
   }
   }
-  
+
   if (empty($features)) {
   if (empty($features)) {
     // Clear & rebuild key caches
     // Clear & rebuild key caches
     features_get_info(NULL, NULL, TRUE);
     features_get_info(NULL, NULL, TRUE);

+ 1 - 1
sites/all/modules/contrib/admin/features/features.drush.inc

@@ -519,7 +519,7 @@ function drush_features_export() {
         drush_die('Aborting.');
         drush_die('Aborting.');
       }
       }
       $export = _drush_features_generate_export($items, $module);
       $export = _drush_features_generate_export($items, $module);
-      _features_populate($items, $export[info], $export[name]);
+      _features_populate($items, $export['info'], $export['name']);
       _drush_features_export($export['info'], $module, $directory);
       _drush_features_export($export['info'], $module, $directory);
     }
     }
   }
   }

+ 13 - 12
sites/all/modules/contrib/admin/features/features.export.inc

@@ -315,7 +315,7 @@ function features_export_render($export, $module_name, $reset = FALSE) {
   $code = array_filter($code);
   $code = array_filter($code);
   foreach ($code as $filename => $contents) {
   foreach ($code as $filename => $contents) {
     if ($filename != '_files') {
     if ($filename != '_files') {
-      $code[$filename] = "<?php\n/**\n * @file\n * {$module_name}.{$filename}.inc\n */\n\n". implode("\n\n", $contents) ."\n";
+      $code[$filename] = "<?php\n\n/**\n * @file\n * {$module_name}.{$filename}.inc\n */\n\n". implode("\n\n", $contents) ."\n";
     }
     }
   }
   }
 
 
@@ -332,8 +332,8 @@ function features_export_render($export, $module_name, $reset = FALSE) {
   $code['info'] = features_export_info($export);
   $code['info'] = features_export_info($export);
 
 
   // Used to create or manipulate the generated .module for features.inc.
   // Used to create or manipulate the generated .module for features.inc.
-  $modulefile_features_inc = "<?php\n/**\n * @file\n * Code for the {$export['name']} feature.\n */\n\ninclude_once '{$module_name}.features.inc';\n";
-  $modulefile_blank = "<?php\n/**\n * @file\n * Drupal needs this blank file.\n */\n";
+  $modulefile_features_inc = "<?php\n\n/**\n * @file\n * Code for the {$export['name']} feature.\n */\n\ninclude_once '{$module_name}.features.inc';\n";
+  $modulefile_blank = "<?php\n\n/**\n * @file\n * Drupal needs this blank file.\n */\n";
 
 
   // Prepare the module
   // Prepare the module
   // If module exists, let it be and include it in the files
   // If module exists, let it be and include it in the files
@@ -1088,13 +1088,6 @@ function _features_is_assoc($array) {
  *   returns a copy of the object or array with recursion removed
  *   returns a copy of the object or array with recursion removed
  */
  */
 function features_remove_recursion($o) {
 function features_remove_recursion($o) {
-  static $replace;
-  if (!isset($replace)) {
-    $replace = create_function(
-      '$m',
-      '$r="\x00{$m[1]}ecursion_features";return \'s:\'.strlen($r.$m[2]).\':"\'.$r.$m[2].\'";\';'
-    );
-  }
   if (is_array($o) || is_object($o)) {
   if (is_array($o) || is_object($o)) {
     $re = '#(r|R):([0-9]+);#';
     $re = '#(r|R):([0-9]+);#';
     $serialize = serialize($o);
     $serialize = serialize($o);
@@ -1104,7 +1097,7 @@ function features_remove_recursion($o) {
         $chunk = substr($serialize, $last, $pos - $last);
         $chunk = substr($serialize, $last, $pos - $last);
         if (preg_match($re, $chunk)) {
         if (preg_match($re, $chunk)) {
           $length = strlen($chunk);
           $length = strlen($chunk);
-          $chunk = preg_replace_callback($re, $replace, $chunk);
+          $chunk = preg_replace_callback($re, '_features_remove_recursion', $chunk);
           $serialize = substr($serialize, 0, $last) . $chunk . substr($serialize, $last + ($pos - $last));
           $serialize = substr($serialize, 0, $last) . $chunk . substr($serialize, $last + ($pos - $last));
           $pos += strlen($chunk) - $length;
           $pos += strlen($chunk) - $length;
         }
         }
@@ -1114,13 +1107,21 @@ function features_remove_recursion($o) {
         $last += 4 + $length;
         $last += 4 + $length;
         $pos = $last;
         $pos = $last;
       }
       }
-      $serialize = substr($serialize, 0, $last) . preg_replace_callback($re, $replace, substr($serialize, $last));
+      $serialize = substr($serialize, 0, $last) . preg_replace_callback($re, '_features_remove_recursion', substr($serialize, $last));
       $o = unserialize($serialize);
       $o = unserialize($serialize);
     }
     }
   }
   }
   return $o;
   return $o;
 }
 }
 
 
+/**
+ * Callback function for preg_replace_callback() to remove recursion.
+ */
+function _features_remove_recursion($m) {
+  $r = "\x00{$m[1]}ecursion_features";
+  return 's:' . strlen($r . $m[2]) . ':"' . $r . $m[2] . '";';
+}
+
 /**
 /**
  * Helper to removes a set of keys an object/array.
  * Helper to removes a set of keys an object/array.
  *
  *

+ 3 - 4
sites/all/modules/contrib/admin/features/features.info

@@ -10,9 +10,8 @@ test_dependencies[] = views
 
 
 configure = admin/structure/features/settings
 configure = admin/structure/features/settings
 
 
-; Information added by Drupal.org packaging script on 2016-04-18
-version = "7.x-2.10"
+; Information added by Drupal.org packaging script on 2018-11-01
+version = "7.x-2.11"
 core = "7.x"
 core = "7.x"
 project = "features"
 project = "features"
-datestamp = "1461011641"
-
+datestamp = "1541050686"

+ 1 - 0
sites/all/modules/contrib/admin/features/features.module

@@ -503,6 +503,7 @@ function features_load_feature($name, $reset = FALSE) {
         $features[$name]->name = $name;
         $features[$name]->name = $name;
         $features[$name]->filename = drupal_get_path('module', $name) . '/' . $name . '.module';
         $features[$name]->filename = drupal_get_path('module', $name) . '/' . $name . '.module';
         $features[$name]->type = 'module';
         $features[$name]->type = 'module';
+        $features[$name]->status = module_exists($name);
         $features[$name]->info = $info + $defaults;
         $features[$name]->info = $info + $defaults;
       }
       }
     }
     }

+ 4 - 4
sites/all/modules/contrib/admin/features/includes/features.field.inc

@@ -274,7 +274,7 @@ function field_base_features_rebuild($module) {
       // Create or update field.
       // Create or update field.
       if (isset($existing_fields[$field['field_name']])) {
       if (isset($existing_fields[$field['field_name']])) {
         $existing_field = $existing_fields[$field['field_name']];
         $existing_field = $existing_fields[$field['field_name']];
-        $array_diff_result = drupal_array_diff_assoc_recursive($field + $existing_field, $existing_field);
+        $array_diff_result = features_array_diff_assoc_recursive($field + $existing_field, $existing_field);
         if (!empty($array_diff_result)) {
         if (!empty($array_diff_result)) {
           try {
           try {
             field_update_field($field);
             field_update_field($field);
@@ -319,7 +319,7 @@ function field_instance_features_rebuild($module) {
       // Create or update field instance.
       // Create or update field instance.
       if (isset($existing_instances[$field_instance['entity_type']][$field_instance['bundle']][$field_instance['field_name']])) {
       if (isset($existing_instances[$field_instance['entity_type']][$field_instance['bundle']][$field_instance['field_name']])) {
         $existing_instance = $existing_instances[$field_instance['entity_type']][$field_instance['bundle']][$field_instance['field_name']];
         $existing_instance = $existing_instances[$field_instance['entity_type']][$field_instance['bundle']][$field_instance['field_name']];
-        if ($field_instance + $existing_instance !== $existing_instance) {
+        if ($field_instance + $existing_instance != $existing_instance) {
           try {
           try {
             field_update_instance($field_instance);
             field_update_instance($field_instance);
           }
           }
@@ -494,7 +494,7 @@ function field_features_rebuild($module) {
       $field_config = $field['field_config'];
       $field_config = $field['field_config'];
       if (isset($existing_fields[$field_config['field_name']])) {
       if (isset($existing_fields[$field_config['field_name']])) {
         $existing_field = $existing_fields[$field_config['field_name']];
         $existing_field = $existing_fields[$field_config['field_name']];
-        $array_diff_result = drupal_array_diff_assoc_recursive($field_config + $existing_field, $existing_field);
+        $array_diff_result = features_array_diff_assoc_recursive($field_config + $existing_field, $existing_field);
         if (!empty($array_diff_result)) {
         if (!empty($array_diff_result)) {
           try {
           try {
             field_update_field($field_config);
             field_update_field($field_config);
@@ -518,7 +518,7 @@ function field_features_rebuild($module) {
       $field_instance = $field['field_instance'];
       $field_instance = $field['field_instance'];
       if (isset($existing_instances[$field_instance['entity_type']][$field_instance['bundle']][$field_instance['field_name']])) {
       if (isset($existing_instances[$field_instance['entity_type']][$field_instance['bundle']][$field_instance['field_name']])) {
         $existing_instance = $existing_instances[$field_instance['entity_type']][$field_instance['bundle']][$field_instance['field_name']];
         $existing_instance = $existing_instances[$field_instance['entity_type']][$field_instance['bundle']][$field_instance['field_name']];
-        if ($field_instance + $existing_instance !== $existing_instance) {
+        if ($field_instance + $existing_instance != $existing_instance) {
           field_update_instance($field_instance);
           field_update_instance($field_instance);
         }
         }
       }
       }

+ 8 - 2
sites/all/modules/contrib/admin/features/includes/features.image.inc

@@ -73,11 +73,17 @@ function image_features_export_render($module_name, $data, $export = NULL) {
  */
  */
 function image_features_revert($module) {
 function image_features_revert($module) {
   if ($default_styles = features_get_default('image', $module)) {
   if ($default_styles = features_get_default('image', $module)) {
-    foreach (array_keys($default_styles) as $default_style) {
-      if ($style = image_style_load($default_style)) {
+    foreach ($default_styles as $default_style_name => $default_style) {
+      if ($style = image_style_load($default_style_name)) {
         if ($style['storage'] != IMAGE_STORAGE_DEFAULT) {
         if ($style['storage'] != IMAGE_STORAGE_DEFAULT) {
           image_default_style_revert($style);
           image_default_style_revert($style);
         }
         }
+        else {
+          // Verify that the loaded style still matches what's in code.
+          if ($default_style['effects'] !== $style['effects']) {
+            image_default_style_revert($style);
+          }
+        }
       }
       }
     }
     }
   }
   }

+ 8 - 4
sites/all/modules/contrib/admin/features/includes/features.menu.inc

@@ -420,8 +420,12 @@ function features_menu_link_load($identifier) {
  * Returns a lowercase clean string with only letters, numbers and dashes
  * Returns a lowercase clean string with only letters, numbers and dashes
  */
  */
 function features_clean_title($str) {
 function features_clean_title($str) {
-  return strtolower(preg_replace_callback('/(\s)|([^a-zA-Z\-0-9])/i', create_function(
-          '$matches',
-          'return $matches[1]?"-":"";'
-      ), $str));
+  return strtolower(preg_replace_callback('/(\s)|([^a-zA-Z\-0-9])/i', '_features_clean_title', $str));
+}
+
+/**
+ * Callback function for preg_replace_callback() to clean a string.
+ */
+function _features_clean_title($matches) {
+  return $matches[1] ? '-' : '';
 }
 }

+ 3 - 0
sites/all/modules/contrib/admin/features/tests/features.test

@@ -14,6 +14,7 @@ class FeaturesUserTestCase extends DrupalWebTestCase {
       'name' => t('Component tests'),
       'name' => t('Component tests'),
       'description' => t('Run tests for components of Features.') ,
       'description' => t('Run tests for components of Features.') ,
       'group' => t('Features'),
       'group' => t('Features'),
+      'dependencies' => array('views', 'strongarm'),
     );
     );
   }
   }
 
 
@@ -182,6 +183,7 @@ class FeaturesEnableTestCase extends DrupalWebTestCase {
       'name' => t('Features enable tests'),
       'name' => t('Features enable tests'),
       'description' => t('Run tests for enabling of features.') ,
       'description' => t('Run tests for enabling of features.') ,
       'group' => t('Features'),
       'group' => t('Features'),
+      'dependencies' => array('views', 'strongarm'),
     );
     );
   }
   }
 
 
@@ -231,6 +233,7 @@ class FeaturesCtoolsIntegrationTest extends DrupalWebTestCase {
       'name' => t('Features Chaos Tools integration'),
       'name' => t('Features Chaos Tools integration'),
       'description' => t('Run tests for ctool integration of features.') ,
       'description' => t('Run tests for ctool integration of features.') ,
       'group' => t('Features'),
       'group' => t('Features'),
+      'dependencies' => array('views', 'strongarm'),
     );
     );
   }
   }
 
 

+ 3 - 4
sites/all/modules/contrib/admin/features/tests/features_test/features_test.info

@@ -21,9 +21,8 @@ features[user_permission][] = create features_test content
 features[views_view][] = features_test
 features[views_view][] = features_test
 hidden = 1
 hidden = 1
 
 
-; Information added by Drupal.org packaging script on 2016-04-18
-version = "7.x-2.10"
+; Information added by Drupal.org packaging script on 2018-11-01
+version = "7.x-2.11"
 core = "7.x"
 core = "7.x"
 project = "features"
 project = "features"
-datestamp = "1461011641"
-
+datestamp = "1541050686"

+ 7 - 7
sites/all/modules/contrib/admin/google_analytics/README.txt

@@ -1,6 +1,6 @@
 
 
 Module: Google Analytics
 Module: Google Analytics
-Author: Alexander Hass <http://drupal.org/user/85918>
+Author: Alexander Hass <https://drupal.org/user/85918>
 
 
 
 
 Description
 Description
@@ -53,15 +53,15 @@ user with 'Administer Google Analytics' permission.
 Like the blocks visibility settings in Drupal core, there is a choice for
 Like the blocks visibility settings in Drupal core, there is a choice for
 "Add if the following PHP code returns TRUE." Sample PHP snippets that can be
 "Add if the following PHP code returns TRUE." Sample PHP snippets that can be
 used in this textarea can be found on the handbook page "Overview-approach to
 used in this textarea can be found on the handbook page "Overview-approach to
-block visibility" at http://drupal.org/node/64135.
+block visibility" at https://drupal.org/node/64135.
 
 
 Custom dimensions and metrics
 Custom dimensions and metrics
 =============================
 =============================
 One example for custom dimensions tracking is the "User roles" tracking.
 One example for custom dimensions tracking is the "User roles" tracking.
 
 
-1. In the Google Analytics Management Interface (http://www.google.com/analytics/)
-   you need to setup Dimension #1 with name e.g. "User roles". This step is
-   required. Do not miss it, please.
+1. In the Google Analytics (https://marketingplatform.google.com/about/analytics/)
+   Management Interface you need to setup Dimension #1 with name 
+   e.g. "User roles". This step is required. Do not miss it, please.
 
 
 2. Enter the below configuration data into the Drupal custom dimensions settings
 2. Enter the below configuration data into the Drupal custom dimensions settings
    form under admin/config/system/googleanalytics. You can also choose another
    form under admin/config/system/googleanalytics. You can also choose another
@@ -77,7 +77,7 @@ Advanced Settings
 =================
 =================
 You can include additional JavaScript snippets in the custom javascript
 You can include additional JavaScript snippets in the custom javascript
 code textarea. These can be found on the official Google Analytics pages
 code textarea. These can be found on the official Google Analytics pages
-and a few examples at http://drupal.org/node/248699. Support is not
+and a few examples at https://drupal.org/node/248699. Support is not
 provided for any customisations you include.
 provided for any customisations you include.
 
 
 To speed up page loading you may also cache the Google Analytics "analytics.js"
 To speed up page loading you may also cache the Google Analytics "analytics.js"
@@ -97,7 +97,7 @@ Body:
   <li><a href="mailto:foo@example.com">Mailto</a></li>
   <li><a href="mailto:foo@example.com">Mailto</a></li>
   <li><a href="/files/test.txt">Download file</a></li>
   <li><a href="/files/test.txt">Download file</a></li>
   <li><a class="colorbox" href="#">Open colorbox</a></li>
   <li><a class="colorbox" href="#">Open colorbox</a></li>
-  <li><a href="http://example.com/">External link</a></li>
+  <li><a href="https://example.com/">External link</a></li>
   <li><a href="/go/test">Go link</a></li>
   <li><a href="/go/test">Go link</a></li>
 </ul>
 </ul>
 
 

File diff suppressed because it is too large
+ 1 - 1
sites/all/modules/contrib/admin/google_analytics/googleanalytics.admin.inc


+ 3 - 3
sites/all/modules/contrib/admin/google_analytics/googleanalytics.debug.js

@@ -122,7 +122,7 @@ $(document).ready(function() {
 Drupal.googleanalytics.isCrossDomain = function (hostname, crossDomains) {
 Drupal.googleanalytics.isCrossDomain = function (hostname, crossDomains) {
   /**
   /**
    * jQuery < 1.6.3 bug: $.inArray crushes IE6 and Chrome if second argument is
    * jQuery < 1.6.3 bug: $.inArray crushes IE6 and Chrome if second argument is
-   * `null` or `undefined`, http://bugs.jquery.com/ticket/10076,
+   * `null` or `undefined`, https://bugs.jquery.com/ticket/10076,
    * https://github.com/jquery/jquery/commit/a839af034db2bd934e4d4fa6758a3fed8de74174
    * https://github.com/jquery/jquery/commit/a839af034db2bd934e4d4fa6758a3fed8de74174
    *
    *
    * @todo: Remove/Refactor in D8
    * @todo: Remove/Refactor in D8
@@ -181,8 +181,8 @@ Drupal.googleanalytics.isInternalSpecial = function (url) {
  * Extract the relative internal URL from an absolute internal URL.
  * Extract the relative internal URL from an absolute internal URL.
  *
  *
  * Examples:
  * Examples:
- * - http://mydomain.com/node/1 -> /node/1
- * - http://example.com/foo/bar -> http://example.com/foo/bar
+ * - https://mydomain.com/node/1 -> /node/1
+ * - https://example.com/foo/bar -> https://example.com/foo/bar
  *
  *
  * @param string url
  * @param string url
  *   The web url to check.
  *   The web url to check.

+ 3 - 4
sites/all/modules/contrib/admin/google_analytics/googleanalytics.info

@@ -5,9 +5,8 @@ package = Statistics
 configure = admin/config/system/googleanalytics
 configure = admin/config/system/googleanalytics
 files[] = googleanalytics.test
 files[] = googleanalytics.test
 test_dependencies[] = token
 test_dependencies[] = token
-; Information added by Drupal.org packaging script on 2016-08-09
-version = "7.x-2.3"
+; Information added by Drupal.org packaging script on 2019-01-31
+version = "7.x-2.6"
 core = "7.x"
 core = "7.x"
 project = "google_analytics"
 project = "google_analytics"
-datestamp = "1470779953"
-
+datestamp = "1548968597"

File diff suppressed because it is too large
+ 21 - 15
sites/all/modules/contrib/admin/google_analytics/googleanalytics.install


+ 3 - 3
sites/all/modules/contrib/admin/google_analytics/googleanalytics.js

@@ -104,7 +104,7 @@ $(document).ready(function() {
 Drupal.googleanalytics.isCrossDomain = function (hostname, crossDomains) {
 Drupal.googleanalytics.isCrossDomain = function (hostname, crossDomains) {
   /**
   /**
    * jQuery < 1.6.3 bug: $.inArray crushes IE6 and Chrome if second argument is
    * jQuery < 1.6.3 bug: $.inArray crushes IE6 and Chrome if second argument is
-   * `null` or `undefined`, http://bugs.jquery.com/ticket/10076,
+   * `null` or `undefined`, https://bugs.jquery.com/ticket/10076,
    * https://github.com/jquery/jquery/commit/a839af034db2bd934e4d4fa6758a3fed8de74174
    * https://github.com/jquery/jquery/commit/a839af034db2bd934e4d4fa6758a3fed8de74174
    *
    *
    * @todo: Remove/Refactor in D8
    * @todo: Remove/Refactor in D8
@@ -163,8 +163,8 @@ Drupal.googleanalytics.isInternalSpecial = function (url) {
  * Extract the relative internal URL from an absolute internal URL.
  * Extract the relative internal URL from an absolute internal URL.
  *
  *
  * Examples:
  * Examples:
- * - http://mydomain.com/node/1 -> /node/1
- * - http://example.com/foo/bar -> http://example.com/foo/bar
+ * - https://mydomain.com/node/1 -> /node/1
+ * - https://example.com/foo/bar -> https://example.com/foo/bar
  *
  *
  * @param string url
  * @param string url
  *   The web url to check.
  *   The web url to check.

+ 32 - 13
sites/all/modules/contrib/admin/google_analytics/googleanalytics.module

@@ -7,7 +7,7 @@
  * Adds the required Javascript to all your Drupal pages to allow tracking by
  * Adds the required Javascript to all your Drupal pages to allow tracking by
  * the Google Analytics statistics package.
  * the Google Analytics statistics package.
  *
  *
- * @author: Alexander Hass <http://drupal.org/user/85918>
+ * @author: Alexander Hass <https://drupal.org/user/85918>
  */
  */
 
 
 /**
 /**
@@ -17,7 +17,7 @@ define('GOOGLEANALYTICS_TRACKFILES_EXTENSIONS', '7z|aac|arc|arj|asf|asx|avi|bin|
 
 
 /**
 /**
  * Define default path exclusion list to remove tracking from admin pages,
  * Define default path exclusion list to remove tracking from admin pages,
- * see http://drupal.org/node/34970 for more information.
+ * see https://drupal.org/node/34970 for more information.
  */
  */
 define('GOOGLEANALYTICS_PAGES', "admin\nadmin/*\nbatch\nnode/add*\nnode/*/*\nuser/*/*");
 define('GOOGLEANALYTICS_PAGES', "admin\nadmin/*\nbatch\nnode/add*\nnode/*/*\nuser/*/*");
 
 
@@ -36,7 +36,7 @@ function googleanalytics_api() {
 function googleanalytics_help($path, $arg) {
 function googleanalytics_help($path, $arg) {
   switch ($path) {
   switch ($path) {
     case 'admin/config/system/googleanalytics':
     case 'admin/config/system/googleanalytics':
-      return t('<a href="@ga_url">Google Analytics</a> is a free (registration required) website traffic and marketing effectiveness service.', array('@ga_url' => 'http://www.google.com/analytics/'));
+      return t('<a href="@ga_url">Google Analytics</a> is a free (registration required) website traffic and marketing effectiveness service.', array('@ga_url' => 'https://marketingplatform.google.com/about/analytics/'));
   }
   }
 }
 }
 
 
@@ -98,7 +98,7 @@ function googleanalytics_menu() {
  * Implements hook_page_alter() to insert JavaScript to the appropriate scope/region of the page.
  * Implements hook_page_alter() to insert JavaScript to the appropriate scope/region of the page.
  */
  */
 function googleanalytics_page_alter(&$page) {
 function googleanalytics_page_alter(&$page) {
-  global $user;
+  global $base_path, $user;
 
 
   $id = variable_get('googleanalytics_account', '');
   $id = variable_get('googleanalytics_account', '');
 
 
@@ -134,7 +134,7 @@ function googleanalytics_page_alter(&$page) {
       $link_settings['trackColorbox'] = $track_colorbox;
       $link_settings['trackColorbox'] = $track_colorbox;
     }
     }
     if ($track_domain_mode = variable_get('googleanalytics_domain_mode', 0)) {
     if ($track_domain_mode = variable_get('googleanalytics_domain_mode', 0)) {
-      $link_settings['trackDomainMode'] = $track_domain_mode;
+      $link_settings['trackDomainMode'] = (int) $track_domain_mode;
     }
     }
     if ($track_cross_domains = variable_get('googleanalytics_cross_domains', '')) {
     if ($track_cross_domains = variable_get('googleanalytics_cross_domains', '')) {
       $link_settings['trackCrossDomains'] = preg_split('/(\r\n?|\n)/', $track_cross_domains);
       $link_settings['trackCrossDomains'] = preg_split('/(\r\n?|\n)/', $track_cross_domains);
@@ -201,11 +201,23 @@ function googleanalytics_page_alter(&$page) {
 
 
     // Track access denied (403) and file not found (404) pages.
     // Track access denied (403) and file not found (404) pages.
     if ($status == '403 Forbidden') {
     if ($status == '403 Forbidden') {
-      // See http://www.google.com/support/analytics/bin/answer.py?answer=86927
-      $url_custom = '"/403.html?page=" + document.location.pathname + document.location.search + "&from=" + document.referrer';
+      // See https://www.google.com/support/analytics/bin/answer.py?answer=86927
+      $url_custom = '"' . $base_path . '403.html?page=" + document.location.pathname + document.location.search + "&from=" + document.referrer';
     }
     }
     elseif ($status == '404 Not Found') {
     elseif ($status == '404 Not Found') {
-      $url_custom = '"/404.html?page=" + document.location.pathname + document.location.search + "&from=" + document.referrer';
+      $url_custom = '"' . $base_path . '404.html?page=" + document.location.pathname + document.location.search + "&from=" + document.referrer';
+    }
+
+    // #2693595: User has entered an invalid login and clicked on forgot
+    // password link. This link contains the username or email address and may
+    // get send to Google if we do not override it. Override only if 'name'
+    // query param exists. Last custom url condition, this need to win.
+    //
+    // URLs to protect are:
+    // - user/password?name=username
+    // - user/password?name=foo@example.com
+    if (arg(0) == 'user' && arg(1) == 'password' && array_key_exists('name', drupal_get_query_parameters())) {
+      $url_custom = '"' . $base_path . 'user/password"';
     }
     }
 
 
     // Add custom dimensions and metrics.
     // Add custom dimensions and metrics.
@@ -256,11 +268,10 @@ function googleanalytics_page_alter(&$page) {
     $script .= '})(window,document,"script",';
     $script .= '})(window,document,"script",';
 
 
     // Which version of the tracking library should be used?
     // Which version of the tracking library should be used?
-    $library_tracker_url = '//www.google-analytics.com/' . ($debug ? 'analytics_debug.js' : 'analytics.js');
-    $library_cache_url = 'http:' . $library_tracker_url;
+    $library_tracker_url = 'https://www.google-analytics.com/' . ($debug ? 'analytics_debug.js' : 'analytics.js');
 
 
     // Should a local cached copy of analytics.js be used?
     // Should a local cached copy of analytics.js be used?
-    if (variable_get('googleanalytics_cache', 0) && $url = _googleanalytics_cache($library_cache_url)) {
+    if (variable_get('googleanalytics_cache', 0) && $url = _googleanalytics_cache($library_tracker_url)) {
       // A dummy query-string is added to filenames, to gain control over
       // A dummy query-string is added to filenames, to gain control over
       // browser-caching. The string changes on every update or full cache
       // browser-caching. The string changes on every update or full cache
       // flush, forcing browsers to load a new copy of the files, as the
       // flush, forcing browsers to load a new copy of the files, as the
@@ -462,7 +473,7 @@ function googleanalytics_user_presave(&$edit, $account, $category) {
 function googleanalytics_cron() {
 function googleanalytics_cron() {
   // Regenerate the tracking code file every day.
   // Regenerate the tracking code file every day.
   if (REQUEST_TIME - variable_get('googleanalytics_last_cache', 0) >= 86400 && variable_get('googleanalytics_cache', 0)) {
   if (REQUEST_TIME - variable_get('googleanalytics_last_cache', 0) >= 86400 && variable_get('googleanalytics_cache', 0)) {
-    _googleanalytics_cache('http://www.google-analytics.com/analytics.js', TRUE);
+    _googleanalytics_cache('https://www.google-analytics.com/analytics.js', TRUE);
     variable_set('googleanalytics_last_cache', REQUEST_TIME);
     variable_set('googleanalytics_last_cache', REQUEST_TIME);
   }
   }
 }
 }
@@ -485,7 +496,7 @@ function googleanalytics_preprocess_search_results(&$variables) {
 /**
 /**
  * Helper function for grabbing search keys. Function is missing in D7.
  * Helper function for grabbing search keys. Function is missing in D7.
  *
  *
- * http://api.drupal.org/api/function/search_get_keys/6
+ * https://api.drupal.org/api/function/search_get_keys/6
  */
  */
 function googleanalytics_search_get_keys() {
 function googleanalytics_search_get_keys() {
   static $return;
   static $return;
@@ -526,6 +537,10 @@ function _googleanalytics_cache($location, $synchronize = FALSE) {
         if ($data_hash_local != $data_hash_remote && file_prepare_directory($path)) {
         if ($data_hash_local != $data_hash_remote && file_prepare_directory($path)) {
           // Save updated tracking code file to disk.
           // Save updated tracking code file to disk.
           file_unmanaged_save_data($result->data, $file_destination, FILE_EXISTS_REPLACE);
           file_unmanaged_save_data($result->data, $file_destination, FILE_EXISTS_REPLACE);
+          // Based on Drupal Core drupal_build_css_cache().
+          if (variable_get('css_gzip_compression', TRUE) && variable_get('clean_url', 0) && extension_loaded('zlib')) {
+            file_unmanaged_save_data(gzencode($result->data, 9, FORCE_GZIP), $file_destination . '.gz', FILE_EXISTS_REPLACE);
+          }
           watchdog('googleanalytics', 'Locally cached tracking code file has been updated.', array(), WATCHDOG_INFO);
           watchdog('googleanalytics', 'Locally cached tracking code file has been updated.', array(), WATCHDOG_INFO);
 
 
           // Change query-strings on css/js files to enforce reload for all users.
           // Change query-strings on css/js files to enforce reload for all users.
@@ -538,6 +553,10 @@ function _googleanalytics_cache($location, $synchronize = FALSE) {
           // There is no need to flush JS here as core refreshes JS caches
           // There is no need to flush JS here as core refreshes JS caches
           // automatically, if new files are added.
           // automatically, if new files are added.
           file_unmanaged_save_data($result->data, $file_destination, FILE_EXISTS_REPLACE);
           file_unmanaged_save_data($result->data, $file_destination, FILE_EXISTS_REPLACE);
+          // Based on Drupal Core drupal_build_css_cache().
+          if (variable_get('css_gzip_compression', TRUE) && variable_get('clean_url', 0) && extension_loaded('zlib')) {
+            file_unmanaged_save_data(gzencode($result->data, 9, FORCE_GZIP), $file_destination . '.gz', FILE_EXISTS_REPLACE);
+          }
           watchdog('googleanalytics', 'Locally cached tracking code file has been saved.', array(), WATCHDOG_INFO);
           watchdog('googleanalytics', 'Locally cached tracking code file has been saved.', array(), WATCHDOG_INFO);
 
 
           // Return the local JS file path.
           // Return the local JS file path.

+ 61 - 13
sites/all/modules/contrib/admin/google_analytics/googleanalytics.test

@@ -83,7 +83,7 @@ class GoogleAnalyticsBasicTest extends DrupalWebTestCase {
     // Verify that no tracking code is embedded into the webpage; if there is
     // Verify that no tracking code is embedded into the webpage; if there is
     // only the module installed, but UA code not configured. See #2246991.
     // only the module installed, but UA code not configured. See #2246991.
     $this->drupalGet('');
     $this->drupalGet('');
-    $this->assertNoRaw('//www.google-analytics.com/analytics.js', '[testGoogleAnalyticsPageVisibility]: Tracking code is not displayed without UA code configured.');
+    $this->assertNoRaw('https://www.google-analytics.com/analytics.js', '[testGoogleAnalyticsPageVisibility]: Tracking code is not displayed without UA code configured.');
 
 
     $ua_code = 'UA-123456-1';
     $ua_code = 'UA-123456-1';
     variable_set('googleanalytics_account', $ua_code);
     variable_set('googleanalytics_account', $ua_code);
@@ -104,7 +104,7 @@ class GoogleAnalyticsBasicTest extends DrupalWebTestCase {
     $this->assertNoRaw($ua_code, '[testGoogleAnalyticsPageVisibility]: Tracking code is not displayed on admin page.');
     $this->assertNoRaw($ua_code, '[testGoogleAnalyticsPageVisibility]: Tracking code is not displayed on admin page.');
     $this->drupalGet('admin/config/system/googleanalytics');
     $this->drupalGet('admin/config/system/googleanalytics');
     // Checking for tracking code URI here, as $ua_code is displayed in the form.
     // Checking for tracking code URI here, as $ua_code is displayed in the form.
-    $this->assertNoRaw('//www.google-analytics.com/analytics.js', '[testGoogleAnalyticsPageVisibility]: Tracking code is not displayed on admin subpage.');
+    $this->assertNoRaw('https://www.google-analytics.com/analytics.js', '[testGoogleAnalyticsPageVisibility]: Tracking code is not displayed on admin subpage.');
 
 
     // Test whether tracking code display is properly flipped.
     // Test whether tracking code display is properly flipped.
     variable_set('googleanalytics_visibility_pages', 1);
     variable_set('googleanalytics_visibility_pages', 1);
@@ -112,7 +112,7 @@ class GoogleAnalyticsBasicTest extends DrupalWebTestCase {
     $this->assertRaw($ua_code, '[testGoogleAnalyticsPageVisibility]: Tracking code is displayed on admin page.');
     $this->assertRaw($ua_code, '[testGoogleAnalyticsPageVisibility]: Tracking code is displayed on admin page.');
     $this->drupalGet('admin/config/system/googleanalytics');
     $this->drupalGet('admin/config/system/googleanalytics');
     // Checking for tracking code URI here, as $ua_code is displayed in the form.
     // Checking for tracking code URI here, as $ua_code is displayed in the form.
-    $this->assertRaw('//www.google-analytics.com/analytics.js', '[testGoogleAnalyticsPageVisibility]: Tracking code is displayed on admin subpage.');
+    $this->assertRaw('https://www.google-analytics.com/analytics.js', '[testGoogleAnalyticsPageVisibility]: Tracking code is displayed on admin subpage.');
     $this->drupalGet('');
     $this->drupalGet('');
     $this->assertNoRaw($ua_code, '[testGoogleAnalyticsPageVisibility]: Tracking code is NOT displayed on front page.');
     $this->assertNoRaw($ua_code, '[testGoogleAnalyticsPageVisibility]: Tracking code is NOT displayed on front page.');
 
 
@@ -126,13 +126,15 @@ class GoogleAnalyticsBasicTest extends DrupalWebTestCase {
     // Enable tracking code for all user roles.
     // Enable tracking code for all user roles.
     variable_set('googleanalytics_roles', array());
     variable_set('googleanalytics_roles', array());
 
 
+    $base_path = base_path();
+
     // Test whether 403 forbidden tracking code is shown if user has no access.
     // Test whether 403 forbidden tracking code is shown if user has no access.
     $this->drupalGet('admin');
     $this->drupalGet('admin');
-    $this->assertRaw('/403.html', '[testGoogleAnalyticsPageVisibility]: 403 Forbidden tracking code shown if user has no access.');
+    $this->assertRaw($base_path . '403.html', '[testGoogleAnalyticsPageVisibility]: 403 Forbidden tracking code shown if user has no access.');
 
 
     // Test whether 404 not found tracking code is shown on non-existent pages.
     // Test whether 404 not found tracking code is shown on non-existent pages.
     $this->drupalGet($this->randomName(64));
     $this->drupalGet($this->randomName(64));
-    $this->assertRaw('/404.html', '[testGoogleAnalyticsPageVisibility]: 404 Not Found tracking code shown on non-existent page.');
+    $this->assertRaw($base_path . '404.html', '[testGoogleAnalyticsPageVisibility]: 404 Not Found tracking code shown on non-existent page.');
 
 
     // DNT Tests:
     // DNT Tests:
     // Enable system internal page cache for anonymous users.
     // Enable system internal page cache for anonymous users.
@@ -168,7 +170,7 @@ class GoogleAnalyticsBasicTest extends DrupalWebTestCase {
     (function(q,u,i,c,k){window['GoogleAnalyticsObject']=q;
     (function(q,u,i,c,k){window['GoogleAnalyticsObject']=q;
     window[q]=window[q]||function(){(window[q].q=window[q].q||[]).push(arguments)},
     window[q]=window[q]||function(){(window[q].q=window[q].q||[]).push(arguments)},
     window[q].l=1*new Date();c=i.createElement(u),k=i.getElementsByTagName(u)[0];
     window[q].l=1*new Date();c=i.createElement(u),k=i.getElementsByTagName(u)[0];
-    c.async=true;c.src='//www.google-analytics.com/analytics.js';
+    c.async=true;c.src='https://www.google-analytics.com/analytics.js';
     k.parentNode.insertBefore(c,k)})('ga','script',document);
     k.parentNode.insertBefore(c,k)})('ga','script',document);
     ga('create', 'UA-123456-7');
     ga('create', 'UA-123456-7');
     ga('send', 'pageview');
     ga('send', 'pageview');
@@ -179,7 +181,7 @@ class GoogleAnalyticsBasicTest extends DrupalWebTestCase {
     // Test whether tracking code uses latest JS.
     // Test whether tracking code uses latest JS.
     variable_set('googleanalytics_cache', 0);
     variable_set('googleanalytics_cache', 0);
     $this->drupalGet('');
     $this->drupalGet('');
-    $this->assertRaw('//www.google-analytics.com/analytics.js', '[testGoogleAnalyticsTrackingCode]: Latest tracking code used.');
+    $this->assertRaw('https://www.google-analytics.com/analytics.js', '[testGoogleAnalyticsTrackingCode]: Latest tracking code used.');
 
 
     // Test whether anonymize visitors IP address feature has been enabled.
     // Test whether anonymize visitors IP address feature has been enabled.
     variable_set('googleanalytics_tracker_anonymizeip', 0);
     variable_set('googleanalytics_tracker_anonymizeip', 0);
@@ -256,13 +258,14 @@ class GoogleAnalyticsBasicTest extends DrupalWebTestCase {
     $this->assertRaw('ga("create", "' . $ua_code . '", {"cookieDomain":"auto","allowLinker":true', '[testGoogleAnalyticsTrackingCode]: "allowLinker" has been found. Cross domain tracking is active.');
     $this->assertRaw('ga("create", "' . $ua_code . '", {"cookieDomain":"auto","allowLinker":true', '[testGoogleAnalyticsTrackingCode]: "allowLinker" has been found. Cross domain tracking is active.');
     $this->assertRaw('ga("require", "linker");', '[testGoogleAnalyticsTrackingCode]: Require linker has been found. Cross domain tracking is active.');
     $this->assertRaw('ga("require", "linker");', '[testGoogleAnalyticsTrackingCode]: Require linker has been found. Cross domain tracking is active.');
     $this->assertRaw('ga("linker:autoLink", ["www.example.com","www.example.net"]);', '[testGoogleAnalyticsTrackingCode]: "linker:autoLink" has been found. Cross domain tracking is active.');
     $this->assertRaw('ga("linker:autoLink", ["www.example.com","www.example.net"]);', '[testGoogleAnalyticsTrackingCode]: "linker:autoLink" has been found. Cross domain tracking is active.');
+    $this->assertRaw('"trackDomainMode":2,', '[testGoogleAnalyticsTrackingCode]: Domain mode value is of type integer.');
     $this->assertRaw('"trackCrossDomains":["www.example.com","www.example.net"]', '[testGoogleAnalyticsTrackingCode]: Cross domain tracking with www.example.com and www.example.net is active.');
     $this->assertRaw('"trackCrossDomains":["www.example.com","www.example.net"]', '[testGoogleAnalyticsTrackingCode]: Cross domain tracking with www.example.com and www.example.net is active.');
     variable_set('googleanalytics_domain_mode', 0);
     variable_set('googleanalytics_domain_mode', 0);
 
 
     // Test whether debugging script has been enabled.
     // Test whether debugging script has been enabled.
     variable_set('googleanalytics_debug', 1);
     variable_set('googleanalytics_debug', 1);
     $this->drupalGet('');
     $this->drupalGet('');
-    $this->assertRaw('//www.google-analytics.com/analytics_debug.js', '[testGoogleAnalyticsTrackingCode]: Google debugging script has been enabled.');
+    $this->assertRaw('https://www.google-analytics.com/analytics_debug.js', '[testGoogleAnalyticsTrackingCode]: Google debugging script has been enabled.');
 
 
     // Check if text and link is shown on 'Status Reports' page.
     // Check if text and link is shown on 'Status Reports' page.
     // Requires 'administer site configuration' permission.
     // Requires 'administer site configuration' permission.
@@ -272,7 +275,7 @@ class GoogleAnalyticsBasicTest extends DrupalWebTestCase {
     // Test whether debugging script has been disabled.
     // Test whether debugging script has been disabled.
     variable_set('googleanalytics_debug', 0);
     variable_set('googleanalytics_debug', 0);
     $this->drupalGet('');
     $this->drupalGet('');
-    $this->assertRaw('//www.google-analytics.com/analytics.js', '[testGoogleAnalyticsTrackingCode]: Google debugging script has been disabled.');
+    $this->assertRaw('https://www.google-analytics.com/analytics.js', '[testGoogleAnalyticsTrackingCode]: Google debugging script has been disabled.');
 
 
     // Test whether the CREATE and BEFORE and AFTER code is added to the tracker.
     // Test whether the CREATE and BEFORE and AFTER code is added to the tracker.
     $codesnippet_create = array(
     $codesnippet_create = array(
@@ -473,6 +476,51 @@ class GoogleAnalyticsCustomDimensionsAndMetricsTest extends DrupalWebTestCase {
   }
   }
 }
 }
 
 
+/**
+ * Test custom url functionality of Google Analytics module.
+ */
+class GoogleAnalyticsCustomUrls extends DrupalWebTestCase {
+
+  public static function getInfo() {
+    return array(
+      'name' => 'Google Analytics custom url tests',
+      'description' => 'Test custom url functionality of Google Analytics module.',
+      'group' => 'Google Analytics',
+    );
+  }
+
+  function setUp() {
+    parent::setUp('googleanalytics');
+
+    $permissions = array(
+      'access administration pages',
+      'administer google analytics',
+    );
+
+    // User to set up google_analytics.
+    $this->admin_user = $this->drupalCreateUser($permissions);
+  }
+
+  /**
+   * Tests if user password page urls are overridden.
+   */
+  public function testGoogleAnalyticsUserPasswordPage() {
+    $base_path = base_path();
+    $ua_code = 'UA-123456-4';
+    variable_set('googleanalytics_account', $ua_code);
+
+    $this->drupalGet('user/password', array('query' => array('name' => 'foo')));
+    $this->assertRaw('ga("set", "page", "' . $base_path . 'user/password"');
+
+    $this->drupalGet('user/password', array('query' => array('name' => 'foo@example.com')));
+    $this->assertRaw('ga("set", "page", "' . $base_path . 'user/password"');
+
+    $this->drupalGet('user/password');
+    $this->assertNoRaw('ga("set", "page",', '[testGoogleAnalyticsCustomUrls]: Custom url not set.');
+  }
+
+}
+
 class GoogleAnalyticsStatusMessagesTest extends DrupalWebTestCase {
 class GoogleAnalyticsStatusMessagesTest extends DrupalWebTestCase {
 
 
   public static function getInfo() {
   public static function getInfo() {
@@ -510,7 +558,7 @@ class GoogleAnalyticsStatusMessagesTest extends DrupalWebTestCase {
     //drupal_set_message('Example status message.', 'status');
     //drupal_set_message('Example status message.', 'status');
     //drupal_set_message('Example warning message.', 'warning');
     //drupal_set_message('Example warning message.', 'warning');
     //drupal_set_message('Example error message.', 'error');
     //drupal_set_message('Example error message.', 'error');
-    //drupal_set_message('Example error <em>message</em> with html tags and <a href="http://example.com/">link</a>.', 'error');
+    //drupal_set_message('Example error <em>message</em> with html tags and <a href="https://example.com/">link</a>.', 'error');
     //$this->drupalGet('');
     //$this->drupalGet('');
     //$this->assertNoRaw('ga("send", "event", "Messages", "Status message", "Example status message.");', '[testGoogleAnalyticsStatusMessages]: Example status message is not enabled for tracking.');
     //$this->assertNoRaw('ga("send", "event", "Messages", "Status message", "Example status message.");', '[testGoogleAnalyticsStatusMessages]: Example status message is not enabled for tracking.');
     //$this->assertNoRaw('ga("send", "event", "Messages", "Warning message", "Example warning message.");', '[testGoogleAnalyticsStatusMessages]: Example warning message is not enabled for tracking.');
     //$this->assertNoRaw('ga("send", "event", "Messages", "Warning message", "Example warning message.");', '[testGoogleAnalyticsStatusMessages]: Example warning message is not enabled for tracking.');
@@ -734,13 +782,13 @@ class GoogleAnalyticsPhpFilterTest extends DrupalWebTestCase {
     // Check tracking code visibility.
     // Check tracking code visibility.
     variable_set('googleanalytics_pages', '<?php return TRUE; ?>');
     variable_set('googleanalytics_pages', '<?php return TRUE; ?>');
     $this->drupalGet('');
     $this->drupalGet('');
-    $this->assertRaw('//www.google-analytics.com/analytics.js', '[testGoogleAnalyticsPhpFilter]: Tracking is displayed on frontpage page.');
+    $this->assertRaw('https://www.google-analytics.com/analytics.js', '[testGoogleAnalyticsPhpFilter]: Tracking is displayed on frontpage page.');
     $this->drupalGet('admin');
     $this->drupalGet('admin');
-    $this->assertRaw('//www.google-analytics.com/analytics.js', '[testGoogleAnalyticsPhpFilter]: Tracking is displayed on admin page.');
+    $this->assertRaw('https://www.google-analytics.com/analytics.js', '[testGoogleAnalyticsPhpFilter]: Tracking is displayed on admin page.');
 
 
     variable_set('googleanalytics_pages', '<?php return FALSE; ?>');
     variable_set('googleanalytics_pages', '<?php return FALSE; ?>');
     $this->drupalGet('');
     $this->drupalGet('');
-    $this->assertNoRaw('//www.google-analytics.com/analytics.js', '[testGoogleAnalyticsPhpFilter]: Tracking is not displayed on frontpage page.');
+    $this->assertNoRaw('https://www.google-analytics.com/analytics.js', '[testGoogleAnalyticsPhpFilter]: Tracking is not displayed on frontpage page.');
 
 
     // Test administration form.
     // Test administration form.
     variable_set('googleanalytics_pages', '<?php return TRUE; ?>');
     variable_set('googleanalytics_pages', '<?php return TRUE; ?>');

+ 8 - 6
sites/all/modules/contrib/admin/google_analytics/googleanalytics.test.js

@@ -77,7 +77,7 @@ $(document).ready(function() {
   Drupal.googleanalytics.test.assertTrue(Drupal.googleanalytics.isInternal(base_url + Drupal.settings.basePath + 'node/1?foo=bar'), "Link '" + base_url + Drupal.settings.basePath + "node/1?foo=bar' has been detected as internal link.");
   Drupal.googleanalytics.test.assertTrue(Drupal.googleanalytics.isInternal(base_url + Drupal.settings.basePath + 'node/1?foo=bar'), "Link '" + base_url + Drupal.settings.basePath + "node/1?foo=bar' has been detected as internal link.");
   Drupal.googleanalytics.test.assertTrue(Drupal.googleanalytics.isInternal(base_url + Drupal.settings.basePath + 'node/1?foo=bar#foo'), "Link '" + base_url + Drupal.settings.basePath + "node/1?foo=bar#foo' has been detected as internal link.");
   Drupal.googleanalytics.test.assertTrue(Drupal.googleanalytics.isInternal(base_url + Drupal.settings.basePath + 'node/1?foo=bar#foo'), "Link '" + base_url + Drupal.settings.basePath + "node/1?foo=bar#foo' has been detected as internal link.");
   Drupal.googleanalytics.test.assertTrue(Drupal.googleanalytics.isInternal(base_url + Drupal.settings.basePath + 'go/foo'), "Link '" + base_url + Drupal.settings.basePath + "go/foo' has been detected as internal link.");
   Drupal.googleanalytics.test.assertTrue(Drupal.googleanalytics.isInternal(base_url + Drupal.settings.basePath + 'go/foo'), "Link '" + base_url + Drupal.settings.basePath + "go/foo' has been detected as internal link.");
-  Drupal.googleanalytics.test.assertFalse(Drupal.googleanalytics.isInternal('http://example.com/node/3'), "Link 'http://example.com/node/3' has been detected as external link.");
+  Drupal.googleanalytics.test.assertFalse(Drupal.googleanalytics.isInternal('https://example.com/node/3'), "Link 'https://example.com/node/3' has been detected as external link.");
   console.groupEnd();
   console.groupEnd();
 
 
   console.group("Test 'isInternalSpecial':");
   console.group("Test 'isInternalSpecial':");
@@ -86,9 +86,11 @@ $(document).ready(function() {
   console.groupEnd();
   console.groupEnd();
 
 
   console.group("Test 'getPageUrl':");
   console.group("Test 'getPageUrl':");
-  Drupal.googleanalytics.test.assertSame(base_path, Drupal.googleanalytics.getPageUrl(base_url + Drupal.settings.basePath + 'node/1'), "Absolute internal URL '" +  Drupal.settings.basePath + "node/1' has been extracted from full qualified url '" + base_url + base_path + "'.");
-  Drupal.googleanalytics.test.assertSame(base_path, Drupal.googleanalytics.getPageUrl(Drupal.settings.basePath + 'node/1'), "Absolute internal URL '" +  Drupal.settings.basePath + "node/1' has been extracted from absolute url '" +  base_path + "'.");
-  Drupal.googleanalytics.test.assertSame('http://example.com/node/2', Drupal.googleanalytics.getPageUrl('http://example.com/node/2'), "Full qualified external url 'http://example.com/node/2' has been extracted.");
+  Drupal.google_analytics.test.assertSame(base_path, Drupal.google_analytics.getPageUrl(window.location.href), "Absolute internal URL '" + base_path + "' has been extracted from full qualified url '" + window.location.href + "'.");
+  Drupal.google_analytics.test.assertSame(base_path, Drupal.google_analytics.getPageUrl(base_path), "Absolute internal URL '" + base_path + "' has been extracted from absolute url '" + base_path + "'.");
+  //Drupal.googleanalytics.test.assertSame(base_path, Drupal.googleanalytics.getPageUrl(base_url + Drupal.settings.basePath + 'node/1'), "Absolute internal URL '" +  Drupal.settings.basePath + "node/1' has been extracted from full qualified url '" + base_url + base_path + "'.");
+  //Drupal.googleanalytics.test.assertSame(base_path, Drupal.googleanalytics.getPageUrl(Drupal.settings.basePath + 'node/1'), "Absolute internal URL '" +  Drupal.settings.basePath + "node/1' has been extracted from absolute url '" +  base_path + "'.");
+  Drupal.googleanalytics.test.assertSame('https://example.com/node/2', Drupal.googleanalytics.getPageUrl('https://example.com/node/2'), "Full qualified external url 'https://example.com/node/2' has been extracted.");
   Drupal.googleanalytics.test.assertSame('//example.com/node/2', Drupal.googleanalytics.getPageUrl('//example.com/node/2'), "Full qualified external url '//example.com/node/2' has been extracted.");
   Drupal.googleanalytics.test.assertSame('//example.com/node/2', Drupal.googleanalytics.getPageUrl('//example.com/node/2'), "Full qualified external url '//example.com/node/2' has been extracted.");
   console.groupEnd();
   console.groupEnd();
 
 
@@ -105,9 +107,9 @@ $(document).ready(function() {
   if (Drupal.settings.googleanalytics.trackCrossDomains) {
   if (Drupal.settings.googleanalytics.trackCrossDomains) {
     console.dir(Drupal.settings.googleanalytics.trackCrossDomains);
     console.dir(Drupal.settings.googleanalytics.trackCrossDomains);
     Drupal.googleanalytics.test.assertTrue(Drupal.googleanalytics.isCrossDomain('example.com', Drupal.settings.googleanalytics.trackCrossDomains), "URL 'example.com' has been found in cross domain list.");
     Drupal.googleanalytics.test.assertTrue(Drupal.googleanalytics.isCrossDomain('example.com', Drupal.settings.googleanalytics.trackCrossDomains), "URL 'example.com' has been found in cross domain list.");
-    Drupal.googleanalytics.test.assertTrue(Drupal.googleanalytics.isCrossDomain('example.net', Drupal.settings.googleanalytics.trackCrossDomains), "URL 'example.com' has been found in cross domain list.");
+    Drupal.googleanalytics.test.assertTrue(Drupal.googleanalytics.isCrossDomain('example.net', Drupal.settings.googleanalytics.trackCrossDomains), "URL 'example.net' has been found in cross domain list.");
     Drupal.googleanalytics.test.assertFalse(Drupal.googleanalytics.isCrossDomain('www.example.com', Drupal.settings.googleanalytics.trackCrossDomains), "URL 'www.example.com' not found in cross domain list.");
     Drupal.googleanalytics.test.assertFalse(Drupal.googleanalytics.isCrossDomain('www.example.com', Drupal.settings.googleanalytics.trackCrossDomains), "URL 'www.example.com' not found in cross domain list.");
-    Drupal.googleanalytics.test.assertFalse(Drupal.googleanalytics.isCrossDomain('www.example.net', Drupal.settings.googleanalytics.trackCrossDomains), "URL 'www.example.com' not found in cross domain list.");
+    Drupal.googleanalytics.test.assertFalse(Drupal.googleanalytics.isCrossDomain('www.example.net', Drupal.settings.googleanalytics.trackCrossDomains), "URL 'www.example.net' not found in cross domain list.");
   }
   }
   else {
   else {
     console.warn('Cross domain tracking is not enabled. Tests skipped.');
     console.warn('Cross domain tracking is not enabled. Tests skipped.');

File diff suppressed because it is too large
+ 0 - 0
sites/all/modules/contrib/admin/google_analytics/googleanalytics.variable.inc


+ 42 - 0
sites/all/modules/contrib/fields/content_taxonomy/CHANGELOG.txt

@@ -0,0 +1,42 @@
+Content_Taxonomy 7.x-1.0-rc1, 2016-03-22
+----------------------------------------
+#1373716 by Owen Barton: Added hook_disable() to disable the custom field
+  widget and prevent site from breaking.
+By mh86: Added hook for altering the term tree callback used in the allowed
+  values function.
+By mh86: Added new submodule that supports the Entity Translation mode for
+  taxonomy terms.
+By mh86: Fixed translated term names on initial autocomplete deluxe suggestions.
+#1208164 by skein, mrded, rbayliss, drzraf, DamienMcKenna: Fix field migration.
+#2580251 by michel.settembrino, DamienMcKenna: Added EntityReference
+  autocomplete support.
+#2379611 by justanothermark: Wording change on autocomplete error message.
+#1160146 by moskito: Added ActiveTags support.
+#1395276 by bigjim: Fixed options field on migration.
+#2348363 by james.williams, DamienMcKenna: Only alter field instances for
+  content_taxonomy fields.
+#1558050 by bdimaggio, DamienMcKenna: The 'array_parents' element might not
+  exist.
+#1643858 by DamienMcKenna, hatuhay, BrightBold, marthinal, benjy, mikhailian,
+  MakaziMtingwa, zhilevan, klidifia, pappuksingh, cameronbprince: Fix invalid
+  default values.
+
+
+Content_Taxonomy 7.x-1.0-beta2, 2013-01-21
+------------------------------------------
+By mh86: Fixed validate handlers for new terms.
+By mh86: Added Search API Postprocessor for filtering out moderated terms from
+  facets.
+#1631000 by klausi: Fixed Strict warning: Declaration of
+  ContentTaxonomyAutocompleteModeratedTermsSearchAPIProcessor.
+By mh86: Added option for selects lists with opt groups
+
+
+Content_Taxonomy 7.x-1.0-beta1, 2011-06-22
+------------------------------------------
+By mh86: Initial port to D7.
+#1079846 by mh86: Fixed error in content_taxonomy_autocomplete when using
+  without autocomplete_deluxe.
+#1079938 by mh86: Fixed error in migration module.
+#1086228 by mh86: Support for upgrading Hierarchical Select fields.
+By mh86: Added option for the tree depth.

+ 42 - 0
sites/all/modules/contrib/fields/content_taxonomy/content_taxonomy.api.php

@@ -0,0 +1,42 @@
+<?php
+
+/**
+ * @file
+ * This file contains no working PHP code; it exists to provide additional
+ * documentation for doxygen as well as to document hooks in the standard
+ * Drupal manner.
+ */
+
+
+/**
+ * @addtogroup hooks
+ * @{
+ */
+
+/**
+ * Alter the term tree callback that is used for content taxonomy options lists.
+ *
+ * By default taxonomy_get_tree is used to retrieve the list of terms. It is
+ * important that any provided tree callback must have the same function
+ * signature as hook_content_taxonomy_tree_callback_alter().
+ * For example this hook can be used to exchange the callback with a language
+ * specific tree function.
+ *
+ * @param $tree_callback
+ *   The current callback that can be overridden.
+ * @param $field
+ *   The term reference field info array.
+ * @param $vocabulary
+ *   The vocabulary object for which the term list should be retrieved. One
+ *   field can have multiple vocabularies attached, which leads to multiple
+ *   invocations of this function.
+ */
+function hook_content_taxonomy_tree_callback_alter(&$tree_callback, $field, $vocabulary) {
+  if ($vocabulary->machine_name == 'my_voc') {
+    $tree_callback = 'my_tree_callback';
+  }
+}
+
+/**
+ * @} End of "addtogroup hooks".
+ */

+ 3 - 3
sites/all/modules/contrib/fields/content_taxonomy/content_taxonomy.info

@@ -8,9 +8,9 @@ dependencies[] = taxonomy
 
 
 
 
 
 
-; Information added by drupal.org packaging script on 2013-02-13
-version = "7.x-1.0-beta2"
+; Information added by Drupal.org packaging script on 2016-03-22
+version = "7.x-1.0-rc1"
 core = "7.x"
 core = "7.x"
 project = "content_taxonomy"
 project = "content_taxonomy"
-datestamp = "1360767812"
+datestamp = "1458667740"
 
 

+ 94 - 0
sites/all/modules/contrib/fields/content_taxonomy/content_taxonomy.install

@@ -0,0 +1,94 @@
+<?php
+
+/**
+ * @file
+ * (Un-) installation tasks for content taxonomy.
+ */
+
+/**
+ * Implements hook_disable().
+ *
+ * Allow uninstall of content taxonomy by removing the callback in field
+ * configuration. Re-enabling requires to save the field configs to re-insert
+ * the callback.
+ */
+function content_taxonomy_disable() {
+  $fields = field_read_fields();
+  foreach ($fields as $field) {
+    if (isset($field['settings']['options_list_callback']) && $field['settings']['options_list_callback'] == 'content_taxonomy_allowed_values') {
+      // We cannot unset this value, because field_update_field() merges in
+      // prior settings before saving. Setting it to NULL works.
+      $field['settings']['options_list_callback'] = NULL;
+    }
+    field_update_field($field);
+  }
+}
+
+/**
+ * Implementations of hook_update_N().
+ */
+
+/**
+ * Fix the default values converted from D6. These values had an empty 'value'
+ * value which could cause errors on D7.
+ */
+function content_taxonomy_update_7100() {
+  $params = array(
+    'type' => 'taxonomy_term_reference',
+  );
+  foreach (field_read_fields($params) as $field) {
+    foreach (field_read_instances(array('field_name' => $field['field_name'])) as $instance) {
+      // If the 'default_value' item doesn't exist there's no point in
+      // continuing.
+      if (!isset($instance['default_value'])) {
+        continue;
+      }
+
+      // Keep track of whether fields are actually changed.
+      $updated = FALSE;
+
+      // Fix each of the default values.
+      foreach ($instance['default_value'] as $key => $defaults) {
+        // Need to check isset() and is_null() because the value could be NULL.
+        if (isset($instance['default_value'][$key]['value']) || is_null($instance['default_value'][$key]['value'])) {
+          // Remove any empty 'value' strings.
+          if (empty($instance['default_value'][$key]['value'])) {
+            unset($instance['default_value'][$key]['value']);
+            $updated = TRUE;
+          }
+
+          // Rename the 'value' string to 'tid'.
+          elseif (!isset($instance_value['default_value'][$key]['tid'])) {
+            $instance_value['default_value'][$key]['tid'] = $instance_value['default_value'][$key]['value'];
+            unset($instance_value['default_value'][$key]['value']);
+            $updated = TRUE;
+          }
+
+          // Look for a junk value carried over from D6.
+          if (isset($instance['default_value'][$key]['_error_element'])) {
+            unset($instance['default_value'][$key]['_error_element']);
+            $updated = TRUE;
+          }
+
+          // If the array is empty, just remove it.
+          if (empty($instance['default_value'][$key])) {
+            unset($instance['default_value'][$key]);
+            $updated = TRUE;
+          }
+        }
+      }
+
+      // If there are no default values left, just remove it.
+      if (empty($instance['default_value'])) {
+        unset($instance['default_value']);
+        $updated = TRUE;
+      }
+
+      // If the field's definition was changed, save it.
+      if ($updated) {
+        field_update_instance($instance);
+        drupal_set_message(t('Fixed configuration of the "@field_name" field ("@type" content type).', array('@field_name' => $instance['field_name'], '@type' => $instance['bundle'])));
+      }
+    }
+  }
+}

+ 49 - 7
sites/all/modules/contrib/fields/content_taxonomy/content_taxonomy.module

@@ -7,12 +7,14 @@ function content_taxonomy_form_field_ui_field_edit_form_alter(&$form, &$form_sta
   $field = $form['#field'];
   $field = $form['#field'];
   $instance = $form['#instance'];
   $instance = $form['#instance'];
 
 
-  // Add parent selector to term reference fields,
-  // except to the autocomplete widget, as it ignores the parent setting.
+  // Add parent selector to term reference fields, except to the autocomplete
+  // widget, as it ignores the parent setting.
   if ($field['type'] == 'taxonomy_term_reference'
   if ($field['type'] == 'taxonomy_term_reference'
-    && !($instance['widget']['type'] == 'taxonomy_autocomplete' || $instance['widget']['type'] == 'autocomplete_deluxe_taxonomy')) {
-
-    // add parent form.
+      && $instance['widget']['type'] != 'taxonomy_autocomplete'
+      && $instance['widget']['type'] != 'autocomplete_deluxe_taxonomy'
+      && $instance['widget']['type'] != 'entityreference_autocomplete'
+      && $instance['widget']['type'] != 'entityreference_autocomplete_tags') {
+    // Add parent form.
     foreach ($field['settings']['allowed_values'] as $delta => $tree) {
     foreach ($field['settings']['allowed_values'] as $delta => $tree) {
       $options[0] = '---';
       $options[0] = '---';
       // todo this might break with huge vocs
       // todo this might break with huge vocs
@@ -76,7 +78,8 @@ function content_taxonomy_allowed_values($field) {
   foreach ($field['settings']['allowed_values'] as $tree) {
   foreach ($field['settings']['allowed_values'] as $tree) {
     if ($vocabulary = taxonomy_vocabulary_machine_name_load($tree['vocabulary'])) {
     if ($vocabulary = taxonomy_vocabulary_machine_name_load($tree['vocabulary'])) {
       $max_depth = (isset($tree['depth']) && !empty($tree['depth'])) ? $tree['depth'] : NULL;
       $max_depth = (isset($tree['depth']) && !empty($tree['depth'])) ? $tree['depth'] : NULL;
-      if ($terms = taxonomy_get_tree($vocabulary->vid, $tree['parent'], $max_depth)) {
+      $terms = content_taxonomy_get_terms($field, $vocabulary, $tree['parent'], $max_depth);
+      if (!empty($terms) && is_array($terms)) {
         foreach ($terms as $term) {
         foreach ($terms as $term) {
           $options[$term->tid] = str_repeat('- ', $term->depth) . $term->name;
           $options[$term->tid] = str_repeat('- ', $term->depth) . $term->name;
         }
         }
@@ -86,6 +89,44 @@ function content_taxonomy_allowed_values($field) {
   return $options;
   return $options;
 }
 }
 
 
+/**
+ * Returns an array of terms that can be used in an options list.
+ *
+ * By default taxonomy_get_tree is used to retrieve the list of terms, but an
+ * alteration via hook_content_taxonomy_tree_callback_alter() is possible. It
+ * is important that any provided tree callback must have the same function
+ * signature as hook_content_taxonomy_tree_callback_alter().
+ * For example this hook can be used to exchange the callback with a language
+ * specific tree function.
+ *
+ * Although we could change the options list callback via the field definitions,
+ * it is easier to do this via the alteration hook provided by this function.
+ *
+ * @param $field
+ *   The term reference field info array.
+ * @param $vocabulary
+ *   The vocabulary object for which the term list should be retrieved. One
+ *   field can have multiple vocabularies attached, which leads to multiple
+ *   invocations of this function.
+ * @param $parent
+ *   The parent term id. Use 0 for the root level.
+ * @param $max_depth
+ *   The maximum depth. Use NULL for non limitation.
+ *
+ * @return array
+ */
+function content_taxonomy_get_terms($field, $vocabulary, $parent, $max_depth) {
+  $terms = array();
+
+  $tree_callback = 'taxonomy_get_tree';
+  drupal_alter('content_taxonomy_tree_callback', $tree_callback, $field, $vocabulary);
+  if (function_exists($tree_callback)) {
+    $terms = $tree_callback($vocabulary->vid, $parent, $max_depth, FALSE);
+  }
+
+  return $terms;
+}
+
 /**
 /**
  * Implements hook_field_widget_info_alter().
  * Implements hook_field_widget_info_alter().
  */
  */
@@ -126,7 +167,8 @@ function content_taxonomy_allowed_values_opt_groups($field) {
   $options = array();
   $options = array();
   foreach ($field['settings']['allowed_values'] as $tree) {
   foreach ($field['settings']['allowed_values'] as $tree) {
     if ($vocabulary = taxonomy_vocabulary_machine_name_load($tree['vocabulary'])) {
     if ($vocabulary = taxonomy_vocabulary_machine_name_load($tree['vocabulary'])) {
-      if ($terms = taxonomy_get_tree($vocabulary->vid, 0, 2)) {
+      $terms = content_taxonomy_get_terms($field, $vocabulary, 0, 2);
+      if (!empty($terms) && is_array($terms)) {
         $current_group_term = NULL;
         $current_group_term = NULL;
         foreach ($terms as $term) {
         foreach ($terms as $term) {
           if ($term->depth == 0) {
           if ($term->depth == 0) {

+ 3 - 3
sites/all/modules/contrib/fields/content_taxonomy/content_taxonomy_autocomplete.info

@@ -10,9 +10,9 @@ files[] = includes/content_taxonomy_autocomplete_moderated_terms.inc
 
 
 
 
 
 
-; Information added by drupal.org packaging script on 2013-02-13
-version = "7.x-1.0-beta2"
+; Information added by Drupal.org packaging script on 2016-03-22
+version = "7.x-1.0-rc1"
 core = "7.x"
 core = "7.x"
 project = "content_taxonomy"
 project = "content_taxonomy"
-datestamp = "1360767812"
+datestamp = "1458667740"
 
 

+ 39 - 8
sites/all/modules/contrib/fields/content_taxonomy/content_taxonomy_autocomplete.module

@@ -10,10 +10,25 @@ function content_taxonomy_autocomplete_field_widget_info_alter(&$info) {
   );
   );
   $info['taxonomy_autocomplete']['settings'] += $ct_settings;
   $info['taxonomy_autocomplete']['settings'] += $ct_settings;
 
 
+  // Add this to the Active Tags as well, if enabled.
+  if (isset($info['active_tags']['settings'])) {
+    $info['active_tags']['settings'] += $ct_settings;
+  }
+
   // Add this to the autocomplete deluxe as well, if enabled.
   // Add this to the autocomplete deluxe as well, if enabled.
   if (isset($info['autocomplete_deluxe_taxonomy']['settings'])) {
   if (isset($info['autocomplete_deluxe_taxonomy']['settings'])) {
     $info['autocomplete_deluxe_taxonomy']['settings'] += $ct_settings;
     $info['autocomplete_deluxe_taxonomy']['settings'] += $ct_settings;
   }
   }
+
+  // Add this to the entityreference autocomplete as well, if enabled.
+  if (isset($info['entityreference_autocomplete']['settings'])) {
+    $info['entityreference_autocomplete']['settings'] += $ct_settings;
+  }
+
+  // Add this to the entityreference autocomplete (tags) as well, if enabled.
+  if (isset($info['entityreference_autocomplete_tags']['settings'])) {
+    $info['entityreference_autocomplete_tags']['settings'] += $ct_settings;
+  }
 }
 }
 
 
 /**
 /**
@@ -22,7 +37,11 @@ function content_taxonomy_autocomplete_field_widget_info_alter(&$info) {
 function content_taxonomy_autocomplete_form_field_ui_field_edit_form_alter(&$form, &$form_state, $form_id) {
 function content_taxonomy_autocomplete_form_field_ui_field_edit_form_alter(&$form, &$form_state, $form_id) {
   $field = $form['#field'];
   $field = $form['#field'];
   $instance = $form['#instance'];
   $instance = $form['#instance'];
-  if ($instance['widget']['type'] == 'taxonomy_autocomplete' || $instance['widget']['type'] == 'autocomplete_deluxe_taxonomy') {
+  if ($instance['widget']['type'] == 'taxonomy_autocomplete'
+      || $instance['widget']['type'] == 'active_tags_taxonomy_autocomplete'
+      || $instance['widget']['type'] == 'autocomplete_deluxe_taxonomy'
+      || $instance['widget']['type'] == 'entityreference_autocomplete'
+      || $instance['widget']['type'] == 'entityreference_autocomplete_tags') {
     // Add a setting form for validating new terms.
     // Add a setting form for validating new terms.
     $options = array(
     $options = array(
       'allow' => t('Allow and insert new terms'),
       'allow' => t('Allow and insert new terms'),
@@ -39,7 +58,14 @@ function content_taxonomy_autocomplete_form_field_ui_field_edit_form_alter(&$for
   }
   }
 
 
   // Show form for second vocabulary.
   // Show form for second vocabulary.
-  if (isset($instance['widget']['settings']['content_taxonomy_autocomplete_new_terms']) && $instance['widget']['settings']['content_taxonomy_autocomplete_new_terms'] == 'moderate') {
+  if (($instance['widget']['type'] == 'taxonomy_autocomplete'
+      || $instance['widget']['type'] == 'active_tags_taxonomy_autocomplete'
+      || $instance['widget']['type'] == 'autocomplete_deluxe_taxonomy'
+      || $instance['widget']['type'] == 'entityreference_autocomplete'
+      || $instance['widget']['type'] == 'entityreference_autocomplete_tags')
+    && isset($form[$instance['field_name']])
+    && isset($instance['widget']['settings']['content_taxonomy_autocomplete_new_terms'])) {
+
     // Initialize settings, if not set.
     // Initialize settings, if not set.
     if (!isset($field['settings']['allowed_values'][1])) {
     if (!isset($field['settings']['allowed_values'][1])) {
       $field['settings']['allowed_values'][1] = array(
       $field['settings']['allowed_values'][1] = array(
@@ -83,8 +109,11 @@ function content_taxonomy_autocomplete_field_attach_form($entity_type, $entity,
   // Add validation function to taxonomy_autocompletes, if necessary.
   // Add validation function to taxonomy_autocompletes, if necessary.
   $instances = field_info_instances($form['#entity_type'], $form['#bundle']);
   $instances = field_info_instances($form['#entity_type'], $form['#bundle']);
   foreach ($instances as $instance) {
   foreach ($instances as $instance) {
-    if (($instance['widget']['type'] == 'taxonomy_autocomplete' || $instance['widget']['type'] == 'autocomplete_deluxe_taxonomy') 
-      && isset($form[$instance['field_name']]) 
+    if (($instance['widget']['type'] == 'taxonomy_autocomplete'
+        || $instance['widget']['type'] == 'autocomplete_deluxe_taxonomy'
+        || $instance['widget']['type'] == 'entityreference_autocomplete'
+        || $instance['widget']['type'] == 'entityreference_autocomplete_tags')
+      && isset($form[$instance['field_name']])
       && isset($instance['widget']['settings']['content_taxonomy_autocomplete_new_terms'])) {
       && isset($instance['widget']['settings']['content_taxonomy_autocomplete_new_terms'])) {
 
 
       // Use the language that is used in this form (which doesn't necessarily
       // Use the language that is used in this form (which doesn't necessarily
@@ -105,12 +134,14 @@ function content_taxonomy_autocomplete_field_attach_form($entity_type, $entity,
  */
  */
 function content_taxonomy_autocomplete_validate_deny_new_terms($element, &$form_state, $form) {
 function content_taxonomy_autocomplete_validate_deny_new_terms($element, &$form_state, $form) {
   $values = $form_state['values'];
   $values = $form_state['values'];
-  foreach ($element['#array_parents'] as $parent) {
-    $values = $values[$parent];
+  if (!empty($element['#array_parents'])) {
+    foreach ($element['#array_parents'] as $parent) {
+      $values = $values[$parent];
+    }
   }
   }
   foreach ($values as $delta => $value) {
   foreach ($values as $delta => $value) {
-    if ($value['tid'] == 'autocreate') {
-      form_error($element, t('%name: new terms are not allowed. Please choose from the given list.', array('%name' => $element['#title'])));
+    if (isset($value['tid']) && $value['tid'] == 'autocreate') {
+      form_error($element, t('%name: new terms are not allowed. Please choose from the suggested options.', array('%name' => $element['#title'])));
     }
     }
   }
   }
 }
 }

+ 15 - 0
sites/all/modules/contrib/fields/content_taxonomy/content_taxonomy_et.info

@@ -0,0 +1,15 @@
+name = Content Taxonomy Entity Translations
+description = Adds support for terms that are translated via the Entity Translation and Title module.
+core = 7.x
+package = Fields
+
+dependencies[] = content_taxonomy
+dependencies[] = entity_translation
+dependencies[] = title
+
+; Information added by Drupal.org packaging script on 2016-03-22
+version = "7.x-1.0-rc1"
+core = "7.x"
+project = "content_taxonomy"
+datestamp = "1458667740"
+

+ 404 - 0
sites/all/modules/contrib/fields/content_taxonomy/content_taxonomy_et.module

@@ -0,0 +1,404 @@
+<?php
+
+/**
+ * @file
+ * Entity Translation integration for taxonomy terms.
+ */
+
+/**
+ * Implements hook_content_taxonomy_tree_callback_alter().
+ */
+function content_taxonomy_et_content_taxonomy_tree_callback_alter(&$tree_callback, $field, $vocabulary) {
+  // Checks whether the Entity Translation mode with the title field is enabled,
+  // if so, replace the tree callback with our custom language specific
+  // implementation.
+  if (title_field_replacement_enabled('taxonomy_term', $vocabulary->machine_name, 'name')) {
+    $tree_callback = 'content_taxonomy_et_get_tree';
+  }
+}
+
+/**
+ * Implements hook_menu_alter().
+ */
+function content_taxonomy_et_menu_alter(&$items) {
+  // Localize autocompletes.
+  $items['taxonomy/autocomplete']['page callback'] = 'content_taxonomy_et_autocomplete';
+  if (isset($items['autocomplete_deluxe/taxonomy'])) {
+    $items['autocomplete_deluxe/taxonomy']['page callback'] = 'content_taxonomy_et_autocomplete_deluxe';
+  }
+}
+
+/**
+ * Implements hook_field_widget_form_alter().
+ */
+function content_taxonomy_et_field_widget_form_alter(&$element, &$form_state, $context) {
+  // Change validation callback for autocompletes in order to fix the
+  // retrieving of terms in the right language.
+  if (in_array($context['instance']['widget']['type'], array('taxonomy_autocomplete', 'autocomplete_deluxe_taxonomy'))) {
+    foreach ($element['#element_validate'] as $key => $validate_callback) {
+      if ($validate_callback == 'taxonomy_autocomplete_validate') {
+        $element['#element_validate'][$key] = 'content_taxonomy_et_autocomplete_validate';
+        break;
+      }
+    }
+  }
+}
+
+/**
+ * Replacement for taxonomy_get_tree().
+ *
+ * Exchanges the term name property with the title field value in the current
+ * language.
+ */
+function content_taxonomy_et_get_tree($vid, $parent = 0, $max_depth = NULL, $load_entities = FALSE) {
+  global $language;
+
+  $children = &drupal_static(__FUNCTION__, array());
+  $parents = &drupal_static(__FUNCTION__ . ':parents', array());
+  $terms = &drupal_static(__FUNCTION__ . ':terms', array());
+
+  // We cache trees, so it's not CPU-intensive to call taxonomy_get_tree() on a
+  // term and its children, too.
+  if (!isset($children[$vid])) {
+    $children[$vid] = array();
+    $parents[$vid] = array();
+    $terms[$vid] = array();
+
+    $query = db_select('taxonomy_term_data', 't');
+    $query->join('taxonomy_term_hierarchy', 'h', 'h.tid = t.tid');
+    $query->leftJoin('field_data_name_field', 'fd', 'fd.entity_id = t.tid AND fd.entity_type = :type AND fd.language = :language',
+      array(':type' => 'taxonomy_term', ':language' => $language->language));
+    $result = $query
+      ->addTag('translatable')
+      ->addTag('term_access')
+      ->fields('t')
+      ->fields('h', array('parent'))
+      ->fields('fd', array('name_field_value'))
+      ->condition('t.vid', $vid)
+      ->orderBy('t.weight')
+      ->orderBy('t.name')
+      ->execute();
+
+    foreach ($result as $term) {
+      $children[$vid][$term->parent][] = $term->tid;
+      $parents[$vid][$term->tid][] = $term->parent;
+      $terms[$vid][$term->tid] = $term;
+    }
+  }
+
+  // Load full entities, if necessary. The entity controller statically
+  // caches the results.
+  if ($load_entities) {
+    $term_entities = taxonomy_term_load_multiple(array_keys($terms[$vid]));
+  }
+
+  $max_depth = (!isset($max_depth)) ? count($children[$vid]) : $max_depth;
+  $tree = array();
+
+  // Keeps track of the parents we have to process, the last entry is used
+  // for the next processing step.
+  $process_parents = array();
+  $process_parents[] = $parent;
+
+  // Loops over the parent terms and adds its children to the tree array.
+  // Uses a loop instead of a recursion, because it's more efficient.
+  while (count($process_parents)) {
+    $parent = array_pop($process_parents);
+    // The number of parents determines the current depth.
+    $depth = count($process_parents);
+    if ($max_depth > $depth && !empty($children[$vid][$parent])) {
+      $has_children = FALSE;
+      $child = current($children[$vid][$parent]);
+      do {
+        if (empty($child)) {
+          break;
+        }
+        $term = $load_entities ? $term_entities[$child] : $terms[$vid][$child];
+        if (isset($parents[$vid][$term->tid])) {
+          // Clone the term so that the depth attribute remains correct
+          // in the event of multiple parents.
+          $term = clone $term;
+        }
+
+        // Use translation if it exists in the name property.
+        if (!empty($term->name_field_value)) {
+          $term->name = $term->name_field_value;
+        }
+
+        $term->depth = $depth;
+        unset($term->parent);
+        $term->parents = $parents[$vid][$term->tid];
+        $tree[] = $term;
+        if (!empty($children[$vid][$term->tid])) {
+          $has_children = TRUE;
+
+          // We have to continue with this parent later.
+          $process_parents[] = $parent;
+          // Use the current term as parent for the next iteration.
+          $process_parents[] = $term->tid;
+
+          // Reset pointers for child lists because we step in there more often
+          // with multi parents.
+          reset($children[$vid][$term->tid]);
+          // Move pointer so that we get the correct term the next time.
+          next($children[$vid][$parent]);
+          break;
+        }
+      } while ($child = next($children[$vid][$parent]));
+
+      if (!$has_children) {
+        // We processed all terms in this hierarchy-level, reset pointer
+        // so that this function works the next time it gets called.
+        reset($children[$vid][$parent]);
+      }
+    }
+  }
+
+  return $tree;
+}
+
+/**
+ * Replacement for form validate handler taxonomy_autocomplete_validate().
+ *
+ * Uses content_taxonomy_et_get_first_possible_term() to retrieve the right term
+ * in the right language, instead of term_load_multiple().
+ */
+function content_taxonomy_et_autocomplete_validate($element, &$form_state) {
+  // Autocomplete widgets do not send their tids in the form, so we must detect
+  // them here and process them independently.
+  $value = array();
+  if ($tags = $element['#value']) {
+    // Collect candidate vocabularies.
+    $field = field_widget_field($element, $form_state);
+    $vocabularies = array();
+    foreach ($field['settings']['allowed_values'] as $tree) {
+      if ($vocabulary = taxonomy_vocabulary_machine_name_load($tree['vocabulary'])) {
+        $vocabularies[$vocabulary->vid] = $vocabulary;
+      }
+    }
+
+    // Translate term names into actual terms.
+    $typed_terms = drupal_explode_tags($tags);
+    foreach ($typed_terms as $typed_term) {
+      // See if the term exists in the chosen vocabulary and return the tid;
+      // otherwise, create a new 'autocreate' term for insert/update.
+      $term = content_taxonomy_et_get_first_possible_term(trim($typed_term), array_keys($vocabularies));
+      if (!$term) {
+        $vocabulary = reset($vocabularies);
+        $term = array(
+          'tid' => 'autocreate',
+          'vid' => $vocabulary->vid,
+          'name' => $typed_term,
+          'vocabulary_machine_name' => $vocabulary->machine_name,
+        );
+      }
+      $value[] = (array)$term;
+    }
+  }
+
+  form_set_value($element, $value, $form_state);
+}
+
+/**
+ * Replacement for taxonomy_autocomplete().
+ *
+ *  Adds an additional left join to the translatable title field.
+ */
+function content_taxonomy_et_autocomplete($field_name = '', $tags_typed = '') {
+  global $language;
+
+  // 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.
+    $vids = array();
+    $vocabularies = taxonomy_vocabulary_get_names();
+    foreach ($field['settings']['allowed_values'] as $tree) {
+      $vids[] = $vocabularies[$tree['vocabulary']]->vid;
+    }
+
+    $query = db_select('taxonomy_term_data', 't');
+    $query->addTag('translatable');
+    $query->addTag('term_access');
+
+    $query->leftJoin('field_data_name_field', 'fd', 'fd.entity_id = t.tid AND fd.entity_type = :type AND fd.language = :language',
+      array(':type' => 'taxonomy_term', ':language' => $language->language));
+
+    // 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'))
+      ->fields('fd', array('name_field_value'))
+      ->condition('t.vid', $vids)
+      ->condition(db_or()->condition('t.name', '%' . db_like($tag_last) . '%', 'LIKE')->condition('fd.name_field_value', '%' . db_like($tag_last) . '%', 'LIKE'))
+      ->range(0, 10)
+      ->execute();
+
+    $prefix = count($tags_typed) ? drupal_implode_tags($tags_typed) . ', ' : '';
+
+    foreach ($tags_return as $record) {
+      $name = !empty($record->name_field_value) ? $record->name_field_value : $record->name;
+      $n = $name;
+      // Term names containing commas or quotes must be wrapped in quotes.
+      if (strpos($name, ',') !== FALSE || strpos($name, '"') !== FALSE) {
+        $n = '"' . str_replace('"', '""', $name) . '"';
+      }
+      $term_matches[$prefix . $n] = check_plain($name);
+    }
+  }
+
+  drupal_json_output($term_matches);
+}
+
+
+/**
+ * Replacement for taxonomy_autocomplete_deluxe().
+ *
+ * Adds an additional left join to the translatable title field.
+ *
+ * @todo
+ *   Merge with content_taxonomy_et_autocomplete().
+ */
+function content_taxonomy_et_autocomplete_deluxe($field_name, $tags_typed = '', $limit = 10) {
+  global $language;
+
+  $field = field_info_field($field_name);
+  $use_synonyms = !empty($_GET['synonyms']);
+
+  // 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));
+
+  $matches = array();
+
+  // Part of the criteria for the query come from the field's own settings.
+  $vids = array();
+  $vocabularies = taxonomy_vocabulary_get_names();
+  foreach ($field['settings']['allowed_values'] as $tree) {
+    // If the content taxonomy setting content_taxonomy_ignore_in_suggestions
+    // is set, then the vocabulary is ignored.
+    if (empty($tree['content_taxonomy_ignore_in_suggestions'])) {
+      $vids[] = $vocabularies[$tree['vocabulary']]->vid;
+    }
+  }
+
+  $query = db_select('taxonomy_term_data', 't');
+  $query->addTag('translatable');
+  $query->addTag('term_access');
+
+  $query->leftJoin('field_data_name_field', 'fd', 'fd.entity_id = t.tid AND fd.entity_type = :type AND fd.language = :language',
+    array(':type' => 'taxonomy_term', ':language' => $language->language));
+
+  if (module_exists('synonyms') && !empty($use_synonyms)) {
+    $query->leftJoin('field_data_synonyms_synonym', 'fdss', 'fdss.entity_id = t.tid');
+  }
+
+  if ($tag_last != '') {
+    // 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.
+    $query
+      ->fields('t', array('tid', 'name'))
+      ->fields('fd', array('name_field_value'))
+      ->condition('t.vid', $vids);
+
+    if (module_exists('synonyms') && !empty($use_synonyms)) {
+      $or = db_or();
+      $or->condition('fdss.synonyms_synonym_value', '%' . db_like($tag_last) . '%', 'LIKE');
+      $or->condition('t.name', '%' . db_like($tag_last) . '%', 'LIKE');
+      $or->condition('fd.name_field_value', '%' . db_like($tag_last) . '%', 'LIKE');
+      $query->condition($or);
+    }
+    else {
+      $query->condition(db_or()->condition('t.name', '%' . db_like($tag_last) . '%', 'LIKE')->condition('fd.name_field_value', '%' . db_like($tag_last) . '%', 'LIKE'));
+
+    }
+
+    if (isset($limit) && $limit > 0) {
+      $query->range(0, $limit);
+    }
+
+    $tags_return = $query->execute();
+  }
+  else {
+    $query
+      ->fields('t', array('tid', 'name'))
+      ->fields('fd', array('name_field_value'))
+      ->condition('t.vid', $vids);
+
+    if (isset($limit) && $limit > 0) {
+      $query->range(0, $limit);
+    }
+
+    $tags_return = $query->execute();
+  }
+
+  $prefix = count($tags_typed) ? drupal_implode_tags($tags_typed) . ', ' : '';
+
+  $term_matches = array();
+  foreach ($tags_return as $record) {
+    $name = !empty($record->name_field_value) ? $record->name_field_value : $record->name;
+    $n = $name;
+    // Term names containing commas or quotes must be wrapped in quotes.
+    if (strpos($name, ',') !== FALSE || strpos($name, '"') !== FALSE) {
+      $n = '"' . str_replace('"', '""', $name) . '"';
+    }
+    $term_matches[$prefix . $n] = check_plain($name);
+  }
+
+  drupal_json_output($term_matches);
+}
+
+/**
+ * Helper function that retrieves the first possible term object for a given
+ * term name and and array of vocabulary ids.
+ *
+ * Used in content_taxonomy_et_autocomplete_validate().
+ */
+function content_taxonomy_et_get_first_possible_term($term_name, $vids) {
+  global $language;
+
+  // EFQ does not work here, as we do not have OR condition possibilities.
+  $query = db_select('taxonomy_term_data', 't');
+  $query->addTag('translatable');
+  $query->addTag('term_access');
+  $query->leftJoin('field_data_name_field', 'fd', 'fd.entity_id = t.tid AND fd.entity_type = :type AND fd.language = :language',
+    array(':type' => 'taxonomy_term', ':language' => $language->language));
+  $query->fields('t', array('tid'))
+    ->condition('t.vid', $vids, 'IN')
+    ->condition(db_or()->condition('t.name', $term_name)->condition('fd.name_field_value', $term_name))
+    ->orderBy('t.tid', 'ASC')
+    ->execute();
+
+  $first_tid = $query->execute()->fetchColumn();
+  if (!empty($first_tid)) {
+    $term = taxonomy_term_load($first_tid);
+    return $term;
+  }
+  return FALSE;
+}

+ 4 - 6
sites/all/modules/contrib/fields/content_taxonomy/content_taxonomy_migrate.info

@@ -1,5 +1,5 @@
 name = Content Taxonomy Migrate
 name = Content Taxonomy Migrate
-description = Migration from Content Taxonomy to Term Reference Fields
+description = Migration from Content Taxonomy to Term Reference fields.
 
 
 core = 7.x
 core = 7.x
 package = Fields
 package = Fields
@@ -7,11 +7,9 @@ package = Fields
 dependencies[] = taxonomy
 dependencies[] = taxonomy
 dependencies[] = content_migrate
 dependencies[] = content_migrate
 
 
-
-
-; Information added by drupal.org packaging script on 2013-02-13
-version = "7.x-1.0-beta2"
+; Information added by Drupal.org packaging script on 2016-03-22
+version = "7.x-1.0-rc1"
 core = "7.x"
 core = "7.x"
 project = "content_taxonomy"
 project = "content_taxonomy"
-datestamp = "1360767812"
+datestamp = "1458667740"
 
 

+ 79 - 8
sites/all/modules/contrib/fields/content_taxonomy/content_taxonomy_migrate.module

@@ -1,11 +1,18 @@
 <?php
 <?php
+/**
+ * @file
+ *
+ */
 
 
+/**
+ * Implements hook_content_migrate_field_alter().
+ */
 function content_taxonomy_migrate_content_migrate_field_alter(&$field_value, $instance_value) {
 function content_taxonomy_migrate_content_migrate_field_alter(&$field_value, $instance_value) {
   if ($field_value['type'] == 'content_taxonomy') {
   if ($field_value['type'] == 'content_taxonomy') {
     $field_value['type'] = 'taxonomy_term_reference';
     $field_value['type'] = 'taxonomy_term_reference';
     $field_value['module'] = 'taxonomy';
     $field_value['module'] = 'taxonomy';
     
     
-    // transform field settings
+    // Transform field settings.
     $old_settings = $field_value['settings'];
     $old_settings = $field_value['settings'];
     $vocabulary = taxonomy_vocabulary_load($old_settings['vid']);
     $vocabulary = taxonomy_vocabulary_load($old_settings['vid']);
     $field_value['settings'] = array();
     $field_value['settings'] = array();
@@ -14,38 +21,102 @@ function content_taxonomy_migrate_content_migrate_field_alter(&$field_value, $in
     $field_value['settings']['allowed_values'][0]['parent'] = $old_settings['parent'];
     $field_value['settings']['allowed_values'][0]['parent'] = $old_settings['parent'];
   }
   }
 }
 }
-  
+
+/**
+ * Implements hook_content_migrate_instance_alter().
+ */
 function content_taxonomy_migrate_content_migrate_instance_alter(&$instance_value, $field_value) {
 function content_taxonomy_migrate_content_migrate_instance_alter(&$instance_value, $field_value) {
+  // Only work on content_taxonomy fields.
+  if ($field_value['type'] != 'content_taxonomy') {
+    return;
+  }
+
+  // Track whether fields are managed by this module.
+  $fix_this_instance = FALSE;
+
+  // Fix the widget.
   if ($instance_value['widget_type'] == "content_taxonomy_autocomplete") {
   if ($instance_value['widget_type'] == "content_taxonomy_autocomplete") {
+    $fix_this_instance = TRUE;
     $instance_value['widget_type'] = 'taxonomy_autocomplete';
     $instance_value['widget_type'] = 'taxonomy_autocomplete';
     $instance_value['widget']['type'] = 'taxonomy_autocomplete';
     $instance_value['widget']['type'] = 'taxonomy_autocomplete';
     $instance_value['widget']['module'] = 'taxonomy';
     $instance_value['widget']['module'] = 'taxonomy';
   }
   }
-  else if ($instance_value['widget_type'] == "content_taxonomy_options" || $instance_value['widget_type'] == "content_taxonomy_tree") {
+  elseif ($instance_value['widget_type'] == "content_taxonomy_options" || $instance_value['widget_type'] == "content_taxonomy_tree") {
+    $fix_this_instance = TRUE;
     $instance_value['widget_type'] = 'options_buttons';
     $instance_value['widget_type'] = 'options_buttons';
     $instance_value['widget']['type'] = 'options_buttons';
     $instance_value['widget']['type'] = 'options_buttons';
     $instance_value['widget']['module'] = 'options';
     $instance_value['widget']['module'] = 'options';
   }
   }
-  else if ($instance_value['widget_type'] == "content_taxonomy_select" || $instance_value['widget_type'] == 'content_taxonomy_hs') {
+  elseif ($instance_value['widget_type'] == "content_taxonomy_select" || $instance_value['widget_type'] == 'content_taxonomy_hs') {
+    $fix_this_instance = TRUE;
     $instance_value['widget_type'] = 'options_select';
     $instance_value['widget_type'] = 'options_select';
     $instance_value['widget']['type'] = 'options_select';
     $instance_value['widget']['type'] = 'options_select';
     $instance_value['widget']['module'] = 'options';
     $instance_value['widget']['module'] = 'options';
   }
   }
   
   
-  // fix formatter
+  // Fix the formatter.
   foreach ($instance_value['display'] as $context => $settings) {
   foreach ($instance_value['display'] as $context => $settings) {
     if ($instance_value['display'][$context]['type'] == 'default') {
     if ($instance_value['display'][$context]['type'] == 'default') {
+      $fix_this_instance = TRUE;
       $instance_value['display'][$context]['type'] = 'taxonomy_term_reference_plain';
       $instance_value['display'][$context]['type'] = 'taxonomy_term_reference_plain';
     }
     }
-    else if ($instance_value['display'][$context]['type'] == 'link') {
+    elseif ($instance_value['display'][$context]['type'] == 'link') {
+      $fix_this_instance = TRUE;
       $instance_value['display'][$context]['type'] = 'taxonomy_term_reference_link';
       $instance_value['display'][$context]['type'] = 'taxonomy_term_reference_link';
     }
     }
+    if ($instance_value['display'][$context]['module'] == 'content_taxonomy_options') {
+      $fix_this_instance = TRUE;
+      $instance_value['display'][$context]['module'] = 'options';
+    }
+  }
+
+  // Fix the defaults.
+  if ($fix_this_instance && !empty($instance_value['default_value'])) {
+    foreach ($instance_value['default_value'] as $key => $default) {
+      // Need to check isset() and is_null() because the value could be NULL.
+      if (isset($instance_value['default_value'][$key]['value']) || is_null($instance_value['default_value'][$key]['value'])) {
+        // Remove any empty 'value' strings.
+        if (empty($instance_value['default_value'][$key]['value'])) {
+          unset($instance_value['default_value'][$key]['value']);
+        }
+
+        // Rename the 'value' string as 'tid'.
+        else {
+          $instance_value['default_value'][$key]['tid'] = $instance_value['default_value'][$key]['value'];
+          unset($instance_value['default_value'][$key]['value']);
+        }
+
+        // Remove a junk value carried over from D6.
+        if (isset($instance_value['default_value'][$key]['_error_element'])) {
+          unset($instance_value['default_value'][$key]['_error_element']);
+          $updated = TRUE;
+        }
+
+        // If the array is empty, just remove it.
+        if (empty($instance_value['default_value'][$key])) {
+          unset($instance_value['default_value'][$key]);
+        }
+      }
+
+      // There are no default values left.
+      if (empty($instance_value['default_value'])) {
+        $instance_value['default_value'] = NULL;
+      }
+    }
   }
   }
 }
 }
 
 
+/**
+ * Implements hook_content_migrate_data_record_alter().
+ */
 function content_taxonomy_migrate_content_migrate_data_record_alter(&$record, $field) {
 function content_taxonomy_migrate_content_migrate_data_record_alter(&$record, $field) {
-  // fill the taxonomy_index
   if ($field['type'] == 'taxonomy_term_reference') {
   if ($field['type'] == 'taxonomy_term_reference') {
+    // Copy field_FIELD_NAME_value (D6) to field_FIELD_NAME_tid (D7).
+    if (isset($record[$field['field_name'] . '_value']) && !isset($record[$field['field_name'] . '_tid'])) {
+      $record[$field['field_name'] . '_tid'] = $record[$field['field_name'] . '_value'];
+    }
+
+    // Fill the taxonomy_index.
     if (variable_get('taxonomy_maintain_index_table', TRUE) && $field['storage']['type'] == 'field_sql_storage' && $record['entity_type'] == 'node') {
     if (variable_get('taxonomy_maintain_index_table', TRUE) && $field['storage']['type'] == 'field_sql_storage' && $record['entity_type'] == 'node') {
       if (isset($record[$field['field_name'] . "_tid"]) && $record[$field['field_name'] . "_tid"]) {
       if (isset($record[$field['field_name'] . "_tid"]) && $record[$field['field_name'] . "_tid"]) {
         $entity = node_load($record['entity_id']);
         $entity = node_load($record['entity_id']);
@@ -61,4 +132,4 @@ function content_taxonomy_migrate_content_migrate_data_record_alter(&$record, $f
       }
       }
     }
     }
   }
   }
-}
+}

+ 58 - 0
sites/all/modules/contrib/form/honeypot/README.md

@@ -0,0 +1,58 @@
+
+# Honeypot
+
+[![Build Status](https://travis-ci.org/geerlingguy/drupal-honeypot.svg?branch=7.x-1.x)](https://travis-ci.org/geerlingguy/drupal-honeypot)
+
+
+## Installation
+
+To install this module, place it in your sites/all/modules folder and enable it
+on the modules page.
+
+
+## Configuration
+
+All settings for this module are on the Honeypot configuration page, under the
+Configuration section, in the Content authoring settings. You can visit the
+configuration page directly at admin/config/content/honeypot.
+
+Note that, when testing Honeypot on your website, make sure you're not logged in
+as an administrative user or user 1; Honeypot allows administrative users to
+bypass Honeypot protection, so by default, Honeypot will not be added to forms
+accessed by site administrators.
+
+
+## Use in Your Own Forms
+
+If you want to add honeypot to your own forms, or to any form through your own
+module's hook_form_alter's, you can simply place the following function call
+inside your form builder function (or inside a hook_form_alter):
+
+    honeypot_add_form_protection(
+      $form,
+      $form_state,
+      array('honeypot', 'time_restriction')
+    );
+
+Note that you can enable or disable either the honeypot field, or the time
+restriction on the form by including or not including the option in the array.
+
+
+## Testing
+
+Honeypot includes a `docker-compose.yml` file that can be used for testing purposes. To build a Drupal 8 environment for local testing, do the following:
+
+  1. Make sure you have Docker for Mac (or for whatever OS you're using) installed.
+  2. Add the following entry to your `/etc/hosts` file: `192.168.22.33   local.drupalhoneypot.com`
+  3. Run `docker-compose up -d` in this directory.
+  4. Install Drupal: `docker exec honeypot install-drupal 7.x` (optionally provide a version after `install-drupal`).
+  5. Link the honeypot module directory into the Drupal modules directory: `docker exec honeypot ln -s /opt/honeypot/ /var/www/drupalvm/drupal/web/sites/all/modules/honeypot`
+  6. Visit `http://local.drupalhoneypot.com/user` and log in using the admin credentials Drush displayed.
+
+> Note: If you're using a Mac, you may also need to perform additional steps to get the hostname working; see [Managing your hosts file](http://docs.drupalvm.com/en/latest/other/docker/#managing-your-hosts-file) in the Drupal VM documentation.
+
+
+## Credit
+
+The Honeypot module was originally developed by Jeff Geerling of Midwestern Mac,
+LLC (midwesternmac.com), and sponsored by Flocknote (flocknote.com).

+ 0 - 43
sites/all/modules/contrib/form/honeypot/README.txt

@@ -1,43 +0,0 @@
-
-Honeypot Module Readme
-----------------------
-
-
-Installation
-------------
-
-To install this module, place it in your sites/all/modules folder and enable it
-on the modules page.
-
-
-Configuration
--------------
-
-All settings for this module are on the Honeypot configuration page, under the
-Configuration section, in the Content authoring settings. You can visit the
-configuration page directly at admin/config/content/honeypot.
-
-Note that, when testing Honeypot on your website, make sure you're not logged in
-as an administrative user or user 1; Honeypot allows administrative users to
-bypass Honeypot protection, so by default, Honeypot will not be added to forms
-accessed by site administrators.
-
-
-Use in Your Own Forms
----------------------
-
-If you want to add honeypot to your own forms, or to any form through your own
-module's hook_form_alter's, you can simply place the following function call
-inside your form builder function (or inside a hook_form_alter):
-
-honeypot_add_form_protection($form, $form_state, array('honeypot', 'time_restriction'));
-
-Note that you can enable or disable either the honeypot field, or the time
-restriction on the form by including or not including the option in the array.
-
-
-Credit
-------
-
-The Honeypot module was originally developed by Jeff Geerling of Midwestern Mac,
-LLC (midwesternmac.com), and sponsored by flockNote (flocknote.com).

+ 32 - 0
sites/all/modules/contrib/form/honeypot/docker-compose.yml

@@ -0,0 +1,32 @@
+version: "3"
+
+services:
+
+  honeypot:
+    image: geerlingguy/drupal-vm
+    container_name: honeypot
+    ports:
+      - 80:80
+      - 443:443
+    privileged: true
+    extra_hosts:
+      local.drupalhoneypot.com: 127.0.0.1
+    dns:
+      - 8.8.8.8
+      - 8.8.4.4
+    volumes:
+      - ./:/opt/honeypot/:rw,delegated
+    command: /lib/systemd/systemd
+    networks:
+      honeypot:
+        ipv4_address: 192.168.22.33
+
+networks:
+
+  honeypot:
+    driver: bridge
+    driver_opts:
+      ip: 192.168.22.1
+    ipam:
+      config:
+        - subnet: "192.168.22.0/16"

+ 20 - 2
sites/all/modules/contrib/form/honeypot/honeypot.admin.inc

@@ -22,7 +22,9 @@ function honeypot_admin_form($form, &$form_state) {
     '#description' => t('Enable Honeypot protection for ALL forms on this site (it is best to only enable Honeypot for the forms you need below).'),
     '#description' => t('Enable Honeypot protection for ALL forms on this site (it is best to only enable Honeypot for the forms you need below).'),
     '#default_value' => variable_get('honeypot_protect_all_forms', 0),
     '#default_value' => variable_get('honeypot_protect_all_forms', 0),
   );
   );
-  $form['configuration']['honeypot_protect_all_forms']['#description'] .= '<br />' . t('<strong>Page caching will be disabled on any page where a form is present if the Honeypot time limit is not set to 0.</strong>');
+  if (!variable_get('honeypot_use_js_for_cached_pages', FALSE)) {
+    $form['configuration']['honeypot_protect_all_forms']['#description'] .= '<br />' . t('<strong>Page caching will be disabled on any page where a form is present if the Honeypot time limit is not set to 0.</strong>');
+  }
   $form['configuration']['honeypot_log'] = array(
   $form['configuration']['honeypot_log'] = array(
     '#type' => 'checkbox',
     '#type' => 'checkbox',
     '#title' => t('Log blocked form submissions'),
     '#title' => t('Log blocked form submissions'),
@@ -46,7 +48,23 @@ function honeypot_admin_form($form, &$form_state) {
     '#size' => 5,
     '#size' => 5,
     '#field_suffix' => t('seconds'),
     '#field_suffix' => t('seconds'),
   );
   );
-  $form['configuration']['honeypot_time_limit']['#description'] .= '<br />' . t('<strong>Page caching will be disabled if there is a form protected by time limit on the page.</strong>');
+  if (!variable_get('honeypot_use_js_for_cached_pages', FALSE)) {
+    $form['configuration']['honeypot_time_limit']['#description'] .= '<br />' . t('<strong>Page caching will be disabled if there is a form protected by time limit on the page.</strong>');
+  }
+
+  $form['configuration']['honeypot_use_js_for_cached_pages'] = array(
+    '#type' => 'checkbox',
+    '#title' => t('Use Javascript protection for cacheable pages. (experimental)'),
+    '#description' => t('Uses Javascript to preserve Page caching.'),
+    '#default_value' => variable_get('honeypot_use_js_for_cached_pages', FALSE),
+    '#states' => array(
+      // Hide this when time limit is disabled.
+      'invisible' => array(
+        'input[name="honeypot_time_limit"]' => array('value' => 0),
+      ),
+    ),
+  );
+  $form['configuration']['honeypot_use_js_for_cached_pages']['#description'] .= '<br />' . t('<strong>Warning: Users who have javascript disabled will need to confirm their form submission on the next page (if the Honeypot-enabled form is on a cacheable page).</strong>');
 
 
   // Honeypot Enabled forms.
   // Honeypot Enabled forms.
   $form['enabled_forms'] = array(
   $form['enabled_forms'] = array(

+ 3 - 4
sites/all/modules/contrib/form/honeypot/honeypot.info

@@ -6,9 +6,8 @@ package = "Spam control"
 
 
 files[] = honeypot.test
 files[] = honeypot.test
 
 
-; Information added by Drupal.org packaging script on 2016-03-11
-version = "7.x-1.22"
+; Information added by Drupal.org packaging script on 2018-08-09
+version = "7.x-1.25"
 core = "7.x"
 core = "7.x"
 project = "honeypot"
 project = "honeypot"
-datestamp = "1457672041"
-
+datestamp = "1533849190"

+ 2 - 2
sites/all/modules/contrib/form/honeypot/honeypot.install

@@ -68,8 +68,8 @@ function honeypot_uninstall() {
     }
     }
   }
   }
 
 
-  // Delete 'honeypot' directory from public file directory.
-  file_unmanaged_delete_recursive('public://honeypot');
+  // Delete 'honeypot' directory from files directory.
+  file_unmanaged_delete_recursive(honeypot_file_default_scheme() . '://honeypot');
 }
 }
 
 
 /**
 /**

+ 125 - 8
sites/all/modules/contrib/form/honeypot/honeypot.module

@@ -78,7 +78,7 @@ function honeypot_form_alter(&$form, &$form_state, $form_id) {
   if (variable_get('honeypot_protect_all_forms', 0) && !in_array($form_id, $unprotected_forms)) {
   if (variable_get('honeypot_protect_all_forms', 0) && !in_array($form_id, $unprotected_forms)) {
     // Don't protect system forms - only admins should have access, and system
     // Don't protect system forms - only admins should have access, and system
     // forms may be programmatically submitted by drush and other modules.
     // forms may be programmatically submitted by drush and other modules.
-    if (strpos($form_id, 'system_') === FALSE && strpos($form_id, 'search_') === FALSE && strpos($form_id, 'views_exposed_form_') === FALSE) {
+    if (preg_match('/[^a-zA-Z]system_/', $form_id) === 0 && preg_match('/[^a-zA-Z]search_/', $form_id) === 0 && preg_match('/[^a-zA-Z]views_exposed_form_/', $form_id) === 0) {
       honeypot_add_form_protection($form, $form_state, array('honeypot', 'time_restriction'));
       honeypot_add_form_protection($form, $form_state, array('honeypot', 'time_restriction'));
     }
     }
   }
   }
@@ -135,6 +135,36 @@ function honeypot_rules_event_info() {
   );
   );
 }
 }
 
 
+/**
+ * Implements hook_library().
+ */
+function honeypot_library() {
+  $info = system_get_info('module', 'honeypot');
+  $version = $info['version'];
+
+  // Library for Honeypot JS.
+  $libraries['timestamp.js'] = array(
+    'title' => 'Javascript to support timelimit on cached pages.',
+    'version' => $version,
+    'js' => array(
+      array(
+        'type' => 'setting',
+        'data' => array(
+          'honeypot' => array(
+            'jsToken' => honeypot_get_signed_timestamp('js_token:' . mt_rand(0, 2147483647)),
+           ),
+         ),
+      ),
+      drupal_get_path('module', 'honeypot') . '/js/honeypot.js' => array(
+        'group' => JS_LIBRARY,
+        'weight' => 3,
+      ),
+    ),
+  );
+
+  return $libraries;
+}
+
 /**
 /**
  * Build an array of all the protected forms on the site, by form_id.
  * Build an array of all the protected forms on the site, by form_id.
  *
  *
@@ -233,8 +263,16 @@ function honeypot_add_form_protection(&$form, &$form_state, $options = array())
     );
     );
 
 
     // Disable page caching to make sure timestamp isn't cached.
     // Disable page caching to make sure timestamp isn't cached.
-    if (user_is_anonymous()) {
-      drupal_page_is_cacheable(FALSE);
+    if (user_is_anonymous() && drupal_page_is_cacheable()) {
+      // Use javascript implementation if this page should be cached.
+      if (variable_get('honeypot_use_js_for_cached_pages', FALSE)) {
+        $form['honeypot_time']['#default_value'] = 'no_js_available';
+        $form['honeypot_time']['#attached']['library'][] = array('honeypot', 'timestamp.js');
+        $form['#attributes']['class'][] = 'honeypot-timestamp-js';
+      }
+      else {
+        drupal_page_is_cacheable(FALSE);
+      }
     }
     }
   }
   }
 
 
@@ -261,7 +299,7 @@ function _honeypot_honeypot_validate($element, &$form_state) {
 /**
 /**
  * Validate honeypot's time restriction field.
  * Validate honeypot's time restriction field.
  */
  */
-function _honeypot_time_restriction_validate($element, &$form_state) {
+function _honeypot_time_restriction_validate(&$element, &$form_state) {
   if (!empty($form_state['programmed'])) {
   if (!empty($form_state['programmed'])) {
     // Don't do anything if the form was submitted programmatically.
     // Don't do anything if the form was submitted programmatically.
     return;
     return;
@@ -272,8 +310,43 @@ function _honeypot_time_restriction_validate($element, &$form_state) {
     return;
     return;
   }
   }
 
 
-  // Get the time value.
-  $honeypot_time = honeypot_get_time_from_signed_timestamp($form_state['values']['honeypot_time']);
+  if ($form_state['values']['honeypot_time'] == 'no_js_available') {
+    // Set an error, but do not penalize the user as it might be a legitimate
+    // attempt.
+    form_set_error('', t('You seem to have javascript disabled. Please confirm your form submission.'));
+
+    if (variable_get('honeypot_log', 0)) {
+      $variables = array(
+        '%form'  => $form_state['values']['form_id'],
+      );
+      watchdog('honeypot', 'User tried to submit form %form without javascript enabled.', $variables);
+    }
+
+    // Update the value in $form_state and $element.
+    $form_state['values']['honeypot_time'] = honeypot_get_signed_timestamp(REQUEST_TIME);
+    $element['#value'] = $form_state['values']['honeypot_time'];
+    return;
+  }
+
+  $honeypot_time = FALSE;
+
+  // Update the honeypot_time for JS requests and get the $honeypot_time value.
+  if (strpos($form_state['values']['honeypot_time'], 'js_token:') === 0) {
+    $interval = _honeypot_get_interval_from_signed_js_value($form_state['values']['honeypot_time']);
+    if ($interval) {
+      // Set correct value for timestamp validation.
+      $honeypot_time = REQUEST_TIME - $interval;
+
+      // Update form_state and element values so they're correct.
+      $form_state['values']['honeypot_time'] = honeypot_get_signed_timestamp($honeypot_time);
+      $element['#value'] = $form_state['values']['honeypot_time'];
+    }
+  }
+  // Otherwise just get the $honeypot_time value.
+  else {
+    // Get the time value.
+    $honeypot_time = honeypot_get_time_from_signed_timestamp($form_state['values']['honeypot_time']);
+  }
 
 
   // Get the honeypot_time_limit.
   // Get the honeypot_time_limit.
   $time_limit = honeypot_get_time_limit($form_state['values']);
   $time_limit = honeypot_get_time_limit($form_state['values']);
@@ -284,11 +357,43 @@ function _honeypot_time_restriction_validate($element, &$form_state) {
     _honeypot_log($form_state['values']['form_id'], 'honeypot_time');
     _honeypot_log($form_state['values']['form_id'], 'honeypot_time');
     // Get the time limit again, since it increases after first failure.
     // Get the time limit again, since it increases after first failure.
     $time_limit = honeypot_get_time_limit($form_state['values']);
     $time_limit = honeypot_get_time_limit($form_state['values']);
+    // Update the honeypot_time value in the form state and element.
     $form_state['values']['honeypot_time'] = honeypot_get_signed_timestamp(REQUEST_TIME);
     $form_state['values']['honeypot_time'] = honeypot_get_signed_timestamp(REQUEST_TIME);
+    $element['#value'] = $form_state['values']['honeypot_time'];
     form_set_error('', t('There was a problem with your form submission. Please wait @limit seconds and try again.', array('@limit' => $time_limit)));
     form_set_error('', t('There was a problem with your form submission. Please wait @limit seconds and try again.', array('@limit' => $time_limit)));
   }
   }
 }
 }
 
 
+/**
+ * Returns an interval if the given javascript submitted value is valid.
+ *
+ * @param string $honeypot_time
+ *   The signed interval as submitted via javascript.
+ *
+ * @return int|FALSE
+ *   The interval in seconds if the token is valid, FALSE otherwise.
+ */
+function _honeypot_get_interval_from_signed_js_value($honeypot_time) {
+  $t = explode('|', $honeypot_time);
+
+  if (count($t) != 3) {
+    return FALSE;
+  }
+
+  $js_token = $t[0] . '|' . $t[1];
+  $token_check = honeypot_get_time_from_signed_timestamp($js_token);
+  if (!$token_check) {
+    return FALSE;
+  }
+
+  $interval = (int) $t[2];
+  if ($interval == 0) {
+    return FALSE;
+  }
+
+  return $interval;
+}
+
 /**
 /**
  * Log blocked form submissions.
  * Log blocked form submissions.
  *
  *
@@ -398,7 +503,7 @@ function honeypot_log_failure($form_id, $type) {
  *   The path to the honeypot.css file.
  *   The path to the honeypot.css file.
  */
  */
 function honeypot_get_css_file_path() {
 function honeypot_get_css_file_path() {
-  return variable_get('file_public_path', conf_path() . '/files') . '/honeypot/honeypot.css';
+  return honeypot_file_default_scheme() . '://honeypot/honeypot.css';
 }
 }
 
 
 /**
 /**
@@ -408,7 +513,7 @@ function honeypot_get_css_file_path() {
  *   The honeypot element class name (e.g. 'url').
  *   The honeypot element class name (e.g. 'url').
  */
  */
 function honeypot_create_css($element_name) {
 function honeypot_create_css($element_name) {
-  $path = 'public://honeypot';
+  $path = honeypot_file_default_scheme() . '://honeypot';
 
 
   if (!file_prepare_directory($path, FILE_CREATE_DIRECTORY)) {
   if (!file_prepare_directory($path, FILE_CREATE_DIRECTORY)) {
     drupal_set_message(t('Unable to create Honeypot CSS directory, %path. Check the permissions on your files directory.', array('%path' => file_uri_target($path))), 'error');
     drupal_set_message(t('Unable to create Honeypot CSS directory, %path. Check the permissions on your files directory.', array('%path' => file_uri_target($path))), 'error');
@@ -487,3 +592,15 @@ function honeypot_get_time_from_signed_timestamp($signed_timestamp) {
 
 
   return $honeypot_time;
   return $honeypot_time;
 }
 }
+
+/**
+ * Gets the default file stream for honeypot.
+ *
+ * @return
+ *   'public', 'private' or any other file scheme defined as the default.
+ *
+ * @see file_default_scheme()
+ */
+function honeypot_file_default_scheme() {
+  return variable_get('honeypot_file_default_scheme', file_default_scheme());
+}

+ 55 - 0
sites/all/modules/contrib/form/honeypot/honeypot.test

@@ -366,6 +366,60 @@ class HoneypotCssTestCase extends DrupalWebTestCase {
     // Revert the honeypot element name back to the original.
     // Revert the honeypot element name back to the original.
     variable_set('honeypot_element_name', $original_element_name);
     variable_set('honeypot_element_name', $original_element_name);
   }
   }
+
+  /**
+   * Test CSS works when default file scheme is not public://
+   */
+  public function testHoneypotCssNonpublicFileSystem() {
+    variable_set('file_default_scheme', 'private');
+
+    $honeypot_css = honeypot_get_css_file_path();
+
+    // Delete the Honeypot CSS file (if it exists).
+    file_unmanaged_delete($honeypot_css);
+
+    // Make sure the Honeypot CSS file doesn't exist.
+    $this->assertFalse(file_exists($honeypot_css));
+
+    // Run cron.
+    honeypot_cron();
+
+    // Make sure the Honeypot CSS file exists.
+    $this->assertTrue(file_exists($honeypot_css));
+  }
+
+  /**
+   * Test CSS file availability.
+   */
+  public function testHoneypotCssAvailability() {
+    // Public CSS file can be consumed.
+    variable_set('file_default_scheme', 'public');
+    if ($wrapper = file_stream_wrapper_get_instance_by_uri(honeypot_get_css_file_path())) {
+      $url = $wrapper->getExternalUrl();
+    }
+    $this->drupalGet($url);
+    $this->assertResponse(200);
+
+
+    // Private CSS file can not be consumed.
+    variable_set('file_default_scheme', 'private');
+    honeypot_cron();
+    if ($wrapper = file_stream_wrapper_get_instance_by_uri(honeypot_get_css_file_path())) {
+      $url = $wrapper->getExternalUrl();
+    }
+    $this->drupalGet($url);
+    $this->assertNoResponse(200);
+
+    // Site default is private, but override honeypot's to public to consume.
+    variable_set('honeypot_file_default_scheme', 'public');
+    honeypot_cron();
+    if ($wrapper = file_stream_wrapper_get_instance_by_uri(honeypot_get_css_file_path())) {
+      $url = $wrapper->getExternalUrl();
+    }
+    $this->drupalGet($url);
+    $this->assertResponse(200);
+  }
+
 }
 }
 
 
 /**
 /**
@@ -423,4 +477,5 @@ class HoneypotTriggerTestCase extends DrupalWebTestCase {
     $this->drupalGet('node');
     $this->drupalGet('node');
     $this->assertText(t('has been banned'), 'User banned successfully.');
     $this->assertText(t('has been banned'), 'User banned successfully.');
   }
   }
+
 }
 }

+ 37 - 0
sites/all/modules/contrib/form/honeypot/js/honeypot.js

@@ -0,0 +1,37 @@
+(function ($) {
+
+  Drupal.honeypot = {};
+  Drupal.honeypot.timestampJS = new Date();
+
+  Drupal.behaviors.honeypotJS = {
+    attach: function (context, settings) {
+      $('form.honeypot-timestamp-js').once('honeypot-timestamp').bind('submit', function() {
+        var $honeypotTime = $(this).find('input[name="honeypot_time"]');
+        $honeypotTime.attr('value', Drupal.behaviors.honeypotJS.getIntervalTimestamp());
+      });
+    },
+    getIntervalTimestamp: function() {
+      var now = new Date();
+      var interval = Math.floor((now - Drupal.honeypot.timestampJS) / 1000);
+      return Drupal.settings.honeypot.jsToken + '|' + interval;
+    }
+  };
+
+  if (Drupal.ajax && Drupal.ajax.prototype && Drupal.ajax.prototype.beforeSubmit) {
+    Drupal.ajax.prototype.honeypotOriginalBeforeSubmit = Drupal.ajax.prototype.beforeSubmit;
+    Drupal.ajax.prototype.beforeSubmit = function (form_values, element, options) {
+      if (this.form && $(this.form).hasClass('honeypot-timestamp-js')) {
+        for (key in form_values) {
+          // Inject the right interval timestamp.
+          if (form_values[key].name == 'honeypot_time' && form_values[key].value == 'no_js_available') {
+            form_values[key].value = Drupal.behaviors.honeypotJS.getIntervalTimestamp();
+          }
+        }
+      }
+
+      // Call the original function in case someone else has overridden it.
+      return Drupal.ajax.prototype.honeypotOriginalBeforeSubmit(form_values, element, options);
+    }
+  }
+
+}(jQuery));

+ 3 - 4
sites/all/modules/contrib/form/honeypot/tests/honeypot_test.info

@@ -4,9 +4,8 @@ core = 7.x
 package = Testing
 package = Testing
 hidden = true
 hidden = true
 
 
-; Information added by Drupal.org packaging script on 2016-03-11
-version = "7.x-1.22"
+; Information added by Drupal.org packaging script on 2018-08-09
+version = "7.x-1.25"
 core = "7.x"
 core = "7.x"
 project = "honeypot"
 project = "honeypot"
-datestamp = "1457672041"
-
+datestamp = "1533849190"

+ 1 - 0
sites/all/modules/contrib/mail/mailgun/README.txt

@@ -0,0 +1 @@
+Mailgun module documentation is here: https://www.drupal.org/node/2547591.

+ 12 - 0
sites/all/modules/contrib/mail/mailgun/composer.json

@@ -0,0 +1,12 @@
+{
+  "name": "drupal/mailgun",
+  "description": "Provides integration with the Mailgun PHP library.",
+  "type": "drupal-module",
+  "homepage": "https://www.drupal.org/project/mailgun",
+  "license": "GPL-2.0+",
+  "require": {
+    "guzzlehttp/psr7": "~1.3",
+    "php-http/guzzle6-adapter": "^1.0",
+    "mailgun/mailgun-php": "~2.0"
+  }
+}

+ 112 - 59
sites/all/modules/contrib/mail/mailgun/mailgun.admin.inc

@@ -16,11 +16,12 @@
  * @return array
  * @return array
  *   An array containing form items to place on the module settings page.
  *   An array containing form items to place on the module settings page.
  */
  */
-function mailgun_admin_settings($form, &$form_state) {
-  $library = libraries_detect('mailgun');
-
-  if (!$library['installed']) {
-    drupal_set_message(t('The Mailgun PHP library is not installed. Please see <a href="@url">documentation</a> for more information.', array('@url' => url('https://www.drupal.org/node/2547591'))), 'error');
+function mailgun_admin_settings(array $form, array &$form_state) {
+  // Check if the Mailgun PHP library is installed.
+  if (!mailgun_check_library()) {
+    drupal_set_message(t('The Mailgun PHP library is not installed. Please see Installation section in the !link.', array(
+      '!link' => l(t('documentation'), MAILGUN_DOCUMENTATION_LINK),
+    )), 'error');
   }
   }
 
 
   $key = variable_get('mailgun_api_key', '');
   $key = variable_get('mailgun_api_key', '');
@@ -28,7 +29,9 @@ function mailgun_admin_settings($form, &$form_state) {
   $form['mailgun_api_key'] = array(
   $form['mailgun_api_key'] = array(
     '#title' => t('Mailgun API key'),
     '#title' => t('Mailgun API key'),
     '#type' => 'textfield',
     '#type' => 'textfield',
-    '#description' => t('Get your Secret API key from the <a href="@url">Mailgun dashboard</a>.', array('@url' => url('https://mailgun.com/app/dashboard'))),
+    '#description' => t('Get your Secret API key from the !link.', array(
+      '!link' => l(t('Mailgun dashboard'), MAILGUN_DASHBOARD_LINK),
+    )),
     '#default_value' => $key,
     '#default_value' => $key,
     '#required' => TRUE,
     '#required' => TRUE,
   );
   );
@@ -37,23 +40,25 @@ function mailgun_admin_settings($form, &$form_state) {
   if (!empty($key)) {
   if (!empty($key)) {
     try {
     try {
       $client = mailgun_get_client($key);
       $client = mailgun_get_client($key);
-    } catch (Exception $e) {
-      watchdog('mailgun', 'An exception occurred. @code: @message', array('@code' => $e->getCode(), '@message' => $e->getMessage()), WATCHDOG_WARNING, 'admin/config/system/mailgun');
+    }
+    catch (Exception $e) {
+      watchdog('mailgun', 'An exception occurred. @code: @message', array(
+        '@code' => $e->getCode(),
+        '@message' => $e->getMessage(),
+      ), WATCHDOG_WARNING, MAILGUN_ADMIN_PAGE);
       drupal_set_message(t('Mailgun: %message', array('%message' => $e->getMessage())), 'error');
       drupal_set_message(t('Mailgun: %message', array('%message' => $e->getMessage())), 'error');
     }
     }
   }
   }
 
 
-  // Display settings only when a valid API key is present and client is active
+  // Display settings only when a valid API key is present and client is active.
   if ($client) {
   if ($client) {
     $domain_options = array(
     $domain_options = array(
       '_sender' => t('Get domain from sender address'),
       '_sender' => t('Get domain from sender address'),
     );
     );
-    $domains = array();
-    $result = $client->get('domains');
-    if ($result && $result->http_response_code == 200) {
-      foreach ($result->http_response_body->items as $domain) {
-        $domains[$domain->name] = $domain;
-        $domain_options[$domain->name] = $domain->name;
+    $result = $client->domains()->index();
+    if (!empty($result)) {
+      foreach ($result->getDomains() as $domain) {
+        $domain_options[$domain->getName()] = $domain->getName();
       }
       }
     }
     }
 
 
@@ -61,7 +66,7 @@ function mailgun_admin_settings($form, &$form_state) {
       '#title' => t('Domain'),
       '#title' => t('Domain'),
       '#type' => 'select',
       '#type' => 'select',
       '#options' => $domain_options,
       '#options' => $domain_options,
-      '#description' => t('Mails will be sent using this domain'),
+      '#description' => t('Mails will be sent using this domain.'),
       '#default_value' => variable_get('mailgun_domain', '_sender'),
       '#default_value' => variable_get('mailgun_domain', '_sender'),
     );
     );
 
 
@@ -69,69 +74,96 @@ function mailgun_admin_settings($form, &$form_state) {
       '#title' => t('Test mode'),
       '#title' => t('Test mode'),
       '#type' => 'checkbox',
       '#type' => 'checkbox',
       '#default_value' => variable_get('mailgun_test', FALSE),
       '#default_value' => variable_get('mailgun_test', FALSE),
-      '#description' => t('Enables sending in test mode'),
-    );
-
-    $form['mailgun_queue'] = array(
-      '#title' => t('Queue mails'),
-      '#type' => 'checkbox',
-      '#description' => t('Mails will be queued and sent during cron runs. Useful for sending a large number of emails.'),
-      '#default_value' => variable_get('mailgun_queue', FALSE),
+      '#description' => t('Mailgun will accept the message but will not send it. This is useful for testing purposes.'),
     );
     );
 
 
     $form['mailgun_log'] = array(
     $form['mailgun_log'] = array(
       '#title' => t('Log mails'),
       '#title' => t('Log mails'),
       '#type' => 'checkbox',
       '#type' => 'checkbox',
-      '#description' => t('Log mails sent through Mailgun. Should not be enabled on production sites. Messages fail to send will be logged regardless of this setting.'),
+      '#description' => t('Log all mails sent through Mailgun. Messages fail to send will be logged regardless of this setting.'),
       '#default_value' => variable_get('mailgun_log', FALSE),
       '#default_value' => variable_get('mailgun_log', FALSE),
     );
     );
 
 
-    $formats = array('_none' => t('- None -'));
-    foreach (filter_formats() as $format) {
-      if ($format->format == 'php_code') {
-        continue;
-      }
-      $formats[$format->format] = t($format->name);
-    }
-    $form['mailgun_format'] = array(
-      '#title' => t('Text format'),
-      '#type' => 'select',
-      '#description' => t('Specify an additional text format to filter the message through before sending the email.'),
-      '#options' => $formats,
-      '#default_value' => variable_get('mailgun_format', '_none'),
+    $form['extra'] = array(
+      '#type' => 'fieldset',
+      '#title' => t('Additional settings'),
+      '#description' => t('These default settings apply to messages sent using Mailgun and may be overriden on a per-message basis.'),
+      '#collapsible' => TRUE,
+      '#collapsed' => TRUE,
     );
     );
 
 
-    $form['defaults'] = array(
+    // We have the same options for all settings.
+    $options = array(
+      'default' => t('Use default setting'),
+      'enabled' => t('Enabled'),
+      'disabled' => t('Disabled'),
+    );
+
+    $form['extra']['tracking'] = array(
       '#type' => 'fieldset',
       '#type' => 'fieldset',
-      '#title' => t('Default settings'),
-      '#description' => t('These default settings apply to messages sent using Mailgun and may be overriden on a per-message basis.'),
-      '#collapsible' => FALSE,
-      '#collapsed' => FALSE,
+      '#title' => t('Tracking'),
     );
     );
 
 
-    $form['defaults']['mailgun_tracking'] = array(
+    $form['extra']['tracking']['mailgun_tracking'] = array(
       '#title' => t('Enable tracking'),
       '#title' => t('Enable tracking'),
       '#type' => 'select',
       '#type' => 'select',
-      '#options' => array('default' => t('Use default setting'), 'enabled' => t('Enabled'), 'disabled' => t('Disabled')),
-      '#description' => t('Whether to enable event tracking by default or not. See <a href="@url">Tracking Messages</a> for details.', array('@url' => url('https://documentation.mailgun.com/user_manual.html#tracking-messages'))),
+      '#options' => $options,
+      '#description' => t('Whether to enable event tracking by default or not. See !link for details.', array(
+        '!link' => l(t('Tracking Messages'), 'https://documentation.mailgun.com/user_manual.html#tracking-messages'),
+      )),
       '#default_value' => variable_get('mailgun_tracking', 'default'),
       '#default_value' => variable_get('mailgun_tracking', 'default'),
     );
     );
 
 
-    $form['defaults']['mailgun_tracking_clicks'] = array(
+    $form['extra']['tracking']['mailgun_tracking_clicks'] = array(
       '#title' => t('Enable click tracking'),
       '#title' => t('Enable click tracking'),
       '#type' => 'select',
       '#type' => 'select',
-      '#options' => array('default' => t('Use default setting'), 'enabled' => t('Enabled'), 'disabled' => t('Disabled')),
+      '#options' => $options,
       '#description' => t('Whether to enable click tracking by default or not.'),
       '#description' => t('Whether to enable click tracking by default or not.'),
       '#default_value' => variable_get('mailgun_tracking_clicks', 'default'),
       '#default_value' => variable_get('mailgun_tracking_clicks', 'default'),
     );
     );
 
 
-    $form['defaults']['mailgun_tracking_opens'] = array(
+    $form['extra']['tracking']['mailgun_tracking_opens'] = array(
       '#title' => t('Enable open tracking'),
       '#title' => t('Enable open tracking'),
       '#type' => 'select',
       '#type' => 'select',
-      '#options' => array('default' => t('Use default setting'), 'enabled' => t('Enabled'), 'disabled' => t('Disabled')),
+      '#options' => $options,
       '#description' => t('Whether to enable open tracking by default or not.'),
       '#description' => t('Whether to enable open tracking by default or not.'),
       '#default_value' => variable_get('mailgun_tracking_opens', 'default'),
       '#default_value' => variable_get('mailgun_tracking_opens', 'default'),
     );
     );
+
+    $formats = array('_none' => t('- None -'));
+    foreach (filter_formats() as $format) {
+      if ($format->format === 'php_code') {
+        continue;
+      }
+      $formats[$format->format] = $format->name;
+    }
+    $form['extra']['mailgun_format'] = array(
+      '#title' => t('Text format'),
+      '#type' => 'select',
+      '#description' => t('Specify an additional text format to filter the message through before sending the email.'),
+      '#options' => $formats,
+      '#default_value' => variable_get('mailgun_format', '_none'),
+    );
+
+    $form['extra']['mailgun_queue'] = array(
+      '#title' => t('Queue mails'),
+      '#type' => 'checkbox',
+      '#description' => t('Mails will be queued and sent during cron runs. Useful for sending a large number of emails.'),
+      '#default_value' => variable_get('mailgun_queue', FALSE),
+    );
+
+    $form['extra']['mailgun_tagging_mailkey'] = array(
+      '#type' => 'checkbox',
+      '#title' => t('Enable tags by mail key'),
+      '#description' => t('See !url for details.', array(
+        '!url' => l(t('Tagging'), 'https://documentation.mailgun.com/user_manual.html#tagging', array(
+          'attributes' => array(
+            'onclick' => "target='_blank'",
+          ),
+        )),
+      )),
+      '#default_value' => variable_get('mailgun_tagging_mailkey', TRUE),
+    );
   }
   }
 
 
   $form = system_settings_form($form);
   $form = system_settings_form($form);
@@ -150,11 +182,21 @@ function mailgun_admin_settings_validate($form, &$form_state) {
     // The API key has changed. Perform validation.
     // The API key has changed. Perform validation.
     $form_state['values']['mailgun_api_key'] = trim($form_state['values']['mailgun_api_key']);
     $form_state['values']['mailgun_api_key'] = trim($form_state['values']['mailgun_api_key']);
     $client = mailgun_get_client($form_state['values']['mailgun_api_key']);
     $client = mailgun_get_client($form_state['values']['mailgun_api_key']);
+
+    if ($client === FALSE) {
+      drupal_set_message(t('Could not connect to Mailgun API. Please check your settings'), 'warning');
+      return;
+    }
+
     try {
     try {
-      $result = $client->get('domains');
+      $client->domains()->index();
       drupal_set_message(t('Your API key has been successfully validated.'));
       drupal_set_message(t('Your API key has been successfully validated.'));
-    } catch (Exception $e) {
-      form_set_error('mailgun_api_key', t('An exception occurred. @code: @message', array('@code' => $e->getCode(), '@message' => $e->getMessage())));
+    }
+    catch (Exception $e) {
+      form_set_error('mailgun_api_key', t('An exception occurred. @code: @message', array(
+        '@code' => $e->getCode(),
+        '@message' => $e->getMessage(),
+      )));
     }
     }
   }
   }
 }
 }
@@ -173,9 +215,11 @@ function mailgun_test_form($form, &$form_state) {
     '#required' => TRUE,
     '#required' => TRUE,
   );
   );
 
 
-  $message = "Howdy!\n\nIf this e-mail is displayed correctly and delivered sound and safe, congrats! You have successfully configured Mailgun.";
-  $message .= ' Visit the <a href="@project">project page</a> to contribute or read <a href="@documentation">documentation</a> to learn more.';
-  $message = t($message, array('@project' => url('https://www.drupal.org/project/mailgun'), '@documentation' => url('https://www.drupal.org/node/2547591')));
+  $message = "Howdy!\n\nIf this e-mail is displayed correctly and delivered sound and safe, congrats! You have successfully configured Mailgun. ";
+  $message .= t('Visit the !project to contribute or read !documentation to learn more.', array(
+    '!project' => l(t('project page'), 'https://www.drupal.org/project/mailgun'),
+    '!documentation' => l(t('documentation'), MAILGUN_DOCUMENTATION_LINK),
+  ));
   $form['message'] = array(
   $form['message'] = array(
     '#type' => 'textarea',
     '#type' => 'textarea',
     '#title' => t('Message'),
     '#title' => t('Message'),
@@ -196,7 +240,7 @@ function mailgun_test_form($form, &$form_state) {
   );
   );
   $form['cancel'] = array(
   $form['cancel'] = array(
     '#type' => 'link',
     '#type' => 'link',
-    '#href' => 'admin/config/system/mailgun',
+    '#href' => MAILGUN_ADMIN_PAGE,
     '#title' => t('Cancel'),
     '#title' => t('Cancel'),
   );
   );
 
 
@@ -205,17 +249,26 @@ function mailgun_test_form($form, &$form_state) {
 
 
 /**
 /**
  * Form submission handler for mailgun_test_form().
  * Form submission handler for mailgun_test_form().
+ *
  * Send the test e-mail.
  * Send the test e-mail.
  */
  */
 function mailgun_test_form_submit($form, &$form_state) {
 function mailgun_test_form_submit($form, &$form_state) {
   $to = $form_state['values']['to'];
   $to = $form_state['values']['to'];
+  $body = explode('\n', $form_state['values']['message']);
+
   $params = array(
   $params = array(
-    'message' => $form_state['values']['message'],
+    'message' => $body,
     'attachment' => $form_state['values']['attachment'],
     'attachment' => $form_state['values']['attachment'],
   );
   );
   $site_name = variable_get('site_name', '');
   $site_name = variable_get('site_name', '');
   $default_from = variable_get('site_mail', ini_get('sendmail_from'));
   $default_from = variable_get('site_mail', ini_get('sendmail_from'));
   $from = (!empty($site_name)) ? $site_name . ' <' . $default_from . '>' : $default_from;
   $from = (!empty($site_name)) ? $site_name . ' <' . $default_from . '>' : $default_from;
   $result = drupal_mail('mailgun', 'test', $to, $GLOBALS['language'], $params, $from);
   $result = drupal_mail('mailgun', 'test', $to, $GLOBALS['language'], $params, $from);
-  drupal_set_message(t('Test email sent from %from to %to. If you have the "Log mails" setting enabled, check the <a href="@url">database log</a> for details.', array('%from' => $result['from'], '%to' => $result['to'], '@url' => url('admin/reports/dblog'))), 'status');
+
+  drupal_set_message(t('Test email sent from %from to %to. If you have the "Log mails" setting enabled, check the <a href="@url">database log</a> for details.',
+    array(
+      '%from' => $result['from'],
+      '%to' => $result['to'],
+      '@url' => url('admin/reports/dblog'),
+    )), 'status');
 }
 }

+ 8 - 7
sites/all/modules/contrib/mail/mailgun/mailgun.info

@@ -1,16 +1,17 @@
+package = Mail
 name = Mailgun
 name = Mailgun
 description = "Provides integration with Mailgun's email sending API."
 description = "Provides integration with Mailgun's email sending API."
 core = 7.x
 core = 7.x
-package = Mailgun
-
-dependencies[] = libraries
-dependencies[] = mailsystem
+php = 5.5
+configure = admin/config/system/mailgun
 
 
 files[] = mailgun.mail.inc
 files[] = mailgun.mail.inc
 
 
-; Information added by Drupal.org packaging script on 2016-06-26
-version = "7.x-1.6+0-dev"
+dependencies[] = mailsystem (>=2.x)
+
+; Information added by Drupal.org packaging script on 2017-12-06
+version = "7.x-1.6"
 core = "7.x"
 core = "7.x"
 project = "mailgun"
 project = "mailgun"
-datestamp = "1466914444"
+datestamp = "1512586085"
 
 

+ 38 - 2
sites/all/modules/contrib/mail/mailgun/mailgun.install

@@ -1,6 +1,5 @@
 <?php
 <?php
 
 
-
 /**
 /**
  * @file
  * @file
  * Install, update and uninstall functions for the Mailgun module.
  * Install, update and uninstall functions for the Mailgun module.
@@ -11,7 +10,19 @@
  */
  */
 function mailgun_uninstall() {
 function mailgun_uninstall() {
   // Delete variables.
   // Delete variables.
-  $variables = array('mailgun_api_key', 'mailgun_from_action', 'mailgun_from_name', 'mailgun_from_mail', 'mailgun_tracking', 'mailgun_tracking_clicks', 'mailgun_tracking_opens', 'mailgun_queue', 'mailgun_log', 'mailgun_format');
+  $variables = array(
+    'mailgun_api_key',
+    'mailgun_from_action',
+    'mailgun_from_name',
+    'mailgun_from_mail',
+    'mailgun_tracking',
+    'mailgun_tracking_clicks',
+    'mailgun_tracking_opens',
+    'mailgun_queue',
+    'mailgun_log',
+    'mailgun_format',
+    'mailgun_tagging_mailkey',
+  );
   foreach ($variables as $variable) {
   foreach ($variables as $variable) {
     variable_del($variable);
     variable_del($variable);
   }
   }
@@ -32,3 +43,28 @@ function mailgun_disable() {
   mailsystem_clear(array('mailgun_test' => 'MailgunMailSystem'));
   mailsystem_clear(array('mailgun_test' => 'MailgunMailSystem'));
   watchdog('mailgun', 'Mailgun has been disabled.');
   watchdog('mailgun', 'Mailgun has been disabled.');
 }
 }
+
+/**
+ * Implements hook_requirements().
+ */
+function mailgun_requirements($phase) {
+  // Ensure translations don't break during installation.
+  $t = get_t();
+
+  $requirements = array();
+
+  if ($phase === 'runtime') {
+    $requirements['mailgun']['title'] = $t('Mailgun');
+
+    if (mailgun_check_library()) {
+      $requirements['mailgun']['value'] = $t('The Mailgun library is installed correctly.');
+      $requirements['mailgun']['severity'] = REQUIREMENT_OK;
+    }
+    else {
+      $requirements['mailgun']['value'] = $t('The Mailgun library has not been installed correctly.');
+      $requirements['mailgun']['severity'] = REQUIREMENT_ERROR;
+    }
+  }
+
+  return $requirements;
+}

+ 77 - 23
sites/all/modules/contrib/mail/mailgun/mailgun.mail.inc

@@ -2,14 +2,14 @@
 
 
 /**
 /**
  * @file
  * @file
- * Implements Mailgun as a Drupal MailSystemInterface
+ * Implements Mailgun as a Drupal MailSystemInterface.
  */
  */
 
 
 /**
 /**
  * Modify the Drupal mail system to use Mailgun when sending e-mails.
  * Modify the Drupal mail system to use Mailgun when sending e-mails.
  */
  */
 class MailgunMailSystem implements MailSystemInterface {
 class MailgunMailSystem implements MailSystemInterface {
-  
+
   /**
   /**
    * Concatenate and wrap the e-mail body for either plain-text or HTML e-mails.
    * Concatenate and wrap the e-mail body for either plain-text or HTML e-mails.
    *
    *
@@ -25,26 +25,34 @@ class MailgunMailSystem implements MailSystemInterface {
       $message['body'] = implode("\n\n", $message['body']);
       $message['body'] = implode("\n\n", $message['body']);
     }
     }
 
 
-    // If a text format is specified in Mailgun settings, run the message through it.
+    // Run the message through text format if specified in Mailgun settings.
     $format = variable_get('mailgun_format', '_none');
     $format = variable_get('mailgun_format', '_none');
-    if ($format != '_none') {
+    if ($format !== '_none') {
       $message['body'] = check_markup($message['body'], $format);
       $message['body'] = check_markup($message['body'], $format);
     }
     }
 
 
+    // Wrap body with theme function.
+    $message['body'] = theme('mailgun_message', array(
+      'subject' => $message['subject'],
+      'body' => $message['body'],
+      'message' => $message,
+    ));
+
     return $message;
     return $message;
   }
   }
 
 
   /**
   /**
    * Send the e-mail message.
    * Send the e-mail message.
    *
    *
-   * @see drupal_mail()
-   * @see https://documentation.mailgun.com/api-sending.html#sending
-   *
    * @param array $message
    * @param array $message
-   *   A message array, as described in hook_mail_alter(). $message['params'] may contain additional parameters. See mailgun_send().
+   *   A message array, as described in hook_mail_alter(). $message['params']
+   *   may contain additional parameters. See mailgun_send().
    *
    *
    * @return bool
    * @return bool
    *   TRUE if the mail was successfully accepted or queued, FALSE otherwise.
    *   TRUE if the mail was successfully accepted or queued, FALSE otherwise.
+   *
+   * @see drupal_mail()
+   * @see https://documentation.mailgun.com/api-sending.html#sending
    */
    */
   public function mail(array $message) {
   public function mail(array $message) {
     // Build the Mailgun message array.
     // Build the Mailgun message array.
@@ -52,7 +60,7 @@ class MailgunMailSystem implements MailSystemInterface {
       'from' => $message['from'],
       'from' => $message['from'],
       'to' => $message['to'],
       'to' => $message['to'],
       'subject' => $message['subject'],
       'subject' => $message['subject'],
-      'text' => check_plain($message['body']),
+      'text' => drupal_html_to_text($message['body']),
       'html' => $message['body'],
       'html' => $message['body'],
     );
     );
 
 
@@ -72,23 +80,32 @@ class MailgunMailSystem implements MailSystemInterface {
     $params = array();
     $params = array();
 
 
     // Populate default settings.
     // Populate default settings.
-    if ($variable = variable_get('mailgun_tracking', 'default') != 'default') {
-      $params['o:tracking'] = $variable;
+    if (($variable = variable_get('mailgun_tracking', 'default')) !== 'default') {
+      $params['o:tracking'] = ($variable === 'enabled');
     }
     }
-    if ($variable = variable_get('mailgun_tracking_clicks', 'default') != 'default') {
-      $params['o:tracking-clicks'] = $variable;
+    if (($variable = variable_get('mailgun_tracking_clicks', 'default')) !== 'default') {
+      $params['o:tracking-clicks'] = ($variable === 'enabled');
     }
     }
-    if ($variable = variable_get('mailgun_tracking_opens', 'default') != 'default') {
-      $params['o:tracking-opens'] = $variable;
+    if (($variable = variable_get('mailgun_tracking_opens', 'default')) !== 'default') {
+      $params['o:tracking-opens'] = ($variable === 'enabled');
     }
     }
 
 
-    // For a full list of allowed parameters, see: https://documentation.mailgun.com/api-sending.html#sending.
-    $allowed_params = array('o:tag', 'o:campaign', 'o:deliverytime', 'o:dkim', 'o:testmode', 'o:tracking', 'o:tracking-clicks', 'o:tracking-opens');
+    // For a full list of allowed parameters,
+    // see: https://documentation.mailgun.com/api-sending.html#sending.
+    $allowed_params = array(
+      'o:tag',
+      'o:campaign',
+      'o:deliverytime',
+      'o:dkim',
+      'o:testmode',
+      'o:tracking',
+      'o:tracking-clicks',
+      'o:tracking-opens',
+    );
     foreach ($message['params'] as $key => $value) {
     foreach ($message['params'] as $key => $value) {
       // Check if it's one of the known parameters.
       // Check if it's one of the known parameters.
-      $allowed = (in_array($key, $allowed_params)) ? TRUE : FALSE;
-      // If more options become available but are not yet supported by the module, uncomment the following line.
-      //$allowed = (substr($key, 0, 2) == 'o:') ? TRUE : FALSE;
+      $allowed = in_array($key, $allowed_params) ? TRUE : FALSE;
+
       if ($allowed) {
       if ($allowed) {
         $params[$key] = $value;
         $params[$key] = $value;
       }
       }
@@ -96,14 +113,51 @@ class MailgunMailSystem implements MailSystemInterface {
       if (substr($key, 0, 2) == 'h:' || substr($key, 0, 2) == 'v:') {
       if (substr($key, 0, 2) == 'h:' || substr($key, 0, 2) == 'v:') {
         $params[$key] = $value;
         $params[$key] = $value;
       }
       }
+
+      // Add additional HIME headers, like Reply-to if it exists.
+      if ($key === 'headers' && is_array($value)) {
+        foreach ($value as $headers_key => $headers_value) {
+          $params['h:' . $headers_key] = $headers_value;
+        }
+      }
+    }
+
+    // Add default tags by mail key if enabled.
+    if (variable_get('mailgun_tagging_mailkey', TRUE)) {
+      $params['o:tag'][] = $message['id'];
     }
     }
 
 
     // Make sure the files provided in the attachments array exist.
     // Make sure the files provided in the attachments array exist.
     if (!empty($message['params']['attachments'])) {
     if (!empty($message['params']['attachments'])) {
-      $params['attachments'] = array();
+      $params['attachment'] = array();
       foreach ($message['params']['attachments'] as $attachment) {
       foreach ($message['params']['attachments'] as $attachment) {
-        if (file_exists($attachment)) {
-          $params['attachments'][] = $attachment;
+        if (is_array($attachment)) {
+          // `filecontent` attachment key can be used by MimeMail as data
+          // of the related file.
+          if (array_key_exists('filecontent', $attachment)) {
+            $temp_file = tmpfile();
+            fwrite($temp_file, $attachment['filecontent']);
+            $temp_f_meta_data = stream_get_meta_data($temp_file);
+            $_attachment = array(
+              'filePath' => $temp_f_meta_data['uri'],
+            );
+            if (array_key_exists('filename', $attachment)) {
+              $_attachment['remoteName'] = $attachment['filename'];
+            }
+            $params['attachment'][] = $_attachment;
+          }
+          elseif (array_key_exists('filepath', $attachment) && file_exists($attachment['filepath'])) {
+            $_attachment = array(
+              'filePath' => $attachment['filepath'],
+            );
+            if (array_key_exists('filename', $attachment)) {
+              $_attachment['remoteName'] = $attachment['filename'];
+            }
+            $params['attachment'][] = $_attachment;
+          }
+        }
+        elseif (file_exists($attachment)) {
+          $params['attachment'][] = $attachment;
         }
         }
       }
       }
     }
     }

+ 188 - 64
sites/all/modules/contrib/mail/mailgun/mailgun.module

@@ -5,13 +5,19 @@
  * Provides integration with Mailgun's email sending API.
  * Provides integration with Mailgun's email sending API.
  */
  */
 
 
+use Mailgun\Mailgun;
+
+define('MAILGUN_DOCUMENTATION_LINK', 'https://www.drupal.org/node/2547591');
+define('MAILGUN_DASHBOARD_LINK', 'https://mailgun.com/app/dashboard');
+define('MAILGUN_ADMIN_PAGE', 'admin/config/services/mailgun');
+
 /**
 /**
  * Implements hook_menu().
  * Implements hook_menu().
  */
  */
 function mailgun_menu() {
 function mailgun_menu() {
   $items = array();
   $items = array();
 
 
-  $items['admin/config/system/mailgun'] = array(
+  $items[MAILGUN_ADMIN_PAGE] = array(
     'title' => 'Mailgun',
     'title' => 'Mailgun',
     'description' => 'Configure Mailgun settings.',
     'description' => 'Configure Mailgun settings.',
     'page callback' => 'drupal_get_form',
     'page callback' => 'drupal_get_form',
@@ -19,12 +25,12 @@ function mailgun_menu() {
     'access arguments' => array('administer mailgun'),
     'access arguments' => array('administer mailgun'),
     'file' => 'mailgun.admin.inc',
     'file' => 'mailgun.admin.inc',
   );
   );
-  $items['admin/config/system/mailgun/settings'] = array(
+  $items[MAILGUN_ADMIN_PAGE . '/settings'] = array(
     'title' => 'Settings',
     'title' => 'Settings',
     'type' => MENU_DEFAULT_LOCAL_TASK,
     'type' => MENU_DEFAULT_LOCAL_TASK,
     'weight' => 0,
     'weight' => 0,
   );
   );
-  $items['admin/config/system/mailgun/test'] = array(
+  $items[MAILGUN_ADMIN_PAGE . '/test'] = array(
     'title' => 'Send test email',
     'title' => 'Send test email',
     'page callback' => 'drupal_get_form',
     'page callback' => 'drupal_get_form',
     'page arguments' => array('mailgun_test_form'),
     'page arguments' => array('mailgun_test_form'),
@@ -46,7 +52,25 @@ function mailgun_permission() {
     'administer mailgun' => array(
     'administer mailgun' => array(
       'title' => t('Administer Mailgun'),
       'title' => t('Administer Mailgun'),
       'description' => t('Perform administration tasks for the Mailgun e-mail sending service.'),
       'description' => t('Perform administration tasks for the Mailgun e-mail sending service.'),
-      "restrict access" => TRUE,
+      'restrict access' => TRUE,
+    ),
+  );
+}
+
+/**
+ * Implements hook_theme().
+ */
+function mailgun_theme($existing, $type, $theme, $path) {
+  return array(
+    'mailgun_message' => array(
+      'variables' => array(
+        'subject' => NULL,
+        'body' => NULL,
+        'message' => array(),
+      ),
+      'template' => 'mailgun-message',
+      'path' => drupal_get_path('module', 'mailgun') . '/templates',
+      'mail theme' => TRUE,
     ),
     ),
   );
   );
 }
 }
@@ -56,12 +80,13 @@ function mailgun_permission() {
  */
  */
 function mailgun_help($path, $arg) {
 function mailgun_help($path, $arg) {
   switch ($path) {
   switch ($path) {
-    case 'admin/config/system/mailgun':
-      return '<p>' . t('See <a href="@url">documentation</a> for instructions on installing and configuring Mailgun.', array('@url' => url('https://www.drupal.org/node/2547591'))) . '</p>';
-      break;
-    case 'admin/config/system/mailgun/test':
+    case MAILGUN_ADMIN_PAGE:
+      return '<p>' . t('See !link for instructions on installing and configuring Mailgun.', array(
+        '!link' => l(t('documentation'), MAILGUN_DOCUMENTATION_LINK),
+      )) . '</p>';
+
+    case MAILGUN_ADMIN_PAGE . '/test':
       return '<p>' . t('Use this form to send a test e-mail to ensure you have correctly configured Mailgun.') . '</p>';
       return '<p>' . t('Use this form to send a test e-mail to ensure you have correctly configured Mailgun.') . '</p>';
-      break;
   }
   }
 }
 }
 
 
@@ -98,14 +123,17 @@ function mailgun_mail($key, &$message, $params) {
 function mailgun_libraries_info() {
 function mailgun_libraries_info() {
   $libraries['mailgun'] = array(
   $libraries['mailgun'] = array(
     'name' => 'Mailgun PHP library',
     'name' => 'Mailgun PHP library',
-    'vendor url' => 'https://documentation.mailgun.com/wrappers.html#php',
-    'download url' => 'https://github.com/mailgun/mailgun-php/archive/v1.7.2.zip',
-    'path' => 'vendor',
+
+    'vendor url' => 'https://documentation.mailgun.com/en/latest/libraries.html#php',
+    'download url' => 'https://github.com/mailgun/mailgun-php',
+
     'version arguments' => array(
     'version arguments' => array(
-      'file' => 'src/Mailgun/Constants/Constants.php',
-      // const SDK_VERSION = "1.7";
-      'pattern' => '/const SDK_VERSION = \"((\d+)\.(\d+))\";/',
+      'file' => 'vendor/mailgun/mailgun-php/CHANGELOG.md',
+      'pattern' => '/##\W+((\d+)\.(\d+))/',
     ),
     ),
+
+    // Path to the 'autoload.php' created by Composer.
+    'path' => 'vendor',
     'files' => array(
     'files' => array(
       'php' => array('autoload.php'),
       'php' => array('autoload.php'),
     ),
     ),
@@ -114,28 +142,77 @@ function mailgun_libraries_info() {
   return $libraries;
   return $libraries;
 }
 }
 
 
+/**
+ * Implements hook_form_FORM_ID_alter().
+ */
+function mailgun_form_libraries_admin_library_status_form_alter(&$form, &$form_state, $form_id) {
+  $library = drupal_array_get_nested_value($form_state, array(
+    'build_info', 'args', 0,
+  ));
+  if (empty($library['machine name']) || $library['machine name'] !== 'mailgun') {
+    return;
+  }
+  // Libraries module provides own instruction "How to install the library".
+  // We override it because this instruction is not correct and may confuse.
+  $form['instructions'] = array(
+    '#markup' => t('The Mailgun PHP library is not installed. Please see Installation section in the !link.', array(
+      '!link' => l(t('documentation'), MAILGUN_DOCUMENTATION_LINK),
+    )),
+  );
+}
+
 /**
 /**
  * Get the Mailgun client to access Mailgun's endpoints.
  * Get the Mailgun client to access Mailgun's endpoints.
  *
  *
  * @param string $key
  * @param string $key
  *   The Mailgun API key. Leave empty to use the API key saved in database.
  *   The Mailgun API key. Leave empty to use the API key saved in database.
+ *
+ * @return \Mailgun\Mailgun
+ *   Mailgun object.
  */
  */
 function mailgun_get_client($key = '') {
 function mailgun_get_client($key = '') {
   // Check if the Mailgun PHP library is installed.
   // Check if the Mailgun PHP library is installed.
-  $library = libraries_load('mailgun');
-  if (!$library['installed']) {
-    watchdog('mailgun', 'Mailgun client initialization failed: Unable to load the Mailgun PHP library.', NULL, WATCHDOG_ERROR);
+  if (!mailgun_check_library()) {
+    watchdog('mailgun', 'Mailgun client initialization failed: Unable to load the Mailgun PHP library.', array(), WATCHDOG_ERROR);
     return FALSE;
     return FALSE;
   }
   }
 
 
   $key = (empty($key)) ? variable_get('mailgun_api_key', '') : $key;
   $key = (empty($key)) ? variable_get('mailgun_api_key', '') : $key;
   if (empty($key)) {
   if (empty($key)) {
-    watchdog('mailgun', 'Mailgun client initialization failed: Missing API key.', NULL, WATCHDOG_ERROR);
+    watchdog('mailgun', 'Mailgun client initialization failed: Missing API key.', array(), WATCHDOG_ERROR);
     return FALSE;
     return FALSE;
   }
   }
 
 
-  $client = new \Mailgun\Mailgun($key);
-  return $client;
+  return Mailgun::create($key);
+}
+
+/**
+ * Detect if Mailgun library is installed.
+ *
+ * @return bool
+ *   TRUE if library is installed, FALSE otherwise.
+ */
+function mailgun_check_library() {
+  if (module_exists('libraries')) {
+    libraries_load('mailgun');
+  }
+  if (method_exists('\Mailgun\Mailgun', 'create')) {
+    return TRUE;
+  }
+  return FALSE;
+}
+
+/**
+ * Prepares variables for mailgun-message.tpl.php.
+ *
+ * Adds id/module/key-specific hook suggestions.
+ *
+ * @see templates/mailgun-message.tpl.php
+ */
+function template_preprocess_mailgun_message(&$variables) {
+  $variables['theme_hook_suggestions'][] = 'mailgun_message__' . $variables['message']['id'];
+  $variables['theme_hook_suggestions'][] = 'mailgun_message__' . $variables['message']['module'];
+  $variables['theme_hook_suggestions'][] = 'mailgun_message__' . $variables['message']['key'];
 }
 }
 
 
 /**
 /**
@@ -146,31 +223,50 @@ function mailgun_get_client($key = '') {
  *   - from: The e-mail addressthe message will be sent from.
  *   - from: The e-mail addressthe message will be sent from.
  *   - to: The e-mail addressthe message will be sent to.
  *   - to: The e-mail addressthe message will be sent to.
  *   - subject: The subject of the message.
  *   - subject: The subject of the message.
- *   - text: The plain-text version of the message. Processed using check_plain().
+ *   - text: The plain-text version of the message. Processed using
+ *    drupal_html_to_text().
  *   - html: The original message content. May contain HTML tags.
  *   - html: The original message content. May contain HTML tags.
- *   - cc: One or more carbon copy recipients. If multiple, separate with commas.
- *   - bcc: One or more blind carbon copy recipients. If multiple, separate with commas.
- *   - o:tag: An array containing the tags to add to the message. See: https://documentation.mailgun.com/user_manual.html#tagging.
- *   - o:campaign: The campaign ID this message belongs to. See: https://documentation.mailgun.com/user_manual.html#um-campaign-analytics.
- *   - o:deliverytime: Desired time of delivery. Messages can be scheduled for a maximum of 3 days in the future. See: https://documentation.mailgun.com/api-intro.html#date-format.
- *   - o:dkim: Boolean indicating whether or not to enable DKIM signatures on per-message basis.
- *   - o:testmode: Boolean indicating whether or not to enable test mode. See: https://documentation.mailgun.com/user_manual.html#manual-testmode.
- *   - o:tracking: Boolean indicating whether or not to toggle tracking on a per-message basis. See: https://documentation.mailgun.com/user_manual.html#tracking-messages.
- *   - o:tracking-clicks: Boolean or string "htmlonly" indicating whether or not to toggle clicks tracking on a per-message basis. Has higher priority than domain-level setting.
- *   - o:tracking-opens: Boolean indicating whether or not to toggle clicks tracking on a per-message basis. Has higher priority than domain-level setting.
- *   - h:X-My-Header: h: prefix followed by an arbitrary value allows to append a custom MIME header to the message (X-My-Header in this case). For example, h:Reply-To to specify Reply-To address.
- *   - v:my-var: v: prefix followed by an arbitrary name allows to attach a custom JSON data to the message. See: https://documentation.mailgun.com/user_manual.html#manual-customdata.
+ *   - cc: One or more carbon copy recipients. If multiple, separate with
+ *    commas.
+ *   - bcc: One or more blind carbon copy recipients. If multiple, separate
+ *    with commas.
+ *   - o:tag: An array containing the tags to add to the message.
+ *    See: https://documentation.mailgun.com/user_manual.html#tagging.
+ *   - o:campaign: The campaign ID this message belongs to.
+ *    https://documentation.mailgun.com/user_manual.html#um-campaign-analytics
+ *   - o:deliverytime: Desired time of delivery. Messages can be scheduled for
+ *    a maximum of 3 days in the future.
+ *    See: https://documentation.mailgun.com/api-intro.html#date-format.
+ *   - o:dkim: Boolean indicating whether or not to enable DKIM signatures on
+ *    per-message basis.
+ *   - o:testmode: Boolean indicating whether or not to enable test mode.
+ *    See: https://documentation.mailgun.com/user_manual.html#manual-testmode.
+ *   - o:tracking: Boolean indicating whether or not to toggle tracking on a
+ *    per-message basis.
+ *    See: https://documentation.mailgun.com/user_manual.html#tracking-messages.
+ *   - o:tracking-clicks: Boolean or string "htmlonly" indicating whether or
+ *    not to toggle clicks tracking on a per-message basis. Has higher
+ *    priority than domain-level setting.
+ *   - o:tracking-opens: Boolean indicating whether or not to toggle clicks
+ *    tracking on a per-message basis. Has higher priority than domain-level
+ *    setting.
+ *   - h:X-My-Header: h: prefix followed by an arbitrary value allows to append
+ *    a custom MIME header to the message (X-My-Header in this case).
+ *    For example, h:Reply-To to specify Reply-To address.
+ *   - v:my-var: v: prefix followed by an arbitrary name allows to attach a
+ *    custom JSON data to the message.
+ *    See: https://documentation.mailgun.com/user_manual.html#manual-customdata.
  *
  *
  * @return bool
  * @return bool
  *   TRUE if the mail was successfully accepted, FALSE otherwise.
  *   TRUE if the mail was successfully accepted, FALSE otherwise.
  */
  */
-function mailgun_send($mailgun_message) {
+function mailgun_send(array $mailgun_message) {
   $client = mailgun_get_client();
   $client = mailgun_get_client();
   if (!$client) {
   if (!$client) {
     return FALSE;
     return FALSE;
   }
   }
 
 
-  // Test mode
+  // Test mode. Mailgun will accept the message but will not send it.
   if (variable_get('mailgun_test', FALSE)) {
   if (variable_get('mailgun_test', FALSE)) {
     $mailgun_message['o:testmode'] = 'yes';
     $mailgun_message['o:testmode'] = 'yes';
   }
   }
@@ -179,35 +275,43 @@ function mailgun_send($mailgun_message) {
   $mailgun_message += $mailgun_message['params'];
   $mailgun_message += $mailgun_message['params'];
   unset($mailgun_message['params']);
   unset($mailgun_message['params']);
 
 
-  if (variable_get('mailgun_domain', '_sender') == '_sender') {
-    // Extract the domain from the sender's email address. Use regular expression to check since it could be either a plain email address or in the form "Name <example@example.com>".
+  if (variable_get('mailgun_domain', '_sender') === '_sender') {
+    // Extract the domain from the sender's email address.
+    // Use regular expression to check since it could be either a plain email
+    // address or in the form "Name <example@example.com>".
     $tokens = (preg_match('/^\s*(.+?)\s*<\s*([^>]+)\s*>$/', $mailgun_message['from'], $matches) === 1) ? explode('@', $matches[2]) : explode('@', $mailgun_message['from']);
     $tokens = (preg_match('/^\s*(.+?)\s*<\s*([^>]+)\s*>$/', $mailgun_message['from'], $matches) === 1) ? explode('@', $matches[2]) : explode('@', $mailgun_message['from']);
     $mail_domain = array_pop($tokens);
     $mail_domain = array_pop($tokens);
 
 
     // Retrieve a list of available domains first.
     // Retrieve a list of available domains first.
     $domains = array();
     $domains = array();
     try {
     try {
-      $result = $client->get('domains');
-      if ($result->http_response_code == 200) {
-        foreach ($result->http_response_body->items as $item) {
-          $domains[$item->name] = $item->name;
+      $result = $client->domains()->index();
+      if (!empty($result)) {
+        foreach ($result->getDomains() as $domain) {
+          $domains[$domain->getName()] = $domain->getName();
         }
         }
       }
       }
       else {
       else {
-        watchdog('mailgun', 'Mailgun server returned a %code error. Could not retrieve domain list.', array('%code' => $result->http_response_code), WATCHDOG_ERROR);
+        watchdog('mailgun', 'Could not retrieve domain list.', array(), WATCHDOG_ERROR);
       }
       }
-    } catch (Exception $e) {
-      watchdog('mailgun', 'An exception occurred while retrieving domains. @code: @message', array('@code' => $e->getCode(), '@message' => $e->getMessage()), WATCHDOG_ERROR);
+    }
+    catch (Exception $e) {
+      watchdog('mailgun', 'An exception occurred while retrieving domains. @code: @message', array(
+        '@code' => $e->getCode(),
+        '@message' => $e->getMessage(),
+      ), WATCHDOG_ERROR);
     }
     }
 
 
     if (empty($domains)) {
     if (empty($domains)) {
-      // No domain available. Although this shouldn't happen, doesn't hurt to check.
+      // No domain available.
+      // Although this shouldn't happen, doesn't hurt to check.
       return FALSE;
       return FALSE;
     }
     }
 
 
-    // Now, we need to get the working domain. This is generally the domain the From address is on or the root domain of it.
+    // Now, we need to get the working domain. This is generally the domain the
+    // From address is on or the root domain of it.
     $working_domain = '';
     $working_domain = '';
-    if ($key = array_search($mail_domain, $domains) !== FALSE) {
+    if (in_array($mail_domain, $domains, TRUE)) {
       // Great. Found it.
       // Great. Found it.
       $working_domain = $mail_domain;
       $working_domain = $mail_domain;
     }
     }
@@ -222,10 +326,13 @@ function mailgun_send($mailgun_message) {
       }
       }
     }
     }
 
 
-    // There is a chance that the user is attempting to send from an email address that's on a domain not yet added to the Mailgun account.
+    // There is a chance that the user is attempting to send from an email
+    // address that's on a domain not yet added to the Mailgun account.
     // In that case, abort sending and report error.
     // In that case, abort sending and report error.
     if (empty($working_domain)) {
     if (empty($working_domain)) {
-      watchdog('mailgun', 'Unable to locate a working domain for From address %mail. Aborting sending.', array('%mail' => $mailgun_message['from']), WATCHDOG_ERROR);
+      watchdog('mailgun', 'Unable to locate a working domain for From address %mail. Aborting sending.', array(
+        '%mail' => $mailgun_message['from'],
+      ), WATCHDOG_ERROR);
       return FALSE;
       return FALSE;
     }
     }
   }
   }
@@ -233,29 +340,46 @@ function mailgun_send($mailgun_message) {
     $working_domain = variable_get('mailgun_domain', '');
     $working_domain = variable_get('mailgun_domain', '');
   }
   }
 
 
-  // Attachments
-  $post_data = array();
-  if (!empty($mailgun_message['attachments'])) {
-    // Send message with attachments.
-    $post_data['attachment'] = $mailgun_message['attachments'];
-    unset($mailgun_message['attachments']);
+  // Send message with attachments.
+  if (!empty($mailgun_message['attachment'])) {
+    foreach ($mailgun_message['attachment'] as &$attachment) {
+      // Ignore array constructions. Not sure what values can be here.
+      if (is_array($attachment)) {
+        continue;
+      }
+      $attachment = array('filePath' => $attachment);
+    }
   }
   }
-  
+
   try {
   try {
-    $result = $client->sendMessage($working_domain, $mailgun_message, $post_data);
+    $result = $client->messages()->send($working_domain, $mailgun_message);
 
 
-    // For a list of HTTP response codes, see: https://documentation.mailgun.com/api-intro.html#errors.
-    if ($result->http_response_code == 200) {
+    if (!empty($result)) {
       if (variable_get('mailgun_log', FALSE)) {
       if (variable_get('mailgun_log', FALSE)) {
-        watchdog('mailgun', 'Successfully sent message from %from to %to. %code: %message.', array('%from' => $mailgun_message['from'], '%to' => $mailgun_message['to'], '%code' => $result->http_response_code, '%message' => $result->http_response_body->message));
+        watchdog('mailgun', 'Successfully sent message from %from to %to. %message.', array(
+          '%from' => $mailgun_message['from'],
+          '%to' => $mailgun_message['to'],
+          '%message' => $result->getMessage(),
+        ));
       }
       }
       return TRUE;
       return TRUE;
     }
     }
     else {
     else {
-      watchdog('mailgun', 'Failed to send message from %from to %to. %code: %message.', array('%from' => $mailgun_message['from'], '%to' => $mailgun_message['to'], '%code' => $result->http_response_code, '%message' => $result->http_response_body->message), WATCHDOG_ERROR);
+      watchdog('mailgun', 'Failed to send message from %from to %to. %message.', array(
+        '%from' => $mailgun_message['from'],
+        '%to' => $mailgun_message['to'],
+        '%message' => $result->getMessage(),
+      ), WATCHDOG_ERROR);
       return FALSE;
       return FALSE;
     }
     }
-  } catch (Exception $e) {
-    watchdog('mailgun', 'Exception occurred while trying to send test email from %from to %to. @code: @message.', array('%from' => $mailgun_message['from'], '%to' => $mailgun_message['to'], '@code' => $e->getCode(), '@message' => $e->getMessage()));
+  }
+  catch (Exception $e) {
+    watchdog('mailgun', 'Exception occurred while trying to send test email from %from to %to. @code: @message.', array(
+      '%from' => $mailgun_message['from'],
+      '%to' => $mailgun_message['to'],
+      '@code' => $e->getCode(),
+      '@message' => $e->getMessage(),
+    ));
+    return FALSE;
   }
   }
 }
 }

+ 28 - 0
sites/all/modules/contrib/mail/mailgun/templates/mailgun-message.tpl.php

@@ -0,0 +1,28 @@
+<?php
+
+/**
+ * @file
+ * Default theme implementation of Mailgun mail.
+ *
+ * Available variables:
+ * - $subject: The message subject.
+ * - $body: The message body.
+ *
+ * @see template_preprocess_mailgun_message()
+ */
+?>
+<html>
+  <head>
+    <style type="text/css">
+      body {
+        font-family: Verdana, Arial, sans-serif;
+        font-size: 12px;
+      }
+    </style>
+  </head>
+  <body>
+    <div>
+      <?php print $body; ?>
+    </div>
+  </body>
+</html>

+ 5 - 4
sites/all/modules/contrib/mail/mailsystem/html_to_text.inc

@@ -407,7 +407,8 @@ function _mailsystem_html_to_text(DOMNode $node, array $allowed_tags, array &$no
   // Copy each child node to output.
   // Copy each child node to output.
   if ($node->hasChildNodes()) {
   if ($node->hasChildNodes()) {
     foreach ($node->childNodes as $child) {
     foreach ($node->childNodes as $child) {
-      $child_text .= _mailsystem_html_to_text($child, $allowed_tags, $notes, $line_length - drupal_strlen($indent), $parents, $child_count);    }
+      $child_text .= _mailsystem_html_to_text($child, $allowed_tags, $notes, $line_length - drupal_strlen($indent), $parents, $child_count);
+    }
   }
   }
   // We only add prefix and suffix if the child nodes were non-empty.
   // We only add prefix and suffix if the child nodes were non-empty.
   if ($child_text > '') {
   if ($child_text > '') {
@@ -416,7 +417,7 @@ function _mailsystem_html_to_text(DOMNode $node, array $allowed_tags, array &$no
       $child_text = drupal_strtoupper($child_text);
       $child_text = drupal_strtoupper($child_text);
     }
     }
     // Don't add a newline to an existing newline.
     // Don't add a newline to an existing newline.
-    if ($suffix === $eol && drupal_substr($child_text, - drupal_strlen($eol)) === $eol) {
+    if ($suffix === $eol && drupal_substr($child_text, -drupal_strlen($eol)) === $eol) {
       $suffix = '';
       $suffix = '';
     }
     }
     // Trim spaces around newlines except with <pre> or inline tags.
     // Trim spaces around newlines except with <pre> or inline tags.
@@ -496,7 +497,7 @@ function _mailsystem_html_to_text_table(DOMNode $node, $allowed_tags = NULL, arr
               $footer[] = $current;
               $footer[] = $current;
               break;
               break;
 
 
-            default: // Either 'tbody' or 'table'
+            default: // Either 'tbody' or 'table'.
               $body[] = $current;
               $body[] = $current;
               break;
               break;
           }
           }
@@ -647,7 +648,7 @@ function _mailsystem_html_to_text_table(DOMNode $node, $allowed_tags = NULL, arr
       }
       }
       // Generate the row separator line.
       // Generate the row separator line.
       $separator = '+';
       $separator = '+';
-      for($i = 0; $i < $num_cols; $i++) {
+      for ($i = 0; $i < $num_cols; $i++) {
         $separator .= str_repeat('-', $widths[$i]) . '+';
         $separator .= str_repeat('-', $widths[$i]) . '+';
       }
       }
       $separator .= $eol;
       $separator .= $eol;

+ 9 - 8
sites/all/modules/contrib/mail/mailsystem/mailsystem.admin.inc

@@ -4,6 +4,7 @@
  * @file
  * @file
  * Administrative form for setting the mail_system variable.
  * Administrative form for setting the mail_system variable.
  */
  */
+
 function mailsystem_admin_settings() {
 function mailsystem_admin_settings() {
   $args = array(
   $args = array(
     '!interface' => url('http://api.drupal.org/api/drupal/includes--mail.inc/interface/MailSystemInterface/7'),
     '!interface' => url('http://api.drupal.org/api/drupal/includes--mail.inc/interface/MailSystemInterface/7'),
@@ -49,13 +50,13 @@ function mailsystem_admin_settings() {
     '#default_value' => $mail_system[mailsystem_default_id()],
     '#default_value' => $mail_system[mailsystem_default_id()],
   );
   );
   $mailsystem_classes = array(
   $mailsystem_classes = array(
-    mailsystem_default_id() => t('Remove this setting.')
+    mailsystem_default_id() => t('Remove this setting.'),
   ) + $mailsystem_classes;
   ) + $mailsystem_classes;
   foreach (array_diff_key($mail_system, $mail_defaults) as $id => $class) {
   foreach (array_diff_key($mail_system, $mail_defaults) as $id => $class) {
     // Separate $id into $module and $key.
     // Separate $id into $module and $key.
     $module = $id;
     $module = $id;
     while ($module && empty($descriptions[$module])) {
     while ($module && empty($descriptions[$module])) {
-      // Remove a key from the end
+      // Remove a key from the end.
       $module = implode('_', explode('_', $module, -1));
       $module = implode('_', explode('_', $module, -1));
     }
     }
     // If an array key of the $mail_system variable is neither "default-system"
     // If an array key of the $mail_system variable is neither "default-system"
@@ -91,11 +92,11 @@ function mailsystem_admin_settings() {
     }
     }
   }
   }
   $form['mailsystem']['mailsystem_theme'] = array(
   $form['mailsystem']['mailsystem_theme'] = array(
-      '#type' => 'select',
-      '#title' => t('Theme to render the emails'),
-      '#description' => t('Select the theme that will be used to render the emails. This can be either the current theme, the default theme, the domain theme or any active theme.'),
-      '#options' => $theme_options,
-      '#default_value' => variable_get('mailsystem_theme', 'current'),
+    '#type' => 'select',
+    '#title' => t('Theme to render the emails'),
+    '#description' => t('Select the theme that will be used to render the emails. This can be either the current theme, the default theme, the domain theme or any active theme.'),
+    '#options' => $theme_options,
+    '#default_value' => variable_get('mailsystem_theme', 'current'),
   );
   );
   $form['class'] = array(
   $form['class'] = array(
     '#type' => 'fieldset',
     '#type' => 'fieldset',
@@ -168,7 +169,7 @@ function mailsystem_admin_settings_submit($form, &$form_state) {
       empty($form_state['values'][$default_id])
       empty($form_state['values'][$default_id])
       ? mailsystem_default_value()
       ? mailsystem_default_value()
       : $form_state['values'][$default_id]
       : $form_state['values'][$default_id]
-    )
+    ),
   );
   );
   foreach (element_children($form_state['values']['mailsystem']) as $module) {
   foreach (element_children($form_state['values']['mailsystem']) as $module) {
     $class = $form_state['values']['mailsystem'][$module];
     $class = $form_state['values']['mailsystem'][$module];

+ 3 - 5
sites/all/modules/contrib/mail/mailsystem/mailsystem.info

@@ -1,14 +1,12 @@
 package = Mail
 package = Mail
 name = Mail System
 name = Mail System
 description = Provides a user interface for per-module and site-wide mail_system selection.
 description = Provides a user interface for per-module and site-wide mail_system selection.
-php = 5.0
 core = 7.x
 core = 7.x
 configure = admin/config/system/mailsystem
 configure = admin/config/system/mailsystem
 dependencies[] = filter
 dependencies[] = filter
 
 
-; Information added by drupal.org packaging script on 2012-04-10
-version = "7.x-2.34"
+; Information added by Drupal.org packaging script on 2018-07-12
+version = "7.x-2.35"
 core = "7.x"
 core = "7.x"
 project = "mailsystem"
 project = "mailsystem"
-datestamp = "1334082653"
-
+datestamp = "1531385928"

+ 35 - 15
sites/all/modules/contrib/mail/mailsystem/mailsystem.module

@@ -132,15 +132,23 @@ function mailsystem_create_class($classes) {
   }
   }
   $class_name = implode('__', $classes);
   $class_name = implode('__', $classes);
   // Ensure that the mailsystem directory exists.
   // Ensure that the mailsystem directory exists.
-  $class_dir = file_build_uri('mailsystem');
-  if (!file_prepare_directory($class_dir, FILE_CREATE_DIRECTORY | FILE_MODIFY_PERMISSIONS)) {
+  // First we try the private filesystem.
+  $private_files = variable_get('file_private_path', '');
+  $private_files_full = $private_files . '/mailsystem';
+  $public_files = variable_get('file_public_path', conf_path() . '/files');
+  $public_files_full = $public_files . '/mailsystem';
+  if ($private_files && file_prepare_directory($private_files_full, FILE_CREATE_DIRECTORY | FILE_MODIFY_PERMISSIONS)) {
+    $class_dir = $private_files . '/mailsystem';
+  }
+  // If private filesystem is not defined or writable, we use the public filesystem.
+  elseif (file_prepare_directory($public_files_full, FILE_CREATE_DIRECTORY | FILE_MODIFY_PERMISSIONS)) {
+    $class_dir = $public_files . '/mailsystem';
+  }
+  else {
     return FALSE;
     return FALSE;
   }
   }
   // Build the class filename.
   // Build the class filename.
-  $class_file = drupal_realpath($class_dir) . DIRECTORY_SEPARATOR . "$class_name.mail.inc";
-  // Strip DRUPAL_ROOT.
-  $drupal_root = drupal_realpath(DRUPAL_ROOT) . DIRECTORY_SEPARATOR;
-  $class_file = preg_replace('#^' . preg_quote($drupal_root, '#') . '#', '', $class_file);
+  $class_file = $class_dir . DIRECTORY_SEPARATOR . "$class_name.mail.inc";
   // Build the class implementation as a string.
   // Build the class implementation as a string.
   $class_contents = '<?php
   $class_contents = '<?php
 class ' . $class_name . ' implements MailSystemInterface {';
 class ' . $class_name . ' implements MailSystemInterface {';
@@ -181,17 +189,19 @@ class ' . $class_name . ' implements MailSystemInterface {';
     $file_condition = db_and()
     $file_condition = db_and()
       ->condition('filename', $class_file);
       ->condition('filename', $class_file);
     db_delete('registry_file')
     db_delete('registry_file')
-      ->condition($file_condition);
+      ->condition($file_condition)
+      ->execute();
     db_delete('registry')->condition(
     db_delete('registry')->condition(
       db_or()->condition($class_condition)
       db_or()->condition($class_condition)
       ->condition($file_condition)
       ->condition($file_condition)
-    );
+    )->execute();
     // Make sure that registry functions are available.
     // Make sure that registry functions are available.
     require_once 'includes/registry.inc';
     require_once 'includes/registry.inc';
     // Parse the newly-created class file and add it to the registry.
     // Parse the newly-created class file and add it to the registry.
     _registry_parse_file($class_file, $class_contents, 'mailsystem');
     _registry_parse_file($class_file, $class_contents, 'mailsystem');
-    // Clear the mailsystem cache so that it will pick up the new class.
+    // Clear the mailsystem caches so that it will pick up the new class.
     drupal_static_reset('mailsystem_get_classes');
     drupal_static_reset('mailsystem_get_classes');
+    cache_clear_all('mailsystem_get_classes', 'cache');
     drupal_set_message(
     drupal_set_message(
       t('Class <code>%class</code> written to <code>%file</code>.',
       t('Class <code>%class</code> written to <code>%file</code>.',
         array('%class' => $class_name, '%file' => $class_file)
         array('%class' => $class_name, '%file' => $class_file)
@@ -257,7 +267,13 @@ function mailsystem_clear(array $setting) {
  * Returns a list of classes which implement MailSystemInterface.
  * Returns a list of classes which implement MailSystemInterface.
  */
  */
 function &mailsystem_get_classes() {
 function &mailsystem_get_classes() {
+  // Load static cache.
   $mailsystem_classes = &drupal_static(__FUNCTION__);
   $mailsystem_classes = &drupal_static(__FUNCTION__);
+  // Check persistent cache if necessary.
+  if (!isset($mailsystem_classes) && $cache = cache_get('mailsystem_get_classes')) {
+    $mailsystem_classes = $cache->data;
+  }
+  // Load from db if no cache was hit.
   if (!isset($mailsystem_classes)) {
   if (!isset($mailsystem_classes)) {
     $mailsystem_classes = array();
     $mailsystem_classes = array();
     // @todo Is there a better way to find all mail-related classes?
     // @todo Is there a better way to find all mail-related classes?
@@ -282,14 +298,14 @@ function &mailsystem_get_classes() {
       ->execute()
       ->execute()
       ->fetchAllKeyed();
       ->fetchAllKeyed();
     foreach ($mail_classes as $classname => $classfile) {
     foreach ($mail_classes as $classname => $classfile) {
-      if ( file_exists($classfile)
+      if (file_exists($classfile)
         && drupal_autoload_class($classname)
         && drupal_autoload_class($classname)
       ) {
       ) {
         $all_classes[$classname] = 1;
         $all_classes[$classname] = 1;
       }
       }
     }
     }
     foreach ($all_classes as $classname => $autoload) {
     foreach ($all_classes as $classname => $autoload) {
-      if ( ($autoload || preg_match('/MailSystem/', $classname))
+      if (($autoload || preg_match('/MailSystem/', $classname))
         && ($object = new $classname)
         && ($object = new $classname)
         && ($object instanceof MailSystemInterface)
         && ($object instanceof MailSystemInterface)
       ) {
       ) {
@@ -311,6 +327,8 @@ function &mailsystem_get_classes() {
       }
       }
     }
     }
     ksort($mailsystem_classes);
     ksort($mailsystem_classes);
+    // Store in persistent cache.
+    cache_set('mailsystem_get_classes', $mailsystem_classes, 'cache', CACHE_TEMPORARY);
   }
   }
   return $mailsystem_classes;
   return $mailsystem_classes;
 }
 }
@@ -324,10 +342,10 @@ function mailsystem_theme_registry_alter(&$theme_registry) {
 }
 }
 
 
 /**
 /**
-* Retrieves the key of the theme used to render the emails.
-*
-* @todo Add some kind of hook to let other modules alter this behavior.
-*/
+ * Retrieves the key of the theme used to render the emails.
+ *
+ * @todo Add some kind of hook to let other modules alter this behavior.
+ */
 function mailsystem_get_mail_theme() {
 function mailsystem_get_mail_theme() {
   global $theme_key;
   global $theme_key;
   $theme = variable_get('mailsystem_theme', 'current');
   $theme = variable_get('mailsystem_theme', 'current');
@@ -335,9 +353,11 @@ function mailsystem_get_mail_theme() {
     case 'default':
     case 'default':
       $theme = variable_get('theme_default', NULL);
       $theme = variable_get('theme_default', NULL);
       break;
       break;
+
     case 'current':
     case 'current':
       $theme = $theme_key;
       $theme = $theme_key;
       break;
       break;
+
     case 'domain':
     case 'domain':
       // Fetch the theme for the current domain.
       // Fetch the theme for the current domain.
       if (module_exists('domain_theme')) {
       if (module_exists('domain_theme')) {

+ 49 - 7
sites/all/modules/contrib/mail/mailsystem/mailsystem.theme.inc

@@ -1,13 +1,13 @@
 <?php
 <?php
 
 
 /**
 /**
-* @file
-* The theme system, which controls the output of email messages.
-*/
+ * @file
+ * The theme system, which controls the output of email messages.
+ */
 
 
 /**
 /**
-* Implements hook_theme_registry_alter().
-*/
+ * Implements hook_theme_registry_alter().
+ */
 function mailsystem_theme_theme_registry_alter(&$theme_registry) {
 function mailsystem_theme_theme_registry_alter(&$theme_registry) {
   global $theme_key;
   global $theme_key;
   static $recursion_prevention = FALSE;
   static $recursion_prevention = FALSE;
@@ -26,6 +26,10 @@ function mailsystem_theme_theme_registry_alter(&$theme_registry) {
     if (isset($themes[$mailsystem_theme])) {
     if (isset($themes[$mailsystem_theme])) {
       $theme = clone $themes[$mailsystem_theme];
       $theme = clone $themes[$mailsystem_theme];
       if (isset($theme)) {
       if (isset($theme)) {
+        // Swap to the mailsystem theme.
+        $old_theme = $theme_key;
+        mailsystem_theme_swap_theme($mailsystem_theme);
+
         // Establish variables for further processing.
         // Establish variables for further processing.
         $base_theme = array();
         $base_theme = array();
         if (isset($theme->base_themes)) {
         if (isset($theme->base_themes)) {
@@ -42,10 +46,10 @@ function mailsystem_theme_theme_registry_alter(&$theme_registry) {
 
 
         // Include template files to let _theme_load_registry add preprocess
         // Include template files to let _theme_load_registry add preprocess
         // functions.
         // functions.
-        include_once(drupal_get_path('theme', $theme->name) . '/template.php');
         foreach ($base_theme as $base) {
         foreach ($base_theme as $base) {
-          include_once(drupal_get_path('theme', $base->name) . '/template.php');
+          include_once drupal_get_path('theme', $base->name) . '/template.php';
         }
         }
+        include_once drupal_get_path('theme', $theme->name) . '/template.php';
 
 
         // Get the theme_registry cache.
         // Get the theme_registry cache.
         $cache = _theme_load_registry($theme, $base_theme, $theme_engine);
         $cache = _theme_load_registry($theme, $base_theme, $theme_engine);
@@ -75,8 +79,46 @@ function mailsystem_theme_theme_registry_alter(&$theme_registry) {
             }
             }
           }
           }
         }
         }
+
+        // Swap back to the original theme.
+        mailsystem_theme_swap_theme($old_theme);
       }
       }
     }
     }
   }
   }
   $recursion_prevention = FALSE;
   $recursion_prevention = FALSE;
 }
 }
+
+/**
+ * Helper to swap themes safely for use by mailsystem_theme_theme_registry_alter().
+ */
+function mailsystem_theme_swap_theme($new_theme) {
+  // Make sure the theme exists.
+  $themes = list_themes();
+  if (empty($themes[$new_theme])) {
+    return;
+  }
+
+  // Both theme/theme_key are set to the new theme.
+  global $theme, $theme_key;
+  $theme = $theme_key = $new_theme;
+
+  // Create the base_theme_info.
+  global $base_theme_info;
+  $base_theme = array();
+  $ancestor = $theme;
+  while ($ancestor && isset($themes[$ancestor]->base_theme)) {
+    $ancestor = $themes[$ancestor]->base_theme;
+    $base_theme[] = $themes[$ancestor];
+  }
+  $base_theme_info = array_reverse($base_theme);
+
+  // Some other theme related globals.
+  global $theme_engine, $theme_info, $theme_path;
+  $theme_engine = $themes[$theme]->engine;
+  $theme_info = $themes[$theme];
+  $theme_path = dirname($themes[$theme]->filename);
+
+  // We need to reset the drupal_alter and module_implements statics.
+  drupal_static_reset('drupal_alter');
+  drupal_static_reset('module_implements');
+}

Some files were not shown because too many files changed in this diff