|
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 |
}
|