last commit i forgot to save changes in x11.c ; this fixes that file
[monky] / src / weather.c
index ca9f542..eea0fae 100644 (file)
@@ -1,10 +1,11 @@
 /* -*- mode: c; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: t -*-
+ * vim: ts=4 sw=4 noet ai cindent syntax=c
  *
  * Conky, a system monitor, based on torsmo
  *
  * Please see COPYING for details
  *
- * Copyright (c) 2005-2009 Brenden Matthews, Philip Kovacs, et. al.
+ * Copyright (c) 2005-2010 Brenden Matthews, Philip Kovacs, et. al.
  *     (see AUTHORS)
  * All rights reserved.
  *
  * You should have received a copy of the GNU General Public License
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  *
- * vim: ts=4 sw=4 noet ai cindent syntax=c
- *
  */
 
+#include "config.h"
 #include "conky.h"
 #include "logging.h"
 #include "weather.h"
 #include "temphelper.h"
+#include "text_object.h"
 #include "ccurl_thread.h"
 #include <time.h>
 #include <ctype.h>
 #ifdef XOAP
 #include <libxml/parser.h>
 #include <libxml/xpath.h>
+#endif /* XOAP */
+
+/* WEATHER data */
+typedef struct PWEATHER_ {
+       char lastupd[32];
+#ifdef XOAP
+       char xoap_t[32];
+       char icon[3];
+#endif /* XOAP */
+       int temp;
+       int dew;
+       int cc;
+       int bar;
+       int wind_s;
+       int wind_d;
+       int hmid;
+       int wc;
+} PWEATHER;
+
+#ifdef XOAP
+#define FORECAST_DAYS 5
+typedef struct PWEATHER_FORECAST_ {
+       int hi[FORECAST_DAYS];
+       int low[FORECAST_DAYS];
+       char icon[FORECAST_DAYS][3];
+       char xoap_t[FORECAST_DAYS][32];
+       char day[FORECAST_DAYS][9];
+       char date[FORECAST_DAYS][7];
+       int wind_s[FORECAST_DAYS];
+       int wind_d[FORECAST_DAYS];
+       int hmid[FORECAST_DAYS];
+       int ppcp[FORECAST_DAYS];
+} PWEATHER_FORECAST;
 
 /* Xpath expressions for XOAP xml parsing */
 #define NUM_XPATH_EXPRESSIONS_CC 8
@@ -46,12 +80,13 @@ const char *xpath_expression_cc[NUM_XPATH_EXPRESSIONS_CC] = {
        "/weather/cc/hmid", "/weather/cc/icon"
 };
 
-#define NUM_XPATH_EXPRESSIONS_DF 8
+#define NUM_XPATH_EXPRESSIONS_DF 10
 const char *xpath_expression_df[NUM_XPATH_EXPRESSIONS_DF] = {
        "/weather/dayf/day[*]/hi", "/weather/dayf/day[*]/low",
        "/weather/dayf/day[*]/part[1]/icon", "/weather/dayf/day[*]/part[1]/t",
        "/weather/dayf/day[*]/part[1]/wind/s","/weather/dayf/day[*]/part[1]/wind/d",
-       "/weather/dayf/day[*]/part[1]/ppcp", "/weather/dayf/day[*]/part[1]/hmid"
+       "/weather/dayf/day[*]/part[1]/ppcp", "/weather/dayf/day[*]/part[1]/hmid",
+       "/weather/dayf/day[*]/@t", "/weather/dayf/day[*]/@dt"
 };
 #endif /* XOAP */
 
@@ -81,6 +116,21 @@ static ccurl_location_t *locations_head_cc = 0;
 static ccurl_location_t *locations_head_df = 0;
 #endif
 
+struct weather_data {
+       char uri[128];
+       char data_type[32];
+       int interval;
+};
+
+#ifdef XOAP
+struct weather_forecast_data {
+       char uri[128];
+       unsigned int day;
+       char data_type[32];
+       int interval;
+};
+#endif
+
 void weather_free_info(void)
 {
        ccurl_free_locations(&locations_head_cc);
@@ -108,6 +158,17 @@ static void parse_df(PWEATHER_FORECAST *res, xmlXPathContextPtr xpathCtx)
        char *content;
        xmlXPathObjectPtr xpathObj;
 
+       xpathObj = xmlXPathEvalExpression((const xmlChar *)"/error/err", xpathCtx);
+       if (xpathObj && xpathObj->nodesetval && xpathObj->nodesetval->nodeNr > 0 &&
+                       xpathObj->nodesetval->nodeTab[0]->type == XML_ELEMENT_NODE) {
+               content = (char *)xmlNodeGetContent(xpathObj->nodesetval->nodeTab[0]);
+               NORM_ERR("XOAP error: %s", content);
+               xmlFree(content);
+               xmlXPathFreeObject(xpathObj);
+               return;
+       }
+       xmlXPathFreeObject(xpathObj);
+
        for (i = 0; i < NUM_XPATH_EXPRESSIONS_DF; i++) {
                xpathObj = xmlXPathEvalExpression((const xmlChar *)xpath_expression_df[i], xpathCtx);
                if (xpathObj != NULL) {
@@ -140,12 +201,21 @@ static void parse_df(PWEATHER_FORECAST *res, xmlXPathContextPtr xpathCtx)
                                        case 7:
                                                res->hmid[k] = atoi(content);
                                        }
-                                       xmlFree(content);
-                                       if (++k == FORECAST_DAYS) break;
+                               } else if (nodes->nodeTab[j]->type == XML_ATTRIBUTE_NODE) {
+                                       content = (char *)xmlNodeGetContent(nodes->nodeTab[k]);
+                                       switch(i) {
+                                       case 8:
+                                               strncpy(res->day[k], content, 8);
+                                               break;
+                                       case 9:
+                                               strncpy(res->date[k], content, 6);
+                                       }
                                }
+                               xmlFree(content);
+                               if (++k == FORECAST_DAYS) break;
                        }
-                       xmlXPathFreeObject(xpathObj);
                }
+               xmlXPathFreeObject(xpathObj);
        }
        return;
 }
@@ -188,6 +258,7 @@ static void parse_cc(PWEATHER *res, xmlXPathContextPtr xpathCtx)
                xmlXPathFreeObject(xpathObj);
                return;
        }
+       xmlXPathFreeObject(xpathObj);
 
        for (i = 0; i < NUM_XPATH_EXPRESSIONS_CC; i++) {
                xpathObj = xmlXPathEvalExpression((const xmlChar *)xpath_expression_cc[i], xpathCtx);
@@ -636,7 +707,7 @@ void wind_deg_to_dir(char *p, int p_max_size, int wind_deg) {
 }
 
 #ifdef XOAP
-void weather_forecast_process_info(char *p, int p_max_size, char *uri, unsigned int day, char *data_type, int interval)
+static void weather_forecast_process_info(char *p, int p_max_size, char *uri, unsigned int day, char *data_type, int interval)
 {
        PWEATHER_FORECAST *data;
 
@@ -671,13 +742,17 @@ void weather_forecast_process_info(char *p, int p_max_size, char *uri, unsigned
                snprintf(p, p_max_size, "%d", data->hmid[day]);
        } else if (strcmp(data_type, "precipitation") == EQUAL) {
                snprintf(p, p_max_size, "%d", data->ppcp[day]);
+       } else if (strcmp(data_type, "day") == EQUAL) {
+               strncpy(p, data->day[day], p_max_size);
+       } else if (strcmp(data_type, "date") == EQUAL) {
+               strncpy(p, data->date[day], p_max_size);
        }
 
        timed_thread_unlock(curloc->p_timed_thread);
 }
 #endif /* XOAP */
 
-void weather_process_info(char *p, int p_max_size, char *uri, char *data_type, int interval)
+static void weather_process_info(char *p, int p_max_size, char *uri, char *data_type, int interval)
 {
        static const char *wc[] = {
                "", "drizzle", "rain", "hail", "soft hail",
@@ -753,10 +828,46 @@ void weather_process_info(char *p, int p_max_size, char *uri, char *data_type, i
 }
 
 #ifdef XOAP
-
 /* xoap suffix for weather from weather.com */
 static char *xoap_cc = NULL;
 static char *xoap_df = NULL;
+#endif /* XOAP */
+
+static int process_weather_uri(char *uri, char *locID, int dayf UNUSED_ATTR)
+{
+       /* locID MUST BE upper-case */
+       char *tmp_p = locID;
+
+       while (*tmp_p) {
+               *tmp_p = toupper(*tmp_p);
+               tmp_p++;
+       }
+
+       /* Construct complete uri */
+#ifdef XOAP
+       if (strstr(uri, "xoap.weather.com")) {
+               if ((dayf == 0) && (xoap_cc != NULL)) {
+                       strcat(uri, locID);
+                       strcat(uri, xoap_cc);
+               } else if ((dayf == 1) && (xoap_df != NULL)) {
+                       strcat(uri, locID);
+                       strcat(uri, xoap_df);
+               } else {
+                       free(uri);
+                       uri = NULL;
+               }
+       } else
+#endif /* XOAP */
+       if (strstr(uri, "weather.noaa.gov")) {
+               strcat(uri, locID);
+               strcat(uri, ".TXT");
+       } else  if (!strstr(uri, "localhost") && !strstr(uri, "127.0.0.1")) {
+               return -1;
+       }
+       return 0;
+}
+
+#ifdef XOAP
 
 /*
  * TODO: make the xoap keys file readable from the config file
@@ -796,38 +907,117 @@ void load_xoap_keys(void)
        free(key);
        free(xoap);
 }
-#endif /* XOAP */
 
-int process_weather_uri(char *uri, char *locID, int dayf UNUSED_ATTR)
+void scan_weather_forecast_arg(struct text_object *obj, const char *arg, void *free_at_crash)
 {
-       /* locID MUST BE upper-case */
-       char *tmp_p = locID;
+       int argc;
+       struct weather_forecast_data *wfd;
+       float interval = 0;
+       char *locID = (char *) malloc(9 * sizeof(char));
 
-       while (*tmp_p) {
-               *tmp_p = toupper(*tmp_p);
-               tmp_p++;
+       wfd = malloc(sizeof(struct weather_forecast_data));
+       memset(wfd, 0, sizeof(struct weather_forecast_data));
+
+       argc = sscanf(arg, "%119s %8s %1u %31s %f", wfd->uri, locID, &wfd->day, wfd->data_type, &interval);
+
+       if (argc < 4) {
+               free(locID);
+               free(wfd);
+               CRIT_ERR(obj, free_at_crash, "wrong number of arguments for $weather_forecast");
+       }
+       if (process_weather_uri(wfd->uri, locID, 1)) {
+               free(locID);
+               free(wfd);
+               CRIT_ERR(obj, free_at_crash, \
+                               "could not recognize the weather forecast uri");
        }
 
-       /* Construct complete uri */
-#ifdef XOAP
-       if (strstr(uri, "xoap.weather.com")) {
-               if ((dayf == 0) && (xoap_cc != NULL)) {
-                       strcat(uri, locID);
-                       strcat(uri, xoap_cc);
-               } else if ((dayf == 1) && (xoap_df != NULL)) {
-                       strcat(uri, locID);
-                       strcat(uri, xoap_df);
-               } else {
-                       free(uri);
-                       uri = NULL;
-               }
-       } else
+       /* Limit the day between 0 (today) and FORECAST_DAYS */
+       if (wfd->day >= FORECAST_DAYS) {
+               wfd->day = FORECAST_DAYS-1;
+       }
+
+       /* Limit the data retrieval interval to 3 hours and an half */
+       if (interval < 210) {
+               interval = 210;
+       }
+
+       /* Convert to seconds */
+       wfd->interval = interval * 60;
+       free(locID);
+
+       DBGP("weather_forecast: fetching %s for day %d from %s every %d seconds", \
+                       wfd->data_type, wfd->day, wfd->uri, wfd->interval);
+
+       obj->data.opaque = wfd;
+}
+
+void print_weather_forecast(struct text_object *obj, char *p, int p_max_size)
+{
+       struct weather_forecast_data *wfd = obj->data.opaque;
+
+       if (!wfd || !wfd->uri) {
+               NORM_ERR("error processing weather forecast data, check that you have a valid XOAP key if using XOAP.");
+               return;
+       }
+       weather_forecast_process_info(p, p_max_size, wfd->uri, wfd->day, wfd->data_type, wfd->interval);
+}
 #endif /* XOAP */
-       if (strstr(uri, "weather.noaa.gov")) {
-               strcat(uri, locID);
-               strcat(uri, ".TXT");
-       } else  if (!strstr(uri, "localhost") && !strstr(uri, "127.0.0.1")) {
-               return -1;
+
+void scan_weather_arg(struct text_object *obj, const char *arg, void *free_at_crash)
+{
+       int argc;
+       struct weather_data *wd;
+       char *locID = (char *) malloc(9 * sizeof(char));
+       float interval = 0;
+
+       wd = malloc(sizeof(struct weather_data));
+       memset(wd, 0, sizeof(struct weather_data));
+
+       argc = sscanf(arg, "%119s %8s %31s %f", wd->uri, locID, wd->data_type, &interval);
+
+       if (argc < 3) {
+               free(locID);
+               free(wd);
+               CRIT_ERR(obj, free_at_crash, "wrong number of arguments for $weather");
+       }
+       if (process_weather_uri(wd->uri, locID, 0)) {
+               free(locID);
+               free(wd);
+               CRIT_ERR(obj, free_at_crash, \
+                               "could not recognize the weather uri");
+       }
+
+       /* Limit the data retrieval interval to half hour min */
+       if (interval < 30) {
+               interval = 30;
+       }
+
+       /* Convert to seconds */
+       wd->interval = interval * 60;
+       free(locID);
+
+       DBGP("weather: fetching %s from %s every %d seconds", \
+                       wd->data_type, wd->uri, wd->interval);
+
+       obj->data.opaque = wd;
+}
+
+void print_weather(struct text_object *obj, char *p, int p_max_size)
+{
+       struct weather_data *wd = obj->data.opaque;
+
+       if (!wd || !wd->uri) {
+               NORM_ERR("error processing weather data, check that you have a valid XOAP key if using XOAP.");
+               return;
+       }
+       weather_process_info(p, p_max_size, wd->uri, wd->data_type, wd->interval);
+}
+
+void free_weather(struct text_object *obj)
+{
+       if (obj->data.opaque) {
+               free(obj->data.opaque);
+               obj->data.opaque = NULL;
        }
-       return 0;
 }