summaryrefslogtreecommitdiff
path: root/libgweather
diff options
context:
space:
mode:
authorBastien Nocera <hadess@hadess.net>2007-11-22 23:17:12 +0000
committerBastien Nocera <hadess@src.gnome.org>2007-11-22 23:17:12 +0000
commit32e0353d86ffc2df26b19608a680b19cfa3cc04f (patch)
treeb83dc88043b3a28c91e9851b189edf219ed5f50d /libgweather
parent09ba31d4c2742b14ac0a75e12e15ac9fc784cbb9 (diff)
downloadlibgweather-32e0353d86ffc2df26b19608a680b19cfa3cc04f.tar.gz
Add, mostly copied from gnome-applets
2007-11-22 Bastien Nocera <hadess@hadess.net> * Makefile.am: * autogen.sh: * configure.in: Add, mostly copied from gnome-applets 2007-11-22 Bastien Nocera <hadess@hadess.net> * *: Move and update from gnome-applets 2007-11-22 Bastien Nocera <hadess@hadess.net> * *: Import from gnome-applets trunk svn path=/trunk/; revision=3
Diffstat (limited to 'libgweather')
-rw-r--r--libgweather/AUTHORS5
-rw-r--r--libgweather/ChangeLog260
-rw-r--r--libgweather/Makefile.am72
-rw-r--r--libgweather/README7
-rw-r--r--libgweather/gweather-gconf.c259
-rw-r--r--libgweather/gweather-gconf.h75
-rw-r--r--libgweather/gweather-prefs.c296
-rw-r--r--libgweather/gweather-prefs.h53
-rw-r--r--libgweather/gweather.pc.in11
-rw-r--r--libgweather/gweather.schemas.in173
-rw-r--r--libgweather/test_metar.c78
-rw-r--r--libgweather/weather-bom.c125
-rw-r--r--libgweather/weather-iwin.c204
-rw-r--r--libgweather/weather-met.c238
-rw-r--r--libgweather/weather-metar.c590
-rw-r--r--libgweather/weather-priv.h211
-rw-r--r--libgweather/weather-sun.c247
-rw-r--r--libgweather/weather-wx.c128
-rw-r--r--libgweather/weather.c1090
-rw-r--r--libgweather/weather.h159
20 files changed, 4281 insertions, 0 deletions
diff --git a/libgweather/AUTHORS b/libgweather/AUTHORS
new file mode 100644
index 0000000..15f2d9f
--- /dev/null
+++ b/libgweather/AUTHORS
@@ -0,0 +1,5 @@
+The library:
+Philip Langdale <philipl@mail.utexas.edu>
+
+Almost all of the code is refactored from the gweather applet,
+so checkout that AUTHORS file too.
diff --git a/libgweather/ChangeLog b/libgweather/ChangeLog
new file mode 100644
index 0000000..50460e1
--- /dev/null
+++ b/libgweather/ChangeLog
@@ -0,0 +1,260 @@
+2007-11-22 Bastien Nocera <hadess@hadess.net>
+
+ * *: Import from gnome-applets trunk
+
+2007-11-16 Callum McKenzie <callum@spooky-possum.org>
+
+ * weather-iwin.c: Removed unused (#if 0) code, look in SVN if it
+ turns out to have been important. Prevent a random space appearing
+ in the forecast (patch from Michael Vrable, Bug #497204). Add a
+ bit of explanation about what that piece of code is trying to do.
+
+2007-11-04 Callum McKenzie <callum@spooky-possum.org>
+
+ * gweather-prefs.c: Change the guard #ifdefs for nl_langinfo stuff
+ so that autoconfig works correctly. Patch from Matthias Clasen
+ (Bug #491438). Also added an #ifdef around the langingo.h #include
+ in case the file isn't present at all (Mac OS X?).
+
+ * weather.c (weather_info_abort): Ensure the requests_pending flag
+ is cleared on abort. Another Matias Clasen special (Bug #491437).
+
+ * weather.h (weather_info_update): Remove a trailing ; from the
+ macro. Spotted by Matthias Clasen (Bug #491435).
+
+2007-10-13 Callum McKenzie <callum@spooky-possum.org>
+
+ * weather.c (temperature_string): Use appropriate unicode Degree
+ Celsius and Degree Fahrenheit symbols instead of the generic
+ Degree symbol. Patch from Alex Jones (Bug #468887).
+
+ * gweather.pc.in (Libs): Make sure the library is linked in. Patch
+ courtesy of Matthias Clasen (bug #479172). Also added -lm to the
+ libs list for completeness.
+
+2007-07-12 Callum McKenzie <callum@spooky-possum.org>
+
+ * weather-metar.c (make_time): Fix the logic to only fiddle the
+ day number on the 1st. Based on Elliott Hughes patch from bug
+ #455012. Improved comments.
+
+2007-07-11 Callum McKenzie <callum@spooky-possum.org>
+
+ * weather-sun.c (calc_sun): Use the current time rather than the
+ observation time to calculate the sunrise and sunset times. Fixes
+ the case where the observation gets horribly out of date. See bug
+ #455012.
+
+2007-05-13 Kjartan Maraas <kmaraas@gnome.org>
+
+ * Makefile.am: Add GNOME_APPLETS_CFLAGS to get
+ GConf includes. Fixes the build for me.
+
+2007-01-05 Kjartan Maraas <kmaraas@gnome.org>
+
+ * weather-met.c: s/malloc.h/stdlib.h/
+ Closes bug #387179. Patch from Roy Marples.
+
+2006-08-07 Davyd Madeley <davyd@madeley.id.au>
+
+ * weather-bom.c:
+ * weather-met.c:
+ - catch possible NULL pointers when parsing strings. Patches from
+ Kevin Bauder <kevin.bauder@gmail.com>. Closes #170628.
+
+2006-07-23 Davyd Madeley <davyd@madeley.id.au>
+
+ * gweather.schemas.in: update schema descriptions, patch from
+ Adam Petaccia. Closes #167195.
+
+2006-07-02 Kjartan Maraas <kmaraas@gnome.org>
+
+ * Makefile.am: Cygwin portability. Patch from Cygwin Ports Maintainer.
+ Closes bug #341495.
+
+2006-01-31 Davyd Madeley <davyd@madeley.id.au>
+
+ * weather.c: replace sscanf with g_strsplit to prevent stack smashing.
+ Closes original #327406.
+
+2006-01-17 Theppitak Karoonboonyanan <thep@linux.thai.net>
+
+ * gweather-prefs.c: add "atm" as possible unit in translator comment
+ for DEFAULT_PRESSURE_UNIT. Closes #327275.
+
+2006-01-15 Davyd Madeley <davyd@madeley.id.au>
+
+ * gweather-prefs.c:
+ * weather-priv.h:
+ * weather.c:
+ * weather.h: add atmospheres as a unit of pressure
+ Patch from Alexandros Frantzis <alfius@freemail.gr>. Closes
+ #325447.
+
+2006-01-15 Davyd Madeley <davyd@madeley.id.au>
+
+ * weather-sun.c: fix a crasher that was hinted to at a compiler
+ warning
+
+2006-01-15 Davyd Madeley <davyd@madeley.id.au>
+
+ * Makefile.am:
+ * test_metar.c: New program to test station report parsing
+ * weather-metar.c: (metar_parse): remove 'static'
+ * weather-priv.h: add metar_parse()
+
+ Patch from Frank Solensky <frank@solensky.org>. Closes #144792.
+
+2006-01-15 Davyd Madeley <davyd@madeley.id.au>
+
+ * weather.c:
+ * weather-priv.h: move prototype for calc_sun to header and remove
+ static declaration.
+
+2006-01-12 Frank Solensky <frank@solensky.org>
+
+ * Makefile.am:
+ * weather.h:
+ * weather.c:
+ * weather-sun.c: move sun calculations out to new source file
+
+2005-12-31 Davyd Madeley <davyd@madeley.id.au>
+
+ * weather-metar.c: (metar_tok_temp):
+ * weather.c: (calc_humidity): dewpoint is optional
+ Closes gweather bug 172711. Patch from Frank Solensky
+ <frank@solensky.org>
+
+ * gweather-gconf.c: looks like the last commit stopped this compiling,
+ fixed it up
+
+2005-12-31 Simos Xenitellis <simos@gnome.org>
+
+ * gweather-gconf.c: Added translator comments for the DEFAULT_*
+ strings, the strings to specify the default location per locale.
+
+2005-12-11 Philip Langdale <philipl@mail.utexas.edu>
+
+ A gweather-gconf.c
+ A gweather-gconf.h
+ A gweather-prefs.c
+ A gweather-prefs.h
+ A gweather.schemas.in: Merge libgweatherprefs into
+ libgweather. The extra library isn't worth the hassle
+ considering that gconf is already a dependency of
+ libgweather and we currently have no clients that want
+ the backend without the prefs.
+
+ I have merged the libgweathepref ChangeLong entries.
+
+ * .cvsignore
+ * ChangeLog
+ * Makefile.am
+ * README
+ * weather-iwin.c
+ * weather-metar.c
+ * weather-wx.c
+ * weather.c: Update to reflect the merged files.
+
+ A AUTHORS:
+ R MAINTAINERS: A more accurate description of what
+ I want to claim at this time. :-)
+
+2005-12-04 Philip Langdale <philipl@mail.utexas.edu>
+
+ * gweather-gconf.c
+ * gweather-gconf.h: Add gweather_gconf_get_client
+ to provide access to the GConfClient.
+
+ * gweather-prefs.c: make gweather_prefs_load work
+ correctly when called multiple times. The old
+ radar url was not previously being freed.
+
+2005-11-27 Philip Langdale <philipl@mail.utexas.edu>
+
+ Initial checkin of libgweatherprefs.
+
+ A .cvsignore
+ A ChangeLog
+ A MAINTAINERS
+ A Makefile.am
+ A README: Usual building blocks.
+
+ A gweather.schemas.in: Brought the schemas over
+ unchanged from gweather.
+
+ A gweatherprefs.pc.in: pkgconfig descriptor.
+
+ A gweather-gconf.c
+ A gweather-gconf.h: Primarily, this encapsulates
+ the 'current path' notion in an identical way
+ to libpanelapplet. It is also the new home of
+ 'weather_location_config_read' which files out
+ a WeatherLocation struct based on the values in
+ gconf.
+
+ A gweather-prefs.c
+ A gweather-prefs.h: This is, essentially unchanged,
+ the 'gweather_pref_load' function along with the
+ enum-to-string helpers it depends on. Obviously
+ the gconf access now uses the gweather-gconf
+ methods rather than the panel applet ones.
+
+2005-11-27 Philip Langdale <philipl@mail.utexas.edu>
+
+ A .cvsignore:
+ A Makefile.am: The things no self respecting directory
+ can be without.
+
+ A gweather.pc.in: pkgconfig descriptor.
+
+ * weather.c: Remove entanglement with the gweather applet:
+ - Introduce a simple WeatherPrefs struct to replace the
+ direct gconf access. The caller can set these prefs as
+ they wish (reading from gconf is obviously a possibility).
+ This struct also encapsulates the two odd-man-out global
+ variables - so the library is now safe for multiple
+ instances of WeatherInfo.
+ - Actually use the WeatherInfoFunc callback instead of
+ hardcoding the applet callback.
+ - Refactor the cancelling of an outstanding retrieval
+ into a public abort method.
+ - Update the weather_info_[new|update] methods to take
+ the WeatherPrefs parameter and return the WeatherInfo
+ rather than directly storing it in GWeatherApplet.
+ The boolean return semantics are retained in that
+ NULL will be returned if the call fails.
+
+ A weather-priv.h
+ * weather.h: The refactored header. Now private calls
+ and the WeatherInfo definition are actually kept private.
+ Gratuitous 'extern' keywords removed.
+
+ * weather-bom.c
+ * weather-iwin.c
+ * weather-met.c
+ * weather-metar.c
+ * weather-wx.c: The service-specific backend files are
+ only minimally modified:
+ - Added Copyright header from weather.c
+ - Fixed any warnings reported by -Wall
+ - Included weather-priv.h
+ - Minimised required header set
+ - Updated to reflect that WeatherInfo is passed as
+ callback data instead of GWeatherApplet.
+
+2005-11-27 Philip Langdale <philipl@mail.utexas.edu>
+
+ * ChangeLog
+ * MAINTAINERS
+ * README
+ * weather-bom.c
+ * weather.c
+ * weather.h
+ * weather-iwin.c
+ * weather-metar.c
+ * weather-met.c
+ * weather-wx.c: Initial checkin of libgweather.
+ I'm checking these in first so that there's a an easy way
+ to see the diff to the versions of these files that actually
+ compile.
diff --git a/libgweather/Makefile.am b/libgweather/Makefile.am
new file mode 100644
index 0000000..a41601e
--- /dev/null
+++ b/libgweather/Makefile.am
@@ -0,0 +1,72 @@
+LIBRARY_VERSION = 0:0:0
+
+lib_LTLIBRARIES = libgweather.la
+
+libgweatherincdir = $(includedir)/libgweather
+libgweatherinc_HEADERS = weather.h gweather-gconf.h gweather-prefs.h
+
+pkgconfigdir = $(libdir)/pkgconfig
+pkgconfig_DATA = gweather.pc
+
+libgweather_la_SOURCES = \
+ weather.c weather.h weather-priv.h \
+ weather-metar.c weather-iwin.c weather-met.c \
+ weather-bom.c weather-wx.c \
+ weather-sun.c \
+ gweather-prefs.c gweather-prefs.h \
+ gweather-gconf.c gweather-gconf.h
+
+libgweather_la_CFLAGS = \
+ -I$(top_srcdir) \
+ -I$(srcdir) \
+ $(WARN_CFLAGS) \
+ $(GTK_CFLAGS) \
+ $(GNOME_VFS_APPLETS_CFLAGS) \
+ $(GNOME_APPLETS_CFLAGS) \
+ -DG_LOG_DOMAIN=\"GWeather\" \
+ -DGNOMELOCALEDIR=\""$(datadir)/locale"\"
+
+libgweather_la_LIBADD = \
+ $(GTK_LIBS) \
+ $(GNOME_VFS_APPLETS_LIBS)
+
+libgweather_la_LDFLAGS = \
+ -version-info $(LIBRARY_VERSION) -no-undefined
+
+test_metar_SOURCES = test_metar.c
+
+test_metar_CFLAGS = \
+ -I$(top_srcdir) \
+ -I$(srcdir) \
+ $(WARN_CFLAGS) \
+ $(GTK_CFLAGS) \
+ $(GNOME_APPLETS_CFLAGS) \
+ $(GNOME_VFS_APPLETS_CFLAGS) \
+ -DG_LOG_DOMAIN=\"GWeather\"
+
+test_metar_LDADD = \
+ $(GNOME_APPLETS_LIB) \
+ $(GNOME_VFS_APPLETS_LIB) \
+ libgweather.la
+
+noinst_HEADERS = weather-priv.h
+noinst_PROGRAMS = test_metar
+
+schemasdir = @GCONF_SCHEMA_FILE_DIR@
+schemas_in_files = gweather.schemas.in
+schemas_DATA = $(schemas_in_files:.schemas.in=.schemas)
+
+@INTLTOOL_SCHEMAS_RULE@
+
+if GCONF_SCHEMAS_INSTALL
+install-data-local:
+ GCONF_CONFIG_SOURCE=$(GCONF_SCHEMA_CONFIG_SOURCE) $(GCONFTOOL) --makefile-install-rule $(schemas_DATA) ;
+uninstall-local:
+ GCONF_CONFIG_SOURCE=$(GCONF_SCHEMA_CONFIG_SOURCE) $(GCONFTOOL) --makefile-uninstall-rule $(schemas_DATA) ;
+endif
+
+EXTRA_DIST = gweather.pc.in $(schemas_in_files)
+
+EXTRA_PROGRAMS = test_metar
+
+CLEANFILES = $(schemas_DATA) $(EXTRA_PROGRAMS)
diff --git a/libgweather/README b/libgweather/README
new file mode 100644
index 0000000..989c0cd
--- /dev/null
+++ b/libgweather/README
@@ -0,0 +1,7 @@
+libgweather
+-----------
+
+libgweather is the retrieval backend from the gweather gnome-applet.
+It's generally useful for applications that need to get weather
+information. It also includes helper functions to access the gweather
+gconf schema.
diff --git a/libgweather/gweather-gconf.c b/libgweather/gweather-gconf.c
new file mode 100644
index 0000000..af4c063
--- /dev/null
+++ b/libgweather/gweather-gconf.c
@@ -0,0 +1,259 @@
+/*
+ * gweather-gconf.c: GConf interaction methods for gweather.
+ *
+ * Copyright (C) 2005 Philip Langdale, Papadimitriou Spiros
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Authors:
+ * Philip Langdale <philipl@mail.utexas.edu>
+ * Papadimitriou Spiros <spapadim+@cs.cmu.edu>
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <string.h>
+#include <glib/gi18n-lib.h>
+#include <libgweather/gweather-gconf.h>
+
+struct _GWeatherGConf
+{
+ GConfClient *gconf;
+ char *prefix;
+};
+
+
+GWeatherGConf *
+gweather_gconf_new(const char *prefix)
+{
+ GWeatherGConf *ctx = g_new0(GWeatherGConf, 1);
+ ctx->gconf = gconf_client_get_default();
+ ctx->prefix = g_strdup(prefix);
+
+ return ctx;
+}
+
+
+void
+gweather_gconf_free(GWeatherGConf *ctx)
+{
+ g_object_unref(ctx->gconf);
+ g_free(ctx->prefix);
+ g_free(ctx);
+}
+
+
+GConfClient *
+gweather_gconf_get_client(GWeatherGConf *ctx)
+{
+ return ctx->gconf;
+}
+
+
+gchar *
+gweather_gconf_get_full_key (GWeatherGConf *ctx,
+ const gchar *key)
+{
+ return g_strdup_printf ("%s/%s", ctx->prefix, key);
+}
+
+void
+gweather_gconf_set_bool (GWeatherGConf *ctx,
+ const gchar *key,
+ gboolean the_bool,
+ GError **opt_error)
+{
+ gchar *full_key = gweather_gconf_get_full_key (ctx, key);
+ gconf_client_set_bool (ctx->gconf, full_key, the_bool, opt_error);
+ g_free (full_key);
+}
+
+void
+gweather_gconf_set_int (GWeatherGConf *ctx,
+ const gchar *key,
+ gint the_int,
+ GError **opt_error)
+{
+ gchar *full_key = gweather_gconf_get_full_key (ctx, key);
+ gconf_client_set_int (ctx->gconf, full_key, the_int, opt_error);
+ g_free (full_key);
+}
+
+void
+gweather_gconf_set_string (GWeatherGConf *ctx,
+ const gchar *key,
+ const gchar *the_string,
+ GError **opt_error)
+{
+ gchar *full_key = gweather_gconf_get_full_key (ctx, key);
+ gconf_client_set_string (ctx->gconf, full_key, the_string, opt_error);
+ g_free (full_key);
+}
+
+gboolean
+gweather_gconf_get_bool (GWeatherGConf *ctx,
+ const gchar *key,
+ GError **opt_error)
+{
+ gchar *full_key = gweather_gconf_get_full_key (ctx, key);
+ gboolean ret = gconf_client_get_bool (ctx->gconf, full_key, opt_error);
+ g_free (full_key);
+ return ret;
+}
+
+gint
+gweather_gconf_get_int (GWeatherGConf *ctx,
+ const gchar *key,
+ GError **opt_error)
+{
+ gchar *full_key = gweather_gconf_get_full_key (ctx, key);
+ gint ret = gconf_client_get_int (ctx->gconf, full_key, opt_error);
+ g_free (full_key);
+ return ret;
+}
+
+gchar *
+gweather_gconf_get_string (GWeatherGConf *ctx,
+ const gchar *key,
+ GError **opt_error)
+{
+ gchar *full_key = gweather_gconf_get_full_key (ctx, key);
+ gchar *ret = gconf_client_get_string (ctx->gconf, full_key, opt_error);
+ g_free (full_key);
+ return ret;
+}
+
+
+WeatherLocation *
+gweather_gconf_get_location(GWeatherGConf *ctx)
+{
+ WeatherLocation *location;
+ gchar *name, *code, *zone, *radar, *coordinates;
+
+ name = gweather_gconf_get_string (ctx, "location4", NULL);
+ if (!name)
+ {
+ /* TRANSLATOR: Change this to the default location name,
+ * used when you first start the Weather Applet. This is
+ * the common localised name that corresponds to
+ * the location code (DEFAULT_CODE) you will put on the next message
+ * For example, for the Greek locale, we set this to "Athens", the
+ * capital city and we write it in Greek. It's important to translate
+ * this name.
+ *
+ * If you do not require a DEFAULT_LOCATION, set this to
+ * "DEFAULT_LOCATION".
+ */
+ if (strcmp ("DEFAULT_LOCATION", _("DEFAULT_LOCATION")))
+ name = g_strdup (_("DEFAULT_LOCATION"));
+ else
+ name = g_strdup ("Pittsburgh");
+ }
+
+ code = gweather_gconf_get_string (ctx, "location1", NULL);
+ if (!code)
+ {
+ /* TRANSLATOR: Change this to the code of your default location that
+ * corresponds to the DEFAULT_LOCATION name you put above. This is
+ * normally a four-letter (ICAO) code and can be found in
+ * http://cvs.gnome.org/viewcvs/gnome-applets/gweather/Locations.xml.in
+ * NB. The web page is over 1.7MB in size.
+ * Pick a default location like a capital city so that it would be ok
+ * for more of your users. For example, for Greek, we use "LGAV" for
+ * the capital city, Athens.
+ *
+ * If you do not require a DEFAULT_CODE, set this to "DEFAULT_CODE".
+ */
+ if (strcmp ("DEFAULT_CODE", _("DEFAULT_CODE")))
+ code = g_strdup (_("DEFAULT_CODE"));
+ else
+ code = g_strdup ("KPIT");
+ }
+
+ zone = gweather_gconf_get_string (ctx, "location2", NULL);
+ if (!zone)
+ {
+ /* TRANSLATOR: Change this to the zone of your default location that
+ * corresponds to the DEFAULT_LOCATION and DEFAULT_CODE you put above.
+ * Normally, US and Canada locations have zones while the rest do not.
+ * Check
+ * http://cvs.gnome.org/viewcvs/gnome-applets/gweather/Locations.xml.in
+ * as any zone you put here must also be present in the Locations.xml
+ * file.
+ *
+ * If your default location does not have a zone, set this to
+ * "DEFAULT_ZONE".
+ */
+ if (strcmp ("DEFAULT_ZONE", _("DEFAULT_ZONE")))
+ zone = g_strdup (_("DEFAULT_ZONE" ));
+ else
+ zone = g_strdup ("PAZ021");
+ }
+
+ radar = gweather_gconf_get_string(ctx, "location3", NULL);
+ if (!radar)
+ {
+ /* TRANSLATOR: Change this to the radar of your default location that
+ * corresponds to the DEFAULT_LOCATION and DEFAULT_CODE you put above.
+ * Normally, US and Canada locations have radar names while the rest do
+ * not. Check
+ * http://cvs.gnome.org/viewcvs/gnome-applets/gweather/Locations.xml.in
+ * as any radar you put here must also be present in the Locations.xml
+ * file.
+ *
+ * If your default location does not have a radar, set this to " "
+ * (or space).
+ * If you do not have a default location, set this to DEFAULT_RADAR.
+ */
+ if (strcmp ("DEFAULT_RADAR", _("DEFAULT_RADAR")))
+ radar = g_strdup (_("DEFAULT_RADAR"));
+ else
+ radar = g_strdup ("pit");
+ }
+
+ coordinates = gweather_gconf_get_string (ctx, "coordinates", NULL);
+ if (!coordinates)
+ {
+ /* TRANSLATOR: Change this to the coordinates of your default location
+ * that corresponds to the DEFAULT_LOCATION and DEFAULT_CODE you put
+ * above. Check
+ * http://cvs.gnome.org/viewcvs/gnome-applets/gweather/Locations.xml.in
+ * as any coordinates you put here must also be present in the
+ * Locations.xml file.
+ *
+ * If your default location does not have known coordinates, set this
+ * to " " (or space).
+ * If you do not have a default location, set this to
+ * DEFAULT_COORDINATES.
+ */
+ if (strcmp ("DEFAULT_COORDINATES", _("DEFAULT_COORDINATES")))
+ coordinates = g_strdup (_("DEFAULT_COORDINATES"));
+ else
+ coordinates = g_strdup ("40-32N 080-13W");
+ }
+
+ location = weather_location_new (name, code, zone, radar, coordinates);
+
+ g_free (name);
+ g_free (code);
+ g_free (zone);
+ g_free (radar);
+ g_free (coordinates);
+
+ return location;
+}
diff --git a/libgweather/gweather-gconf.h b/libgweather/gweather-gconf.h
new file mode 100644
index 0000000..e5446a2
--- /dev/null
+++ b/libgweather/gweather-gconf.h
@@ -0,0 +1,75 @@
+/*
+ * gweather-gconf.h: GConf interaction methods for gweather.
+ *
+ * Copyright (C) 2005 Philip Langdale, Papadimitriou Spiros
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Authors:
+ * Philip Langdale <philipl@mail.utexas.edu>
+ * Papadimitriou Spiros <spapadim+@cs.cmu.edu>
+ */
+
+#ifndef __GWEATHER_GCONF_WRAPPER_H__
+#define __GWEATHER_GCONF_WRAPPER_H__
+
+#include <glib/gmacros.h>
+#include <glib/gerror.h>
+#include <gconf/gconf-client.h>
+#include <gconf/gconf-value.h>
+
+#include <libgweather/weather.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GWeatherGConf GWeatherGConf;
+
+GWeatherGConf * gweather_gconf_new (const char *prefix);
+void gweather_gconf_free (GWeatherGConf *ctx);
+
+GConfClient * gweather_gconf_get_client (GWeatherGConf *ctx);
+
+WeatherLocation * gweather_gconf_get_location (GWeatherGConf *ctx);
+
+gchar * gweather_gconf_get_full_key (GWeatherGConf *ctx,
+ const gchar *key);
+
+void gweather_gconf_set_bool (GWeatherGConf *ctx,
+ const gchar *key,
+ gboolean the_bool,
+ GError **opt_error);
+void gweather_gconf_set_int (GWeatherGConf *ctx,
+ const gchar *key,
+ gint the_int,
+ GError **opt_error);
+void gweather_gconf_set_string (GWeatherGConf *ctx,
+ const gchar *key,
+ const gchar *the_string,
+ GError **opt_error);
+
+gboolean gweather_gconf_get_bool (GWeatherGConf *ctx,
+ const gchar *key,
+ GError **opt_error);
+gint gweather_gconf_get_int (GWeatherGConf *ctx,
+ const gchar *key,
+ GError **opt_error);
+gchar * gweather_gconf_get_string (GWeatherGConf *ctx,
+ const gchar *key,
+ GError **opt_error);
+
+G_END_DECLS
+
+#endif /* __GWEATHER_GCONF_WRAPPER_H__ */
diff --git a/libgweather/gweather-prefs.c b/libgweather/gweather-prefs.c
new file mode 100644
index 0000000..d24e180
--- /dev/null
+++ b/libgweather/gweather-prefs.c
@@ -0,0 +1,296 @@
+/*
+ * Papadimitriou Spiros <spapadim+@cs.cmu.edu>
+ *
+ * This code released under the GNU GPL.
+ * Read the file COPYING for more information.
+ *
+ * Preference handling functions.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#ifdef HAVE__NL_MEASUREMENT_MEASUREMENT
+#include <langinfo.h>
+#endif
+
+#include <glib/gi18n-lib.h>
+#include <gconf/gconf-client.h>
+#include <libgweather/gweather-prefs.h>
+
+static GConfEnumStringPair temp_unit_enum_map [] = {
+ { TEMP_UNIT_DEFAULT, "Default" },
+ { TEMP_UNIT_KELVIN, "K" },
+ { TEMP_UNIT_CENTIGRADE, "C" },
+ { TEMP_UNIT_FAHRENHEIT, "F" },
+ { 0, NULL }
+};
+
+static GConfEnumStringPair speed_unit_enum_map [] = {
+ { SPEED_UNIT_DEFAULT, "Default" },
+ { SPEED_UNIT_MS, "m/s" },
+ { SPEED_UNIT_KPH, "km/h" },
+ { SPEED_UNIT_MPH, "mph" },
+ { SPEED_UNIT_KNOTS, "knots" },
+ { SPEED_UNIT_BFT, "Beaufort scale" },
+ { 0, NULL }
+};
+
+static GConfEnumStringPair pressure_unit_enum_map [] = {
+ { PRESSURE_UNIT_DEFAULT, "Default" },
+ { PRESSURE_UNIT_KPA, "kPa" },
+ { PRESSURE_UNIT_HPA, "hPa" },
+ { PRESSURE_UNIT_MB, "mb" },
+ { PRESSURE_UNIT_MM_HG, "mmHg" },
+ { PRESSURE_UNIT_INCH_HG, "inHg" },
+ { PRESSURE_UNIT_ATM, "atm" },
+ { 0, NULL }
+};
+
+static GConfEnumStringPair distance_unit_enum_map [] = {
+ { DISTANCE_UNIT_DEFAULT, "Default" },
+ { DISTANCE_UNIT_METERS, "m" },
+ { DISTANCE_UNIT_KM, "km" },
+ { DISTANCE_UNIT_MILES, "mi" },
+ { 0, NULL }
+};
+
+
+static void parse_temp_string (const gchar *gconf_str, GWeatherPrefs *prefs)
+{
+ gint value = 0;
+#ifdef HAVE__NL_MEASUREMENT_MEASUREMENT
+ char *imperial = NULL;
+#endif
+
+ prefs->use_temperature_default = TRUE;
+
+ if ( gconf_str && gconf_string_to_enum (temp_unit_enum_map, gconf_str, &value) ) {
+ prefs->temperature_unit = value;
+
+ if ((prefs->temperature_unit == TEMP_UNIT_DEFAULT) &&
+ (gconf_string_to_enum (temp_unit_enum_map, _("DEFAULT_TEMP_UNIT"), &value)) ) {
+ prefs->temperature_unit = value;
+ } else {
+ prefs->use_temperature_default = FALSE;
+ }
+ }
+ else {
+ /* TRANSLATOR: This is the default unit to use for temperature measurements. */
+ /* Valid values are: "K" (Kelvin), "C" (Celsius) and "F" (Fahrenheit) */
+ if (gconf_string_to_enum (temp_unit_enum_map, _("DEFAULT_TEMP_UNIT"), &value) ) {
+ prefs->temperature_unit = value;
+ }
+ }
+ if (!prefs->temperature_unit || prefs->temperature_unit == TEMP_UNIT_DEFAULT ) {
+#ifdef HAVE__NL_MEASUREMENT_MEASUREMENT
+ imperial = nl_langinfo(_NL_MEASUREMENT_MEASUREMENT);
+ if ( imperial && imperial[0] == 2 ) {
+ /* imperial */
+ prefs->temperature_unit = TEMP_UNIT_FAHRENHEIT;
+ } else
+#endif
+ prefs->temperature_unit = TEMP_UNIT_CENTIGRADE;
+ }
+}
+
+static void parse_speed_string (const gchar *gconf_str, GWeatherPrefs *prefs)
+{
+ gint value = 0;
+#ifdef HAVE__NL_MEASUREMENT_MEASUREMENT
+ char *imperial = NULL;
+#endif
+
+ prefs->use_speed_default = TRUE;
+
+ if ( gconf_str && gconf_string_to_enum (speed_unit_enum_map, gconf_str, &value) ) {
+ prefs->speed_unit = value;
+ if ((prefs->speed_unit == SPEED_UNIT_DEFAULT) &&
+ (gconf_string_to_enum (speed_unit_enum_map, _("DEFAULT_SPEED_UNIT"), &value)) ) {
+ prefs->speed_unit = value;
+ } else {
+ prefs->use_speed_default = FALSE;
+ }
+ }
+ else {
+ /* TRANSLATOR: This is the default unit to use for wind speed. */
+ /* Valid values are: "m/s" (meters per second), "km/h" (kilometers per hour), */
+ /* "mph" (miles per hour) and "knots" */
+ if (gconf_string_to_enum (speed_unit_enum_map, _("DEFAULT_SPEED_UNIT"), &value) ) {
+ prefs->speed_unit = value;
+ }
+ }
+ if ( (!prefs->speed_unit) || prefs->speed_unit == SPEED_UNIT_DEFAULT ) {
+#ifdef HAVE__NL_MEASUREMENT_MEASUREMENT
+ imperial = nl_langinfo(_NL_MEASUREMENT_MEASUREMENT);
+ if ( imperial && imperial[0] == 2 ) {
+ /* imperial */
+ prefs->speed_unit = SPEED_UNIT_KNOTS;
+ } else
+#endif
+ prefs->speed_unit = SPEED_UNIT_MS;
+ }
+}
+
+
+static void parse_pressure_string (const gchar *gconf_str, GWeatherPrefs *prefs)
+{
+ gint value = 0;
+#ifdef _NL_MEASUREMENT_MEASUREMENT
+ char *imperial = NULL;
+#endif
+
+ prefs->use_pressure_default = TRUE;
+
+ if ( gconf_str && gconf_string_to_enum (pressure_unit_enum_map, gconf_str, &value) ) {
+ prefs->pressure_unit = value;
+
+ if ((prefs->pressure_unit == PRESSURE_UNIT_DEFAULT) &&
+ (gconf_string_to_enum (pressure_unit_enum_map, _("DEFAULT_PRESSURE_UNIT"), &value)) ) {
+ prefs->pressure_unit = value;
+ } else {
+ prefs->use_pressure_default = FALSE;
+ }
+ }
+ else {
+ /* TRANSLATOR: This is the default unit to use for atmospheric pressure. */
+ /* Valid values are: "kPa" (kiloPascals), "hPa" (hectoPascals),
+ "mb" (millibars), "mmHg" (millimeters of mercury),
+ "inHg" (inches of mercury) and "atm" (atmosphere) */
+ if (gconf_string_to_enum (pressure_unit_enum_map, _("DEFAULT_PRESSURE_UNIT"), &value) ) {
+ prefs->pressure_unit = value;
+ }
+ }
+ if ( (!prefs->pressure_unit) || prefs->pressure_unit == PRESSURE_UNIT_DEFAULT ) {
+#ifdef _NL_MEASUREMENT_MEASUREMENT
+ imperial = nl_langinfo(_NL_MEASUREMENT_MEASUREMENT);
+ if ( imperial && imperial[0] == 2 ) {
+ /* imperial */
+ prefs->pressure_unit = PRESSURE_UNIT_INCH_HG;
+ } else
+#endif
+ prefs->pressure_unit = PRESSURE_UNIT_HPA;
+ }
+}
+
+static void parse_distance_string (const gchar *gconf_str, GWeatherPrefs *prefs)
+{
+ gint value = 0;
+#ifdef _NL_MEASUREMENT_MEASUREMENT
+ char *imperial = NULL;
+#endif
+
+ prefs->use_distance_default = TRUE;
+ if ( gconf_str && gconf_string_to_enum (distance_unit_enum_map, gconf_str, &value) ) {
+ prefs->distance_unit = value;
+
+ if ((prefs->distance_unit == DISTANCE_UNIT_DEFAULT) &&
+ (gconf_string_to_enum (distance_unit_enum_map, _("DEFAULT_DISTANCE_UNIT"), &value)) ) {
+ prefs->distance_unit = value;
+ } else {
+ prefs->use_distance_default = FALSE;
+ }
+ }
+ else {
+ /* TRANSLATOR: This is the default unit to use for visibility distance. */
+ /* Valid values are: "m" (meters), "km" (kilometers) and "mi" (miles) */
+ if (gconf_string_to_enum (distance_unit_enum_map, _("DEFAULT_DISTANCE_UNIT"), &value) ) {
+ prefs->distance_unit = value;
+ }
+ }
+
+ if ((!prefs->distance_unit) || prefs->distance_unit == DISTANCE_UNIT_DEFAULT ) {
+#ifdef _NL_MEASUREMENT_MEASUREMENT
+ imperial = nl_langinfo(_NL_MEASUREMENT_MEASUREMENT);
+ if ( imperial && imperial[0] == 2 ) {
+ /* imperial */
+ prefs->distance_unit = DISTANCE_UNIT_MILES;
+ } else
+#endif
+ prefs->distance_unit = DISTANCE_UNIT_METERS;
+ }
+
+ return;
+}
+
+const char *gweather_prefs_temp_enum_to_string (TempUnit temp)
+{
+ return gconf_enum_to_string(temp_unit_enum_map, temp);
+}
+
+const char *gweather_prefs_speed_enum_to_string (SpeedUnit speed)
+{
+ return gconf_enum_to_string(speed_unit_enum_map, speed);
+}
+
+const char *gweather_prefs_pressure_enum_to_string (PressureUnit pressure)
+{
+ return gconf_enum_to_string(pressure_unit_enum_map, pressure);
+}
+
+const char *gweather_prefs_distance_enum_to_string (DistanceUnit distance)
+{
+ return gconf_enum_to_string(distance_unit_enum_map, distance);
+}
+
+
+void gweather_prefs_load (GWeatherPrefs *prefs, GWeatherGConf *ctx)
+{
+ GError *error = NULL;
+ gchar *gconf_str = NULL;
+
+ if (prefs->location) {
+ weather_location_free(prefs->location);
+ }
+ prefs->location = gweather_gconf_get_location(ctx);
+
+ /* Assume we use unit defaults */
+ prefs->use_temperature_default = TRUE;
+ prefs->use_speed_default = TRUE;
+ prefs->use_pressure_default = TRUE;
+ prefs->use_distance_default = TRUE;
+
+ prefs->update_interval =
+ gweather_gconf_get_int(ctx, "auto_update_interval", &error);
+ if (error) {
+ g_print ("%s \n", error->message);
+ g_error_free (error);
+ error = NULL;
+ }
+ prefs->update_interval = MAX (prefs->update_interval, 60);
+ prefs->update_enabled =
+ gweather_gconf_get_bool(ctx, "auto_update", NULL);
+ prefs->detailed =
+ gweather_gconf_get_bool(ctx, "enable_detailed_forecast", NULL);
+ prefs->radar_enabled =
+ gweather_gconf_get_bool(ctx, "enable_radar_map", NULL);
+ prefs->use_custom_radar_url =
+ gweather_gconf_get_bool(ctx, "use_custom_radar_url", NULL);
+
+ if (prefs->radar) {
+ g_free(prefs->radar);
+ prefs->radar = NULL;
+ }
+ prefs->radar = gweather_gconf_get_string (ctx, "radar", NULL);
+
+ gconf_str = gweather_gconf_get_string (ctx, GCONF_TEMP_UNIT, NULL);
+ parse_temp_string(gconf_str, prefs);
+ g_free (gconf_str);
+
+ gconf_str = gweather_gconf_get_string (ctx, GCONF_SPEED_UNIT, NULL);
+ parse_speed_string(gconf_str, prefs);
+ g_free (gconf_str);
+
+ gconf_str = gweather_gconf_get_string (ctx, GCONF_PRESSURE_UNIT, NULL);
+ parse_pressure_string(gconf_str, prefs);
+ g_free (gconf_str);
+
+ gconf_str = gweather_gconf_get_string (ctx, GCONF_DISTANCE_UNIT, NULL);
+ parse_distance_string(gconf_str, prefs);
+ g_free (gconf_str);
+
+ return;
+}
+
diff --git a/libgweather/gweather-prefs.h b/libgweather/gweather-prefs.h
new file mode 100644
index 0000000..44824ff
--- /dev/null
+++ b/libgweather/gweather-prefs.h
@@ -0,0 +1,53 @@
+/*
+ * Papadimitriou Spiros <spapadim+@cs.cmu.edu>
+ *
+ * This code released under the GNU GPL.
+ * Read the file COPYING for more information.
+ *
+ * Preference handling functions.
+ *
+ */
+
+#ifndef __GWEATHER_PREFS_H_
+#define __GWEATHER_PREFS_H_
+
+#include <libgweather/weather.h>
+#include <libgweather/gweather-gconf.h>
+
+/* gconf keys */
+#define GCONF_TEMP_UNIT "temperature_unit"
+#define GCONF_SPEED_UNIT "speed_unit"
+#define GCONF_PRESSURE_UNIT "pressure_unit"
+#define GCONF_DISTANCE_UNIT "distance_unit"
+
+typedef struct _GWeatherPrefs GWeatherPrefs;
+
+struct _GWeatherPrefs {
+ WeatherLocation *location;
+ gint update_interval; /* in seconds */
+ gboolean update_enabled;
+ gboolean detailed;
+ gboolean radar_enabled;
+ gboolean use_custom_radar_url;
+ gchar *radar;
+
+ TempUnit temperature_unit;
+ gboolean use_temperature_default;
+ SpeedUnit speed_unit;
+ gboolean use_speed_default;
+ PressureUnit pressure_unit;
+ gboolean use_pressure_default;
+ DistanceUnit distance_unit;
+ gboolean use_distance_default;
+};
+
+void gweather_prefs_load (GWeatherPrefs *prefs,
+ GWeatherGConf *ctx);
+
+const char * gweather_prefs_temp_enum_to_string (TempUnit temp);
+const char * gweather_prefs_speed_enum_to_string (SpeedUnit speed);
+const char * gweather_prefs_pressure_enum_to_string (PressureUnit pressure);
+const char * gweather_prefs_distance_enum_to_string (DistanceUnit distance);
+
+
+#endif /* __GWEATHER_PREFS_H_ */
diff --git a/libgweather/gweather.pc.in b/libgweather/gweather.pc.in
new file mode 100644
index 0000000..d9aaf00
--- /dev/null
+++ b/libgweather/gweather.pc.in
@@ -0,0 +1,11 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: GWeather
+Description: GWeather shared library
+Version: @VERSION@
+Requires: gtk+-2.0, gnome-vfs-2.0
+Libs: -L${libdir} -lgweather -lm
+Cflags: -I${includedir}
diff --git a/libgweather/gweather.schemas.in b/libgweather/gweather.schemas.in
new file mode 100644
index 0000000..424b6f4
--- /dev/null
+++ b/libgweather/gweather.schemas.in
@@ -0,0 +1,173 @@
+<gconfschemafile>
+<schemalist>
+
+<schema>
+ <key>/schemas/apps/gweather/prefs/auto_update</key>
+ <owner>gweather-applet-2</owner>
+ <type>bool</type>
+ <default>true</default>
+ <locale name="C">
+ <short>Update the data automatically</short>
+ <long>Determines whether the applet automatically updates its weather statistics or not.</long>
+ </locale>
+</schema>
+<schema>
+ <key>/schemas/apps/gweather/prefs/auto_update_interval</key>
+ <owner>gweather-applet-2</owner>
+ <type>int</type>
+ <default>1800</default>
+ <locale name="C">
+ <short>Update interval</short>
+ <long>The interval, in seconds, between automatic updates.</long>
+ </locale>
+</schema>
+<schema>
+ <key>/schemas/apps/gweather/prefs/enable_metric</key>
+ <owner>gweather-applet-2</owner>
+ <type>bool</type>
+ <default>false</default>
+ <locale name="C">
+ <short>Use metric units</short>
+ <long>Use metric units instead of english units.</long>
+ </locale>
+</schema>
+<schema>
+ <key>/schemas/apps/gweather/prefs/distance_unit</key>
+ <owner>gweather-applet-2</owner>
+ <type>string</type>
+ <default>Default</default>
+ <locale name="C">
+ <short>Distance unit</short>
+ <long>The unit to use for visibility.</long>
+ </locale>
+</schema>
+<schema>
+ <key>/schemas/apps/gweather/prefs/pressure_unit</key>
+ <owner>gweather-applet-2</owner>
+ <type>string</type>
+ <default>Default</default>
+ <locale name="C">
+ <short>Pressure unit</short>
+ <long>The unit to use for pressure.</long>
+ </locale>
+</schema>
+<schema>
+ <key>/schemas/apps/gweather/prefs/speed_unit</key>
+ <owner>gweather-applet-2</owner>
+ <type>string</type>
+ <default>Default</default>
+ <locale name="C">
+ <short>Speed unit</short>
+ <long>The unit to use for wind speed.</long>
+ </locale>
+</schema>
+<schema>
+ <key>/schemas/apps/gweather/prefs/temperature_unit</key>
+ <owner>gweather-applet-2</owner>
+ <type>string</type>
+ <default>Default</default>
+ <locale name="C">
+ <short>Temperature unit</short>
+ <long>The unit to use for temperature.</long>
+ </locale>
+</schema>
+<schema>
+ <key>/schemas/apps/gweather/prefs/enable_detailed_forecast</key>
+ <owner>gweather-applet-2</owner>
+ <type>bool</type>
+ <default>false</default>
+ <locale name="C">
+ <short>Not used anymore</short>
+ </locale>
+</schema>
+<schema>
+ <key>/schemas/apps/gweather/prefs/enable_radar_map</key>
+ <owner>gweather-applet-2</owner>
+ <type>bool</type>
+ <default>false</default>
+ <locale name="C">
+ <short>Display radar map</short>
+ <long>Fetch a radar map on each update.</long>
+ </locale>
+</schema>
+<schema>
+ <key>/schemas/apps/gweather/prefs/location0</key>
+ <owner>gweather-applet-2</owner>
+ <type>string</type>
+ <locale name="C">
+ <default>DEFAULT_LOCATION</default>
+ <short>Weather location information</short>
+ <long>Weather location information.</long>
+ </locale>
+</schema>
+<schema>
+ <key>/schemas/apps/gweather/prefs/location1</key>
+ <owner>gweather-applet-2</owner>
+ <type>string</type>
+ <locale name="C">
+ <default>DEFAULT_CODE</default>
+ <short>Nearby city</short>
+ <long>Nearby major zone, such as a capital city, as found from http://cvs.gnome.org/viewcvs/*checkout*/gnome-applets/gweather/Locations.xml.in</long>
+ </locale>
+</schema>
+<schema>
+ <key>/schemas/apps/gweather/prefs/location2</key>
+ <owner>gweather-applet-2</owner>
+ <type>string</type>
+ <locale name="C">
+ <default>DEFAULT_ZONE</default>
+ <short>Zone location</short>
+ <long>A unique zone for the city, as found from http://cvs.gnome.org/viewcvs/*checkout*/gnome-applets/gweather/Locations.xml.in</long>
+ </locale>
+</schema>
+<schema>
+ <key>/schemas/apps/gweather/prefs/location3</key>
+ <owner>gweather-applet-2</owner>
+ <type>string</type>
+ <locale name="C">
+ <default>DEFAULT_RADAR</default>
+ <short>Radar location</short>
+ <long>A three-digit-long code for retrieving radar maps from weather.com, found from http://cvs.gnome.org/viewcvs/*checkout*/gnome-applets/gweather/Locations.xml.in</long>
+ </locale>
+</schema>
+<schema>
+ <key>/schemas/apps/gweather/prefs/location4</key>
+ <owner>gweather-applet-2</owner>
+ <type>string</type>
+ <locale name="C">
+ <default>DEFAULT_LOCATION</default>
+ <short>Weather for a city</short>
+ <long>The city that gweather displays information for.</long>
+ </locale>
+</schema>
+<schema>
+ <key>/schemas/apps/gweather/prefs/coordinates</key>
+ <owner>gweather-applet-2</owner>
+ <type>string</type>
+ <locale name="C">
+ <default>DEFAULT_COORDINATES</default>
+ <short>Location coordinates</short>
+ <long>Latitude and longitude of your location expressed in DD-MM-SS[NS] DD-MM-SS[EW].</long>
+ </locale>
+</schema>
+<schema>
+ <key>/schemas/apps/gweather/prefs/use_custom_radar_url</key>
+ <owner>gweather-applet-2</owner>
+ <type>bool</type>
+ <default>false</default>
+ <locale name="C">
+ <short>Use custom url for the radar map</short>
+ <long>If true, then retrieve a radar map from a location specified by the "radar" key.</long>
+ </locale>
+</schema>
+<schema>
+ <key>/schemas/apps/gweather/prefs/radar</key>
+ <owner>gweather-applet-2</owner>
+ <type>string</type>
+ <locale name="C">
+ <short>Url for the radar map</short>
+ <long>The custom url from where to retrieve a radar map.</long>
+ </locale>
+</schema>
+</schemalist>
+</gconfschemafile>
diff --git a/libgweather/test_metar.c b/libgweather/test_metar.c
new file mode 100644
index 0000000..afa6d49
--- /dev/null
+++ b/libgweather/test_metar.c
@@ -0,0 +1,78 @@
+/* $Id: test_metar.c 9270 2006-01-15 10:15:19Z davyd $ */
+
+/*
+ * Simple program to reproduce METAR parsing results from command line
+ */
+
+#include <glib.h>
+#include <string.h>
+#include <stdio.h>
+#include "weather-priv.h"
+
+#ifndef BUFLEN
+#define BUFLEN 4096
+#endif /* BUFLEN */
+
+int
+main (int argc, char **argv)
+{
+ FILE* stream = stdin;
+ gchar* filename = NULL;
+ GOptionEntry entries[] =
+ {
+ { "file", 'f', 0, G_OPTION_ARG_FILENAME, &filename,
+ "file constaining metar observations", NULL },
+ { NULL }
+ };
+ GOptionContext* context;
+ GError* error = NULL;
+ char buf[BUFLEN];
+ int len;
+ WeatherInfo info;
+
+
+ context = g_option_context_new ("- test libgweather metar parser");
+ g_option_context_add_main_entries (context, entries, NULL);
+ g_option_context_parse (context, &argc, &argv, &error);
+
+ if (error) {
+ perror(error->message);
+ return error->code;
+ }
+ if (filename) {
+ stream = fopen(filename, "r");
+ if (!stream) {
+ perror("fopen");
+ return -1;
+ }
+ }
+ else
+ {
+ fprintf (stderr, "Enter a METAR string...\n");
+ }
+
+ while (fgets(buf, sizeof(buf), stream)) {
+ len = strlen(buf);
+ if (buf[len - 1] == '\n') {
+ buf[--len] = '\0';
+ }
+ printf("\n%s\n", buf);
+
+ memset (&info, 0, sizeof(info));
+ info.valid = 1;
+ metar_parse(buf, &info);
+ printf("Returned info:\n");
+ printf(" update: %s", ctime(&info.update));
+ printf(" sky: %s\n", weather_info_get_sky(&info));
+ printf(" cond: %s\n", weather_info_get_conditions(&info));
+ printf(" temp: %g F\n", info.temp);
+ printf(" dewp: %g F\n", info.dew);
+ printf(" winddir: %s\n", weather_wind_direction_string(info.wind));
+ printf(" windsp: %d knots\n", info.windspeed);
+ printf(" pressure: %g\" Hg\n", info.pressure);
+ printf(" vis: %g miles\n", info.visibility);
+
+ // TODO: retrieve location's lat/lon to display sunrise/set times
+ }
+ return 0;
+}
diff --git a/libgweather/weather-bom.c b/libgweather/weather-bom.c
new file mode 100644
index 0000000..3bc74ca
--- /dev/null
+++ b/libgweather/weather-bom.c
@@ -0,0 +1,125 @@
+/* $Id: weather-bom.c 9804 2006-08-07 14:05:56Z davyd $ */
+
+/*
+ * Papadimitriou Spiros <spapadim+@cs.cmu.edu>
+ *
+ * This code released under the GNU GPL.
+ * Read the file COPYING for more information.
+ *
+ * Weather server functions (BOM)
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <string.h>
+#include <libgweather/weather.h>
+#include "weather-priv.h"
+
+static gchar *bom_parse (gchar *meto)
+{
+ gchar *p, *rp;
+
+ g_return_val_if_fail (meto != NULL, NULL);
+
+ p = strstr(meto, "<pre>");
+ g_return_val_if_fail (p != NULL, NULL);
+
+ rp = strstr(p, "</pre>");
+ g_return_val_if_fail (rp !=NULL, NULL);
+
+ p += 5; /* skip the <pre> */
+
+ return g_strndup(p, rp-p);
+}
+
+static void bom_finish_read(GnomeVFSAsyncHandle *handle, GnomeVFSResult result,
+ gpointer buffer, GnomeVFSFileSize requested,
+ GnomeVFSFileSize body_len, gpointer data)
+{
+ WeatherInfo *info = (WeatherInfo *)data;
+ gchar *body, *forecast, *temp;
+
+ g_return_if_fail(info != NULL);
+ g_return_if_fail(handle == info->bom_handle);
+
+ info->forecast = NULL;
+ body = (gchar *)buffer;
+ body[body_len] = '\0';
+
+ if (info->bom_buffer == NULL)
+ info->bom_buffer = g_strdup(body);
+ else
+ {
+ temp = g_strdup(info->bom_buffer);
+ g_free(info->bom_buffer);
+ info->bom_buffer = g_strdup_printf("%s%s", temp, body);
+ g_free(temp);
+ }
+
+ if (result == GNOME_VFS_ERROR_EOF)
+ {
+ forecast = bom_parse(info->bom_buffer);
+ info->forecast = forecast;
+ }
+ else if (result != GNOME_VFS_OK) {
+ info->bom_handle = NULL;
+ requests_done_check (info);
+ g_warning("Failed to get BOM data.\n");
+ } else {
+ gnome_vfs_async_read(handle, body, DATA_SIZE - 1, bom_finish_read, info);
+
+ return;
+ }
+
+ request_done(info->bom_handle, info);
+ g_free (buffer);
+ return;
+}
+
+static void bom_finish_open (GnomeVFSAsyncHandle *handle, GnomeVFSResult result, gpointer data)
+{
+ WeatherInfo *info = (WeatherInfo *)data;
+ WeatherLocation *loc;
+ gchar *body;
+
+ g_return_if_fail(info != NULL);
+ g_return_if_fail(handle == info->bom_handle);
+
+ body = g_malloc0(DATA_SIZE);
+
+ info->bom_buffer = NULL;
+ if (info->forecast)
+ g_free (info->forecast);
+ info->forecast = NULL;
+ loc = info->location;
+ g_return_if_fail(loc != NULL);
+
+ if (result != GNOME_VFS_OK) {
+ g_warning("Failed to get BOM forecast data.\n");
+ info->bom_handle = NULL;
+ requests_done_check (info);
+ g_free (body);
+ } else {
+ gnome_vfs_async_read(handle, body, DATA_SIZE - 1, bom_finish_read, info);
+ }
+ return;
+}
+
+void bom_start_open (WeatherInfo *info)
+{
+ gchar *url;
+ WeatherLocation *loc;
+ loc = info->location;
+
+ url = g_strdup_printf("http://www.bom.gov.au/cgi-bin/wrap_fwo.pl?%s.txt",
+ loc->zone+1);
+
+ gnome_vfs_async_open(&info->bom_handle, url, GNOME_VFS_OPEN_READ,
+ 0, bom_finish_open, info);
+ g_free(url);
+
+ return;
+}
diff --git a/libgweather/weather-iwin.c b/libgweather/weather-iwin.c
new file mode 100644
index 0000000..15f3a60
--- /dev/null
+++ b/libgweather/weather-iwin.c
@@ -0,0 +1,204 @@
+/* $Id: weather-iwin.c 10523 2007-11-16 08:03:22Z callum $ */
+
+/*
+ * Papadimitriou Spiros <spapadim+@cs.cmu.edu>
+ *
+ * This code released under the GNU GPL.
+ * Read the file COPYING for more information.
+ *
+ * Weather server functions (IWIN)
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <regex.h>
+#include <glib/gi18n-lib.h>
+
+#include <libgweather/weather.h>
+#include "weather-priv.h"
+
+#define IWIN_RE_STR "([A-Z][A-Z]Z(([0-9]{3}>[0-9]{3}-)|([0-9]{3}-))+)+([0-9]{6}-)?"
+
+/**
+ * Unused. Are these functions useful?
+ */
+
+/**
+ * Human's don't deal well with .MONDAY...SUNNY AND BLAH BLAH.TUESDAY...THEN THIS AND THAT.WEDNESDAY...RAINY BLAH BLAH.
+ * This function makes it easier to read.
+ */
+static gchar* formatWeatherMsg (gchar* forecast) {
+
+ gchar* ptr = forecast;
+ gchar* startLine = NULL;
+
+ while (0 != *ptr) {
+ if (ptr[0] == '\n' && ptr[1] == '.') {
+ /* This removes the preamble by shifting the relevant data
+ * down to the start of the buffer. */
+ if (NULL == startLine) {
+ memmove(forecast, ptr, strlen(ptr) + 1);
+ ptr = forecast;
+ ptr[0] = ' ';
+ }
+ ptr[1] = '\n';
+ ptr += 2;
+ startLine = ptr;
+ } else if (ptr[0] == '.' && ptr[1] == '.' && ptr[2] == '.' && NULL != startLine) {
+ memmove(startLine + 2, startLine, (ptr - startLine) * sizeof(gchar));
+ startLine[0] = ' ';
+ startLine[1] = '\n';
+ ptr[2] = '\n';
+
+ ptr += 3;
+
+ } else if (ptr[0] == '$' && ptr[1] == '$') {
+ ptr[0] = ptr[1] = ' ';
+
+ } else {
+ ptr++;
+ }
+ }
+
+ return forecast;
+}
+
+
+static void iwin_finish_read(GnomeVFSAsyncHandle *handle, GnomeVFSResult result,
+ gpointer buffer, GnomeVFSFileSize requested,
+ GnomeVFSFileSize body_len, gpointer data)
+{
+ WeatherInfo *info = (WeatherInfo *)data;
+ gchar *body, *temp;
+
+ g_return_if_fail(info != NULL);
+ g_return_if_fail(handle == info->iwin_handle);
+
+ info->forecast = NULL;
+ body = (gchar *)buffer;
+ body[body_len] = '\0';
+
+ if (info->iwin_buffer == NULL)
+ info->iwin_buffer = g_strdup(body);
+ else
+ {
+ temp = g_strdup(info->iwin_buffer);
+ g_free(info->iwin_buffer);
+ info->iwin_buffer = g_strdup_printf("%s%s", temp, body);
+ g_free(temp);
+ }
+
+ if (result == GNOME_VFS_ERROR_EOF)
+ {
+ info->forecast = formatWeatherMsg(g_strdup (info->iwin_buffer));
+ }
+ else if (result != GNOME_VFS_OK) {
+ g_print("%s", gnome_vfs_result_to_string(result));
+ g_warning("Failed to get IWIN data.\n");
+ } else {
+ gnome_vfs_async_read(handle, body, DATA_SIZE - 1, iwin_finish_read, info);
+ return;
+ }
+
+ request_done(info->iwin_handle, info);
+ g_free (buffer);
+ return;
+}
+
+static void iwin_finish_open (GnomeVFSAsyncHandle *handle, GnomeVFSResult result, gpointer data)
+{
+ WeatherInfo *info = (WeatherInfo *)data;
+ WeatherLocation *loc;
+ gchar *body;
+
+ g_return_if_fail(info != NULL);
+ g_return_if_fail(handle == info->iwin_handle);
+
+ body = g_malloc0(DATA_SIZE);
+
+ if (info->iwin_buffer)
+ g_free (info->iwin_buffer);
+ info->iwin_buffer = NULL;
+ if (info->forecast)
+ g_free (info->forecast);
+ info->forecast = NULL;
+ loc = info->location;
+ if (loc == NULL) {
+ g_warning (_("WeatherInfo missing location"));
+ request_done(info->iwin_handle, info);
+ info->iwin_handle = NULL;
+ requests_done_check(info);
+ g_free (body);
+ return;
+ }
+
+ if (result != GNOME_VFS_OK) {
+ /* forecast data is not really interesting anyway ;) */
+ g_warning("Failed to get IWIN forecast data.\n");
+ info->iwin_handle = NULL;
+ requests_done_check (info);
+ g_free (body);
+ } else {
+ gnome_vfs_async_read(handle, body, DATA_SIZE - 1, iwin_finish_read, info);
+ }
+ return;
+}
+
+/* Get forecast into newly alloc'ed string */
+void iwin_start_open (WeatherInfo *info)
+{
+ gchar *url, *state, *zone;
+ WeatherLocation *loc;
+
+ g_return_if_fail(info != NULL);
+ loc = info->location;
+ g_return_if_fail(loc != NULL);
+
+ if (loc->zone[0] == '-')
+ return;
+
+ if (loc->zone[0] == ':') /* Met Office Region Names */
+ {
+ metoffice_start_open (info);
+ return;
+ }
+ if (loc->zone[0] == '@') /* Australian BOM forecasts */
+ {
+ bom_start_open (info);
+ return;
+ }
+
+#if 0
+ if (info->forecast_type == FORECAST_ZONE)
+ url = g_strdup_printf("http://iwin.nws.noaa.gov/iwin/%s/zone.html",
+ loc->zone);
+ else
+ url = g_strdup_printf("http://iwin.nws.noaa.gov/iwin/%s/state.html",
+ loc->zone);
+#endif
+
+ /* The zone for Pittsburgh (for example) is given as PAZ021 in the locations
+ ** file (the PA stands for the state pennsylvania). The url used wants the state
+ ** as pa, and the zone as lower case paz021.
+ */
+ zone = g_ascii_strdown (loc->zone, -1);
+ state = g_strndup (zone, 2);
+
+ url = g_strdup_printf ("http://weather.noaa.gov/pub/data/forecasts/zone/%s/%s.txt",
+ state, zone);
+ g_free (zone);
+ g_free (state);
+
+ gnome_vfs_async_open(&info->iwin_handle, url, GNOME_VFS_OPEN_READ,
+ 0, iwin_finish_open, info);
+ g_free(url);
+
+}
+
diff --git a/libgweather/weather-met.c b/libgweather/weather-met.c
new file mode 100644
index 0000000..c10cede
--- /dev/null
+++ b/libgweather/weather-met.c
@@ -0,0 +1,238 @@
+/* $Id: weather-met.c 10124 2007-01-05 14:02:46Z kmaraas $ */
+
+/*
+ * Papadimitriou Spiros <spapadim+@cs.cmu.edu>
+ *
+ * This code released under the GNU GPL.
+ * Read the file COPYING for more information.
+ *
+ * Weather server functions (MET)
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+
+#include <libgweather/weather.h>
+#include "weather-priv.h"
+
+static char *met_reprocess(char *x, int len)
+{
+ char *p = x;
+ char *o;
+ int spacing = 0;
+ static gchar *buf;
+ static gint buflen = 0;
+ gchar *lastspace = NULL;
+ int count = 0;
+
+ if(buflen < len)
+ {
+ if(buf)
+ g_free(buf);
+ buf=g_malloc(len + 1);
+ buflen=len;
+ }
+
+ o=buf;
+ x += len; /* End mark */
+
+ while(*p && p < x)
+ {
+ if(isspace(*p))
+ {
+ if(!spacing)
+ {
+ spacing = 1;
+ lastspace = o;
+ count++;
+ *o++ = ' ';
+ }
+ p++;
+ continue;
+ }
+ spacing = 0;
+ if(count > 75 && lastspace)
+ {
+ count = o - lastspace - 1;
+ *lastspace = '\n';
+ lastspace = NULL;
+ }
+
+ if(*p=='&')
+ {
+ if(strncasecmp(p, "&amp;", 5)==0)
+ {
+ *o++='&';
+ count++;
+ p+=5;
+ continue;
+ }
+ if(strncasecmp(p, "&lt;", 4)==0)
+ {
+ *o++='<';
+ count++;
+ p+=4;
+ continue;
+ }
+ if(strncasecmp(p, "&gt;", 4)==0)
+ {
+ *o++='>';
+ count++;
+ p+=4;
+ continue;
+ }
+ }
+ if(*p=='<')
+ {
+ if(strncasecmp(p, "<BR>", 4)==0)
+ {
+ *o++='\n';
+ count = 0;
+ }
+ if(strncasecmp(p, "<B>", 3)==0)
+ {
+ *o++='\n';
+ *o++='\n';
+ count = 0;
+ }
+ p++;
+ while(*p && *p != '>')
+ p++;
+ if(*p)
+ p++;
+ continue;
+ }
+ *o++=*p++;
+ count++;
+ }
+ *o=0;
+ return buf;
+}
+
+
+/*
+ * Parse the metoffice forecast info.
+ * For gnome 3.0 we want to just embed an HTML bonobo component and
+ * be done with this ;)
+ */
+
+static gchar *met_parse (gchar *meto)
+{
+ gchar *p;
+ gchar *rp;
+ gchar *r = g_strdup("Met Office Forecast\n");
+ gchar *t;
+
+ g_return_val_if_fail (meto != NULL, r);
+
+ p = strstr(meto, "Summary: </b>");
+ g_return_val_if_fail (p != NULL, r);
+
+ rp = strstr(p, "Text issued at:");
+ g_return_val_if_fail (rp != NULL, r);
+
+ p += 13;
+ /* p to rp is the text block we want but in HTML malformat */
+ t = g_strconcat(r, met_reprocess(p, rp-p), NULL);
+ g_free(r);
+
+ return t;
+}
+
+static void met_finish_read(GnomeVFSAsyncHandle *handle, GnomeVFSResult result,
+ gpointer buffer, GnomeVFSFileSize requested,
+ GnomeVFSFileSize body_len, gpointer data)
+{
+ WeatherInfo *info = (WeatherInfo *)data;
+ WeatherLocation *loc;
+ gchar *body, *forecast, *temp;
+
+ g_return_if_fail(info != NULL);
+ g_return_if_fail(handle == info->met_handle);
+
+ info->forecast = NULL;
+ loc = info->location;
+ body = (gchar *)buffer;
+ body[body_len] = '\0';
+
+ if (info->met_buffer == NULL)
+ info->met_buffer = g_strdup(body);
+ else
+ {
+ temp = g_strdup(info->met_buffer);
+ g_free(info->met_buffer);
+ info->met_buffer = g_strdup_printf("%s%s", temp, body);
+ g_free(temp);
+ }
+
+ if (result == GNOME_VFS_ERROR_EOF)
+ {
+ forecast = met_parse(info->met_buffer);
+ info->forecast = forecast;
+ }
+ else if (result != GNOME_VFS_OK) {
+ g_print("%s", gnome_vfs_result_to_string(result));
+ info->met_handle = NULL;
+ requests_done_check (info);
+ g_warning("Failed to get Met Office data.\n");
+ } else {
+ gnome_vfs_async_read(handle, body, DATA_SIZE - 1, met_finish_read, info);
+ return;
+ }
+
+ request_done(info->met_handle, info);
+ g_free (buffer);
+ return;
+}
+
+static void met_finish_open (GnomeVFSAsyncHandle *handle, GnomeVFSResult result, gpointer data)
+{
+ WeatherInfo *info = (WeatherInfo *)data;
+ WeatherLocation *loc;
+ gchar *body;
+
+ g_return_if_fail(info != NULL);
+ g_return_if_fail(handle == info->met_handle);
+
+ body = g_malloc0(DATA_SIZE);
+
+ info->met_buffer = NULL;
+ if (info->forecast)
+ g_free (info->forecast);
+ info->forecast = NULL;
+ loc = info->location;
+ g_return_if_fail(loc != NULL);
+
+ if (result != GNOME_VFS_OK) {
+ g_warning("Failed to get Met Office forecast data.\n");
+ info->met_handle = NULL;
+ requests_done_check (info);
+ g_free (body);
+ } else {
+ gnome_vfs_async_read(handle, body, DATA_SIZE - 1, met_finish_read, info);
+ }
+ return;
+}
+
+void metoffice_start_open (WeatherInfo *info)
+{
+ gchar *url;
+ WeatherLocation *loc;
+ loc = info->location;
+
+ url = g_strdup_printf("http://www.metoffice.gov.uk/weather/europe/uk/%s.html", loc->zone+1);
+
+ gnome_vfs_async_open(&info->met_handle, url, GNOME_VFS_OPEN_READ,
+ 0, met_finish_open, info);
+ g_free(url);
+
+ return;
+}
+
diff --git a/libgweather/weather-metar.c b/libgweather/weather-metar.c
new file mode 100644
index 0000000..b386d48
--- /dev/null
+++ b/libgweather/weather-metar.c
@@ -0,0 +1,590 @@
+/* $Id: weather-metar.c 10286 2007-07-12 08:52:56Z callum $ */
+
+/*
+ * Papadimitriou Spiros <spapadim+@cs.cmu.edu>
+ *
+ * This code released under the GNU GPL.
+ * Read the file COPYING for more information.
+ *
+ * Weather server functions (METAR)
+ *
+ */
+
+/*
+ * Code for parsing METAR weather observations
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <regex.h>
+#include <glib/gi18n-lib.h>
+
+#include <libgweather/weather.h>
+#include "weather-priv.h"
+
+
+enum
+{
+ TIME_RE,
+ WIND_RE,
+ VIS_RE,
+ COND_RE,
+ CLOUD_RE,
+ TEMP_RE,
+ PRES_RE,
+
+ RE_NUM
+};
+
+/* Return time of weather report as secs since epoch UTC */
+static time_t make_time (gint utcDate, gint utcHour, gint utcMin)
+{
+ const time_t now = time(NULL);
+ struct tm tm;
+
+ localtime_r (&now, &tm);
+
+ /* If last reading took place just before midnight UTC on the
+ * first, adjust the date downward to allow for the month
+ * change-over. This ASSUMES that the reading won't be more than
+ * 24 hrs old! */
+ if ((utcDate > tm.tm_mday) && (tm.tm_mday == 1)) {
+ tm.tm_mday = 0; /* mktime knows this is the last day of the previous
+ * month. */
+ } else {
+ tm.tm_mday = utcDate;
+ }
+ tm.tm_hour = utcHour;
+ tm.tm_min = utcMin;
+ tm.tm_sec = 0;
+
+ /* mktime() assumes value is local, not UTC. Use tm_gmtoff to compensate */
+#ifdef HAVE_TM_TM_GMOFF
+ return tm.tm_gmtoff + mktime(&tm);
+#elif defined HAVE_TIMEZONE
+ return timezone + mktime(&tm);
+#endif
+}
+
+static void metar_tok_time (gchar *tokp, WeatherInfo *info)
+{
+ gint day, hr, min;
+
+ sscanf(tokp, "%2u%2u%2u", &day, &hr, &min);
+ info->update = make_time(day, hr, min);
+}
+
+static void metar_tok_wind (gchar *tokp, WeatherInfo *info)
+{
+ gchar sdir[4], sspd[4], sgust[4];
+ gint dir, spd = -1;
+ gchar *gustp;
+ size_t glen;
+
+ strncpy(sdir, tokp, 3);
+ sdir[3] = 0;
+ dir = (!strcmp(sdir, "VRB")) ? -1 : atoi(sdir);
+
+ memset(sspd, 0, sizeof(sspd));
+ glen = strspn(tokp+3, CONST_DIGITS);
+ strncpy(sspd, tokp+3, glen);
+ spd = atoi(sspd);
+ tokp += glen + 3;
+
+ gustp = strchr(tokp, 'G');
+ if (gustp) {
+ memset(sgust, 0, sizeof(sgust));
+ glen = strspn(gustp+1, CONST_DIGITS);
+ strncpy(sgust, gustp+1, glen);
+ }
+
+ if ((349 <= dir) || (dir <= 11))
+ info->wind = WIND_N;
+ else if ((12 <= dir) && (dir <= 33))
+ info->wind = WIND_NNE;
+ else if ((34 <= dir) && (dir <= 56))
+ info->wind = WIND_NE;
+ else if ((57 <= dir) && (dir <= 78))
+ info->wind = WIND_ENE;
+ else if ((79 <= dir) && (dir <= 101))
+ info->wind = WIND_E;
+ else if ((102 <= dir) && (dir <= 123))
+ info->wind = WIND_ESE;
+ else if ((124 <= dir) && (dir <= 146))
+ info->wind = WIND_SE;
+ else if ((147 <= dir) && (dir <= 168))
+ info->wind = WIND_SSE;
+ else if ((169 <= dir) && (dir <= 191))
+ info->wind = WIND_S;
+ else if ((192 <= dir) && (dir <= 213))
+ info->wind = WIND_SSW;
+ else if ((214 <= dir) && (dir <= 236))
+ info->wind = WIND_SW;
+ else if ((237 <= dir) && (dir <= 258))
+ info->wind = WIND_WSW;
+ else if ((259 <= dir) && (dir <= 281))
+ info->wind = WIND_W;
+ else if ((282 <= dir) && (dir <= 303))
+ info->wind = WIND_WNW;
+ else if ((304 <= dir) && (dir <= 326))
+ info->wind = WIND_NW;
+ else if ((327 <= dir) && (dir <= 348))
+ info->wind = WIND_NNW;
+
+ info->windspeed = (WeatherWindSpeed)spd;
+}
+
+static void metar_tok_vis (gchar *tokp, WeatherInfo *info)
+{
+ gchar *pfrac, *pend, *psp;
+ gchar sval[6];
+ gint num, den, val;
+
+ memset(sval, 0, sizeof(sval));
+
+ if (!strcmp(tokp,"CAVOK")) {
+ // "Ceiling And Visibility OK": visibility >= 10 KM
+ info->visibility=10000. / VISIBILITY_SM_TO_M(1.);
+ info->sky = SKY_CLEAR;
+ }
+ else if (0 != (pend = strstr(tokp, "SM"))) {
+ // US observation: field ends with "SM"
+ pfrac = strchr(tokp, '/');
+ if (pfrac) {
+ if (*tokp == 'M') {
+ info->visibility = 0.001;
+ } else {
+ num = (*(pfrac-1) - '0');
+ strncpy(sval, pfrac + 1, pend - pfrac - 1);
+ den = atoi(sval);
+ info->visibility =
+ ((WeatherVisibility)num / ((WeatherVisibility)den));
+
+ psp = strchr(tokp, ' ');
+ if (psp) {
+ *psp = '\0';
+ val = atoi(tokp);
+ info->visibility += (WeatherVisibility)val;
+ }
+ }
+ } else {
+ strncpy(sval, tokp, pend - tokp);
+ val = atoi(sval);
+ info->visibility = (WeatherVisibility)val;
+ }
+ } else {
+ // International observation: NNNN(DD NNNNDD)?
+ // For now: use only the minimum visibility and ignore its direction
+ strncpy (sval, tokp, strspn(tokp, CONST_DIGITS));
+ val = atoi(sval);
+ info->visibility = (WeatherVisibility)val / VISIBILITY_SM_TO_M(1.);
+ }
+}
+
+static void metar_tok_cloud (gchar *tokp, WeatherInfo *info)
+{
+ gchar stype[4], salt[4];
+
+ strncpy(stype, tokp, 3);
+ stype[3] = 0;
+ if (strlen(tokp) == 6) {
+ strncpy(salt, tokp+3, 3);
+ salt[3] = 0;
+ }
+
+ if (!strcmp(stype, "CLR")) {
+ info->sky = SKY_CLEAR;
+ } else if (!strcmp(stype, "SKC")) {
+ info->sky = SKY_CLEAR;
+ } else if (!strcmp(stype, "NSC")) {
+ info->sky = SKY_CLEAR;
+ } else if (!strcmp(stype, "BKN")) {
+ info->sky = SKY_BROKEN;
+ } else if (!strcmp(stype, "SCT")) {
+ info->sky = SKY_SCATTERED;
+ } else if (!strcmp(stype, "FEW")) {
+ info->sky = SKY_FEW;
+ } else if (!strcmp(stype, "OVC")) {
+ info->sky = SKY_OVERCAST;
+ }
+}
+
+static void metar_tok_pres (gchar *tokp, WeatherInfo *info)
+{
+ if (*tokp == 'A') {
+ gchar sintg[3], sfract[3];
+ gint intg, fract;
+
+ strncpy(sintg, tokp+1, 2);
+ sintg[2] = 0;
+ intg = atoi(sintg);
+
+ strncpy(sfract, tokp+3, 2);
+ sfract[2] = 0;
+ fract = atoi(sfract);
+
+ info->pressure = (WeatherPressure)intg + (((WeatherPressure)fract)/100.0);
+ } else { /* *tokp == 'Q' */
+ gchar spres[5];
+ gint pres;
+
+ strncpy(spres, tokp+1, 4);
+ spres[4] = 0;
+ pres = atoi(spres);
+
+ info->pressure = PRESSURE_MBAR_TO_INCH((WeatherPressure)pres);
+ }
+}
+
+static void metar_tok_temp (gchar *tokp, WeatherInfo *info)
+{
+ gchar *ptemp, *pdew, *psep;
+
+ psep = strchr(tokp, '/');
+ *psep = 0;
+ ptemp = tokp;
+ pdew = psep + 1;
+
+ info->temp = (*ptemp == 'M') ? TEMP_C_TO_F(-atoi(ptemp+1))
+ : TEMP_C_TO_F(atoi(ptemp));
+ if (*pdew) {
+ info->dew = (*pdew == 'M') ? TEMP_C_TO_F(-atoi(pdew+1))
+ : TEMP_C_TO_F(atoi(pdew));
+ } else {
+ info->dew = -1000.0;
+ }
+}
+
+static void metar_tok_cond (gchar *tokp, WeatherInfo *info)
+{
+ gchar squal[3], sphen[4];
+ gchar *pphen;
+
+ if ((strlen(tokp) > 3) && ((*tokp == '+') || (*tokp == '-')))
+ ++tokp; /* FIX */
+
+ if ((*tokp == '+') || (*tokp == '-'))
+ pphen = tokp + 1;
+ else if (strlen(tokp) < 4)
+ pphen = tokp;
+ else
+ pphen = tokp + 2;
+
+ memset(squal, 0, sizeof(squal));
+ strncpy(squal, tokp, pphen - tokp);
+ squal[pphen - tokp] = 0;
+
+ memset(sphen, 0, sizeof(sphen));
+ strncpy(sphen, pphen, sizeof(sphen));
+ sphen[sizeof(sphen)-1] = '\0';
+
+ /* Defaults */
+ info->cond.qualifier = QUALIFIER_NONE;
+ info->cond.phenomenon = PHENOMENON_NONE;
+ info->cond.significant = FALSE;
+
+ if (!strcmp(squal, "")) {
+ info->cond.qualifier = QUALIFIER_MODERATE;
+ } else if (!strcmp(squal, "-")) {
+ info->cond.qualifier = QUALIFIER_LIGHT;
+ } else if (!strcmp(squal, "+")) {
+ info->cond.qualifier = QUALIFIER_HEAVY;
+ } else if (!strcmp(squal, "VC")) {
+ info->cond.qualifier = QUALIFIER_VICINITY;
+ } else if (!strcmp(squal, "MI")) {
+ info->cond.qualifier = QUALIFIER_SHALLOW;
+ } else if (!strcmp(squal, "BC")) {
+ info->cond.qualifier = QUALIFIER_PATCHES;
+ } else if (!strcmp(squal, "PR")) {
+ info->cond.qualifier = QUALIFIER_PARTIAL;
+ } else if (!strcmp(squal, "TS")) {
+ info->cond.qualifier = QUALIFIER_THUNDERSTORM;
+ } else if (!strcmp(squal, "BL")) {
+ info->cond.qualifier = QUALIFIER_BLOWING;
+ } else if (!strcmp(squal, "SH")) {
+ info->cond.qualifier = QUALIFIER_SHOWERS;
+ } else if (!strcmp(squal, "DR")) {
+ info->cond.qualifier = QUALIFIER_DRIFTING;
+ } else if (!strcmp(squal, "FZ")) {
+ info->cond.qualifier = QUALIFIER_FREEZING;
+ } else {
+ return;
+ }
+
+ if (!strcmp(sphen, "DZ")) {
+ info->cond.phenomenon = PHENOMENON_DRIZZLE;
+ } else if (!strcmp(sphen, "RA")) {
+ info->cond.phenomenon = PHENOMENON_RAIN;
+ } else if (!strcmp(sphen, "SN")) {
+ info->cond.phenomenon = PHENOMENON_SNOW;
+ } else if (!strcmp(sphen, "SG")) {
+ info->cond.phenomenon = PHENOMENON_SNOW_GRAINS;
+ } else if (!strcmp(sphen, "IC")) {
+ info->cond.phenomenon = PHENOMENON_ICE_CRYSTALS;
+ } else if (!strcmp(sphen, "PE")) {
+ info->cond.phenomenon = PHENOMENON_ICE_PELLETS;
+ } else if (!strcmp(sphen, "GR")) {
+ info->cond.phenomenon = PHENOMENON_HAIL;
+ } else if (!strcmp(sphen, "GS")) {
+ info->cond.phenomenon = PHENOMENON_SMALL_HAIL;
+ } else if (!strcmp(sphen, "UP")) {
+ info->cond.phenomenon = PHENOMENON_UNKNOWN_PRECIPITATION;
+ } else if (!strcmp(sphen, "BR")) {
+ info->cond.phenomenon = PHENOMENON_MIST;
+ } else if (!strcmp(sphen, "FG")) {
+ info->cond.phenomenon = PHENOMENON_FOG;
+ } else if (!strcmp(sphen, "FU")) {
+ info->cond.phenomenon = PHENOMENON_SMOKE;
+ } else if (!strcmp(sphen, "VA")) {
+ info->cond.phenomenon = PHENOMENON_VOLCANIC_ASH;
+ } else if (!strcmp(sphen, "SA")) {
+ info->cond.phenomenon = PHENOMENON_SAND;
+ } else if (!strcmp(sphen, "HZ")) {
+ info->cond.phenomenon = PHENOMENON_HAZE;
+ } else if (!strcmp(sphen, "PY")) {
+ info->cond.phenomenon = PHENOMENON_SPRAY;
+ } else if (!strcmp(sphen, "DU")) {
+ info->cond.phenomenon = PHENOMENON_DUST;
+ } else if (!strcmp(sphen, "SQ")) {
+ info->cond.phenomenon = PHENOMENON_SQUALL;
+ } else if (!strcmp(sphen, "SS")) {
+ info->cond.phenomenon = PHENOMENON_SANDSTORM;
+ } else if (!strcmp(sphen, "DS")) {
+ info->cond.phenomenon = PHENOMENON_DUSTSTORM;
+ } else if (!strcmp(sphen, "PO")) {
+ info->cond.phenomenon = PHENOMENON_DUST_WHIRLS;
+ } else if (!strcmp(sphen, "+FC")) {
+ info->cond.phenomenon = PHENOMENON_TORNADO;
+ } else if (!strcmp(sphen, "FC")) {
+ info->cond.phenomenon = PHENOMENON_FUNNEL_CLOUD;
+ } else {
+ return;
+ }
+
+ if ((info->cond.qualifier != QUALIFIER_NONE) || (info->cond.phenomenon != PHENOMENON_NONE))
+ info->cond.significant = TRUE;
+}
+
+#define TIME_RE_STR "([0-9]{6})Z"
+#define WIND_RE_STR "(([0-9]{3})|VRB)([0-9]?[0-9]{2})(G[0-9]?[0-9]{2})?KT"
+#define VIS_RE_STR "((([0-9]?[0-9])|(M?([12] )?([1357]/1?[0-9])))SM)|" \
+ "([0-9]{4}(N|NE|E|SE|S|SW|W|NW( [0-9]{4}(N|NE|E|SE|S|SW|W|NW))?)?)|" \
+ "CAVOK"
+#define COND_RE_STR "(-|\\+)?(VC|MI|BC|PR|TS|BL|SH|DR|FZ)?(DZ|RA|SN|SG|IC|PE|GR|GS|UP|BR|FG|FU|VA|SA|HZ|PY|DU|SQ|SS|DS|PO|\\+?FC)"
+#define CLOUD_RE_STR "((CLR|BKN|SCT|FEW|OVC|SKC|NSC)([0-9]{3}|///)?(CB|TCU|///)?)"
+#define TEMP_RE_STR "(M?[0-9][0-9])/(M?(//|[0-9][0-9])?)"
+#define PRES_RE_STR "(A|Q)([0-9]{4})"
+
+/* POSIX regular expressions do not allow us to express "match whole words
+ * only" in a simple way, so we have to wrap them all into
+ * (^| )(...regex...)( |$)
+ */
+#define RE_PREFIX "(^| )("
+#define RE_SUFFIX ")( |$)"
+
+static regex_t metar_re[RE_NUM];
+static void (*metar_f[RE_NUM])(gchar *tokp, WeatherInfo *info);
+
+static void metar_init_re (void)
+{
+ static gboolean initialized = FALSE;
+ if (initialized)
+ return;
+ initialized = TRUE;
+
+ regcomp(&metar_re[TIME_RE], RE_PREFIX TIME_RE_STR RE_SUFFIX, REG_EXTENDED);
+ regcomp(&metar_re[WIND_RE], RE_PREFIX WIND_RE_STR RE_SUFFIX, REG_EXTENDED);
+ regcomp(&metar_re[VIS_RE], RE_PREFIX VIS_RE_STR RE_SUFFIX, REG_EXTENDED);
+ regcomp(&metar_re[COND_RE], RE_PREFIX COND_RE_STR RE_SUFFIX, REG_EXTENDED);
+ regcomp(&metar_re[CLOUD_RE], RE_PREFIX CLOUD_RE_STR RE_SUFFIX, REG_EXTENDED);
+ regcomp(&metar_re[TEMP_RE], RE_PREFIX TEMP_RE_STR RE_SUFFIX, REG_EXTENDED);
+ regcomp(&metar_re[PRES_RE], RE_PREFIX PRES_RE_STR RE_SUFFIX, REG_EXTENDED);
+
+ metar_f[TIME_RE] = metar_tok_time;
+ metar_f[WIND_RE] = metar_tok_wind;
+ metar_f[VIS_RE] = metar_tok_vis;
+ metar_f[COND_RE] = metar_tok_cond;
+ metar_f[CLOUD_RE] = metar_tok_cloud;
+ metar_f[TEMP_RE] = metar_tok_temp;
+ metar_f[PRES_RE] = metar_tok_pres;
+}
+
+gboolean metar_parse (gchar *metar, WeatherInfo *info)
+{
+ gchar *p;
+ //gchar *rmk;
+ gint i, i2;
+ regmatch_t rm, rm2;
+ gchar *tokp;
+
+ g_return_val_if_fail(info != NULL, FALSE);
+ g_return_val_if_fail(metar != NULL, FALSE);
+
+ metar_init_re();
+
+ /*
+ * Force parsing to end at "RMK" field. This prevents a subtle
+ * problem when info within the remark happens to match an earlier state
+ * and, as a result, throws off all the remaining expression
+ */
+ if (0 != (p = strstr(metar, " RMK "))) {
+ *p = '\0';
+ //rmk = p+5; // uncomment this if RMK data becomes useful
+ }
+
+ p = metar;
+ i = TIME_RE;
+ while (*p) {
+
+ i2 = RE_NUM;
+ rm2.rm_so = strlen(p);
+ rm2.rm_eo = rm2.rm_so;
+
+ for (i = 0; i < RE_NUM && rm2.rm_so > 0; i++) {
+ if (0 == regexec(&metar_re[i], p, 1, &rm, 0)
+ && rm.rm_so < rm2.rm_so)
+ {
+ i2 = i;
+ /* Skip leading and trailing space characters, if present.
+ (the regular expressions include those characters to
+ only get matches limited to whole words). */
+ if (p[rm.rm_so] == ' ') rm.rm_so++;
+ if (p[rm.rm_eo-1] == ' ') rm.rm_eo--;
+ rm2.rm_so = rm.rm_so;
+ rm2.rm_eo = rm.rm_eo;
+ }
+ }
+
+ if (i2 != RE_NUM) {
+ tokp = g_strndup(p+rm2.rm_so, rm2.rm_eo-rm2.rm_so);
+ metar_f[i2](tokp, info);
+ g_free (tokp);
+ }
+
+ p += rm2.rm_eo;
+ p += strspn(p, " ");
+ }
+ return TRUE;
+}
+
+static void metar_finish_read(GnomeVFSAsyncHandle *handle, GnomeVFSResult result,
+ gpointer buffer, GnomeVFSFileSize requested,
+ GnomeVFSFileSize body_len, gpointer data)
+{
+ WeatherInfo *info = (WeatherInfo *)data;
+ WeatherLocation *loc;
+ gchar *metar, *eoln, *body, *temp;
+ gboolean success = FALSE;
+ gchar *searchkey;
+
+ g_return_if_fail(info != NULL);
+ g_return_if_fail(handle == info->metar_handle);
+
+ loc = info->location;
+ body = (gchar *)buffer;
+
+ body[body_len] = '\0';
+
+ if (info->metar_buffer == NULL)
+ info->metar_buffer = g_strdup(body);
+ else
+ {
+ temp = g_strdup(info->metar_buffer);
+ g_free(info->metar_buffer);
+ info->metar_buffer = g_strdup_printf("%s%s", temp, body);
+ g_free(temp);
+ }
+
+ if (result == GNOME_VFS_ERROR_EOF)
+ {
+
+ searchkey = g_strdup_printf("\n%s", loc->code);
+
+ metar = strstr(info->metar_buffer, searchkey);
+ g_free (searchkey);
+ if (metar == NULL) {
+ success = FALSE;
+ } else {
+ metar += WEATHER_LOCATION_CODE_LEN + 2;
+ eoln = strchr(metar, '\n');
+ if (eoln != NULL)
+ *eoln = 0;
+ success = metar_parse(metar, info);
+ if (eoln != NULL)
+ *eoln = '\n';
+ }
+
+ info->valid = success;
+ }
+ else if (result != GNOME_VFS_OK) {
+ g_print("%s", gnome_vfs_result_to_string(result));
+ g_warning(_("Failed to get METAR data.\n"));
+ } else {
+ gnome_vfs_async_read(handle, body, DATA_SIZE - 1, metar_finish_read, info);
+ return;
+ }
+
+ request_done(info->metar_handle, info);
+ g_free (buffer);
+ return;
+}
+
+static void metar_finish_open (GnomeVFSAsyncHandle *handle, GnomeVFSResult result, gpointer data)
+{
+ WeatherInfo *info = (WeatherInfo *)data;
+ WeatherLocation *loc;
+ gchar *body;
+
+ g_return_if_fail(info != NULL);
+ g_return_if_fail(handle == info->metar_handle);
+
+ body = g_malloc0(DATA_SIZE);
+
+ if (info->metar_buffer)
+ g_free (info->metar_buffer);
+ info->metar_buffer = NULL;
+ loc = info->location;
+ if (loc == NULL) {
+ g_warning (_("WeatherInfo missing location"));
+ request_done(info->metar_handle, info);
+ requests_done_check(info);
+ g_free (body);
+ return;
+ }
+
+ if (result != GNOME_VFS_OK) {
+ g_warning(_("Failed to get METAR data.\n"));
+ info->metar_handle = NULL;
+ requests_done_check(info);
+ g_free (body);
+ } else {
+ gnome_vfs_async_read(handle, body, DATA_SIZE - 1, metar_finish_read, info);
+ }
+ return;
+}
+
+/* Read current conditions and fill in info structure */
+void metar_start_open (WeatherInfo *info)
+{
+ gchar *url;
+ WeatherLocation *loc;
+
+ g_return_if_fail(info != NULL);
+ info->valid = FALSE;
+ loc = info->location;
+ if (loc == NULL) {
+ g_warning (_("WeatherInfo missing location"));
+ return;
+ }
+
+ url = g_strdup_printf("http://weather.noaa.gov/cgi-bin/mgetmetar.pl?cccc=%s", loc->code);
+ gnome_vfs_async_open(&info->metar_handle, url, GNOME_VFS_OPEN_READ,
+ 0, metar_finish_open, info);
+ g_free(url);
+
+}
diff --git a/libgweather/weather-priv.h b/libgweather/weather-priv.h
new file mode 100644
index 0000000..160ebba
--- /dev/null
+++ b/libgweather/weather-priv.h
@@ -0,0 +1,211 @@
+/*
+ * Papadimitriou Spiros <spapadim+@cs.cmu.edu>
+ *
+ * This code released under the GNU GPL.
+ * Read the file COPYING for more information.
+ *
+ * Private header for weather server functions.
+ *
+ */
+
+#ifndef __WEATHER_PRIV_H_
+#define __WEATHER_PRIV_H_
+
+#include <time.h>
+#include <libgnomevfs/gnome-vfs.h>
+
+#include "weather.h"
+
+/*
+ * Weather information.
+ */
+
+enum _WeatherWindDirection {
+ WIND_VARIABLE,
+ WIND_N, WIND_NNE, WIND_NE, WIND_ENE,
+ WIND_E, WIND_ESE, WIND_SE, WIND_SSE,
+ WIND_S, WIND_SSW, WIND_SW, WIND_WSW,
+ WIND_W, WIND_WNW, WIND_NW, WIND_NNW
+};
+
+typedef enum _WeatherWindDirection WeatherWindDirection;
+
+enum _WeatherSky {
+ SKY_INVALID = -1,
+ SKY_CLEAR,
+ SKY_BROKEN,
+ SKY_SCATTERED,
+ SKY_FEW,
+ SKY_OVERCAST
+};
+
+typedef enum _WeatherSky WeatherSky;
+
+enum _WeatherConditionPhenomenon {
+ PHENOMENON_NONE,
+
+ PHENOMENON_DRIZZLE,
+ PHENOMENON_RAIN,
+ PHENOMENON_SNOW,
+ PHENOMENON_SNOW_GRAINS,
+ PHENOMENON_ICE_CRYSTALS,
+ PHENOMENON_ICE_PELLETS,
+ PHENOMENON_HAIL,
+ PHENOMENON_SMALL_HAIL,
+ PHENOMENON_UNKNOWN_PRECIPITATION,
+
+ PHENOMENON_MIST,
+ PHENOMENON_FOG,
+ PHENOMENON_SMOKE,
+ PHENOMENON_VOLCANIC_ASH,
+ PHENOMENON_SAND,
+ PHENOMENON_HAZE,
+ PHENOMENON_SPRAY,
+ PHENOMENON_DUST,
+
+ PHENOMENON_SQUALL,
+ PHENOMENON_SANDSTORM,
+ PHENOMENON_DUSTSTORM,
+ PHENOMENON_FUNNEL_CLOUD,
+ PHENOMENON_TORNADO,
+ PHENOMENON_DUST_WHIRLS
+};
+
+typedef enum _WeatherConditionPhenomenon WeatherConditionPhenomenon;
+
+enum _WeatherConditionQualifier {
+ QUALIFIER_NONE,
+
+ QUALIFIER_VICINITY,
+
+ QUALIFIER_LIGHT,
+ QUALIFIER_MODERATE,
+ QUALIFIER_HEAVY,
+ QUALIFIER_SHALLOW,
+ QUALIFIER_PATCHES,
+ QUALIFIER_PARTIAL,
+ QUALIFIER_THUNDERSTORM,
+ QUALIFIER_BLOWING,
+ QUALIFIER_SHOWERS,
+ QUALIFIER_DRIFTING,
+ QUALIFIER_FREEZING
+};
+
+typedef enum _WeatherConditionQualifier WeatherConditionQualifier;
+
+struct _WeatherConditions {
+ gboolean significant;
+ WeatherConditionPhenomenon phenomenon;
+ WeatherConditionQualifier qualifier;
+};
+
+typedef struct _WeatherConditions WeatherConditions;
+
+typedef gdouble WeatherTemperature;
+typedef gdouble WeatherHumidity;
+typedef gint WeatherWindSpeed;
+typedef gdouble WeatherPressure;
+typedef gdouble WeatherVisibility;
+typedef time_t WeatherUpdate;
+
+struct _WeatherInfo {
+ WeatherForecastType forecast_type;
+
+ TempUnit temperature_unit;
+ SpeedUnit speed_unit;
+ PressureUnit pressure_unit;
+ DistanceUnit distance_unit;
+
+ gboolean valid;
+ gboolean sunValid;
+ WeatherLocation *location;
+ WeatherUpdate update;
+ WeatherSky sky;
+ WeatherConditions cond;
+ WeatherTemperature temp;
+ WeatherTemperature dew;
+ WeatherWindDirection wind;
+ WeatherWindSpeed windspeed;
+ WeatherPressure pressure;
+ WeatherVisibility visibility;
+ WeatherUpdate sunrise;
+ WeatherUpdate sunset;
+ gchar *forecast;
+ gchar *metar_buffer;
+ gchar *iwin_buffer;
+ gchar *met_buffer;
+ gchar *bom_buffer;
+ gchar *radar_buffer;
+ gchar *radar_url;
+ GdkPixbufLoader *radar_loader;
+ GdkPixbufAnimation *radar;
+ GnomeVFSAsyncHandle *metar_handle;
+ GnomeVFSAsyncHandle *iwin_handle;
+ GnomeVFSAsyncHandle *wx_handle;
+ GnomeVFSAsyncHandle *met_handle;
+ GnomeVFSAsyncHandle *bom_handle;
+ gboolean requests_pending;
+
+ WeatherInfoFunc finish_cb;
+ gpointer cb_data;
+};
+
+/*
+ * Enum -> string conversions.
+ */
+
+const gchar * weather_wind_direction_string (WeatherWindDirection wind);
+const gchar * weather_sky_string (WeatherSky sky);
+const gchar * weather_conditions_string (WeatherConditions cond);
+
+/* Values common to the parsing source files */
+
+#define DATA_SIZE 5000
+
+#define CONST_DIGITS "0123456789"
+#define CONST_ALPHABET "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+
+/* Units conversions and names */
+
+#define TEMP_F_TO_C(f) (((f) - 32.0) * 0.555556)
+#define TEMP_F_TO_K(f) (TEMP_F_TO_C(f) + 273.15)
+#define TEMP_C_TO_F(c) (((c) * 1.8) + 32.0)
+
+#define WINDSPEED_KNOTS_TO_KPH(knots) ((knots) * 1.851965)
+#define WINDSPEED_KNOTS_TO_MPH(knots) ((knots) * 1.150779)
+#define WINDSPEED_KNOTS_TO_MS(knots) ((knots) * 0.514444)
+/* 1 bft ~= (1 m/s / 0.836) ^ (2/3) */
+#define WINDSPEED_KNOTS_TO_BFT(knots) (pow ((knots) * 0.615363, 0.666666))
+
+#define PRESSURE_INCH_TO_KPA(inch) ((inch) * 3.386)
+#define PRESSURE_INCH_TO_HPA(inch) ((inch) * 33.86)
+#define PRESSURE_INCH_TO_MM(inch) ((inch) * 25.40005)
+#define PRESSURE_INCH_TO_MB(inch) (PRESSURE_INCH_TO_HPA(inch))
+#define PRESSURE_INCH_TO_ATM(inch) ((inch) * 0.033421052)
+#define PRESSURE_MBAR_TO_INCH(mbar) ((mbar) * 0.029533373)
+
+#define VISIBILITY_SM_TO_KM(sm) ((sm) * 1.609344)
+#define VISIBILITY_SM_TO_M(sm) (VISIBILITY_SM_TO_KM(sm) * 1000)
+
+#define DEGREES_TO_RADIANS(deg) ((fmod(deg,360.) / 180.) * M_PI)
+#define RADIANS_TO_DEGREES(rad) ((rad) * 180. / M_PI)
+#define RADIANS_TO_HOURS(rad) ((rad) * 12. / M_PI)
+
+void metar_start_open (WeatherInfo *info);
+void iwin_start_open (WeatherInfo *info);
+void metoffice_start_open (WeatherInfo *info);
+void bom_start_open (WeatherInfo *info);
+void wx_start_open (WeatherInfo *info);
+
+gboolean metar_parse (gchar *metar,
+ WeatherInfo *info);
+
+gboolean requests_init (WeatherInfo *info);
+void request_done (GnomeVFSAsyncHandle *handle,
+ WeatherInfo *info);
+void requests_done_check (WeatherInfo *info);
+
+gboolean calc_sun (WeatherInfo *info);
+
+#endif /* __WEATHER_PRIV_H_ */
+
diff --git a/libgweather/weather-sun.c b/libgweather/weather-sun.c
new file mode 100644
index 0000000..527b793
--- /dev/null
+++ b/libgweather/weather-sun.c
@@ -0,0 +1,247 @@
+/* $Id: weather-sun.c 10286 2007-07-12 08:52:56Z callum $ */
+
+/*
+ * Astronomy calculations for gweather
+ *
+ * Formulas from:
+ * "Practical Astronomy With Your Calculator" (3e), Peter Duffett-Smith
+ * Cambridge University Press 1988
+ *
+ * Planetary Mean Orbit parameters from http://ssd.jpl.nasa.gov/elem_planets.html,
+ * converting longitudes from heliocentric to geocentric coordinates
+ * epoch J2000 (2000 Jan 1 12:00:00 UTC)
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#ifdef __FreeBSD__
+#include <sys/types.h>
+#endif
+
+#include <math.h>
+#include <time.h>
+#include <glib.h>
+
+#include "weather-priv.h"
+
+#define EPOCH_TO_J2000(t) (t-946728000)
+#define MEAN_ECLIPTIC_LONGITUDE 280.46435
+#define PERIGEE_LONGITUDE 282.94719
+#define ECCENTRICITY 0.01671002
+#define MEAN_ECLIPTIC_OBLIQUITY
+#define SOL_PROGRESSION (360./365.242191)
+
+/*
+ * Convert ecliptic longitude (radians) to equitorial coordinates,
+ * expressed as right ascension (hours) and declination (radians)
+ * Assume ecliptic latitude is 0.0
+ */
+static void ecl2equ (gdouble time, gdouble eclipLon,
+ gdouble *ra, gdouble *decl)
+{
+ gdouble jc = EPOCH_TO_J2000(time) / (36525. * 86400.);
+ gdouble mEclipObliq = DEGREES_TO_RADIANS(23.439291667
+ - .013004166 * jc
+ - 1.666667e-7 * jc * jc
+ + 5.027777e-7 * jc * jc * jc);
+ *ra = RADIANS_TO_HOURS(atan2 ( sin(eclipLon) * cos(mEclipObliq), cos(eclipLon)));
+ if (*ra < 0.)
+ *ra += 24.;
+ *decl = asin ( sin(mEclipObliq) * sin(eclipLon) );
+}
+
+/*
+ * Calculate rising and setting times of an object
+ * based on it equitorial coordinates
+ */
+static void gstObsv (gdouble ra, gdouble decl,
+ gdouble obsLat, gdouble obsLon,
+ gdouble *rise, gdouble *set)
+{
+ double a = acos(-tan(obsLat) * tan(decl));
+ double b;
+
+ if (isnan(a) != 0) {
+ *set = *rise = a;
+ return;
+ }
+ a = RADIANS_TO_HOURS(a);
+ b = 24. - a + ra;
+ a += ra;
+ a -= RADIANS_TO_HOURS(obsLon);
+ b -= RADIANS_TO_HOURS(obsLon);
+ if ((a = fmod(a, 24.)) < 0)
+ a += 24.;
+ if ((b = fmod(b, 24.)) < 0)
+ b += 24.;
+
+ *set = a;
+ *rise = b;
+}
+
+
+static gdouble t0(time_t date)
+{
+ register gdouble t = ((gdouble)(EPOCH_TO_J2000(date) / 86400)) / 36525.0;
+ gdouble t0 = fmod( 6.697374558 + 2400.051366 * t + 2.5862e-5 * t * t, 24.);
+ if (t0 < 0.)
+ t0 += 24.;
+ return t0;
+}
+
+
+
+static gboolean calc_sun2 (time_t t, gdouble obsLat, gdouble obsLon,
+ time_t *rise, time_t *set)
+{
+ time_t gm_midn;
+ time_t lcl_midn;
+ gdouble gm_hoff, ndays, meanAnom, eccenAnom, delta, lambda;
+ gdouble ra1, ra2, decl1, decl2;
+ gdouble rise1, rise2, set1, set2;
+ gdouble tt, t00;
+ gdouble x, u, dt;
+
+ /* Approximate preceding local midnight at observer's longitude */
+ gm_midn = t - (t % 86400);
+ gm_hoff = floor((RADIANS_TO_DEGREES(obsLon) + 7.5) / 15.);
+ lcl_midn = gm_midn - 3600. * gm_hoff;
+ if (t - lcl_midn >= 86400)
+ lcl_midn += 86400;
+ else if (lcl_midn > t)
+ lcl_midn -= 86400;
+
+ /*
+ * Ecliptic longitude of the sun at midnight local time
+ * Start with an estimate based on a fixed daily rate
+ */
+ ndays = EPOCH_TO_J2000(lcl_midn) / 86400.;
+ meanAnom = DEGREES_TO_RADIANS(ndays * SOL_PROGRESSION
+ + MEAN_ECLIPTIC_LONGITUDE - PERIGEE_LONGITUDE);
+
+ /*
+ * Approximate solution of Kepler's equation:
+ * Find E which satisfies E - e sin(E) = M (mean anomaly)
+ */
+ eccenAnom = meanAnom;
+
+ while (1e-12 < fabs( delta = eccenAnom - ECCENTRICITY * sin(eccenAnom) - meanAnom))
+ {
+ eccenAnom -= delta / (1.- ECCENTRICITY * cos(eccenAnom));
+ }
+
+ /* Sun's longitude on the ecliptic */
+ lambda = fmod( DEGREES_TO_RADIANS ( PERIGEE_LONGITUDE )
+ + 2. * atan( sqrt((1.+ECCENTRICITY)/(1.-ECCENTRICITY))
+ * tan ( eccenAnom / 2. ) ),
+ 2. * M_PI);
+
+ /* Calculate equitorial coordinates of sun at previous and next local midnights */
+
+ ecl2equ (lcl_midn, lambda, &ra1, &decl1);
+ ecl2equ (lcl_midn + 86400., lambda + DEGREES_TO_RADIANS(SOL_PROGRESSION), &ra2, &decl2);
+
+ /* Convert to rise and set times assuming the earth were to stay in its position
+ * in its orbit around the sun. This will soon be followed by interpolating
+ * between the two
+ */
+
+ gstObsv (ra1, decl1, obsLat, obsLon - (gm_hoff * M_PI / 12.), &rise1, &set1);
+ gstObsv (ra2, decl2, obsLat, obsLon - (gm_hoff * M_PI / 12.), &rise2, &set2);
+
+ /* TODO: include calculations for regions near the poles. */
+ if (isnan(rise1) || isnan(rise2))
+ return FALSE;
+
+ if (rise2 < rise1) {
+ rise2 += 24.;
+ }
+ if (set2 < set1) {
+ set2 += 24.;
+ }
+
+ tt = t0(lcl_midn);
+ t00 = tt - (gm_hoff + RADIANS_TO_HOURS(obsLon)) * 1.002737909;
+
+ if (t00 < 0.)
+ t00 += 24.;
+
+ if (rise1 < t00) {
+ rise1 += 24.;
+ rise2 += 24.;
+ }
+ if (set1 < t00) {
+ set1 += 24.;
+ set2 += 24.;
+ }
+
+ /*
+ * Interpolate between the two
+ */
+ rise1 = (24.07 * rise1 - t00 * (rise2 - rise1)) / (24.07 + rise1 - rise2);
+ set1 = (24.07 * set1 - t00 * (set2 - set1)) / (24.07 + set1 - set2);
+
+ decl2 = (decl1 + decl2) / 2.;
+ x = DEGREES_TO_RADIANS(0.830725);
+ u = acos ( sin(obsLat) / cos(decl2) );
+ dt = RADIANS_TO_HOURS ( asin ( sin(x) / sin(u) )
+ / cos(decl2) );
+
+ rise1 = (rise1 - dt - tt) * 0.9972695661;
+ set1 = (set1 + dt - tt) * 0.9972695661;
+ if (rise1 < 0.)
+ rise1 += 24;
+ else if (rise1 >= 24.)
+ rise1 -= 24.;
+ if (set1 < 0.)
+ set1 += 24;
+ else if (set1 >= 24.)
+ set1 -= 24.;
+
+ *rise = (rise1 * 3600.) + lcl_midn;
+ *set = (set1 * 3600.) + lcl_midn;
+ return TRUE;
+}
+
+
+gboolean calc_sun (WeatherInfo *info)
+{
+ time_t now = time (NULL);
+
+ return info->location->latlon_valid
+ && calc_sun2(now, info->location->latitude, info->location->longitude,
+ &info->sunrise, &info->sunset);
+}
+
+
+/*
+ * Returns the interval, in seconds, until the next "sun event":
+ * - local midnight, when rise and set times are recomputed
+ * - next sunrise, when icon changes to daytime version
+ * - next sunset, when icon changes to nighttime version
+ */
+gint weather_info_next_sun_event(WeatherInfo *info)
+{
+ time_t now = time(NULL);
+ struct tm ltm;
+ time_t nxtEvent;
+
+ if (!calc_sun(info))
+ return -1;
+
+ /* Determine when the next local midnight occurs */
+ (void) localtime_r (&now, &ltm);
+ ltm.tm_sec = 0;
+ ltm.tm_min = 0;
+ ltm.tm_hour = 0;
+ ltm.tm_mday++;
+ nxtEvent = mktime(&ltm);
+
+ if (info->sunset > now && info->sunset < nxtEvent)
+ nxtEvent = info->sunset;
+ if (info->sunrise > now && info->sunrise < nxtEvent)
+ nxtEvent = info->sunrise;
+ return (gint)(nxtEvent - now);
+}
diff --git a/libgweather/weather-wx.c b/libgweather/weather-wx.c
new file mode 100644
index 0000000..64d2ad3
--- /dev/null
+++ b/libgweather/weather-wx.c
@@ -0,0 +1,128 @@
+/* $Id: weather-wx.c 9147 2005-12-12 00:22:17Z philipl $ */
+
+/*
+ * Papadimitriou Spiros <spapadim+@cs.cmu.edu>
+ *
+ * This code released under the GNU GPL.
+ * Read the file COPYING for more information.
+ *
+ * Weather server functions (WX Radar)
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <glib/gi18n-lib.h>
+
+#include <libgweather/weather.h>
+#include "weather-priv.h"
+
+static void wx_finish_read(GnomeVFSAsyncHandle *handle, GnomeVFSResult result,
+ gpointer buffer, GnomeVFSFileSize requested,
+ GnomeVFSFileSize body_len, gpointer data)
+{
+ WeatherInfo *info = (WeatherInfo *)data;
+
+ g_return_if_fail(info != NULL);
+ g_return_if_fail(handle == info->wx_handle);
+
+ info->radar = NULL;
+
+ if (result == GNOME_VFS_OK && body_len != 0) {
+ GError *error = NULL;
+ gdk_pixbuf_loader_write (info->radar_loader, buffer, body_len, &error);
+ if (error) {
+ g_print ("%s \n", error->message);
+ g_error_free (error);
+ }
+ gnome_vfs_async_read(handle, buffer, DATA_SIZE - 1, wx_finish_read, info);
+ return;
+ }
+ else if (result == GNOME_VFS_ERROR_EOF)
+ {
+ GdkPixbufAnimation *animation;
+
+ gdk_pixbuf_loader_close (info->radar_loader, NULL);
+ animation = gdk_pixbuf_loader_get_animation (info->radar_loader);
+ if (animation != NULL)
+ {
+ if (info->radar)
+ g_object_unref (info->radar);
+ info->radar = animation;
+ g_object_ref (info->radar);
+ }
+ g_object_unref (G_OBJECT (info->radar_loader));
+
+ }
+ else
+ {
+ g_print("%s", gnome_vfs_result_to_string(result));
+ g_warning(_("Failed to get METAR data.\n"));
+ info->wx_handle = NULL;
+ requests_done_check (info);
+ if(info->radar_loader) g_object_unref (G_OBJECT (info->radar_loader));
+ }
+
+ request_done(info->wx_handle, info);
+ g_free (buffer);
+ return;
+}
+
+static void wx_finish_open (GnomeVFSAsyncHandle *handle, GnomeVFSResult result, gpointer data)
+{
+ WeatherInfo *info = (WeatherInfo *)data;
+ WeatherLocation *loc;
+ gchar *body;
+
+ g_return_if_fail(info != NULL);
+ g_return_if_fail(handle == info->wx_handle);
+
+ body = g_malloc0(DATA_SIZE);
+
+ info->radar_buffer = NULL;
+ info->radar = NULL;
+ loc = info->location;
+ g_return_if_fail(loc != NULL);
+
+ if (result != GNOME_VFS_OK) {
+ g_warning("Failed to get radar map image.\n");
+ info->wx_handle = NULL;
+ requests_done_check (info);
+ g_free (body);
+ } else {
+ gnome_vfs_async_read(handle, body, DATA_SIZE -1, wx_finish_read, info);
+
+ }
+ return;
+}
+
+/* Get radar map and into newly allocated pixmap */
+void wx_start_open (WeatherInfo *info)
+{
+ gchar *url;
+ WeatherLocation *loc;
+
+ g_return_if_fail(info != NULL);
+ info->radar = NULL;
+ info->radar_loader = gdk_pixbuf_loader_new ();
+ loc = info->location;
+ g_return_if_fail(loc != NULL);
+
+
+ if (info->radar_url)
+ url = g_strdup (info->radar_url);
+ else {
+ if (loc->radar[0] == '-') return;
+ url = g_strdup_printf ("http://image.weather.com/web/radar/us_%s_closeradar_medium_usen.jpg", loc->radar);
+ }
+
+ gnome_vfs_async_open(&info->wx_handle, url, GNOME_VFS_OPEN_READ,
+ 0, wx_finish_open, info);
+
+ g_free(url);
+
+ return;
+}
+
diff --git a/libgweather/weather.c b/libgweather/weather.c
new file mode 100644
index 0000000..2120014
--- /dev/null
+++ b/libgweather/weather.c
@@ -0,0 +1,1090 @@
+/* $Id: weather.c 10520 2007-11-14 21:49:57Z ryanl $ */
+
+/*
+ * Papadimitriou Spiros <spapadim+@cs.cmu.edu>
+ *
+ * This code released under the GNU GPL.
+ * Read the file COPYING for more information.
+ *
+ * Overall weather server functions.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <string.h>
+#include <ctype.h>
+#include <math.h>
+
+#ifdef HAVE_VALUES_H
+#include <values.h>
+#endif
+
+#ifdef __FreeBSD__
+#include <sys/types.h>
+#endif
+#include <regex.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <glib/gi18n-lib.h>
+#include <gtk/gtkicontheme.h>
+#include <gdk-pixbuf/gdk-pixbuf.h>
+#include <gdk-pixbuf/gdk-pixbuf-loader.h>
+#include <libgnomevfs/gnome-vfs.h>
+
+#include <libgweather/weather.h>
+#include "weather-priv.h"
+
+void
+close_cb (GnomeVFSAsyncHandle *handle, GnomeVFSResult result, gpointer data);
+
+
+/*
+ * Convert string of the form "DD-MM-SSH" to radians
+ * DD:degrees (to 3 digits), MM:minutes, SS:seconds H:hemisphere (NESW)
+ * Return value is positive for N,E; negative for S,W.
+ */
+static gdouble dmsh2rad (const gchar *latlon)
+{
+ char *p1, *p2;
+ int deg, min, sec, dir;
+ gdouble value;
+
+ if (latlon == NULL)
+ return DBL_MAX;
+ p1 = strchr(latlon, '-');
+ p2 = strrchr(latlon, '-');
+ if (p1 == NULL || p1 == latlon) {
+ return DBL_MAX;
+ } else if (p1 == p2) {
+ sscanf (latlon, "%d-%d", &deg, &min);
+ sec = 0;
+ } else if (p2 == 1 + p1) {
+ return DBL_MAX;
+ } else {
+ sscanf (latlon, "%d-%d-%d", &deg, &min, &sec);
+ }
+ if (deg > 180 || min >= 60 || sec >= 60)
+ return DBL_MAX;
+ value = (gdouble)((deg * 60 + min) * 60 + sec) * M_PI / 648000.;
+
+ dir = toupper(latlon[strlen(latlon) - 1]);
+ if (dir == 'W' || dir == 'S')
+ value = -value;
+ else if (dir != 'E' && dir != 'N' && (value != 0.0 || dir != '0'))
+ value = DBL_MAX;
+ return value;
+}
+
+WeatherLocation *weather_location_new (const gchar *name, const gchar *code,
+ const gchar *zone, const gchar *radar,
+ const gchar *coordinates)
+{
+ WeatherLocation *location;
+
+ location = g_new(WeatherLocation, 1);
+
+ /* name and metar code must be set */
+ location->name = g_strdup(name);
+ location->code = g_strdup(code);
+
+ if (zone) {
+ location->zone = g_strdup(zone);
+ } else {
+ location->zone = g_strdup("------");
+ }
+
+ if (radar) {
+ location->radar = g_strdup(radar);
+ } else {
+ location->radar = g_strdup("---");
+ }
+
+ if (location->zone[0] == '-') {
+ location->zone_valid = FALSE;
+ } else {
+ location->zone_valid = TRUE;
+ }
+
+ location->coordinates = NULL;
+ if (coordinates)
+ {
+ char **pieces;
+
+ pieces = g_strsplit (coordinates, " ", -1);
+
+ if (g_strv_length (pieces) == 2)
+ {
+ location->coordinates = g_strdup(coordinates);
+ location->latitude = dmsh2rad (pieces[0]);
+ location->longitude = dmsh2rad (pieces[1]);
+ }
+
+ g_strfreev (pieces);
+ }
+
+ if (!location->coordinates)
+ {
+ location->coordinates = g_strdup("---");
+ location->latitude = DBL_MAX;
+ location->longitude = DBL_MAX;
+ }
+
+ location->latlon_valid = (location->latitude < DBL_MAX && location->longitude < DBL_MAX);
+
+ return location;
+}
+
+WeatherLocation *weather_location_clone (const WeatherLocation *location)
+{
+ WeatherLocation *clone;
+
+ clone = weather_location_new (location->name,
+ location->code, location->zone,
+ location->radar, location->coordinates);
+ clone->latitude = location->latitude;
+ clone->longitude = location->longitude;
+ clone->latlon_valid = location->latlon_valid;
+ return clone;
+}
+
+void weather_location_free (WeatherLocation *location)
+{
+ if (location) {
+ g_free (location->name);
+ g_free (location->code);
+ g_free (location->zone);
+ g_free (location->radar);
+ g_free (location->coordinates);
+
+ g_free (location);
+ }
+}
+
+gboolean weather_location_equal (const WeatherLocation *location1, const WeatherLocation *location2)
+{
+ if (!location1->code || !location2->code)
+ return 1;
+ return ( (strcmp(location1->code, location2->code) == 0) &&
+ (strcmp(location1->name, location2->name) == 0) );
+}
+
+static const gchar *wind_direction_str[] = {
+ N_("Variable"),
+ N_("North"), N_("North - NorthEast"), N_("Northeast"), N_("East - NorthEast"),
+ N_("East"), N_("East - Southeast"), N_("Southeast"), N_("South - Southeast"),
+ N_("South"), N_("South - Southwest"), N_("Southwest"), N_("West - Southwest"),
+ N_("West"), N_("West - Northwest"), N_("Northwest"), N_("North - Northwest")
+};
+
+const gchar *weather_wind_direction_string (WeatherWindDirection wind)
+{
+ if (wind < 0)
+ return _("Unknown");
+ if (wind >= (sizeof (wind_direction_str) / sizeof (char *)))
+ return _("Invalid");
+
+ return _(wind_direction_str[(int)wind]);
+}
+
+static const gchar *sky_str[] = {
+ N_("Clear Sky"),
+ N_("Broken clouds"),
+ N_("Scattered clouds"),
+ N_("Few clouds"),
+ N_("Overcast")
+};
+
+const gchar *weather_sky_string (WeatherSky sky)
+{
+ if (sky < 0 ||
+ sky >= (sizeof (sky_str) / sizeof (char *)))
+ return _("Invalid");
+
+ return _(sky_str[(int)sky]);
+}
+
+
+/*
+ * Even though tedious, I switched to a 2D array for weather condition
+ * strings, in order to facilitate internationalization, esp. for languages
+ * with genders.
+ */
+
+/*
+ * Almost all reportable combinations listed in
+ * http://www.crh.noaa.gov/arx/wx.tbl.html are entered below, except those
+ * having 2 qualifiers mixed together [such as "Blowing snow in vicinity"
+ * (VCBLSN), "Thunderstorm in vicinity" (VCTS), etc].
+ * Combinations that are not possible are filled in with "??".
+ * Some other exceptions not handled yet, such as "SN BLSN" which has
+ * special meaning.
+ */
+
+/*
+ * Note, magic numbers, when you change the size here, make sure to change
+ * the below function so that new values are recognized
+ */
+/* NONE VICINITY LIGHT MODERATE HEAVY SHALLOW PATCHES PARTIAL THUNDERSTORM BLOWING SHOWERS DRIFTING FREEZING */
+/* *******************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************/
+static const gchar *conditions_str[24][13] = {
+/* TRANSLATOR: If you want to know what "blowing" "shallow" "partial"
+ * etc means, you can go to http://www.weather.com/glossary/ and
+ * http://www.crh.noaa.gov/arx/wx.tbl.html */
+/* NONE */ {"??", "??", "??", "??", "??", "??", "??", "??", N_("Thunderstorm"), "??", "??", "??", "??" },
+/* DRIZZLE */ {N_("Drizzle"), "??", N_("Light drizzle"), N_("Moderate drizzle"), N_("Heavy drizzle"), "??", "??", "??", "??", "??", "??", "??", N_("Freezing drizzle") },
+/* RAIN */ {N_("Rain"), "??", N_("Light rain"), N_("Moderate rain"), N_("Heavy rain"), "??", "??", "??", N_("Thunderstorm"), "??", N_("Rain showers"), "??", N_("Freezing rain") },
+/* SNOW */ {N_("Snow"), "??", N_("Light snow"), N_("Moderate snow"), N_("Heavy snow"), "??", "??", "??", N_("Snowstorm"), N_("Blowing snowfall"), N_("Snow showers"), N_("Drifting snow"), "??" },
+/* SNOW_GRAINS */ {N_("Snow grains"), "??", N_("Light snow grains"), N_("Moderate snow grains"), N_("Heavy snow grains"), "??", "??", "??", "??", "??", "??", "??", "??" },
+/* ICE_CRYSTALS */ {N_("Ice crystals"), "??", "??", N_("Ice crystals"), "??", "??", "??", "??", "??", "??", "??", "??", "??" },
+/* ICE_PELLETS */ {N_("Ice pellets"), "??", N_("Few ice pellets"), N_("Moderate ice pellets"), N_("Heavy ice pellets"), "??", "??", "??", N_("Ice pellet storm"), "??", N_("Showers of ice pellets"), "??", "??" },
+/* HAIL */ {N_("Hail"), "??", "??", N_("Hail"), "??", "??", "??", "??", N_("Hailstorm"), "??", N_("Hail showers"), "??", "??", },
+/* SMALL_HAIL */ {N_("Small hail"), "??", "??", N_("Small hail"), "??", "??", "??", "??", N_("Small hailstorm"), "??", N_("Showers of small hail"), "??", "??" },
+/* PRECIPITATION */ {N_("Unknown precipitation"), "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??" },
+/* MIST */ {N_("Mist"), "??", "??", N_("Mist"), "??", "??", "??", "??", "??", "??", "??", "??", "??" },
+/* FOG */ {N_("Fog"), N_("Fog in the vicinity") , "??", N_("Fog"), "??", N_("Shallow fog"), N_("Patches of fog"), N_("Partial fog"), "??", "??", "??", "??", N_("Freezing fog") },
+/* SMOKE */ {N_("Smoke"), "??", "??", N_("Smoke"), "??", "??", "??", "??", "??", "??", "??", "??", "??" },
+/* VOLCANIC_ASH */ {N_("Volcanic ash"), "??", "??", N_("Volcanic ash"), "??", "??", "??", "??", "??", "??", "??", "??", "??" },
+/* SAND */ {N_("Sand"), "??", "??", N_("Sand"), "??", "??", "??", "??", "??", N_("Blowing sand"), "", N_("Drifting sand"), "??" },
+/* HAZE */ {N_("Haze"), "??", "??", N_("Haze"), "??", "??", "??", "??", "??", "??", "??", "??", "??" },
+/* SPRAY */ {"??", "??", "??", "??", "??", "??", "??", "??", "??", N_("Blowing sprays"), "??", "??", "??" },
+/* DUST */ {N_("Dust"), "??", "??", N_("Dust"), "??", "??", "??", "??", "??", N_("Blowing dust"), "??", N_("Drifting dust"), "??" },
+/* SQUALL */ {N_("Squall"), "??", "??", N_("Squall"), "??", "??", "??", "??", "??", "??", "??", "??", "??" },
+/* SANDSTORM */ {N_("Sandstorm"), N_("Sandstorm in the vicinity") , "??", N_("Sandstorm"), N_("Heavy sandstorm"), "??", "??", "??", "??", "??", "??", "??", "??" },
+/* DUSTSTORM */ {N_("Duststorm"), N_("Duststorm in the vicinity") , "??", N_("Duststorm"), N_("Heavy duststorm"), "??", "??", "??", "??", "??", "??", "??", "??" },
+/* FUNNEL_CLOUD */ {N_("Funnel cloud"), "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??" },
+/* TORNADO */ {N_("Tornado"), "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??" },
+/* DUST_WHIRLS */ {N_("Dust whirls"), N_("Dust whirls in the vicinity") , "??", N_("Dust whirls"), "??", "??", "??", "??", "??", "??", "??", "??", "??" }
+};
+
+const gchar *weather_conditions_string (WeatherConditions cond)
+{
+ const gchar *str;
+
+ if (!cond.significant) {
+ return "-";
+ } else {
+ if (cond.phenomenon >= 0 &&
+ cond.phenomenon < 24 &&
+ cond.qualifier >= 0 &&
+ cond.qualifier < 13)
+ str = _(conditions_str[(int)cond.phenomenon][(int)cond.qualifier]);
+ else
+ str = _("Invalid");
+ return (strlen(str) > 0) ? str : "-";
+ }
+}
+
+/* Locals turned global to facilitate asynchronous HTTP requests */
+
+
+gboolean requests_init (WeatherInfo *info)
+{
+ if (info->requests_pending)
+ return FALSE;
+
+ /*g_assert(!metar_handle && !iwin_handle && !wx_handle && !met_handle);*/
+
+ info->requests_pending = TRUE;
+
+ return TRUE;
+}
+
+void request_done (GnomeVFSAsyncHandle *handle, WeatherInfo *info)
+{
+ if (!handle)
+ return;
+
+ gnome_vfs_async_close(handle, close_cb, info);
+
+ info->sunValid = info->valid && calc_sun(info);
+ return;
+}
+
+void requests_done_check (WeatherInfo *info)
+{
+ g_return_if_fail(info->requests_pending);
+
+ if (!info->metar_handle && !info->iwin_handle &&
+ !info->wx_handle && !info->met_handle &&
+ !info->bom_handle) {
+ info->requests_pending = FALSE;
+ info->finish_cb(info, info->cb_data);
+ }
+}
+
+void
+close_cb (GnomeVFSAsyncHandle *handle, GnomeVFSResult result, gpointer data)
+{
+ WeatherInfo *info = (WeatherInfo *)data;
+
+ g_return_if_fail (info != NULL);
+
+ if (result != GNOME_VFS_OK)
+ g_warning("Error closing GnomeVFSAsyncHandle.\n");
+
+ if (handle == info->metar_handle)
+ info->metar_handle = NULL;
+ if (handle == info->iwin_handle)
+ info->iwin_handle = NULL;
+ if (handle == info->wx_handle)
+ info->wx_handle = NULL;
+ if (handle == info->met_handle)
+ info->met_handle = NULL;
+ if (handle == info->bom_handle)
+ info->bom_handle = NULL;
+
+ requests_done_check(info);
+
+ return;
+}
+
+/* Relative humidity computation - thanks to <Olof.Oberg@modopaper.modogroup.com> */
+
+
+static inline gdouble calc_humidity(gdouble temp, gdouble dewp)
+{
+ gdouble esat, esurf;
+
+ if (temp > -500.0 && dewp > -500.0) {
+ temp = TEMP_F_TO_C(temp);
+ dewp = TEMP_F_TO_C(dewp);
+
+ esat = 6.11 * pow(10.0, (7.5 * temp) / (237.7 + temp));
+ esurf = 6.11 * pow(10.0, (7.5 * dewp) / (237.7 + dewp));
+ } else {
+ esurf = -1.0;
+ esat = 1.0;
+ }
+ return ((esurf/esat) * 100.0);
+}
+
+static inline gdouble calc_apparent (WeatherInfo *info)
+{
+ gdouble temp = info->temp;
+ gdouble wind = WINDSPEED_KNOTS_TO_MPH(info->windspeed);
+ gdouble apparent = -1000.;
+
+
+ /*
+ * Wind chill calculations as of 01-Nov-2001
+ * http://www.nws.noaa.gov/om/windchill/index.shtml
+ * Some pages suggest that the formula will soon be adjusted
+ * to account for solar radiation (bright sun vs cloudy sky)
+ */
+ if (temp <= 50.0) {
+ if (wind > 3.0) {
+ gdouble v = pow(wind, 0.16);
+ apparent = 35.74 + 0.6215 * temp - 35.75 * v + 0.4275 * temp * v;
+ } else if (wind >= 0.) {
+ apparent = temp;
+ }
+ }
+ /*
+ * Heat index calculations:
+ * http://www.srh.noaa.gov/fwd/heatindex/heat5.html
+ */
+ else if (temp >= 80.0) {
+ if (info->temp >= -500. && info->dew >= -500.) {
+ gdouble humidity = calc_humidity(info->temp, info->dew);
+ gdouble t2 = temp * temp;
+ gdouble h2 = humidity * humidity;
+
+#if 1
+ /*
+ * A really precise formula. Note that overall precision is
+ * constrained by the accuracy of the instruments and that the
+ * we receive the temperature and dewpoints as integers.
+ */
+ gdouble t3 = t2 * temp;
+ gdouble h3 = h2 * temp;
+
+ apparent = 16.923
+ + 0.185212 * temp
+ + 5.37941 * humidity
+ - 0.100254 * temp * humidity
+ + 9.41695e-3 * t2
+ + 7.28898e-3 * h2
+ + 3.45372e-4 * t2 * humidity
+ - 8.14971e-4 * temp * h2
+ + 1.02102e-5 * t2 * h2
+ - 3.8646e-5 * t3
+ + 2.91583e-5 * h3
+ + 1.42721e-6 * t3 * humidity
+ + 1.97483e-7 * temp * h3
+ - 2.18429e-8 * t3 * h2
+ + 8.43296e-10 * t2 * h3
+ - 4.81975e-11 * t3 * h3;
+#else
+ /*
+ * An often cited alternative: values are within 5 degrees for
+ * most ranges between 10% and 70% humidity and to 110 degrees.
+ */
+ apparent = - 42.379
+ + 2.04901523 * temp
+ + 10.14333127 * humidity
+ - 0.22475541 * temp * humidity
+ - 6.83783e-3 * t2
+ - 5.481717e-2 * h2
+ + 1.22874e-3 * t2 * humidity
+ + 8.5282e-4 * temp * h2
+ - 1.99e-6 * t2 * h2;
+#endif
+ }
+ }
+ else {
+ apparent = temp;
+ }
+
+ return apparent;
+}
+
+
+WeatherInfo *
+_weather_info_fill (WeatherInfo *info,
+ WeatherLocation *location,
+ const WeatherPrefs *prefs,
+ WeatherInfoFunc cb,
+ gpointer data)
+{
+ g_return_val_if_fail(((info == NULL) && (location != NULL)) || \
+ ((info != NULL) && (location == NULL)), NULL);
+ g_return_val_if_fail(prefs != NULL, NULL);
+
+ /* FIXME: i'm not sure this works as intended anymore */
+ if (!info) {
+ info = g_new0(WeatherInfo, 1);
+ info->metar_handle = NULL;
+ info->iwin_handle = NULL;
+ info->wx_handle = NULL;
+ info->met_handle = NULL;
+ info->bom_handle = NULL;
+ info->requests_pending = FALSE;
+ info->metar_buffer = NULL;
+ info->iwin_buffer = NULL;
+ info->met_buffer = NULL;
+ info->bom_buffer = NULL;
+ info->location = weather_location_clone(location);
+ } else {
+ location = info->location;
+ if (info->forecast)
+ g_free (info->forecast);
+
+ info->forecast = NULL;
+ if (info->radar != NULL) {
+ g_object_unref (info->radar);
+ info->radar = NULL;
+ }
+ }
+
+ /* Update in progress */
+ if (!requests_init(info)) {
+ return NULL;
+ }
+
+ /* Defaults (just in case...) */
+ /* Well, no just in case anymore. We may actually fail to fetch some
+ * fields. */
+ info->forecast_type = prefs->type;
+
+ info->temperature_unit = prefs->temperature_unit;
+ info->speed_unit = prefs->speed_unit;
+ info->pressure_unit = prefs->pressure_unit;
+ info->distance_unit = prefs->distance_unit;
+
+ info->update = 0;
+ info->sky = -1;
+ info->cond.significant = FALSE;
+ info->cond.phenomenon = PHENOMENON_NONE;
+ info->cond.qualifier = QUALIFIER_NONE;
+ info->temp = -1000.0;
+ info->dew = -1000.0;
+ info->wind = -1;
+ info->windspeed = -1;
+ info->pressure = -1.0;
+ info->visibility = -1.0;
+ info->sunValid = FALSE;
+ info->sunrise = 0;
+ info->sunset = 0;
+ info->forecast = NULL;
+ info->radar = NULL;
+ info->radar_url = prefs->radar && prefs->radar_custom_url ?
+ g_strdup (prefs->radar_custom_url) : NULL;
+ info->metar_handle = NULL;
+ info->iwin_handle = NULL;
+ info->wx_handle = NULL;
+ info->met_handle = NULL;
+ info->bom_handle = NULL;
+ info->requests_pending = TRUE;
+ info->finish_cb = cb;
+ info->cb_data = data;
+
+ metar_start_open(info);
+ iwin_start_open(info);
+
+ if (prefs->radar)
+ wx_start_open(info);
+
+ return info;
+}
+
+void weather_info_abort (WeatherInfo *info)
+{
+ if (info->metar_handle) {
+ gnome_vfs_async_cancel(info->metar_handle);
+ info->metar_handle = NULL;
+ }
+
+ if (info->iwin_handle) {
+ gnome_vfs_async_cancel(info->iwin_handle);
+ info->iwin_handle = NULL;
+ }
+
+ if (info->wx_handle) {
+ gnome_vfs_async_cancel(info->wx_handle);
+ info->wx_handle = NULL;
+ }
+
+ if (info->met_handle) {
+ gnome_vfs_async_cancel(info->met_handle);
+ info->met_handle = NULL;
+ }
+
+ if (info->bom_handle) {
+ gnome_vfs_async_cancel(info->bom_handle);
+ info->bom_handle = NULL;
+ }
+
+ info->requests_pending = FALSE;
+}
+
+WeatherInfo *weather_info_clone (const WeatherInfo *info)
+{
+ WeatherInfo *clone;
+
+ g_return_val_if_fail(info != NULL, NULL);
+
+ clone = g_new(WeatherInfo, 1);
+
+
+ /* move everything */
+ g_memmove(clone, info, sizeof(WeatherInfo));
+
+
+ /* special moves */
+ clone->location = weather_location_clone(info->location);
+ /* This handles null correctly */
+ clone->forecast = g_strdup(info->forecast);
+ clone->radar_url = g_strdup (info->radar_url);
+
+ clone->radar = info->radar;
+ if (clone->radar != NULL)
+ g_object_ref (clone->radar);
+
+ return clone;
+}
+
+void weather_info_free (WeatherInfo *info)
+{
+ if (!info)
+ return;
+
+ weather_info_abort (info);
+
+ weather_location_free(info->location);
+ info->location = NULL;
+
+ g_free(info->forecast);
+ info->forecast = NULL;
+
+ if (info->radar != NULL) {
+ g_object_unref (info->radar);
+ info->radar = NULL;
+ }
+
+ if (info->iwin_buffer)
+ g_free (info->iwin_buffer);
+
+ if (info->metar_buffer)
+ g_free (info->metar_buffer);
+
+ if (info->met_buffer)
+ g_free (info->met_buffer);
+
+ if (info->bom_buffer)
+ g_free (info->bom_buffer);
+
+ g_free(info);
+}
+
+gboolean weather_info_is_valid (WeatherInfo *info)
+{
+ g_return_val_if_fail(info != NULL, FALSE);
+ return info->valid;
+}
+
+const WeatherLocation *weather_info_get_location (WeatherInfo *info)
+{
+ g_return_val_if_fail(info != NULL, NULL);
+ return info->location;
+}
+
+const gchar *weather_info_get_location_name (WeatherInfo *info)
+{
+ g_return_val_if_fail(info != NULL, NULL);
+ g_return_val_if_fail(info->location != NULL, NULL);
+ return info->location->name;
+}
+
+const gchar *weather_info_get_update (WeatherInfo *info)
+{
+ static gchar buf[200];
+ char *utf8, *timeformat;
+
+ g_return_val_if_fail(info != NULL, NULL);
+
+ if (!info->valid)
+ return "-";
+
+ if (info->update != 0) {
+ struct tm tm;
+ localtime_r (&info->update, &tm);
+ /* TRANSLATOR: this is a format string for strftime
+ * see `man 3 strftime` for more details
+ */
+ timeformat = g_locale_from_utf8 (_("%a, %b %d / %H:%M"), -1,
+ NULL, NULL, NULL);
+ if (!timeformat) {
+ strcpy (buf, "???");
+ }
+ else if (strftime(buf, sizeof(buf), timeformat, &tm) <= 0) {
+ strcpy (buf, "???");
+ }
+ g_free (timeformat);
+
+ /* Convert to UTF-8 */
+ utf8 = g_locale_to_utf8 (buf, -1, NULL, NULL, NULL);
+ strcpy (buf, utf8);
+ g_free (utf8);
+ } else {
+ strncpy(buf, _("Unknown observation time"), sizeof (buf));
+ buf[sizeof(buf)-1] = '\0';
+ }
+
+ return buf;
+}
+
+const gchar *weather_info_get_sky (WeatherInfo *info)
+{
+ g_return_val_if_fail(info != NULL, NULL);
+ if (!info->valid)
+ return "-";
+ if (info->sky < 0)
+ return _("Unknown");
+ return weather_sky_string(info->sky);
+}
+
+const gchar *weather_info_get_conditions (WeatherInfo *info)
+{
+ g_return_val_if_fail(info != NULL, NULL);
+ if (!info->valid)
+ return "-";
+ return weather_conditions_string(info->cond);
+}
+
+static const gchar *temperature_string (gfloat far, TempUnit to_unit, gboolean round)
+{
+ static gchar buf[100];
+
+ switch (to_unit) {
+ case TEMP_UNIT_FAHRENHEIT:
+ if (!round) {
+ /* TRANSLATOR: This is the temperature in degrees Fahrenheit (\342\204\211 is the "DEGREE FAHRENHEIT" symbol) */
+ g_snprintf(buf, sizeof (buf), _("%.1f \342\204\211"), far);
+ } else {
+ /* TRANSLATOR: This is the temperature in degrees Fahrenheit (\342\204\211 is the "DEGREE FAHRENHEIT" symbol) */
+ g_snprintf(buf, sizeof (buf), _("%d \342\204\211"), (int)floor(far + 0.5));
+ }
+ break;
+ case TEMP_UNIT_CENTIGRADE:
+ if (!round) {
+ /* TRANSLATOR: This is the temperature in degrees Celsius (\342\204\203 is the "DEGREE CELSIUS" symbol) */
+ g_snprintf (buf, sizeof (buf), _("%.1f \342\204\203"), TEMP_F_TO_C(far));
+ } else {
+ /* TRANSLATOR: This is the temperature in degrees Celsius (\342\204\203 is the "DEGREE CELSIUS" symbol) */
+ g_snprintf (buf, sizeof (buf), _("%d \342\204\203"), (int)floor(TEMP_F_TO_C(far) + 0.5));
+ }
+ break;
+ case TEMP_UNIT_KELVIN:
+ if (!round) {
+ /* TRANSLATOR: This is the temperature in kelvin */
+ g_snprintf (buf, sizeof (buf), _("%.1f K"), TEMP_F_TO_K(far));
+ } else {
+ /* TRANSLATOR: This is the temperature in kelvin */
+ g_snprintf (buf, sizeof (buf), _("%d K"), (int)floor(TEMP_F_TO_K(far)));
+ }
+ break;
+
+ case TEMP_UNIT_INVALID:
+ case TEMP_UNIT_DEFAULT:
+ default:
+ g_warning("Conversion to illegal temperature unit: %d", to_unit);
+ return (_("Unknown"));
+ }
+
+ return buf;
+}
+
+const gchar *weather_info_get_temp (WeatherInfo *info)
+{
+ g_return_val_if_fail(info != NULL, NULL);
+
+ if (!info->valid)
+ return "-";
+ if (info->temp < -500.0)
+ return _("Unknown");
+
+ return temperature_string (info->temp, info->temperature_unit, FALSE);
+}
+
+const gchar *weather_info_get_dew (WeatherInfo *info)
+{
+ g_return_val_if_fail(info != NULL, NULL);
+
+ if (!info->valid)
+ return "-";
+ if (info->dew < -500.0)
+ return _("Unknown");
+
+ return temperature_string (info->dew, info->temperature_unit, FALSE);
+}
+
+const gchar *weather_info_get_humidity (WeatherInfo *info)
+{
+ static gchar buf[20];
+ gdouble humidity;
+ g_return_val_if_fail(info != NULL, NULL);
+ if (!info->valid)
+ return "-";
+
+ humidity = calc_humidity(info->temp, info->dew);
+ if (humidity < 0.0)
+ return _("Unknown");
+
+ /* TRANSLATOR: This is the humidity in percent */
+ g_snprintf(buf, sizeof (buf), _("%.f%%"), humidity);
+ return buf;
+}
+
+const gchar *weather_info_get_apparent (WeatherInfo *info)
+{
+ gdouble apparent;
+ g_return_val_if_fail(info != NULL, NULL);
+ if (!info->valid)
+ return "-";
+
+ apparent = calc_apparent(info);
+ if (apparent < -500.0)
+ return _("Unknown");
+
+ return temperature_string (apparent, info->temperature_unit, FALSE);
+}
+
+static const gchar *windspeed_string (gfloat knots, SpeedUnit to_unit)
+{
+ static gchar buf[100];
+
+ switch (to_unit) {
+ case SPEED_UNIT_KNOTS:
+ /* TRANSLATOR: This is the wind speed in knots */
+ g_snprintf(buf, sizeof (buf), _("%0.1f knots"), knots);
+ break;
+ case SPEED_UNIT_MPH:
+ /* TRANSLATOR: This is the wind speed in miles per hour */
+ g_snprintf(buf, sizeof (buf), _("%.1f mph"), WINDSPEED_KNOTS_TO_MPH(knots));
+ break;
+ case SPEED_UNIT_KPH:
+ /* TRANSLATOR: This is the wind speed in kilometers per hour */
+ g_snprintf(buf, sizeof (buf), _("%.1f km/h"), WINDSPEED_KNOTS_TO_KPH(knots));
+ break;
+ case SPEED_UNIT_MS:
+ /* TRANSLATOR: This is the wind speed in meters per second */
+ g_snprintf(buf, sizeof (buf), _("%.1f m/s"), WINDSPEED_KNOTS_TO_MS(knots));
+ break;
+ case SPEED_UNIT_BFT:
+ /* TRANSLATOR: This is the wind speed as a Beaufort force factor
+ * (commonly used in nautical wind estimation).
+ */
+ g_snprintf (buf, sizeof (buf), _("Beaufort force %.1f"),
+ WINDSPEED_KNOTS_TO_BFT (knots));
+ break;
+ case SPEED_UNIT_INVALID:
+ case SPEED_UNIT_DEFAULT:
+ default:
+ g_warning("Conversion to illegal speed unit: %d", to_unit);
+ return _("Unknown");
+ }
+
+ return buf;
+}
+const gchar *weather_info_get_wind (WeatherInfo *info)
+{
+ static gchar buf[200];
+ g_return_val_if_fail(info != NULL, NULL);
+ if (!info->valid)
+ return "-";
+ if (info->windspeed < 0.0 || info->wind < 0)
+ return _("Unknown");
+ if (info->windspeed == 0.00) {
+ strncpy(buf, _("Calm"), sizeof(buf));
+ buf[sizeof(buf)-1] = '\0';
+ } else
+ /* TRANSLATOR: This is 'wind direction' / 'wind speed' */
+ g_snprintf(buf, sizeof(buf), _("%s / %s"),
+ weather_wind_direction_string(info->wind),
+ windspeed_string(info->windspeed, info->speed_unit));
+ return buf;
+}
+
+const gchar *weather_info_get_pressure (WeatherInfo *info)
+{
+ static gchar buf[100];
+ g_return_val_if_fail(info != NULL, NULL);
+ if (!info->valid)
+ return "-";
+ if (info->pressure < 0.0)
+ return _("Unknown");
+
+ switch (info->pressure_unit) {
+ case PRESSURE_UNIT_INCH_HG:
+ /* TRANSLATOR: This is pressure in inches of mercury */
+ g_snprintf (buf, sizeof (buf), _("%.2f inHg"), info->pressure);
+ break;
+ case PRESSURE_UNIT_MM_HG:
+ /* TRANSLATOR: This is pressure in millimeters of mercury */
+ g_snprintf (buf, sizeof (buf), _("%.1f mmHg"), PRESSURE_INCH_TO_MM(info->pressure));
+ break;
+ case PRESSURE_UNIT_KPA:
+ /* TRANSLATOR: This is pressure in kiloPascals */
+ g_snprintf (buf, sizeof (buf), _("%.2f kPa"), PRESSURE_INCH_TO_KPA(info->pressure));
+ break;
+ case PRESSURE_UNIT_HPA:
+ /* TRANSLATOR: This is pressure in hectoPascals */
+ g_snprintf (buf, sizeof (buf), _("%.2f hPa"), PRESSURE_INCH_TO_HPA(info->pressure));
+ break;
+ case PRESSURE_UNIT_MB:
+ /* TRANSLATOR: This is pressure in millibars */
+ g_snprintf (buf, sizeof (buf), _("%.2f mb"), PRESSURE_INCH_TO_MB(info->pressure));
+ break;
+ case PRESSURE_UNIT_ATM:
+ /* TRANSLATOR: This is pressure in atmospheres */
+ g_snprintf (buf, sizeof (buf), _("%.3f atm"), PRESSURE_INCH_TO_ATM(info->pressure));
+ break;
+
+ case PRESSURE_UNIT_INVALID:
+ case PRESSURE_UNIT_DEFAULT:
+ default:
+ g_warning("Conversion to illegal pressure unit: %d", info->pressure_unit);
+ return _("Unknown");
+ }
+
+ return buf;
+}
+
+const gchar *weather_info_get_visibility (WeatherInfo *info)
+{
+ static gchar buf[100];
+ g_return_val_if_fail(info != NULL, NULL);
+ if (!info->valid)
+ return "-";
+ if (info->visibility < 0.0)
+ return _("Unknown");
+
+ switch (info->distance_unit) {
+ case DISTANCE_UNIT_MILES:
+ /* TRANSLATOR: This is the visibility in miles */
+ g_snprintf(buf, sizeof (buf), _("%.1f miles"), info->visibility);
+ break;
+ case DISTANCE_UNIT_KM:
+ /* TRANSLATOR: This is the visibility in kilometers */
+ g_snprintf(buf, sizeof (buf), _("%.1f km"), VISIBILITY_SM_TO_KM(info->visibility));
+ break;
+ case DISTANCE_UNIT_METERS:
+ /* TRANSLATOR: This is the visibility in meters */
+ g_snprintf(buf, sizeof (buf), _("%.0fm"), VISIBILITY_SM_TO_M(info->visibility));
+ break;
+
+ case DISTANCE_UNIT_INVALID:
+ case DISTANCE_UNIT_DEFAULT:
+ default:
+ g_warning("Conversion to illegal visibility unit: %d", info->pressure_unit);
+ return _("Unknown");
+ }
+
+ return buf;
+}
+
+const gchar *weather_info_get_sunrise (WeatherInfo *info)
+{
+ static gchar buf[200];
+ struct tm tm;
+
+ g_return_val_if_fail(info && info->location, NULL);
+
+ if (!info->location->latlon_valid)
+ return "-";
+ if (!info->valid)
+ return "-";
+ if (!calc_sun (info))
+ return "-";
+
+ localtime_r(&info->sunrise, &tm);
+ if (strftime(buf, sizeof(buf), _("%H:%M"), &tm) <= 0)
+ return "-";
+ return buf;
+}
+
+const gchar *weather_info_get_sunset (WeatherInfo *info)
+{
+ static gchar buf[200];
+ struct tm tm;
+
+ g_return_val_if_fail(info && info->location, NULL);
+
+ if (!info->location->latlon_valid)
+ return "-";
+ if (!info->valid)
+ return "-";
+ if (!calc_sun (info))
+ return "-";
+
+ localtime_r(&info->sunset, &tm);
+ if (strftime(buf, sizeof(buf), _("%H:%M"), &tm) <= 0)
+ return "-";
+ return buf;
+}
+
+const gchar *weather_info_get_forecast (WeatherInfo *info)
+{
+ g_return_val_if_fail(info != NULL, NULL);
+ return info->forecast;
+}
+
+GdkPixbufAnimation *weather_info_get_radar (WeatherInfo *info)
+{
+ g_return_val_if_fail(info != NULL, NULL);
+ return info->radar;
+}
+
+const gchar *weather_info_get_temp_summary (WeatherInfo *info)
+{
+ if (!info)
+ return NULL;
+ if (!info->valid || info->temp < -500.0)
+ return "--";
+
+ return temperature_string (info->temp, info->temperature_unit, TRUE);
+
+}
+
+gchar *weather_info_get_weather_summary (WeatherInfo *info)
+{
+ const gchar *buf;
+ g_return_val_if_fail(info != NULL, NULL);
+ if (!info->valid)
+ return g_strdup (_("Retrieval failed"));
+ buf = weather_info_get_conditions(info);
+ if (!strcmp(buf, "-"))
+ buf = weather_info_get_sky(info);
+ return g_strdup_printf ("%s: %s", weather_info_get_location_name (info), buf);
+}
+
+const gchar *
+weather_info_get_icon_name (WeatherInfo *info)
+{
+ WeatherConditions cond;
+ WeatherSky sky;
+ time_t current_time;
+ gboolean daytime;
+
+ if (!info || !info->valid)
+ return NULL;
+
+ cond = info->cond;
+ sky = info->sky;
+
+ if (cond.significant) {
+ if (cond.phenomenon != PHENOMENON_NONE &&
+ cond.qualifier == QUALIFIER_THUNDERSTORM)
+ return "weather-storm";
+
+ switch (cond.phenomenon) {
+ case PHENOMENON_NONE:
+ break;
+
+ case PHENOMENON_DRIZZLE:
+ case PHENOMENON_RAIN:
+ case PHENOMENON_UNKNOWN_PRECIPITATION:
+ case PHENOMENON_HAIL:
+ case PHENOMENON_SMALL_HAIL:
+ return "weather-showers";
+
+ case PHENOMENON_SNOW:
+ case PHENOMENON_SNOW_GRAINS:
+ case PHENOMENON_ICE_PELLETS:
+ case PHENOMENON_ICE_CRYSTALS:
+ return "weather-snow";
+
+ case PHENOMENON_TORNADO:
+ case PHENOMENON_SQUALL:
+ return "weather-storm";
+
+ case PHENOMENON_MIST:
+ case PHENOMENON_FOG:
+ case PHENOMENON_SMOKE:
+ case PHENOMENON_VOLCANIC_ASH:
+ case PHENOMENON_SAND:
+ case PHENOMENON_HAZE:
+ case PHENOMENON_SPRAY:
+ case PHENOMENON_DUST:
+ case PHENOMENON_SANDSTORM:
+ case PHENOMENON_DUSTSTORM:
+ case PHENOMENON_FUNNEL_CLOUD:
+ case PHENOMENON_DUST_WHIRLS:
+ return "weather-fog";
+ }
+ }
+
+ current_time = time (NULL);
+ daytime = ((!info->sunValid) ||
+ (current_time >= info->sunrise &&
+ current_time < info->sunset));
+
+ switch (sky) {
+ case SKY_INVALID:
+ case SKY_CLEAR:
+ if (daytime)
+ return "weather-clear";
+ else
+ return "weather-clear-night";
+
+ case SKY_BROKEN:
+ case SKY_SCATTERED:
+ case SKY_FEW:
+ if (daytime)
+ return "weather-few-clouds";
+ else
+ return "weather-few-clouds-night";
+
+ case SKY_OVERCAST:
+ return "weather-overcast";
+ }
+
+ return NULL;
+}
diff --git a/libgweather/weather.h b/libgweather/weather.h
new file mode 100644
index 0000000..2ecddd9
--- /dev/null
+++ b/libgweather/weather.h
@@ -0,0 +1,159 @@
+#ifndef __WEATHER_H_
+#define __WEATHER_H_
+
+/* $Id: weather.h 10520 2007-11-14 21:49:57Z ryanl $ */
+
+/*
+ * Papadimitriou Spiros <spapadim+@cs.cmu.edu>
+ *
+ * This code released under the GNU GPL.
+ * Read the file COPYING for more information.
+ *
+ * Public header for weather server functions.
+ *
+ */
+
+#include <gdk-pixbuf/gdk-pixbuf-loader.h>
+
+G_BEGIN_DECLS
+
+/*
+ * Location
+ */
+
+#define WEATHER_LOCATION_CODE_LEN 4
+
+struct _WeatherLocation {
+ gchar *name;
+ gchar *code;
+ gchar *zone;
+ gchar *radar;
+ gboolean zone_valid;
+ gchar *coordinates;
+ gdouble latitude;
+ gdouble longitude;
+ gboolean latlon_valid;
+};
+
+typedef struct _WeatherLocation WeatherLocation;
+
+WeatherLocation * weather_location_new (const gchar *trans_name,
+ const gchar *code,
+ const gchar *zone,
+ const gchar *radar,
+ const gchar *coordinates);
+WeatherLocation * weather_location_clone (const WeatherLocation *location);
+void weather_location_free (WeatherLocation *location);
+gboolean weather_location_equal (const WeatherLocation *location1,
+ const WeatherLocation *location2);
+
+/*
+ * Weather prefs
+ */
+
+typedef enum _WeatherForecastType {
+ FORECAST_STATE,
+ FORECAST_ZONE
+} WeatherForecastType;
+
+typedef enum {
+ TEMP_UNIT_INVALID = 0,
+ TEMP_UNIT_DEFAULT,
+ TEMP_UNIT_KELVIN,
+ TEMP_UNIT_CENTIGRADE,
+ TEMP_UNIT_FAHRENHEIT
+} TempUnit;
+
+typedef enum {
+ SPEED_UNIT_INVALID = 0,
+ SPEED_UNIT_DEFAULT,
+ SPEED_UNIT_MS, /* metres per second */
+ SPEED_UNIT_KPH, /* kilometres per hour */
+ SPEED_UNIT_MPH, /* miles per hour */
+ SPEED_UNIT_KNOTS, /* Knots */
+ SPEED_UNIT_BFT /* Beaufort scale */
+} SpeedUnit;
+
+typedef enum {
+ PRESSURE_UNIT_INVALID = 0,
+ PRESSURE_UNIT_DEFAULT,
+ PRESSURE_UNIT_KPA, /* kiloPascal */
+ PRESSURE_UNIT_HPA, /* hectoPascal */
+ PRESSURE_UNIT_MB, /* 1 millibars = 1 hectoPascal */
+ PRESSURE_UNIT_MM_HG, /* millimeters of mecury */
+ PRESSURE_UNIT_INCH_HG, /* inches of mercury */
+ PRESSURE_UNIT_ATM /* atmosphere */
+} PressureUnit;
+
+typedef enum {
+ DISTANCE_UNIT_INVALID = 0,
+ DISTANCE_UNIT_DEFAULT,
+ DISTANCE_UNIT_METERS,
+ DISTANCE_UNIT_KM,
+ DISTANCE_UNIT_MILES
+} DistanceUnit;
+
+struct _WeatherPrefs {
+ WeatherForecastType type;
+
+ gboolean radar;
+ const char *radar_custom_url;
+
+ TempUnit temperature_unit;
+ SpeedUnit speed_unit;
+ PressureUnit pressure_unit;
+ DistanceUnit distance_unit;
+};
+
+typedef struct _WeatherPrefs WeatherPrefs;
+
+/*
+ * Weather Info
+ */
+
+typedef struct _WeatherInfo WeatherInfo;
+
+typedef void (*WeatherInfoFunc) (WeatherInfo *info, gpointer data);
+
+WeatherInfo * _weather_info_fill (WeatherInfo *info,
+ WeatherLocation *location,
+ const WeatherPrefs *prefs,
+ WeatherInfoFunc cb,
+ gpointer data);
+#define weather_info_new(location, prefs, cb, data) _weather_info_fill(NULL, (location), (prefs), (cb), (data))
+#define weather_info_update(info, prefs, cb, data) _weather_info_fill((info), NULL, (prefs), (cb), (data))
+
+void weather_info_abort (WeatherInfo *info);
+WeatherInfo * weather_info_clone (const WeatherInfo *info);
+void weather_info_free (WeatherInfo *info);
+
+gboolean weather_info_is_valid (WeatherInfo *info);
+
+void weather_info_to_metric (WeatherInfo *info);
+void weather_info_to_imperial (WeatherInfo *info);
+
+const WeatherLocation * weather_info_get_location (WeatherInfo *info);
+const gchar * weather_info_get_location_name (WeatherInfo *info);
+const gchar * weather_info_get_update (WeatherInfo *info);
+const gchar * weather_info_get_sky (WeatherInfo *info);
+const gchar * weather_info_get_conditions (WeatherInfo *info);
+const gchar * weather_info_get_temp (WeatherInfo *info);
+const gchar * weather_info_get_dew (WeatherInfo *info);
+const gchar * weather_info_get_humidity (WeatherInfo *info);
+const gchar * weather_info_get_wind (WeatherInfo *info);
+const gchar * weather_info_get_pressure (WeatherInfo *info);
+const gchar * weather_info_get_visibility (WeatherInfo *info);
+const gchar * weather_info_get_apparent (WeatherInfo *info);
+const gchar * weather_info_get_sunrise (WeatherInfo *info);
+const gchar * weather_info_get_sunset (WeatherInfo *info);
+const gchar * weather_info_get_forecast (WeatherInfo *info);
+GdkPixbufAnimation * weather_info_get_radar (WeatherInfo *info);
+
+const gchar * weather_info_get_temp_summary (WeatherInfo *info);
+gchar * weather_info_get_weather_summary(WeatherInfo *info);
+
+const gchar * weather_info_get_icon_name (WeatherInfo *info);
+gint weather_info_next_sun_event (WeatherInfo *info);
+G_END_DECLS
+
+#endif /* __WEATHER_H_ */