Blame libgweather/weather-owm.c

rpm-build ca2b01
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
rpm-build ca2b01
/* weather-owm.c - Open Weather Map backend
rpm-build ca2b01
 *
rpm-build ca2b01
 * This program is free software; you can redistribute it and/or
rpm-build ca2b01
 * modify it under the terms of the GNU General Public License as
rpm-build ca2b01
 * published by the Free Software Foundation; either version 2 of the
rpm-build ca2b01
 * License, or (at your option) any later version.
rpm-build ca2b01
 *
rpm-build ca2b01
 * This program is distributed in the hope that it will be useful, but
rpm-build ca2b01
 * WITHOUT ANY WARRANTY; without even the implied warranty of
rpm-build ca2b01
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
rpm-build ca2b01
 * General Public License for more details.
rpm-build ca2b01
 *
rpm-build ca2b01
 * You should have received a copy of the GNU General Public License
rpm-build ca2b01
 * along with this program; if not, see
rpm-build ca2b01
 * <http://www.gnu.org/licenses/>.
rpm-build ca2b01
 */
rpm-build ca2b01
rpm-build ca2b01
#ifdef HAVE_CONFIG_H
rpm-build ca2b01
#include <config.h>
rpm-build ca2b01
#endif
rpm-build ca2b01
rpm-build ca2b01
#include <stdio.h>
rpm-build ca2b01
#include <stdlib.h>
rpm-build ca2b01
#include <assert.h>
rpm-build ca2b01
#include <string.h>
rpm-build ca2b01
#include <ctype.h>
rpm-build ca2b01
#include <math.h>
rpm-build ca2b01
#include <time.h>
rpm-build ca2b01
#include <unistd.h>
rpm-build ca2b01
#include <langinfo.h>
rpm-build ca2b01
rpm-build ca2b01
#include <libxml/parser.h>
rpm-build ca2b01
#include <libxml/xpath.h>
rpm-build ca2b01
#include <libxml/xpathInternals.h>
rpm-build ca2b01
rpm-build ca2b01
#include "gweather-private.h"
rpm-build ca2b01
rpm-build ca2b01
#define XC(t) ((const xmlChar *)(t))
rpm-build ca2b01
rpm-build ca2b01
/* Reference for symbols at http://bugs.openweathermap.org/projects/api/wiki/Weather_Condition_Codes */
rpm-build ca2b01
/* FIXME: the libgweather API is not expressive enough */
rpm-build ca2b01
static struct owm_symbol {
rpm-build ca2b01
    int symbol;
rpm-build ca2b01
    GWeatherSky sky;
rpm-build ca2b01
    GWeatherConditions condition;
rpm-build ca2b01
} symbols[] = {
rpm-build ca2b01
    { 200, GWEATHER_SKY_OVERCAST, { TRUE, GWEATHER_PHENOMENON_RAIN, GWEATHER_QUALIFIER_THUNDERSTORM } }, /* Thunderstorm with light rain */
rpm-build ca2b01
    { 201, GWEATHER_SKY_OVERCAST, { TRUE, GWEATHER_PHENOMENON_RAIN, GWEATHER_QUALIFIER_THUNDERSTORM } }, /* Thunderstorm with rain */
rpm-build ca2b01
    { 202, GWEATHER_SKY_OVERCAST, { TRUE, GWEATHER_PHENOMENON_RAIN, GWEATHER_QUALIFIER_THUNDERSTORM } }, /* Thunderstorm with heavy rain */
rpm-build ca2b01
    { 210, GWEATHER_SKY_OVERCAST, { TRUE, GWEATHER_PHENOMENON_RAIN, GWEATHER_QUALIFIER_THUNDERSTORM } }, /* Light thunderstorm */
rpm-build ca2b01
    { 211, GWEATHER_SKY_OVERCAST, { TRUE, GWEATHER_PHENOMENON_RAIN, GWEATHER_QUALIFIER_THUNDERSTORM } }, /* Thunderstorm */
rpm-build ca2b01
    { 212, GWEATHER_SKY_OVERCAST, { TRUE, GWEATHER_PHENOMENON_RAIN, GWEATHER_QUALIFIER_THUNDERSTORM } }, /* Heavy thunderstorm */
rpm-build ca2b01
    { 221, GWEATHER_SKY_OVERCAST, { TRUE, GWEATHER_PHENOMENON_RAIN, GWEATHER_QUALIFIER_THUNDERSTORM } }, /* Ragged thunderstorm */
rpm-build ca2b01
    { 230, GWEATHER_SKY_OVERCAST, { TRUE, GWEATHER_PHENOMENON_DRIZZLE, GWEATHER_QUALIFIER_THUNDERSTORM } }, /* Thunderstorm with light drizzle */
rpm-build ca2b01
    { 231, GWEATHER_SKY_OVERCAST, { TRUE, GWEATHER_PHENOMENON_DRIZZLE, GWEATHER_QUALIFIER_THUNDERSTORM } }, /* Thunderstorm with drizzle */
rpm-build ca2b01
    { 232, GWEATHER_SKY_OVERCAST, { TRUE, GWEATHER_PHENOMENON_DRIZZLE, GWEATHER_QUALIFIER_THUNDERSTORM } }, /* Thunderstorm with heavy drizzle */
rpm-build ca2b01
rpm-build ca2b01
    { 300, GWEATHER_SKY_OVERCAST, { TRUE, GWEATHER_PHENOMENON_DRIZZLE, GWEATHER_QUALIFIER_LIGHT } }, /* Light intensity drizzle */
rpm-build ca2b01
    { 301, GWEATHER_SKY_OVERCAST, { TRUE, GWEATHER_PHENOMENON_DRIZZLE, GWEATHER_QUALIFIER_NONE } }, /* Drizzle */
rpm-build ca2b01
    { 302, GWEATHER_SKY_OVERCAST, { TRUE, GWEATHER_PHENOMENON_DRIZZLE, GWEATHER_QUALIFIER_HEAVY } }, /* Heavy intensity drizzle */
rpm-build ca2b01
    { 310, GWEATHER_SKY_OVERCAST, { TRUE, GWEATHER_PHENOMENON_DRIZZLE, GWEATHER_QUALIFIER_LIGHT } }, /* Light intensity drizzle rain */
rpm-build ca2b01
    { 311, GWEATHER_SKY_OVERCAST, { TRUE, GWEATHER_PHENOMENON_DRIZZLE, GWEATHER_QUALIFIER_NONE } }, /* Drizzle rain */
rpm-build ca2b01
    { 312, GWEATHER_SKY_OVERCAST, { TRUE, GWEATHER_PHENOMENON_DRIZZLE, GWEATHER_QUALIFIER_HEAVY } }, /* Heavy intensity drizzle rain */
rpm-build ca2b01
    { 321, GWEATHER_SKY_OVERCAST, { TRUE, GWEATHER_PHENOMENON_DRIZZLE, GWEATHER_QUALIFIER_SHOWERS } }, /* Drizzle showers */
rpm-build ca2b01
rpm-build ca2b01
    { 500, GWEATHER_SKY_OVERCAST, { TRUE, GWEATHER_PHENOMENON_RAIN, GWEATHER_QUALIFIER_LIGHT } }, /* Light rain */
rpm-build ca2b01
    { 501, GWEATHER_SKY_OVERCAST, { TRUE, GWEATHER_PHENOMENON_RAIN, GWEATHER_QUALIFIER_MODERATE } }, /* Moderate rain */
rpm-build ca2b01
    { 502, GWEATHER_SKY_OVERCAST, { TRUE, GWEATHER_PHENOMENON_RAIN, GWEATHER_QUALIFIER_HEAVY } }, /* Heavy intensity rain */
rpm-build ca2b01
    { 503, GWEATHER_SKY_OVERCAST, { TRUE, GWEATHER_PHENOMENON_RAIN, GWEATHER_QUALIFIER_HEAVY } }, /* Very heavy rain */
rpm-build ca2b01
    { 504, GWEATHER_SKY_OVERCAST, { TRUE, GWEATHER_PHENOMENON_RAIN, GWEATHER_QUALIFIER_HEAVY } }, /* Extreme rain */
rpm-build ca2b01
    { 511, GWEATHER_SKY_OVERCAST, { TRUE, GWEATHER_PHENOMENON_RAIN, GWEATHER_QUALIFIER_FREEZING } }, /* Freezing rain */
rpm-build ca2b01
    { 520, GWEATHER_SKY_OVERCAST, { TRUE, GWEATHER_PHENOMENON_RAIN, GWEATHER_QUALIFIER_SHOWERS } }, /* Light intensity shower rain */
rpm-build ca2b01
    { 521, GWEATHER_SKY_OVERCAST, { TRUE, GWEATHER_PHENOMENON_RAIN, GWEATHER_QUALIFIER_SHOWERS } }, /* Shower rain */
rpm-build ca2b01
    { 522, GWEATHER_SKY_OVERCAST, { TRUE, GWEATHER_PHENOMENON_RAIN, GWEATHER_QUALIFIER_SHOWERS } }, /* Heavy intensity shower rain */
rpm-build ca2b01
rpm-build ca2b01
    { 600, GWEATHER_SKY_OVERCAST, { TRUE, GWEATHER_PHENOMENON_SNOW, GWEATHER_QUALIFIER_LIGHT } }, /* Light snow */
rpm-build ca2b01
    { 601, GWEATHER_SKY_OVERCAST, { TRUE, GWEATHER_PHENOMENON_SNOW, GWEATHER_QUALIFIER_NONE } }, /* Snow */
rpm-build ca2b01
    { 602, GWEATHER_SKY_OVERCAST, { TRUE, GWEATHER_PHENOMENON_SNOW, GWEATHER_QUALIFIER_HEAVY } }, /* Heavy snow */
rpm-build ca2b01
    { 611, GWEATHER_SKY_OVERCAST, { TRUE, GWEATHER_PHENOMENON_ICE_PELLETS, GWEATHER_QUALIFIER_NONE } }, /* Sleet */
rpm-build ca2b01
    { 621, GWEATHER_SKY_OVERCAST, { TRUE, GWEATHER_PHENOMENON_SNOW, GWEATHER_QUALIFIER_SHOWERS } }, /* Shower snow */
rpm-build ca2b01
rpm-build ca2b01
    { 701, GWEATHER_SKY_CLEAR, { TRUE, GWEATHER_PHENOMENON_MIST, GWEATHER_QUALIFIER_NONE } }, /* Mist */
rpm-build ca2b01
    { 711, GWEATHER_SKY_CLEAR, { TRUE, GWEATHER_PHENOMENON_SMOKE, GWEATHER_QUALIFIER_NONE } }, /* Smoke */
rpm-build ca2b01
    { 721, GWEATHER_SKY_CLEAR, { TRUE, GWEATHER_PHENOMENON_HAZE, GWEATHER_QUALIFIER_NONE } }, /* Haze */
rpm-build ca2b01
    { 731, GWEATHER_SKY_CLEAR, { TRUE, GWEATHER_PHENOMENON_DUST_WHIRLS, GWEATHER_QUALIFIER_NONE } }, /* Dust/sand whirls */
rpm-build ca2b01
    { 741, GWEATHER_SKY_CLEAR, { TRUE, GWEATHER_PHENOMENON_FOG, GWEATHER_QUALIFIER_NONE } }, /* Fog */
rpm-build ca2b01
rpm-build ca2b01
    { 800, GWEATHER_SKY_CLEAR, { FALSE, GWEATHER_PHENOMENON_NONE, GWEATHER_QUALIFIER_NONE } }, /* Clear sky */
rpm-build ca2b01
    { 801, GWEATHER_SKY_FEW, { FALSE, GWEATHER_PHENOMENON_NONE, GWEATHER_QUALIFIER_NONE } }, /* Few clouds */
rpm-build ca2b01
    { 802, GWEATHER_SKY_SCATTERED, { FALSE, GWEATHER_PHENOMENON_NONE, GWEATHER_QUALIFIER_NONE } }, /* Scattered clouds */
rpm-build ca2b01
    { 803, GWEATHER_SKY_BROKEN, { FALSE, GWEATHER_PHENOMENON_NONE, GWEATHER_QUALIFIER_NONE } }, /* Broken clouds */
rpm-build ca2b01
    { 804, GWEATHER_SKY_OVERCAST, { FALSE, GWEATHER_PHENOMENON_NONE, GWEATHER_QUALIFIER_NONE } }, /* Overcast clouds */
rpm-build ca2b01
rpm-build ca2b01
    /* XXX: all these are a bit iffy */
rpm-build ca2b01
    { 900, GWEATHER_SKY_OVERCAST, { TRUE, GWEATHER_PHENOMENON_TORNADO, GWEATHER_QUALIFIER_NONE } }, /* Tornado */
rpm-build ca2b01
    { 901, GWEATHER_SKY_OVERCAST, { TRUE, GWEATHER_PHENOMENON_TORNADO, GWEATHER_QUALIFIER_NONE } }, /* Tropical storm */
rpm-build ca2b01
    { 902, GWEATHER_SKY_OVERCAST, { TRUE, GWEATHER_PHENOMENON_TORNADO, GWEATHER_QUALIFIER_NONE } }, /* Hurricane */
rpm-build ca2b01
    { 903, GWEATHER_SKY_CLEAR, { FALSE, GWEATHER_PHENOMENON_NONE, GWEATHER_QUALIFIER_NONE } }, /* Cold */
rpm-build ca2b01
    { 904, GWEATHER_SKY_CLEAR, { FALSE, GWEATHER_PHENOMENON_NONE, GWEATHER_QUALIFIER_NONE } }, /* Hot */
rpm-build ca2b01
    { 905, GWEATHER_SKY_CLEAR, { FALSE, GWEATHER_PHENOMENON_NONE, GWEATHER_QUALIFIER_NONE } }, /* Windy */
rpm-build ca2b01
    { 906, GWEATHER_SKY_OVERCAST, { TRUE, GWEATHER_PHENOMENON_HAIL, GWEATHER_QUALIFIER_NONE } }, /* Hail */
rpm-build ca2b01
};
rpm-build ca2b01
rpm-build ca2b01
static struct {
rpm-build ca2b01
    const char *name;
rpm-build ca2b01
    GWeatherWindDirection direction;
rpm-build ca2b01
} wind_directions[] = {
rpm-build ca2b01
    { "N", GWEATHER_WIND_N },
rpm-build ca2b01
    { "NNE", GWEATHER_WIND_NNE },
rpm-build ca2b01
    { "NE", GWEATHER_WIND_NE },
rpm-build ca2b01
    { "ENE", GWEATHER_WIND_ENE },
rpm-build ca2b01
    { "E", GWEATHER_WIND_E },
rpm-build ca2b01
    { "ESE", GWEATHER_WIND_ESE },
rpm-build ca2b01
    { "SE", GWEATHER_WIND_SE },
rpm-build ca2b01
    { "SSE", GWEATHER_WIND_SSE },
rpm-build ca2b01
    { "S", GWEATHER_WIND_S },
rpm-build ca2b01
    { "SSW", GWEATHER_WIND_SSW },
rpm-build ca2b01
    { "SW", GWEATHER_WIND_SW },
rpm-build ca2b01
    { "WSW", GWEATHER_WIND_WSW },
rpm-build ca2b01
    { "W", GWEATHER_WIND_W },
rpm-build ca2b01
    { "WNW", GWEATHER_WIND_WNW },
rpm-build ca2b01
    { "NW", GWEATHER_WIND_NW },
rpm-build ca2b01
    { "NNW", GWEATHER_WIND_NNW },
rpm-build ca2b01
};
rpm-build ca2b01
rpm-build ca2b01
static time_t
rpm-build ca2b01
date_to_time_t (const xmlChar *str, const char * tzid)
rpm-build ca2b01
{
rpm-build ca2b01
    struct tm time = { 0 };
rpm-build ca2b01
    GTimeZone *tz;
rpm-build ca2b01
    GDateTime *dt;
rpm-build ca2b01
    time_t rval;
rpm-build ca2b01
    char *after;
rpm-build ca2b01
rpm-build ca2b01
    after = strptime ((const char*) str, "%Y-%m-%dT%T", &time);
rpm-build ca2b01
    if (after == NULL) {
rpm-build ca2b01
	g_warning ("Cannot parse date string \"%s\"", str);
rpm-build ca2b01
	return 0;
rpm-build ca2b01
    }
rpm-build ca2b01
rpm-build ca2b01
    if (*after == 'Z')
rpm-build ca2b01
	tzid = "UTC";
rpm-build ca2b01
rpm-build ca2b01
    tz = g_time_zone_new (tzid);
rpm-build ca2b01
    dt = g_date_time_new (tz,
rpm-build ca2b01
			  time.tm_year + 1900,
rpm-build ca2b01
			  time.tm_mon + 1,
rpm-build ca2b01
			  time.tm_mday,
rpm-build ca2b01
			  time.tm_hour,
rpm-build ca2b01
			  time.tm_min,
rpm-build ca2b01
			  time.tm_sec);
rpm-build ca2b01
rpm-build ca2b01
    rval = g_date_time_to_unix (dt);
rpm-build ca2b01
rpm-build ca2b01
    g_time_zone_unref (tz);
rpm-build ca2b01
    g_date_time_unref (dt);
rpm-build ca2b01
rpm-build ca2b01
    return rval;
rpm-build ca2b01
}
rpm-build ca2b01
rpm-build ca2b01
static int
rpm-build ca2b01
symbol_compare (const void *key,
rpm-build ca2b01
                const void *element)
rpm-build ca2b01
{
rpm-build ca2b01
    const struct owm_symbol *s_key = key;
rpm-build ca2b01
    const struct owm_symbol *s_element = element;
rpm-build ca2b01
rpm-build ca2b01
    return s_key->symbol - s_element->symbol;
rpm-build ca2b01
}
rpm-build ca2b01
rpm-build ca2b01
static inline void
rpm-build ca2b01
read_symbol (GWeatherInfo *info,
rpm-build ca2b01
	     xmlNodePtr    node)
rpm-build ca2b01
{
rpm-build ca2b01
    xmlChar *val;
rpm-build ca2b01
    GWeatherInfoPrivate *priv = info->priv;
rpm-build ca2b01
    struct owm_symbol *obj, ref;
rpm-build ca2b01
rpm-build ca2b01
    val = xmlGetProp (node, XC("number"));
rpm-build ca2b01
rpm-build ca2b01
    ref.symbol = strtol ((char*) val, NULL, 0) - 1;
rpm-build ca2b01
    obj = bsearch (&ref, symbols, G_N_ELEMENTS (symbols),
rpm-build ca2b01
                   sizeof (struct owm_symbol), symbol_compare);
rpm-build ca2b01
rpm-build ca2b01
    if (obj == NULL) {
rpm-build ca2b01
        g_warning ("Unknown symbol %d returned from OpenWeatherMap",
rpm-build ca2b01
                   ref.symbol);
rpm-build ca2b01
        return;
rpm-build ca2b01
    }
rpm-build ca2b01
rpm-build ca2b01
    priv->valid = TRUE;
rpm-build ca2b01
    priv->sky = obj->sky;
rpm-build ca2b01
    priv->cond = obj->condition;
rpm-build ca2b01
}
rpm-build ca2b01
rpm-build ca2b01
static inline void
rpm-build ca2b01
read_wind_direction (GWeatherInfo *info,
rpm-build ca2b01
		     xmlNodePtr    node)
rpm-build ca2b01
{
rpm-build ca2b01
    xmlChar *val;
rpm-build ca2b01
    unsigned int i;
rpm-build ca2b01
rpm-build ca2b01
    val = xmlGetProp (node, XC("code"));
rpm-build ca2b01
    if (val == NULL)
rpm-build ca2b01
	return;
rpm-build ca2b01
rpm-build ca2b01
    for (i = 0; i < G_N_ELEMENTS (wind_directions); i++) {
rpm-build ca2b01
	if (strcmp ((char*) val, wind_directions[i].name) == 0) {
rpm-build ca2b01
	    info->priv->wind = wind_directions[i].direction;
rpm-build ca2b01
	    return;
rpm-build ca2b01
	}
rpm-build ca2b01
    }
rpm-build ca2b01
}
rpm-build ca2b01
rpm-build ca2b01
static inline void
rpm-build ca2b01
read_wind_speed (GWeatherInfo *info,
rpm-build ca2b01
		 xmlNodePtr    node)
rpm-build ca2b01
{
rpm-build ca2b01
    xmlChar *val;
rpm-build ca2b01
    double mps;
rpm-build ca2b01
rpm-build ca2b01
    val = xmlGetProp (node, XC("mps"));
rpm-build ca2b01
    if (val == NULL)
rpm-build ca2b01
	return;
rpm-build ca2b01
rpm-build ca2b01
    mps = g_ascii_strtod ((char*) val, NULL);
rpm-build ca2b01
    info->priv->windspeed = WINDSPEED_MS_TO_KNOTS (mps);
rpm-build ca2b01
}
rpm-build ca2b01
rpm-build ca2b01
static inline void
rpm-build ca2b01
read_temperature (GWeatherInfo *info,
rpm-build ca2b01
		  xmlNodePtr    node)
rpm-build ca2b01
{
rpm-build ca2b01
    xmlChar *unit;
rpm-build ca2b01
    xmlChar *val;
rpm-build ca2b01
    double celsius;
rpm-build ca2b01
rpm-build ca2b01
    unit = xmlGetProp (node, XC("unit"));
rpm-build ca2b01
    if (unit == NULL || strcmp ((char*)unit, "celsius"))
rpm-build ca2b01
        return;
rpm-build ca2b01
rpm-build ca2b01
    val = xmlGetProp (node, XC("value"));
rpm-build ca2b01
    if (val == NULL)
rpm-build ca2b01
	return;
rpm-build ca2b01
rpm-build ca2b01
    celsius = g_ascii_strtod ((char*) val, NULL);
rpm-build ca2b01
    info->priv->temp = TEMP_C_TO_F (celsius);
rpm-build ca2b01
}
rpm-build ca2b01
rpm-build ca2b01
static inline void
rpm-build ca2b01
read_pressure (GWeatherInfo *info,
rpm-build ca2b01
	       xmlNodePtr    node)
rpm-build ca2b01
{
rpm-build ca2b01
    xmlChar *unit;
rpm-build ca2b01
    xmlChar *val;
rpm-build ca2b01
    double hpa;
rpm-build ca2b01
rpm-build ca2b01
    /* hPa == mbar */
rpm-build ca2b01
    unit = xmlGetProp (node, XC("unit"));
rpm-build ca2b01
    if (unit == NULL || strcmp ((char*)unit, "hPa"))
rpm-build ca2b01
        return;
rpm-build ca2b01
rpm-build ca2b01
    val = xmlGetProp (node, XC("value"));
rpm-build ca2b01
    if (val == NULL)
rpm-build ca2b01
	return;
rpm-build ca2b01
rpm-build ca2b01
    hpa = g_ascii_strtod ((char*) val, NULL);
rpm-build ca2b01
    info->priv->pressure = PRESSURE_MBAR_TO_INCH (hpa);
rpm-build ca2b01
}
rpm-build ca2b01
rpm-build ca2b01
static inline void
rpm-build ca2b01
read_humidity (GWeatherInfo *info,
rpm-build ca2b01
               xmlNodePtr    node)
rpm-build ca2b01
{
rpm-build ca2b01
    xmlChar *unit;
rpm-build ca2b01
    xmlChar *val;
rpm-build ca2b01
    double percent;
rpm-build ca2b01
rpm-build ca2b01
    unit = xmlGetProp (node, XC("unit"));
rpm-build ca2b01
    if (unit == NULL || strcmp ((char*)unit, "%"))
rpm-build ca2b01
        return;
rpm-build ca2b01
rpm-build ca2b01
    val = xmlGetProp (node, XC("value"));
rpm-build ca2b01
    if (val == NULL)
rpm-build ca2b01
	return;
rpm-build ca2b01
rpm-build ca2b01
    percent = g_ascii_strtod ((char*) val, NULL);
rpm-build ca2b01
    info->priv->humidity = percent;
rpm-build ca2b01
    info->priv->hasHumidity = TRUE;
rpm-build ca2b01
}
rpm-build ca2b01
rpm-build ca2b01
static inline void
rpm-build ca2b01
read_child_node (GWeatherInfo *info,
rpm-build ca2b01
		 xmlNodePtr    node)
rpm-build ca2b01
{
rpm-build ca2b01
    if (strcmp ((char*) node->name, "symbol") == 0)
rpm-build ca2b01
	read_symbol (info, node);
rpm-build ca2b01
    else if (strcmp ((char*) node->name, "windDirection") == 0)
rpm-build ca2b01
	read_wind_direction (info, node);
rpm-build ca2b01
    else if (strcmp ((char*) node->name, "windSpeed") == 0)
rpm-build ca2b01
	read_wind_speed (info, node);
rpm-build ca2b01
    else if (strcmp ((char*) node->name, "temperature") == 0)
rpm-build ca2b01
	read_temperature (info, node);
rpm-build ca2b01
    else if (strcmp ((char*) node->name, "pressure") == 0)
rpm-build ca2b01
	read_pressure (info, node);
rpm-build ca2b01
    else if (strcmp ((char*) node->name, "humidity") == 0)
rpm-build ca2b01
        read_humidity (info, node);
rpm-build ca2b01
}
rpm-build ca2b01
rpm-build ca2b01
static inline void
rpm-build ca2b01
fill_info_from_node (GWeatherInfo *info,
rpm-build ca2b01
		     xmlNodePtr    node)
rpm-build ca2b01
{
rpm-build ca2b01
    xmlNodePtr child;
rpm-build ca2b01
rpm-build ca2b01
    for (child = node->children; child != NULL; child = child->next) {
rpm-build ca2b01
	if (child->type == XML_ELEMENT_NODE)
rpm-build ca2b01
	    read_child_node (info, child);
rpm-build ca2b01
    }
rpm-build ca2b01
}
rpm-build ca2b01
rpm-build ca2b01
static GWeatherInfo *
rpm-build ca2b01
make_info_from_node (GWeatherInfo *master_info,
rpm-build ca2b01
                     xmlNodePtr    node)
rpm-build ca2b01
{
rpm-build ca2b01
    GWeatherInfo *info;
rpm-build ca2b01
    GWeatherInfoPrivate *priv;
rpm-build ca2b01
    xmlChar *val;
rpm-build ca2b01
rpm-build ca2b01
    g_return_val_if_fail (node->type == XML_ELEMENT_NODE, NULL);
rpm-build ca2b01
rpm-build ca2b01
    info = _gweather_info_new_clone (master_info);
rpm-build ca2b01
    priv = info->priv;
rpm-build ca2b01
rpm-build ca2b01
    val = xmlGetProp (node, XC("from"));
rpm-build ca2b01
    priv->current_time = priv->update = date_to_time_t (val, info->priv->location.tz_hint);
rpm-build ca2b01
    xmlFree (val);
rpm-build ca2b01
rpm-build ca2b01
    fill_info_from_node (info, node);
rpm-build ca2b01
rpm-build ca2b01
    return info;
rpm-build ca2b01
}
rpm-build ca2b01
rpm-build ca2b01
static void
rpm-build ca2b01
parse_forecast_xml (GWeatherInfo    *master_info,
rpm-build ca2b01
                    SoupMessageBody *body)
rpm-build ca2b01
{
rpm-build ca2b01
    GWeatherInfoPrivate *priv;
rpm-build ca2b01
    xmlDocPtr doc;
rpm-build ca2b01
    xmlXPathContextPtr xpath_ctx;
rpm-build ca2b01
    xmlXPathObjectPtr xpath_result;
rpm-build ca2b01
    int i;
rpm-build ca2b01
rpm-build ca2b01
    priv = master_info->priv;
rpm-build ca2b01
rpm-build ca2b01
    doc = xmlParseMemory (body->data, body->length);
rpm-build ca2b01
    if (!doc)
rpm-build ca2b01
	return;
rpm-build ca2b01
rpm-build ca2b01
    xpath_ctx = xmlXPathNewContext (doc);
rpm-build ca2b01
    xpath_result = xmlXPathEval (XC("/weatherdata/forecast/time"), xpath_ctx);
rpm-build ca2b01
rpm-build ca2b01
    if (!xpath_result || xpath_result->type != XPATH_NODESET)
rpm-build ca2b01
	goto out;
rpm-build ca2b01
rpm-build ca2b01
    for (i = 0; i < xpath_result->nodesetval->nodeNr; i++) {
rpm-build ca2b01
	xmlNodePtr node;
rpm-build ca2b01
	GWeatherInfo *info;
rpm-build ca2b01
rpm-build ca2b01
	node = xpath_result->nodesetval->nodeTab[i];
rpm-build ca2b01
	info = make_info_from_node (master_info, node);
rpm-build ca2b01
rpm-build ca2b01
	priv->forecast_list = g_slist_append (priv->forecast_list, info);
rpm-build ca2b01
    }
rpm-build ca2b01
rpm-build ca2b01
    xmlXPathFreeObject (xpath_result);
rpm-build ca2b01
rpm-build ca2b01
    xpath_result = xmlXPathEval (XC("/weatherdata/credit/link"), xpath_ctx);
rpm-build ca2b01
    if (!xpath_result || xpath_result->type != XPATH_NODESET)
rpm-build ca2b01
	goto out;
rpm-build ca2b01
rpm-build ca2b01
    priv->forecast_attribution = g_strdup(_("Weather data from the Open Weather Map project"));
rpm-build ca2b01
rpm-build ca2b01
 out:
rpm-build ca2b01
    if (xpath_result)
rpm-build ca2b01
	xmlXPathFreeObject (xpath_result);
rpm-build ca2b01
    xmlXPathFreeContext (xpath_ctx);
rpm-build ca2b01
    xmlFreeDoc (doc);
rpm-build ca2b01
}
rpm-build ca2b01
rpm-build ca2b01
static void
rpm-build ca2b01
owm_finish (SoupSession *session,
rpm-build ca2b01
            SoupMessage *msg,
rpm-build ca2b01
            gpointer     user_data)
rpm-build ca2b01
{
rpm-build ca2b01
    GWeatherInfo *info = GWEATHER_INFO (user_data);
rpm-build ca2b01
rpm-build ca2b01
    if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)) {
rpm-build ca2b01
	/* forecast data is not really interesting anyway ;) */
rpm-build ca2b01
	if (msg->status_code != SOUP_STATUS_CANCELLED)
rpm-build ca2b01
	    g_message ("Failed to get OpenWeatherMap forecast data: %d %s\n",
rpm-build ca2b01
		       msg->status_code, msg->reason_phrase);
rpm-build ca2b01
	_gweather_info_request_done (info, msg);
rpm-build ca2b01
	return;
rpm-build ca2b01
    }
rpm-build ca2b01
rpm-build ca2b01
    parse_forecast_xml (info, msg->response_body);
rpm-build ca2b01
    _gweather_info_request_done (info, msg);
rpm-build ca2b01
}
rpm-build ca2b01
rpm-build ca2b01
gboolean
rpm-build ca2b01
owm_start_open (GWeatherInfo *info)
rpm-build ca2b01
{
rpm-build ca2b01
    GWeatherInfoPrivate *priv;
rpm-build ca2b01
    gchar *url;
rpm-build ca2b01
    SoupMessage *message;
rpm-build ca2b01
    WeatherLocation *loc;
rpm-build ca2b01
    gchar latstr[G_ASCII_DTOSTR_BUF_SIZE], lonstr[G_ASCII_DTOSTR_BUF_SIZE];
rpm-build ca2b01
rpm-build ca2b01
    priv = info->priv;
rpm-build ca2b01
    loc = &priv->location;
rpm-build ca2b01
rpm-build ca2b01
    if (!loc->latlon_valid)
rpm-build ca2b01
	return FALSE;
rpm-build ca2b01
rpm-build ca2b01
    /* see the description here: http://bugs.openweathermap.org/projects/api/wiki/Api_2_5_forecast */
rpm-build ca2b01
rpm-build ca2b01
    g_ascii_dtostr (latstr, sizeof(latstr), RADIANS_TO_DEGREES (loc->latitude));
rpm-build ca2b01
    g_ascii_dtostr (lonstr, sizeof(lonstr), RADIANS_TO_DEGREES (loc->longitude));
rpm-build ca2b01
rpm-build ca2b01
#define TEMPLATE_START "http://api.openweathermap.org/data/2.5/forecast?lat=%s&lon=%s&mode=xml&units=metric"
rpm-build ca2b01
#ifdef OWM_APIKEY
rpm-build ca2b01
 #define TEMPLATE TEMPLATE_START "&APPID=" OWM_APIKEY
rpm-build ca2b01
#else
rpm-build ca2b01
 #define TEMPLATE TEMPLATE_START
rpm-build ca2b01
#endif
rpm-build ca2b01
rpm-build ca2b01
    url = g_strdup_printf (TEMPLATE, latstr, lonstr);
rpm-build ca2b01
rpm-build ca2b01
#undef TEMPLATE
rpm-build ca2b01
rpm-build ca2b01
    message = soup_message_new ("GET", url);
rpm-build ca2b01
    _gweather_info_begin_request (info, message);
rpm-build ca2b01
    soup_session_queue_message (priv->session, message, owm_finish, info);
rpm-build ca2b01
rpm-build ca2b01
    g_free (url);
rpm-build ca2b01
rpm-build ca2b01
    return TRUE;
rpm-build ca2b01
}