? browscap-664424.patch
Index: browscap.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/browscap/browscap.module,v
retrieving revision 1.6
diff -u -p -r1.6 browscap.module
--- browscap.module	13 Apr 2006 15:49:30 -0000	1.6
+++ browscap.module	1 Jan 2010 17:54:15 -0000
@@ -1,5 +1,5 @@
 <?php
-// $Id: browscap.module,v 1.6 2006/04/13 15:49:30 unconed Exp $
+// $Id: browscap.module,v 1.6.2.3.2.11 2009/09/30 17:16:40 greggles Exp $
 
 /**
  * @file
@@ -7,221 +7,70 @@
  */
 
 /**
- * Implementation of hook_help().
+ * ******************** Drupal Hooks ************************
  */
-function browscap_help($section) {
-  switch ($section) {
-    case 'admin/modules#description':
-      return t('Provides statistics on browsers, and a replacement for '.
-        "PHP's get_browser() function.");
-  }
-}
-
-function browscap_get_browser($useragent = NULL, $return_array = FALSE) {
-  if (!$useragent) {
-    $useragent = $_SERVER['HTTP_USER_AGENT'];
-  }
-  // Cache the results
-  $cacheid = 'browscap:'.$useragent;
-  $cache = cache_get($cacheid);
-  if ((!empty($cache)) and ($cache->created > time() - 60*60*24)) {
-    // Found a fresh entry in the cache
-    $browserinfo = unserialize($cache->data);
-  } else {
-    // Note the 'backwards' use of LIKE - the useragent column contains
-    // the wildcarded pattern to match against our full-length string
-    // The ORDER BY chooses the most-specific matching pattern
-    $browserinfo = db_fetch_object(db_query_range(
-      "SELECT * from {browscap} WHERE '%s' LIKE useragent ORDER BY LENGTH(useragent) DESC",
-      $useragent, 0, 1));
-    // A couple of fieldnames not in our database, provided for
-    // compatibility with PHP's get_browser()
-    $browserinfo->browser_name_pattern = strtr($browserinfo->useragent, '%_', '*?');
-    $browserinfo->tables = $browserinfo->htmltables;
-    cache_set($cacheid, serialize($browserinfo));
-  }
-
-  if ($return_array) {
-    return get_object_vars($browserinfo);
-  } else {
-    return $browserinfo;
-  }
-}
-
-/**
- * Implementation of hook_cron().
- */
-function browscap_cron() {
-  // Has it been a week since the last (attempt to) import?
-  $last_imported = variable_get('browscap_imported', 0);
-  if (($last_imported + 60*60*24*7) < time()) {
-    _browscap_import();
-    variable_set('browscap_imported', time());
-  }
-}
-
-// A numeric interpretation of browscap.csv's TRUE/FALSE/default fields
-function _browscap_boolean($value) {
-  switch ($value) {
-    case 'TRUE':
-    case 'true':
-      return 1;
-    case 'FALSE':
-    case 'false':
-    case 'default':
-    default:
-      return 0;
-  }
-}
 
 /**
- * If there's a new version of browscap.csv, fetch it and update the
- * database.
+ * Implementation of hook_menu().
+ *
+ * @return array
  */
-function _browscap_import() {
-  // Politely check the version for updates before fetching the file
-  $versionpage = drupal_http_request('http://www.garykeith.com/browsers/version.asp');
-  if ($versionpage->error) {
-    watchdog('browscap', "Couldn't check version: ".$versionpage->error);
-    return;
-  }
-  $browscapversion = trim($versionpage->data);
-  $oldversion = variable_get('browscap_version', 'Never fetched');
-  if ($browscapversion == $oldversion) {
-    // No update, nothing to do here
-    watchdog('browscap', 'No new version of browscap to import');
-    return;
-  }
+function browscap_menu() {
+  // LOG PAGES
+  $items['admin/reports/browscap'] = array(
+    'title' => t('Browscap'),
+    'description' => t('Browser-specific site statistics.'),
+    'page callback' => 'browscap_top_useragents',
+    'page arguments' => array('all'),
+    'access arguments' => array('access administration pages'),
+    'weight' => 5);
+  $items['admin/reports/browscap/useragents'] = array(
+    'title' => t('All user agents'),
+    'access arguments' => array('access administration pages'),
+    'weight' => 1,
+    'type' => MENU_DEFAULT_LOCAL_TASK
+  );
+  $items['admin/reports/browscap/browsers'] = array(
+    'title' => t('Browsers'),
+    'page callback' => 'browscap_top_useragents',
+    'page arguments' => array('browsers'),
+    'access arguments' => array('access administration pages'),
+    'weight' => 2,
+    'type' => MENU_LOCAL_TASK
+  );
+  $items['admin/reports/browscap/crawlers'] = array(
+    'title' => t('Crawlers'),
+    'page callback' => 'browscap_top_useragents',
+    'page arguments' => array('crawlers'),
+    'access arguments' => array('access administration pages'),
+    'weight' => 3,
+    'type' => MENU_LOCAL_TASK
+  );
 
-  // Fetch the new version, and dump it in the temp directory
-  $server = $_SERVER['SERVER_NAME'];
-  $path = variable_get('file_directory_temp', '/tmp');
-  $browscapfile = "$path/browscap_$server.csv";
+  // SETTINGS PAGE
+  $items['admin/settings/browscap'] = array(
+    'title' => t('Browscap'),
+    'description' => t('Enable browscap site statistics.'),
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('browscap_settings'),
+    'access arguments' => array('administer site configuration'),
+  );
 
-  // If we can, download the zipped version and extract the file
-  if (is_callable('zip_open')) {
-    $browscapzipfile = "$path/csv_browscap_$server.zip";
-    $browscapzip = drupal_http_request('http://www.garykeith.com/browsers/stream.asp?CSV_BrowsCapZIP');
-    if ($browscapzip->error or !trim($browscapzip->data)) {
-      watchdog('browscap', "Couldn't retrieve updated browscap: ".$browscapzip->error);
-      return;
-    }
-    $browscapzipfp = fopen($browscapzipfile, "w");
-    fwrite($browscapzipfp, $browscapzip->data);
-    fclose($browscapzipfp);
-    $zip = zip_open($browscapzipfile);
-    if ($zip) {
-      while ($zip_entry = zip_read($zip)) {
-        if (zip_entry_name($zip_entry) == 'browscap.csv') {
-          if (zip_entry_open($zip, $zip_entry, 'rb')) {
-            $browscapfp = fopen($browscapfile, 'w');
-            fwrite($browscapfp, zip_entry_read($zip_entry, zip_entry_filesize($zip_entry)));
-            fclose($browscapfp);
-            break;
-          }
-        }
-      }
-      zip_close($zip);
-    }
-    unlink($browscapzipfile);
-  // Can't handle zip, get the unzipped version
-  } else {
-    $browscap = drupal_http_request('http://www.garykeith.com/browsers/stream.asp?BrowsCapCSV');
-    if ($browscap->error or !trim($browscap->data)) {
-      watchdog('browscap', "Couldn't retrieve updated browscap: ".$browscap->error);
-      return;
-    }
-    $browscapfp = fopen($browscapfile, "w");
-    fwrite($browscapfp, $browscap->data);
-    fclose($browscapfp);
-  }
-
-  // Parse the .csv file, importing each row (except the first two)
-  // into the {browscap} table
-  $browscapfp = fopen($browscapfile, 'r');
-  if ($browscapfp) {
-    // Ignore the first two rows (column headers & version info)
-    fgetcsv($browscapfp, 1000); fgetcsv($browscapfp, 1000);
-    while (($browserinfo = fgetcsv($browscapfp, 1000)) != FALSE) {
-      // Strip brackets
-      $useragent = substr($browserinfo[0], 1, -1);
-      // Replace wildcards with SQL equivalents
-      $useragent = strtr($useragent, '*?', '%_');
-      $parent = $browserinfo[1];
-      $browser = $browserinfo[2];
-      $version = $browserinfo[3];
-      $majorversion = $browserinfo[4];
-      $minorversion = $browserinfo[5];
-      $platform = $browserinfo[6];
-      $authenticodeupdate = $browserinfo[7];
-      if ($browserinfo[8] == 'default') {
-        $cssversion = -1;
-      } else {
-        $cssversion = $browserinfo[8];
-      }
-      $frames = _browscap_boolean($browserinfo[9]);
-      $iframes = _browscap_boolean($browserinfo[10]);
-      $htmltables = _browscap_boolean($browserinfo[11]);
-      $cookies = _browscap_boolean($browserinfo[12]);
-      $backgroundsounds = _browscap_boolean($browserinfo[13]);
-      $vbscript = _browscap_boolean($browserinfo[14]);
-      $javascript = _browscap_boolean($browserinfo[15]);
-      $javaapplets = _browscap_boolean($browserinfo[16]);
-      $activexcontrols = _browscap_boolean($browserinfo[17]);
-      $cdf = _browscap_boolean($browserinfo[18]);
-      $aol = _browscap_boolean($browserinfo[19]);
-      $beta = _browscap_boolean($browserinfo[20]);
-      $win16 = _browscap_boolean($browserinfo[21]);
-      $crawler = _browscap_boolean($browserinfo[22]);
-      $stripper = _browscap_boolean($browserinfo[23]);
-      $wap = _browscap_boolean($browserinfo[24]);
-      $netclr = _browscap_boolean($browserinfo[25]);
-
-      db_query('REPLACE {browscap} (useragent,parent,browser,version,'.
-        'majorversion,minorversion,platform,authenticodeupdate,'.
-        'cssversion,frames,iframes,htmltables,cookies,backgroundsounds,'.
-        'vbscript,javascript,javaapplets,activexcontrols,cdf,aol,'.
-        'beta,win16,crawler,stripper,wap,netclr) '.
-        "VALUES('%s','%s','%s','%s','%s','%s','%s','%s',%d,%d,%d,%d,%d,".
-        '%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d)',
-        $useragent, $parent, $browser, $version,
-        $majorversion, $minorversion, $platform, $authenticodeupdate,
-        $cssversion, $frames, $iframes, $htmltables, $cookies, $backgroundsounds,
-        $vbscript, $javascript, $javaapplets, $activexcontrols, $cdf, $aol,
-        $beta, $win16, $crawler, $stripper, $wap, $netclr);
-    }
-    fclose($browscapfp);
-    unlink($browscapfile);
-
-    // Phase 2 - for every entry which isn't a top-level entry, plug
-    // in the data from its parent
-    $query = 'SELECT useragent,parent from {browscap} WHERE useragent <> parent';
-    $result = db_query($query);
-    while ($destrow = db_fetch_object($result)) {
-      $query = "SELECT * FROM {browscap} WHERE useragent='%s'";
-      $srcrow = db_fetch_object(db_query($query, $destrow->parent));
-      db_query("UPDATE {browscap} SET browser='%s',version='%s',".
-        "majorversion='%s',minorversion='%s',platform='%s',".
-        "authenticodeupdate='%s',cssversion=%d,frames=%d,iframes=%d,".
-        "htmltables=%d,cookies=%d,backgroundsounds=%d,vbscript=%d,".
-        "javascript=%d,javaapplets=%d,activexcontrols=%d,cdf=%d,".
-        "aol=%d,beta=%d,win16=%d,crawler=%d,stripper=%d,wap=%d,netclr=%d ".
-        "WHERE useragent='%s'",
-        $srcrow->browser,$srcrow->version,
-        $srcrow->majorversion,$srcrow->minorversion,$srcrow->platform,
-        $srcrow->authenticodeupdate,$srcrow->cssversion,$srcrow->frames,$srcrow->iframes,
-        $srcrow->htmltables,$srcrow->cookies,$srcrow->backgroundsounds,$srcrow->vbscript,
-        $srcrow->javascript,$srcrow->javaapplets,$srcrow->activexcontrols,$srcrow->cdf,
-        $srcrow->aol,$srcrow->beta,$srcrow->win16,$srcrow->crawler,$srcrow->stripper,$srcrow->wap,$srcrow->netclr,
-        $destrow->useragent);
-    }
-  // All done updating the browscap info - invalidate cached data
-  // from the last version, and record the version we're currently
-  // using
-  cache_clear_all('browscap:', TRUE);
-  variable_set('browscap_version', $browscapversion);
-  watchdog('browscap', "New version of browscap imported: $browscapversion");
-  }
+  $items['admin/settings/browscap/refresh'] = array(
+    'title' => t('Browscap Refresh'),
+    'page callback' => 'browscap_refresh',
+    'access arguments' => array('administer site configuration'),
+    'type' => MENU_CALLBACK,
+  );
+  $items['admin/reports/browscap/useragent/%browscap_useragent'] = array(
+    'title' => 'Useragent details',
+    'page callback' => 'browscap_useragent_properties',
+    'page arguments' => array(4),
+    'access arguments' => array('access administration pages'),
+    'weight' => 5,
+    'type' => MENU_LOCAL_TASK
+  );
+  return $items;
 }
 
 /**
@@ -230,105 +79,75 @@ function _browscap_import() {
  * Keep tabs on browsers that visit
  */
 function browscap_exit() {
-  // No point if statistics aren't enabled
-  if (!module_exist('statistics')) {
-    return;
-  }
-
   // If monitoring is enabled, record the browser
   if (variable_get('browscap_monitor', FALSE)) {
-    $browser = browscap_get_browser();
-    $browserstring = substr(trim($browser->parent), 0, 255);
-    if ($browserstring == '' or $browserstring == 'Default Browser') {
-      $browserstring = trim($_SERVER['HTTP_USER_AGENT']);
-    }
-    db_query("UPDATE {browscap_statistics} SET counter = counter + 1, is_crawler=%d ".
-      "WHERE parent='%s'", $browser->crawler, $browserstring);
-    // If we affected 0 rows, this is the first time we've seen this browser
-    if (!db_affected_rows()) {
-      // We must create a new row to store counters for the new browser.
-      db_query('INSERT INTO {browscap_statistics} (parent,counter,is_crawler) '.
-        "VALUES('%s', 1, %d)", $browserstring, $browser->crawler);
+    if ($browser = browscap_get_browser()) {
+      $browserstring = substr(trim($browser['parent']), 0, 255);
+      if ($browserstring == '' or $browserstring == 'Default Browser') {
+        $browserstring = trim($_SERVER['HTTP_USER_AGENT']);
+      }
+      db_query("UPDATE {browscap_statistics} SET counter = counter + 1, is_crawler=%d ".
+        "WHERE parent='%s'", $browser['crawler'], $browserstring);
+      // If we affected 0 rows, this is the first time we've seen this browser
+      if (!db_affected_rows()) {
+        // We must create a new row to store counters for the new browser.
+        db_query('INSERT INTO {browscap_statistics} (parent,counter,is_crawler) '.
+          "VALUES('%s', 1, %d)", $browserstring, $browser['crawler']);
+      }
     }
   }
 }
 
-/*
- * Undo a recorded browser visit by request
- *
- * This function serves the statistics_filter module, enabling it
- * to ignore visits from specified roles.
+/**
+ * Implementation of hook_cron().
  */
-function browscap_unmonitor() {
-  // No point if statistics aren't enabled
-  if (!module_exist('statistics')) {
-    return;
-  }
-
-  // If monitoring is enabled, unrecord the browser
-  if (variable_get('browscap_monitor', FALSE)) {
-    $browser = browscap_get_browser();
-    $browserstring = trim($browser->parent);
-    if ($browserstring == '' or $browserstring == 'Default Browser') {
-      $browserstring = trim($_SERVER['HTTP_USER_AGENT']);
-    }
-    db_query("UPDATE {browscap_statistics} SET counter = counter - 1, is_crawler=%d ".
-      "WHERE parent='%s'", $browser->crawler, $browserstring);
+function browscap_cron() {
+  // Has it been a week since the last (attempt to) import?
+  $last_imported = variable_get('browscap_imported', 0);
+  if (($last_imported + 60*60*24*7) < time()) {
+    _browscap_import();
+    variable_set('browscap_imported', time());
   }
 }
 
 /**
- * Implementation of hook_perm().
- *
- * @return array
+ * ******************** Menu Callbacks ************************
  */
-function browscap_perm() {
-  return array('administer browscap');
-}
 
 /**
- * Turn monitor on or off
+ * Callback for settings form.
+ * Turn monitoring on or off and refresh the reference data.
  *
  * @return array
  */
 function browscap_settings() {
-  // Restrict administration of this module
-  if (user_access('administer browscap') === false) {
-    return drupal_access_denied();
-  }
+  $form['browscap_data_status'] = array(
+    '#value' => t('<p>Browscap data current as of %fileversion. [<a href="!refresh">Refresh now</a>]</p>',
+                   array(
+                     '%fileversion' => variable_get('browscap_version', t('Never fetched')),
+                     '!refresh' => url('admin/settings/browscap/refresh'),
+                   )),
+  );
 
   $form['browscap_monitor'] = array(
     '#type' => 'checkbox',
-    '#prefix' => t('<p>Browscap data current as of %fileversion</p>',
-                   array('%fileversion' => variable_get('browscap_version', 'Never fetched'))),
     '#title' => t('Monitor browsers'),
     '#default_value' => variable_get('browscap_monitor', FALSE),
-    '#description' => t('Monitor all user agents visiting the site.')
+    '#description' => t('Monitor all user agents visiting the site. View the reports in the <a href="!reports">Browscap reports</a> area.',
+                        array(
+                          '!reports' => url('admin/reports/browscap'),
+                        )),
   );
-  return $form;
+  return system_settings_form($form);
 }
 
 /**
- * Implementation of hook_menu().
+ * Simple page callback to manually refresh the data.
  *
- * @return array
  */
-function browscap_menu($may_cache) {
-  $items = array();
-
-  if ($may_cache && variable_get('browscap_monitor', FALSE)) {
-    $access = user_access('access statistics');
-
-    $items[] = array('path' => 'admin/logs/useragents',
-      'title' => t('user agents'), 'callback' => 'browscap_top_useragents',
-      'access' => $access, 'weight' => 5);
-    $items[] = array('path' => 'admin/logs/useragents/browsers',
-      'title' => t('browsers'), 'access' => $access);
-    $items[] = array('path' => 'admin/logs/useragents/crawlers',
-      'title' => t('crawlers'), 'access' => $access);
-  }
-
-  return $items;
+function browscap_refresh() {
+  _browscap_import(FALSE);
+  drupal_goto('admin/settings/browscap');
 }
 
 /**
@@ -366,7 +185,8 @@ function browscap_top_useragents($view =
       array('data' => t('Count'), 'field' => 'counter', 'sort' => 'desc'),
       array('data' => t('Percent'), 'field' => 'percent')
     );
-  } else {
+  }
+  else {
     $result = db_query('SELECT SUM(counter) FROM {browscap_statistics} WHERE is_crawler=1');
     $total = db_result($result);
     if (!$total) $total = 1;
@@ -380,29 +200,241 @@ function browscap_top_useragents($view =
     );
   }
 
+  drupal_set_title($title);
+
   $query .= tablesort_sql($header);
 
   $result = pager_query($query, 50, 0, $query_cnt);
+  $rows = array();
 
   while ($useragent = db_fetch_object($result)) {
+    if (db_result(db_query_range("SELECT useragent FROM {browscap} WHERE useragent = '%s'", $useragent->parent, 0, 1))) {
+      $parent = l($useragent->parent, 'admin/reports/browscap/useragent/'. urlencode($useragent->parent));
+    }
+    else {
+      $parent = check_plain($useragent->parent);
+    }
     if ($view == 'all') {
       if ($useragent->is_crawler) {
-        $is_crawler = 'Yes';
-      } else {
-        $is_crawler = 'No';
+        $is_crawler = t('Yes');
       }
-      $rows[] = array($useragent->parent, $useragent->counter, $useragent->percent, $is_crawler);
-    } else {
-      $rows[] = array($useragent->parent, $useragent->counter, $useragent->percent);
+      else {
+        $is_crawler = t('No');
+      }
+      $rows[] = array($parent, $useragent->counter, $useragent->percent, $is_crawler);
+    }
+    else {
+      $rows[] = array($parent, $useragent->counter, $useragent->percent);
     }
   }
   if ($pager = theme('pager', NULL, 50, 0)) {
     $rows[] = array(array('data' => $pager, 'colspan' => 2));
   }
 
+  $output = '';
+  if (empty($rows)) {
+    $output .= t('It appears that your site has not recorded any visits. If you want to record the visitors to your site you can enable "Monitor browsers" on the <a href="!settings_uri">Browscap settings screen</a>.', array('!settings_uri' => url('admin/settings/browscap')));
+  }
   $output .= theme('table', $header, $rows);
 
   print theme('page', $output, $title);
 }
 
-?>
+/**
+ * Provide data about the current browser or a known user agent string.
+ *
+ * @param string $useragent
+ *   Optional user agent string to test.  If empty use the value from the current request.
+ * @return array
+ *  An array of data about the user agent.
+ */
+function browscap_get_browser($useragent = NULL) {
+  if (!$useragent) {
+    $useragent = $_SERVER['HTTP_USER_AGENT'];
+  }
+  // Cache the results
+  $cacheid = $useragent;
+  $cache = cache_get($cacheid, 'cache_browscap');
+  if ((!empty($cache)) and ($cache->created > time() - 60*60*24)) {
+    // Found a fresh entry in the cache
+    $browserinfo = $cache->data;
+  }
+  else {
+    // Note the 'backwards' use of LIKE - the useragent column contains
+    // the wildcarded pattern to match against our full-length string
+    // The ORDER BY chooses the most-specific matching pattern
+    $browserinfo = db_fetch_object(db_query_range(
+      "SELECT * from {browscap} WHERE '%s' LIKE useragent ORDER BY LENGTH(useragent) DESC",
+      $useragent, 0, 1));
+    // A couple of fieldnames not in our database, provided for
+    // compatibility with PHP's get_browser()
+    //$browserinfo->tables = $browserinfo->htmltables;
+    cache_set($cacheid, $browserinfo, 'cache_browscap');
+  }
+  if (isset($browserinfo) && isset($browserinfo->data)) {
+    $info = unserialize($browserinfo->data);
+    $info['useragent'] = $useragent;
+    $info['browser_name_pattern'] = strtr($browserinfo->useragent, '%_', '*?');
+    return $info;
+  }
+}
+
+/**
+ * Determine whether the current visitor
+ *
+ * @param string $useragent
+ *   Optional user agent string.
+ */
+function browscap_is_crawler($useragent = NULL) {
+  $browser = browscap_get_browser($useragent);
+  return (bool)$browser['crawler'];
+}
+
+// A numeric interpretation of browscap.csv's TRUE/FALSE/default fields
+function _browscap_boolean($value) {
+  switch ($value) {
+    case 'TRUE':
+    case 'true':
+      return 1;
+    case 'FALSE':
+    case 'false':
+    case 'default':
+    default:
+      return 0;
+  }
+}
+
+/**
+ * If there's a new version of browscap.csv, fetch it and update the
+ * database.
+ */
+function _browscap_import($cron = TRUE) {
+  // Politely check the version for updates before fetching the file
+  $versionpage = drupal_http_request('http://browsers.garykeith.com/versions/version-number.asp');
+  if (isset($versionpage->error)) {
+    watchdog('browscap', 'Couldn\'t check version: '. $versionpage->error);
+    if (!$cron) {
+      drupal_set_message(t('Couldn\'t check version: ') . $versionpage->error, 'error');
+    }
+    return;
+  }
+  $browscapversion = trim($versionpage->data);
+  $oldversion = variable_get('browscap_version', 'Never fetched');
+  if ($browscapversion == $oldversion) {
+    // No update, nothing to do here
+    watchdog('browscap', 'No new version of browscap to import');
+    if (!$cron) {
+      drupal_set_message(t('No new version of browscap to import'));
+    }
+    return;
+  }
+
+  // Fetch the new version, and dump it in the temp directory
+  $server = $_SERVER['SERVER_NAME'];
+  $path = variable_get('file_directory_temp', '/tmp');
+  $browscapfile = "$path/browscap_$server.ini";
+
+  $browscap = drupal_http_request('http://browsers.garykeith.com/stream.asp?PHP_BrowsCapINI');
+  if (isset($browscap->error) || empty($browscap)) {
+    watchdog('browscap', t("Couldn't retrieve updated browscap: ") . $browscap->error);
+    if (!$cron) {
+      drupal_set_message(t("Couldn't retrieve updated browscap: ") . $browscap->error);
+    }
+    return;
+  }
+  $browscapfp = fopen($browscapfile, "w");
+  fwrite($browscapfp, $browscap->data);
+  fclose($browscapfp);
+
+  if (version_compare(PHP_VERSION, '5.3.0') >= 0) {
+		$a = parse_ini_file($browscapfile, TRUE, INI_SCANNER_RAW);
+	}else{
+		$a = parse_ini_file($browscapfile, TRUE);
+	}
+  
+  if ($a) {
+    // the first entry in the array is the version info
+    $version = array_shift($a);
+    foreach ($a as $key => $vals) {
+      $e = $vals;
+      // some recursive magic!
+      $last_parent = array();
+      while (isset($vals['Parent']) && $vals['Parent'] !== $last_parent) {
+        $vals = isset($a[$vals['Parent']]) ? $a[$vals['Parent']] : array();
+        $e = array_merge($vals, $e);
+        $last_parent = $vals;
+      }
+      $useragent = strtr($key, '*?', '%_');
+      $e = array_change_key_case($e);
+      db_query("DELETE FROM {browscap} WHERE useragent = '%s'", $useragent);
+      db_query("INSERT INTO {browscap} (useragent, data) VALUES ('%s', '%s')", $useragent, serialize($e));
+    }
+
+    cache_clear_all('*', 'cache_browscap', TRUE);
+    variable_set('browscap_version', $browscapversion);
+    watchdog('browscap', 'New version of browscap imported: '. $browscapversion);
+    if (!$cron) {
+      drupal_set_message(t('New version of browscap imported: ') . $browscapversion);
+    }
+  }
+}
+
+/*
+ * Undo a recorded browser visit by request
+ *
+ * This function serves the statistics_filter module, enabling it
+ * to ignore visits from specified roles.
+ */
+function browscap_unmonitor() {
+  // No point if statistics aren't enabled
+  if (!module_exists('statistics')) {
+    return;
+  }
+
+  // If monitoring is enabled, unrecord the browser
+  if (variable_get('browscap_monitor', FALSE)) {
+    $browser = browscap_get_browser();
+    $browserstring = trim($browser->parent);
+    if ($browserstring == '' or $browserstring == 'Default Browser') {
+      $browserstring = trim($_SERVER['HTTP_USER_AGENT']);
+    }
+    db_query("UPDATE {browscap_statistics} SET counter = counter - 1, is_crawler=%d ".
+      "WHERE parent='%s'", $browser->crawler, $browserstring);
+  }
+}
+
+/**
+ * Loads details about a given useragent. Also used as a menu object loader.
+ *
+ * @param $useragent
+ *   The name of the useragent to load.
+ * @return
+ *   The useragent array, FALSE otherwise.
+ */
+function browscap_useragent_load($useragent = NULL) {
+  if (empty($useragent)) {
+    return FALSE;
+  }
+  $row = db_fetch_object(db_query('SELECT * FROM {browscap} WHERE useragent = "%s"', $useragent));
+  if (!$row) {
+    return FALSE;
+  }
+  return unserialize($row->data);
+}
+
+/**
+ * Page callback to show details about known useragents.
+ *
+ * @param $useragent
+ *   The useragent object, loaded from the database.
+ * @return string an HTMl blob representing the data about this useragent.
+ */
+function browscap_useragent_properties($useragent = NULL) {
+  drupal_set_title(check_plain($useragent['browser'] .' '. $useragent['version']));
+  $headers = array(t('Property'), t('Value'));
+  foreach ($useragent as $key => $val) {
+    $rows[] = array(check_plain($key), check_plain($val));
+  }
+  $output = theme('table', $headers, $rows);
+  return $output;
+}
