From abae5612155504ff82912331e9a586dafcab41f4 Mon Sep 17 00:00:00 2001
From: Unconfigured <Unconfigured>
Date: Thu, 9 Jul 2009 14:13:40 +0930
Subject: LinHES-timezone: Add -z guess option to auto-detect timezone from IP
 addr

---
 abs/core-testing/LinHES-timezone/PKGBUILD          |   4 +-
 abs/core-testing/LinHES-timezone/linhes_timezone.c | 364 +++++++++++++++++----
 2 files changed, 295 insertions(+), 73 deletions(-)

diff --git a/abs/core-testing/LinHES-timezone/PKGBUILD b/abs/core-testing/LinHES-timezone/PKGBUILD
index ffad3a9..0b0d2ad 100644
--- a/abs/core-testing/LinHES-timezone/PKGBUILD
+++ b/abs/core-testing/LinHES-timezone/PKGBUILD
@@ -2,7 +2,7 @@
 # Maintainer: Greg Frost <gregfrost1@bigpond.com>
 pkgname=LinHES-timezone
 pkgver=1
-pkgrel=5
+pkgrel=6
 pkgdesc="GUI timezone selector used by LinHES-config."
 arch=i686
 depends=()
@@ -27,4 +27,4 @@ md5sums=('53976e51e938c555f84b43c933339051'
          '0d9e51af5f650dd329edce4531c42a58'
          'c01e2335603d8395004e32bae9060fde'
          'b20bd68272644f607fbfe7d50e7be42a'
-         'b35602b7330c32a472223b22d95a1d6c')
+         '448ffca8f38b2dcd989e599ff2057399')
diff --git a/abs/core-testing/LinHES-timezone/linhes_timezone.c b/abs/core-testing/LinHES-timezone/linhes_timezone.c
index 024560f..ff75549 100644
--- a/abs/core-testing/LinHES-timezone/linhes_timezone.c
+++ b/abs/core-testing/LinHES-timezone/linhes_timezone.c
@@ -2,6 +2,8 @@
 #include <math.h>
 #include <stdlib.h>
 #include <stdio.h>
+#define _GNU_SOURCE
+#include <string.h>
 #include <strings.h>
 #include <X11/Xlib.h>
 #include <X11/Intrinsic.h>
@@ -49,6 +51,41 @@ double lat_rotate[2] = {1, 0};
 double acceleration = 0.01;
 char input_keys[200];
 
+int guessing_timezone = FALSE;
+
+void select_place (int place)
+{
+  target_lon = atan2 (zone_data[selected_zone].place_info[place].v.y,
+               zone_data[selected_zone].place_info[place].v.x);
+  target_lat = acos (zone_data[selected_zone].place_info[place].v.z /2);
+
+  selected_place = place;
+}
+
+void default_zone (char *arg_zone)
+{
+  int found_zone = FALSE;
+
+  for (int zone = 0; zone < NUM_ZONES; zone++)
+  {
+    for (int place = 0; place < zone_data[zone].num_places; place++)
+    {
+      if (strstr (zone_data[zone].place_info[place].zonename, 
+                  arg_zone[0] ? arg_zone : "Los_Angeles"))
+      {
+        selected_zone = zone;
+        select_place (place);
+        found_zone = TRUE;
+      }
+    }
+  }
+
+  if (!found_zone)
+  {
+    default_zone ("");
+  }
+}
+
 int translate_point (vect_type *v, XPoint *p)
 {
   vect_type v2;
@@ -259,53 +296,53 @@ void redraw_map ()
   for (int zone = 0; zone < NUM_ZONES - 1; zone++)
     draw_zone (pixmap, zone, 0, 0);
   
-  draw_zone (pixmap, selected_zone, 1, 1);
-  XSetForeground (display, gc, selected_border.pixel);
-  draw_zone (pixmap, selected_zone, 0, 1);  
-
-  for (int place = 0; place < zone_data[selected_zone].num_places; place++)
+  if (guessing_timezone)
   {
-    XPoint point;
+    char *s = "Guessing Timezone";
+    int text_width = XTextWidth (font, s, strlen (s));
+    draw_string (width/2 - text_width/2, height/2, s, name_colour.pixel);
+  }
+  else
+  {
+    draw_zone (pixmap, selected_zone, 1, 1);
+    XSetForeground (display, gc, selected_border.pixel);
+    draw_zone (pixmap, selected_zone, 0, 1);  
 
-    translate_point (&zone_data[selected_zone].place_info[place].v, &point);
+    for (int place = 0; place < zone_data[selected_zone].num_places; place++)
+    {
+      XPoint point;
+
+      translate_point (&zone_data[selected_zone].place_info[place].v, &point);
     
-    draw_point (point, NULL);
+      draw_point (point, NULL);
 
-    if (place == selected_place)
-    {
-      char *underscore;
-      selected_point = point;
-      strcpy (selected_name, strchr (zone_data[selected_zone].place_info[place].zonename, '/') + 1);
-      while (underscore = strchr (selected_name, '_'))
-        underscore[0] = ' ';
+      if ((place == selected_place) && (!guessing_timezone))
+      {
+        char *underscore;
+        selected_point = point;
+        strcpy (selected_name, strchr (zone_data[selected_zone].place_info[place].zonename, '/') + 1);
+        while (underscore = strchr (selected_name, '_'))
+          underscore[0] = ' ';
+      }
     }
-  }
 
-  draw_point (selected_point, selected_name);
+    draw_point (selected_point, selected_name);
 
-  {
-    char zone_offset[100];
-    sprintf (zone_offset, "UTC%s", zone_data[selected_zone].offset);
-    draw_string (
-      ((width * 0.95 - XTextWidth (font, zone_offset, strlen (zone_offset))) +
-       ((width / 2) + radius / sqrt (2))) / 2, 
-      ((lrint (height * 0.05) + font->ascent) +
-       (height / 2 - radius / sqrt (2))) / 2, 
-      zone_offset, name_colour.pixel);
+    {
+      char zone_offset[100];
+      sprintf (zone_offset, "UTC%s", zone_data[selected_zone].offset);
+      draw_string (
+        ((width * 0.95 - XTextWidth (font, zone_offset, strlen (zone_offset))) +
+         ((width / 2) + radius / sqrt (2))) / 2, 
+        ((lrint (height * 0.05) + font->ascent) +
+         (height / 2 - radius / sqrt (2))) / 2, 
+        zone_offset, name_colour.pixel);
+    }
   }
   
   XCopyArea (display, pixmap, window, gc, 0, 0, width, height, 0, 0);
 }
 
-void select_place (int place)
-{
-  target_lon = atan2 (zone_data[selected_zone].place_info[place].v.y,
-               zone_data[selected_zone].place_info[place].v.x);
-  target_lat = acos (zone_data[selected_zone].place_info[place].v.z /2);
-
-  selected_place = place;
-}
-
 int nearest_z (double near_z)
 {
   double min_delta = 
@@ -417,31 +454,37 @@ void next_view ()
   double lat_error = target_lat - displayed_lat;
   double lon_error = target_lon - displayed_lon;
 
-  lat_error = atan2 (sin (lat_error), cos( lat_error));
-  lon_error = atan2 (sin (lon_error), cos (lon_error));
-
-  error_total = sqrt (lat_error * lat_error + lon_error * lon_error);
-      
-  if (error_total < acceleration)
+  if (guessing_timezone)
   {
-    displayed_lat = target_lat;
-    displayed_lon = target_lon;
+    displayed_lon += 1 / 180.0 * M_PI;
   }
   else
   {
-    if (error_total > (step_size + acceleration) * 
-                      (step_size + acceleration) / acceleration / 2)
-      step_size += acceleration;
+    lat_error = atan2 (sin (lat_error), cos( lat_error));
+    lon_error = atan2 (sin (lon_error), cos (lon_error));
+
+    error_total = sqrt (lat_error * lat_error + lon_error * lon_error);
+      
+    if (error_total < acceleration)
+    {
+      displayed_lat = target_lat;
+      displayed_lon = target_lon;
+    }
     else
-      step_size -= acceleration;
+    {
+      if (error_total > (step_size + acceleration) * 
+                        (step_size + acceleration) / acceleration / 2)
+        step_size += acceleration;
+      else
+        step_size -= acceleration;
       
-    if (step_size < acceleration)
-      step_size = acceleration;
+      if (step_size < acceleration)
+        step_size = acceleration;
     
-    displayed_lat += step_size * (lat_error / error_total);
-    displayed_lon += step_size * (lon_error / error_total);
+      displayed_lat += step_size * (lat_error / error_total);
+      displayed_lon += step_size * (lon_error / error_total);
+    }
   }
-
 }
 
 void *lirc_thread (void *unused)
@@ -493,6 +536,176 @@ void *lirc_thread (void *unused)
   }
 }
 
+void get_value (FILE *input, char*output, int out_len)
+{
+  const char *value_pattern = "value=\"";
+  char *value;
+
+  output[0] = 0;
+  fgets (output, out_len, input);
+
+  if (value = strcasestr (output, value_pattern))
+  {
+    memmove (output, value + strlen (value_pattern), 
+	     strlen (value + strlen (value_pattern)) + 1);
+  }
+
+  if (value = strchr (output, '"'))
+    value[0] = 0;
+}
+
+void *timezone_guess (void *unused)
+{
+  const double invalid = 99999;
+  FILE *guess_data;
+  char line_in[1000];
+  double guess_latitude = invalid;
+  double guess_longitude = invalid;
+  char guess_zone[1000] = {0};
+  char *timezone_info_command; 
+
+  if (getenv ("FAKE_GEOBYTES"))
+  {
+    timezone_info_command = 
+      "sleep 2 ; "
+      "echo Latitude ; "
+      "echo \" <td value=\\\"-34.993\\\"\" ;"
+      "echo Longitude ; "
+      "echo \" <td value=\\\"138.6\\\"\" ;"
+      "echo TimeZone ; "
+      "echo \" <td value=\\\"+09:30\\\"\"";
+  }
+  else
+  {
+    timezone_info_command = 
+      "wget http://www.geobytes.com/IpLocator.htm -O - 2> /dev/null |"
+      "grep \"^ <td \" |"
+      "grep -i -E -A1 \"Latitude|Longitude|TimeZone\" | grep -v \"^--$\"";
+  }
+
+  guess_data = popen (timezone_info_command, "r");
+
+  if (!guess_data)
+  {
+    fprintf (stderr, "error parsing web page for timezone guess\n");
+    guessing_timezone = FALSE;
+    return NULL;
+  }
+
+  while (fgets (line_in, sizeof (line_in), guess_data))
+  {
+    // Look for the entries in the guess data and then the next line 
+    // will hold the value.
+
+    if (strcasestr (line_in, "latitude"))
+    {
+      get_value (guess_data, line_in, sizeof (line_in));
+      sscanf (line_in, "%lf", &guess_latitude);
+    }
+    else if (strcasestr (line_in, "longitude"))
+    {
+      get_value (guess_data, line_in, sizeof (line_in));
+      sscanf (line_in, "%lf", &guess_longitude);
+    }
+    else if (strcasestr (line_in, "timezone"))
+    {
+      get_value (guess_data, line_in, sizeof (line_in));
+ 
+      // The geobytes timezone data is of the form "+09:30" whereas the
+      // map timezone data is of the form "+6" or "+9.5". Convert
+      // to the map timezone data format so we can find the timezone.
+
+      if (strcmp (&line_in[3], ":30") == 0)
+        sprintf (&line_in[3], ".5");
+      else
+	line_in[3] = 0;
+
+      if (line_in[1] == '0')
+        memmove (&line_in[1], &line_in[2], strlen (&line_in[2]) + 1);
+
+      strncpy (guess_zone, line_in, sizeof (guess_zone)); 
+    }
+  }
+
+  pclose (guess_data);
+
+  if ((guess_latitude != invalid) && 
+      (guess_longitude != invalid) &&
+      guess_zone[0] != 0) 
+  {
+    int zone;
+
+    fprintf (stderr, "guessed lat lon %f %f %s\n", 
+	     guess_latitude, guess_longitude, guess_zone);
+
+    // Look for the guessed zone in the zone_data structure.
+    for (zone = 0; zone < NUM_ZONES; zone++)
+    {
+      if (strcmp (guess_zone, zone_data[zone].offset) == 0)
+	break;
+    }
+
+    if (zone == NUM_ZONES)
+    {
+      fprintf (stderr, "couldnt find zone %s\n", guess_zone);
+      default_zone ("");
+    }
+    else
+    {
+      double x,y,z;
+      double min_dist_squared;
+      int closest_place;
+
+      // Look for the location in the zone nearest to the guess lat/lon.
+
+      // Convert the guessed lat/lon to x,y,z.
+
+      guess_latitude *= M_PI / 180.0;
+      guess_longitude *= M_PI / 180.0;
+
+      x = cos (guess_longitude) * cos (guess_latitude);
+      y = sin (guess_longitude) * cos (guess_latitude);
+      z = sin (guess_latitude);
+
+      min_dist_squared = 
+        pow (x - zone_data[zone].place_info[0].v.x, 2) + 
+        pow (y - zone_data[zone].place_info[0].v.y, 2) + 
+        pow (z - zone_data[zone].place_info[0].v.z, 2);
+      closest_place = 0;
+
+      for (int place = 1; place < zone_data[zone].num_places; place++)
+      {
+        double dist_squared;
+
+	dist_squared = 
+          pow (x - zone_data[zone].place_info[place].v.x, 2) + 
+          pow (y - zone_data[zone].place_info[place].v.y, 2) + 
+          pow (z - zone_data[zone].place_info[place].v.z, 2);
+
+        if (dist_squared < min_dist_squared)
+        {
+          closest_place = place;
+	  min_dist_squared = dist_squared;
+        }
+      }
+
+      fprintf (stderr, "Guess=%s %s\n", 
+	zone_data[zone].place_info[closest_place].zonename,
+	zone_data[zone].offset);
+
+      selected_zone = zone;
+      select_place (closest_place);
+    }
+  }
+  else
+  {
+    default_zone ("");
+  }
+  
+  guessing_timezone = FALSE;
+  return NULL;
+}
+
 void remove_titlebar_and_borders ()
 {
   XClassHint* classHint;
@@ -547,7 +760,7 @@ int main (int argc, char *argv[])
   int arg_width = -1;
   int arg_height = -1;
   char arg_zone[100] = {0};
-  
+
   if (getenv ("ACCEL"))
     acceleration = atof (getenv ("ACCEL"));
 
@@ -557,6 +770,13 @@ int main (int argc, char *argv[])
     {
       case 'z':
         strncpy (arg_zone, optarg, sizeof (arg_zone) - 1);
+
+	if (strcasecmp (arg_zone, "guess") == 0)
+	{
+	  guessing_timezone = TRUE;
+	  arg_zone[0]=0;
+	}
+
         break;
 
       case 'w':
@@ -574,14 +794,16 @@ int main (int argc, char *argv[])
       case '?':
         printf ("usage: %s [-a accelleration] [-z timezone] "
                 "[-w width] [-h height]\n"
-                "e.g. linhes_timezone -w 1920 -h 1090 -z Australia/Adelaide\n",
+                "e.g. linhes_timezone -w 1920 -h 1090 -z Australia/Adelaide\n"
+		"specify a timezone of 'guess' to determine the initial "
+		"timezone from\n"
+		"your ip address using geocache.\n",
           argv[0]);
         exit (0);
         break;
     }
   }
 
-
   pthread_create (&tid, NULL, lirc_thread, NULL);
 
   /* Connect to the X server. */
@@ -636,7 +858,6 @@ int main (int argc, char *argv[])
 
   remove_titlebar_and_borders ();
 
-
   if (!window) 
   {
     fprintf (stderr, "cannot open window\n");            
@@ -726,21 +947,21 @@ int main (int argc, char *argv[])
   if (XAllocColor (display, cmap, &location_dot) == 0)
     printf ("Cant allocate color\n");
 
-  // Find LA and make that the selected zone and place.
-  
-  for (int zone = 0; zone < NUM_ZONES; zone++)
+  // Find the selected timezone (or LA if a timezone was not selected) and 
+  // make that the selected zone and place.
+
+  default_zone (arg_zone);
+
+  if (guessing_timezone)
   {
-    for (int place = 0; place < zone_data[zone].num_places; place++)
-    {
-      if (strstr (zone_data[zone].place_info[place].zonename, 
-                  arg_zone[0] ? arg_zone : "Los_Angeles"))
-      {
-        selected_zone = zone;
-        select_place (place);
-        displayed_lat = target_lat;
-        displayed_lon = target_lon;
-      }
-    }
+    pthread_create (&tid, NULL, timezone_guess, NULL);
+    displayed_lat = M_PI/2;
+    displayed_lon = 0;
+  }
+  else
+  {
+    displayed_lat = target_lat;
+    displayed_lon = target_lon;
   }
 
   /* ask for exposure event and keyboard events */
@@ -753,7 +974,8 @@ int main (int argc, char *argv[])
     
   while (1)
   {
-    if ((displayed_lat != target_lat) || (displayed_lon != target_lon))
+    if ((displayed_lat != target_lat) || (displayed_lon != target_lon) || 
+        guessing_timezone)
     {
       next_view ();
       redraw_map ();
-- 
cgit v0.12