? handlers/location_handler_argument_location_distance.inc
Index: location.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/location/location.inc,v
retrieving revision 1.95.2.4
diff -u -p -r1.95.2.4 location.inc
--- location.inc	19 Jan 2010 02:02:03 -0000	1.95.2.4
+++ location.inc	15 Mar 2010 21:52:02 -0000
@@ -78,6 +78,8 @@ function location_map_link($location = a
  *     'province'       => the province code defined in the country-specific include file
  *     'country'        => the lower-case of the two-letter ISO code (REQUIRED)
  *     'postal_code'    => the postal-code (REQUIRED)
+ * @param $geocode_in_db
+ *   Boolean. If TRUE, the coordinates for the zipcode may be geocoded, and cached in the database.
  *
  * @return
  *   Array or NULL. NULL if the delegated-to function that does the
@@ -88,10 +90,26 @@ function location_map_link($location = a
  *
  * @ingroup Location
  */
-function location_get_postalcode_data($location = array()) {
+function location_get_postalcode_data($location = array(), $geocode_in_db = FALSE) {
   $location['country'] = isset($location['country']) ? trim($location['country']) : NULL;
   $location['postal_code'] = isset($location['postal_code']) ? trim($location['postal_code']) : NULL;
-  if (is_null($location['postal_code']) || is_null($location['country']) || empty($location['country']) || empty($location['postal_code']) || $location['postal_code'] == 'xx') {
+
+  // TK edit: add city and province (they are in the zipcode table and are useful)
+  $location['city'] = isset($location['city']) ? trim($location['city']) : NULL;
+  $location['province'] = isset($location['province']) ? trim($location['province']) : NULL;
+  
+  // TK edit: separated out country check from postal code check for flexibility
+  // TK edit: ensure we have a country
+  if (is_null($location['country']) || empty($location['country'])) {
+    return NULL;
+  }
+  // TK edit: ensure if we have a postcode.
+  if (is_null($location['postal_code']) || empty($location['postal_code']) || $location['postal_code'] == 'xx') {
+      return NULL;
+  }
+
+  // Normalize postalcode data
+  if (!location_standardize_postalcode($location['postal_code'], $location['country'])) {
     return NULL;
   }
   location_load_country($location['country']);
@@ -100,6 +118,158 @@ function location_get_postalcode_data($l
     return $country_specific_function($location);
   }
   else {
+    
+    // Check whether postalcode data is present in zipcode table
+    $result = db_query("SELECT * FROM {zipcodes} WHERE country = '%s' AND zip = '%s'", $location['country'], $location['postal_code']);
+    if ($row = db_fetch_object($result)) {
+      // We can't be absolutely sure that city/province are filled in the database, but some callers use it
+      // TK edit: also return the 'postal_code' for completeness sake and to make sure the return array is uniform
+      return array('lat' => $row->latitude, 'lon' => $row->longitude, 'city' => $row->city, 'postal_code' => $row->zip, 'province' => $row->state, 'country' => $row->country);
+    }
+    elseif ($geocode_in_db) {
+
+      // Try to get exact location. If it succeeds, cache it in zipcode table
+      if ($data = location_latlon_exact($location)) {
+        $location['latitude'] = $data['lat'];
+        $location['longitude'] = $data['lon'];
+        // TK edit: update our values to the values from our results if available
+        // this way we are using verified values ones when we store them and return them to the function
+        if (array_key_exists('city', $data) && !empty($data['city'])) {
+          $location['city'] = $data['city'];
+        }
+        if (array_key_exists('postal_code', $data) && !empty($data['postal_code'])) {
+          $location['postal_code'] = $data['postal_code'];
+        }
+        if (array_key_exists('province', $data) && !empty($data['province'])) {
+          $location['province'] = $data['province'];
+        }
+       // Try to see whether we can get timezone/dst data based on location. If not, we'll insert zeroes.
+        $country_specific_function = 'location_timezone_data_'. $location['country'];
+        if (function_exists($country_specific_function)) {
+          $tzdata = $country_specific_function($location);
+        }
+        else {
+          $tzdata = array('timezone' => 0, 'dst' => 0);
+        }
+        // Make sure values have the right keys and write record to database.
+        if (isset($location['province'])) {
+          $tzdata['state'] = $location['province'];
+        }
+        $tzdata['zip'] = $location['postal_code'];
+        // only write to the db if it isn't there already
+        $result = db_query("SELECT * FROM {zipcodes} WHERE country = '%s' AND zip = '%s'", $location['country'], $location['postal_code']);
+        if (!$row = db_fetch_object($result)) {
+           drupal_write_record('zipcodes', array_merge($location, $tzdata));
+        }
+        //TK edit: added city postal_code and province to the return array to give complete results
+        return array('lat' => $location['latitude'], 'lon' => $location['longitude'], 'city' => $location['city'], 'postal_code' => $location['postal_code'], 'province' => $location['province']);
+      }
+    }
+    return NULL;
+  }
+}
+
+/**
+ * Try to extract the the Latitude and Longitude data from the
+ * city.
+ *
+ * @param $location
+ *   Array. the location data
+ *   -> the values are:
+ *     'street'         => the string representing the street location 
+ *     'additional'     => the string representing the additional street location portion in the location form
+ *     'city'           => the city name (REQUIRED)
+ *     'province'       => the province code defined in the country-specific include file
+ *     'country'        => the lower-case of the two-letter ISO code (REQUIRED)
+ *     'postal_code'    => the postal-code 
+ * @param $geocode_in_db
+ *   Boolean. If TRUE, the coordinates for the zipcode may be geocoded, and cached in the database.
+ *
+ * @return
+ *   Array or NULL. NULL if the delegated-to function that does the
+ *   actual look-up does not exist. If the appropriate function exists,
+ *   then this function returns an associative array where
+ *    'lon' => A floating point number for the longitude coordinate of the parameter location
+ *    'lat' => A floating point number for the latitude coordinate of the parameter location
+ *
+ * @ingroup Location
+ */
+function location_get_city_data($location = array()) {
+  $location['country'] = isset($location['country']) ? trim($location['country']) : NULL;
+  $location['postal_code'] = isset($location['postal_code']) ? trim($location['postal_code']) : NULL;
+  $location['city'] = isset($location['city']) ? trim($location['city']) : NULL;
+  $location['province'] = isset($location['province']) ? trim($location['province']) : NULL;
+  
+  // ensure we have a country
+  if (is_null($location['country']) || empty($location['country'])) {
+    return NULL;
+  }
+  // ensure if we have a city.
+  if (is_null($location['city']) || empty($location['city']) || $location['city'] == 'xx') {
+      return NULL;
+  }
+
+  // Normalize city data -- note: function implemented starting on line 641
+  if (!location_standardize_postalcode($location['city'], $location['city'])) {
+    return NULL;
+  }
+  location_load_country($location['country']);
+  $country_specific_function = 'location_get_city_data_'. $location['country'];
+  if (function_exists($country_specific_function)) {
+    return $country_specific_function($location);
+  }
+  else {
+    
+    /*
+     * @@@ Should we try to get city from the db? - problem is that we either need a cities table or we need to
+     *     query the zipcodes table, in which case we will likely get multiple results and need to determine
+     *     the best one to use - the code below takes the first one (we could sort on postalcode first)
+     *
+     *     I personally dont care about this and will always hit the geocoder for a city search.
+     *
+    $result = db_query("SELECT * FROM {zipcodes} WHERE country = '%s' AND city = '%s'", $location['country'], $location['city']);
+    if ($row = db_fetch_object($result)) {
+      return array('lat' => $row[0]->latitude, 'lon' => $row[0]->longitude, 'city' => $location['city'], 'postal_code' => $row[0]->zip, 'province' => $row[0]->state, 'country' => $row->country);
+    }
+    elseif ($geocode_in_db) {
+    */
+      // Try to get exact location. If it succeeds, cache it in zipcode table
+      if ($data = location_latlon_exact($location)) {
+        $location['latitude'] = $data['lat'];
+        $location['longitude'] = $data['lon'];
+        // TK edit: update our values to the values from our results if available
+        if (array_key_exists('city', $data) && !empty($data['city'])) {
+          $location['city'] = $data['city'];
+        }
+        if (array_key_exists('postal_code', $data) && !empty($data['postal_code'])) {
+          $location['postal_code'] = $data['postal_code'];
+        }
+        if (array_key_exists('province', $data) && !empty($data['province'])) {
+          $location['province'] = $data['province'];
+        }
+        /*
+         * @@@ I dont care about adding my results to the db, but others might, so I leave this in
+         *
+        // Try to see whether we can get timezone/dst data based on location. If not, we'll insert zeroes.
+        $country_specific_function = 'location_timezone_data_'. $location['country'];
+        if (function_exists($country_specific_function)) {
+          $tzdata = $country_specific_function($location);
+        }
+        else {
+          $tzdata = array('timezone' => 0, 'dst' => 0);
+        }
+        // Make sure values have the right keys and write record to database.
+        if (isset($location['province'])) {
+          $tzdata['state'] = $location['province'];
+        }
+        $tzdata['zip'] = $location['postal_code'];
+        drupal_write_record('zipcodes', array_merge($location, $tzdata));
+        }
+         */
+        return array('lat' => $location['latitude'], 'lon' => $location['longitude'], 'city' => $location['city'], 'postal_code' => $location['postal_code'], 'province' => $location['province']);
+      }
+      
+    // - uncomment if you decide to check the db first }
     return NULL;
   }
 }
@@ -458,6 +628,45 @@ function location_province_code($country
 
 // @@@ New in 3.x, document.
 /**
+ * Canonicalize a postal code.
+ */
+function location_standardize_postalcode(&$postalcode, $country = 'us') {
+
+  // Standard things go here
+  $postalcode = trim($postalcode);
+
+  // Country-custom stuff
+  location_load_country($country);
+  $country_specific_function = 'location_standardize_postalcode_'. $country;
+  if (function_exists($country_specific_function)) {
+    return $country_specific_function($postalcode);
+  }
+
+  // If no custom functions yielded 'invalid', the postal code is OK
+  return TRUE;
+}
+
+/**
+ * Canonicalize a city.
+ */
+function location_standardize_city(&$city, $country = 'us') {
+
+  // Standard things go here
+  $city = trim($city);
+
+  // Country-custom stuff
+  location_load_country($country);
+  $country_specific_function = 'location_standardize_city_'. $country;
+  if (function_exists($country_specific_function)) {
+    return $country_specific_function($city);
+  }
+
+  // If no custom functions yielded 'invalid', the postal code is OK
+  return TRUE;
+}
+
+// @@@ New in 3.x, document.
+/**
  * Canonicalize a country code.
  */
 function location_standardize_country_code(&$country) {
Index: location.views.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/location/location.views.inc,v
retrieving revision 1.16
diff -u -p -r1.16 location.views.inc
--- location.views.inc	3 Dec 2008 22:51:23 -0000	1.16
+++ location.views.inc	15 Mar 2010 21:52:02 -0000
@@ -51,6 +51,12 @@ function location_views_handlers() {
       'location_handler_argument_location_province' => array(
         'parent' => 'views_handler_argument',
       ),
+      'location_handler_argument_location_distance' => array(
+        'parent' => 'views_handler_argument',
+      ),
+//      'location_handler_argument_location_proximity' => array(
+//        'parent' => 'views_handler_argument',
+//      ),
       'location_handler_field_location_address' => array(
         'parent' => 'views_handler_field',
       ),
@@ -306,6 +312,9 @@ function location_views_data() {
     'filter' => array(
       'handler' => 'location_views_handler_filter_proximity',
     ),
+    'argument' => array(
+      'handler' => 'location_handler_argument_location_distance',
+    ),
 //    'relationship' => array(
 //      'handler' => 'location_handler_relationship_location_distance',
 //    ),
Index: geocoding/google.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/location/geocoding/google.inc,v
retrieving revision 1.11.2.3
diff -u -p -r1.11.2.3 google.inc
--- geocoding/google.inc	29 Jun 2009 14:11:16 -0000	1.11.2.3
+++ geocoding/google.inc	15 Mar 2010 21:52:02 -0000
@@ -142,10 +142,23 @@ function google_geocode_location($locati
 
   $latlon_match = array();
   preg_match('/<coordinates>(.*)<\/coordinates>/', $http_reply->data, $latlon_match);
-
   $latlon_exploded = explode(',', $latlon_match[1]);
 
-  return array('lat' => $latlon_exploded[1], 'lon' => $latlon_exploded[0]);
+  //TK edit: also get and return city postcode and province
+  preg_match('/<LocalityName>(.*)<\/LocalityName>/', $http_reply->data, $city_match);
+  $city_exploded = explode(',', $city_match[1]);
+
+  preg_match('/<PostalCodeNumber>(.*)<\/PostalCodeNumber>/', $http_reply->data, $postcode_match);
+  $postcode = '';
+  if (!empty($postcode_match)) {
+    $postcode_exploded = explode(',', $postcode_match[1]);
+    $postcode = $postcode_exploded[0];
+  }
+  
+  preg_match('/<AdministrativeAreaName>(.*)<\/AdministrativeAreaName>/', $http_reply->data, $province_match);
+  $province_exploded = explode(',', $province_match[1]);
+
+  return array('lat' => $latlon_exploded[1], 'lon' => $latlon_exploded[0], 'city'=> $city_exploded[0], 'postal_code' => $postcode, 'province'=> $province_exploded[0]);
 }
 
 /**
Index: handlers/location_handler_field_location_distance.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/location/handlers/location_handler_field_location_distance.inc,v
retrieving revision 1.2.2.1
diff -u -p -r1.2.2.1 location_handler_field_location_distance.inc
--- handlers/location_handler_field_location_distance.inc	21 Jan 2009 21:39:16 -0000	1.2.2.1
+++ handlers/location_handler_field_location_distance.inc	15 Mar 2010 21:52:02 -0000
@@ -40,6 +40,7 @@ class location_handler_field_location_di
         'hybrid' => t("User's location (fall back to static if unset)"),
         'static' => t("Static location"),
         'tied' => t("Use Distance / Proximity filter"),
+        'arg' => t("Use Distance / Proximity argument"),
       ),
       '#description' => t('FIXME'),
       '#default_value' => $this->options['origin'],
@@ -104,6 +105,18 @@ class location_handler_field_location_di
         }
       }
     }
+    if ($this->options['origin'] == 'arg') {
+      if (!empty($this->view->argument)) {
+        foreach ($this->view->argument as $k => $v) {
+          if ($v->table == 'location' && $v->field == 'distance' && $v->options['relationship'] == $this->options['relationship']) {
+            if ($v->calculate_coords()) {
+              $latitude = (float)$v->value['latitude'];
+              $longitude = (float)$v->value['longitude'];
+            }
+          }
+        }
+      }
+    }
 
     $this->ensure_my_table();
 
Index: handlers/location_views_handler_filter_proximity.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/location/handlers/location_views_handler_filter_proximity.inc,v
retrieving revision 1.3.2.1
diff -u -p -r1.3.2.1 location_views_handler_filter_proximity.inc
--- handlers/location_views_handler_filter_proximity.inc	22 Jan 2010 16:38:05 -0000	1.3.2.1
+++ handlers/location_views_handler_filter_proximity.inc	15 Mar 2010 21:52:03 -0000
@@ -22,7 +22,8 @@ class location_views_handler_filter_prox
         'latitude' => '',
         'longitude' => '',
         'postal_code' => '',
-        'country' => '',
+        'city' => '',
+        'country' => variable_get('location_default_country', 'us'),
         'search_distance' => 100,
         'search_units' => 'mile',
       ),
@@ -56,6 +57,10 @@ class location_views_handler_filter_prox
         'latlon' => t('Latitude / Longitude input'),
         'postal' => t('Postal Code / Country'),
         'postal_default' => t('Postal Code (assume default country)'),
+        'city' => t('City / Country'),
+        'city_default' => t('City (assume default country)'),
+        'postal_or_city' => t('Postal Code or City / Country'),
+        'postal_or_city_default' => t('Postal Code or City (assume default country)'),
       ),
       //'#id' => 'edit-options-type',
       '#description' => t('FIXME'),
@@ -126,6 +131,14 @@ class location_views_handler_filter_prox
       '#dependency' => array('edit-options-type' => array('postal', 'postal_default')),
     );
 
+    $form['value']['city'] = array(
+      '#type' => 'textfield',
+      '#title' => t('City'),
+      '#default_value' => $this->value['city'],
+      '#process' => array('views_process_dependency'),
+      '#dependency' => array('edit-options-type' => array('city')),
+    );
+
     $form['value']['country'] = array(
       '#type' => 'select',
       '#title' => t('Country'),
@@ -172,11 +185,19 @@ class location_views_handler_filter_prox
       unset($form[$key]['longitude']);
     }
     if ($type != 'postal' && $type != 'postal_default') {
-      unset($form[$key]['postal_code']);
+      if ($type == 'postal_or_city' || $type == 'postal_or_city_default') {
+         $form[$key]['postal_code']['#title'] = t('Postal Code or City');
+      }
+      else {
+        unset($form[$key]['postal_code']);
+      }
     }
     if ($type != 'postal') {
       unset($form[$key]['country']);
     }
+    if ($type != 'city' && $type != 'city_default') {
+      unset($form[$key]['city']);
+    }
   }
 
   // Used from the distance field.
@@ -187,28 +208,60 @@ class location_views_handler_filter_prox
     }
     // @@@ Switch to mock location object and rely on location more?
 
-    if ($this->options['type'] == 'postal' || $this->options['type'] == 'postal_default') {
+    if (in_array($this->options['type'], array('postal', 'postal_default', 'city', 'city_default', 'postal_or_city', 'postal_or_city_default'))) {
       // Force default for country.
-      if ($this->options['type'] == 'postal_default') {
+      if (in_array($this->options['type'], array('postal_default', 'city_default', 'postal_or_city_default'))) {
         $this->value['country'] = variable_get('location_default_country', 'us');
       }
-
+      // we need a country, so if it is not set, return false
+      if (empty($this->value['country'])) {
+        return false;
+      }
       // Zip code lookup.
-      if (!empty($this->value['postal_code']) && !empty($this->value['country'])) {
-        $coord = location_latlon_rough($this->value);
-        if ($coord) {
-          $this->value['latitude'] = $coord['lat'];
-          $this->value['longitude'] = $coord['lon'];
-        }
-        else {
+      $coord = NULL;
+      if (!empty($this->value['postal_code']) && in_array($this->options['type'], array('postal', 'postal_default', 'postal_or_city', 'postal_or_city_default'))) {
+        $coord = location_get_postalcode_data($this->value, TRUE);
+        //will fail validation if not a proper postal code and $coord will be NULL
+      }
+      // City lookup using postcode value 
+      if (!$coord && empty($this->value['city']) && in_array($this->options['type'], array('postal_or_city', 'postal_or_city_default'))) {
+        //copy the value of postal_code into city
+        $this->value['city'] = $this->value['postal_code'];
+        unset($this->value['postal_code']);
+        $coord = location_get_city_data($this->value, TRUE);
+        // clean up by setting the values back and returning false;
+        if (!$coord){
+          $this->value['postal_code'] = $this->value['city'];
+          unset($this->value['city']);
           return false;
         }
       }
+      // City lookup. 
+      if (!empty($this->value['city']) && in_array($this->options['type'], array('city', 'city_default'))) {
+        $coord = location_get_city_data($this->value, TRUE);
+      }
+      if ($coord) {
+        $this->value['latitude'] = $coord['lat'];
+        $this->value['longitude'] = $coord['lon'];
+        // TK edit: Add city, post_code and province from our results to $this->value,
+        // which keeps things accurate and tidy
+        if (array_key_exists('city', $coord) && !empty($coord['city'])) {
+          $this->value['city'] = $coord['city'];
+        }
+        if (array_key_exists('postal_code', $coord) && !empty($coord['postal_code'])) {
+          $this->value['postal_code'] = $coord['postal_code'];
+        }
+        if (array_key_exists('province', $coord) && !empty($coord['province'])) {
+          $this->value['province'] = $coord['province'];
+        }
+      }
       else {
-        // @@@ Implement full address lookup?
         return false;
       }
     }
+    else {
+        return false;
+    }
     if (empty($this->value['latitude']) || empty($this->value['longitude'])) {
       return false;
     }
@@ -219,7 +272,6 @@ class location_views_handler_filter_prox
     if (empty($this->value)) {
       return;
     }
-
     // Coordinates available?
     if (!$this->calculate_coords()) {
       // Distance set?
Index: supported/location.ca.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/location/supported/location.ca.inc,v
retrieving revision 1.11
diff -u -p -r1.11 location.ca.inc
--- supported/location.ca.inc	8 Mar 2008 22:25:39 -0000	1.11
+++ supported/location.ca.inc	15 Mar 2010 21:52:03 -0000
@@ -387,3 +387,24 @@ function location_geocode_ca_geocoder($l
     }
   }
 }
+
+function location_standardize_postalcode_ca(&$postalcode) {
+  if (!is_string($postalcode)) {
+    return FALSE;
+  }
+
+  $code = strtoupper(str_replace(' ','',$postalcode));
+  if (preg_match("/^[A-Z]{1,2}[0-9]{2,3}[A-Z]{2}$/", $code)
+    || preg_match("/^[A-Z]{1,2}[0-9]{1}[A-Z]{1}[0-9]{1}[A-Z]{2}$/", $code)
+    || preg_match("/^GIR0[A-Z]{2}$/", $code)) {
+
+    preg_match('/^[a-zA-Z]*[0-9 ]+/', $postalcode, $matches);
+    $postalcode = substr_replace(str_replace(' ', '', $matches[0]), '', -1);
+    return TRUE;
+  }
+  // Return TRUE anyway. The code in http://drupal.org/files/issues/location.proximity.handler.patch
+  // does not protest if the postal code does not adhere to above regexps.
+  // @@@ Someone with knowledge about CA zipcodes please check whether we should return FALSE.
+  //     The database ({zipcode} cache) is better off when 'wrongly formatted' postal codes get denied.
+  return TRUE;
+}
Index: supported/location.de.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/location/supported/location.de.inc,v
retrieving revision 1.16.4.1
diff -u -p -r1.16.4.1 location.de.inc
--- supported/location.de.inc	4 Feb 2009 23:16:17 -0000	1.16.4.1
+++ supported/location.de.inc	15 Mar 2010 21:52:03 -0000
@@ -256,3 +256,11 @@ function location_get_postalcode_data_de
     return NULL;
   }
 }
+
+function location_standardize_postalcode_de(&$postalcode) {
+  // @@@ omg, like, srly. The "$dash_index === FALSE" SO does not make sense.
+  //     Someone please check the code in location_get_postalcode_data_de()
+  //     and insert something _proper_ here, please?
+  //     (Was someone trying to strip a trailing 'D-', or something?)
+  return TRUE;
+}
Index: supported/location.nl.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/location/supported/location.nl.inc,v
retrieving revision 1.7
diff -u -p -r1.7 location.nl.inc
--- supported/location.nl.inc	23 Jul 2008 18:13:07 -0000	1.7
+++ supported/location.nl.inc	15 Mar 2010 21:52:03 -0000
@@ -20,6 +20,13 @@ function location_province_list_nl() {
   );
 }
 
+function location_timezone_data_nl($location) {
+  return array(
+    'timezone' => 1,
+    'dst' => 1
+  );
+}
+
 function location_map_link_nl_providers() {
   return array(
     'google' => array(
@@ -50,3 +57,19 @@ function location_map_link_nl_google($lo
     return NULL;
   }
 }
+
+function location_standardize_postalcode_nl(&$postalcode) {
+  if (!is_string($postalcode)) {
+    return FALSE;
+  }
+  $postalcode = strtoupper(str_replace(' ', '', $postalcode));
+  // 4-digit as well as 4+2 letters are accepted. (The latter yields better geocoding)
+  switch (strlen($postalcode)) {
+    case 4:
+      return is_numeric($postalcode);
+    case 6:
+      return is_numeric(substr($postalcode,0,4)) && preg_match('/^[A-Z]{2}/', substr($postalcode,-2));
+    default:
+      return FALSE;
+  }
+}
Index: supported/location.uk.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/location/supported/location.uk.inc,v
retrieving revision 1.7
diff -u -p -r1.7 location.uk.inc
--- supported/location.uk.inc	8 Mar 2008 18:55:18 -0000	1.7
+++ supported/location.uk.inc	15 Mar 2010 21:52:03 -0000
@@ -238,6 +238,13 @@ function location_province_list_uk() {
     'WRX' => "Wrexham");
 }
 
+function location_timezone_data_uk($location) {
+  return array(
+    'timezone' => 0,
+    'dst' => 1
+  );
+}
+
 function location_map_link_uk_providers() {
   return array(
     'google' => array(
@@ -268,3 +275,26 @@ function location_map_link_uk_google($lo
     return NULL;
   }
 }
+
+function location_standardize_postalcode_uk(&$postalcode) {
+  if (!is_string($postalcode)) {
+    return FALSE;
+  }
+  //capitalize it
+  $postalcode = strtoupper($postalcode);
+  // return true if it is a full valid postcode
+  $pattern = '/(^gir\s0aa$)|(^[a-pr-uwyz]((\d{1,2})|([a-hk-y]\d{1,2})|(\d[a-hjks-uw])|([a-hk-y]\d[abehmnprv-y]))\s\d[abd-hjlnp-uw-z]{2}$)/i';
+  if (preg_match($pattern, $postalcode)) {
+    // first change it so that only the outward (first) part and the first digit of the inward
+    // part are used (that's all google uses for licensing reasons - Royal Mail prohibits them from
+    // providing full postcode geocoding data to third parties) - this will keep our db accurate
+    $postalcode = substr($postalcode, 0, strpos($postalcode, ' ')+2);
+    return TRUE;
+  }
+  // return true if it is a valid outward
+  $pattern = '/(^gir\s0aa$)|(^[a-pr-uwyz]((\d{1,2})|([a-hk-y]\d{1,2})|(\d[a-hjks-uw])|([a-hk-y]\d[abehmnprv-y])))/i';
+  if (preg_match($pattern, $postalcode)) {
+    return TRUE;
+  }
+  return FALSE;
+}
Index: supported/location.us.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/location/supported/location.us.inc,v
retrieving revision 1.23.2.1
diff -u -p -r1.23.2.1 location.us.inc
--- supported/location.us.inc	4 Feb 2009 23:16:17 -0000	1.23.2.1
+++ supported/location.us.inc	15 Mar 2010 21:52:03 -0000
@@ -605,3 +605,16 @@ function location_province_list_numeric_
                '059' => 'Virgin Islands'
               );
 }
+
+function location_standardize_postalcode_us(&$postalcode) {
+  if (!is_string($postalcode)) {
+    return FALSE;
+  }
+
+  // If we're dealing with a 9-digit US zipcode, strip hyphen and the last 4 digits
+  $dash_index = strpos($postalcode, '-');
+  if ($dash_index !== FALSE) {
+    $postalcode = substr($postalcode, 0, $dash_index);
+  }
+  return is_numeric($postalcode);
+}
