From c05c157eadc1720713c20a174f1ebad5f8d5d29f Mon Sep 17 00:00:00 2001 From: Brenden Matthews Date: Sun, 19 Jul 2009 23:43:36 -0600 Subject: [PATCH] Overhauled RSS and weather, added $curl. I've taken the curl stuff out of weather and RSS and moved it into it's own entity. It should be easier to create curl-based objects if needed now. --- configure.ac.in | 67 +++++++++++------ doc/docs.xml | 15 ++++ doc/variables.xml | 55 +++++++++++--- src/Makefile.am | 23 +++--- src/common.c | 17 ----- src/common.h | 10 --- src/conky.c | 185 ++++++++++++++++++++--------------------------- src/conky.h | 13 ++-- src/prss.c | 45 ++++-------- src/prss.h | 3 +- src/rss.c | 207 +++++++++++++++++++++++------------------------------ src/rss.h | 6 +- src/text_object.h | 17 +++-- src/weather.c | 205 +++++++++++++--------------------------------------- src/weather.h | 5 +- 15 files changed, 374 insertions(+), 499 deletions(-) diff --git a/configure.ac.in b/configure.ac.in index 46c3579..976647b 100644 --- a/configure.ac.in +++ b/configure.ac.in @@ -308,6 +308,14 @@ if test x$want_xmms2 = xyes; then fi dnl +dnl libcurl, see below for more (this has to be above the other uses of want_curl) +dnl + +AC_ARG_ENABLE([curl], + AC_HELP_STRING([--enable-curl], [enable if you want curl support @<:@default=no@:>@]), + [want_curl="$enableval"], [want_curl=no]) + +dnl dnl EVE Skill Monitor dnl @@ -317,10 +325,8 @@ AC_ARG_ENABLE([eve], AM_CONDITIONAL(BUILD_EVE, test x$want_eve = xyes) if test x$want_eve = xyes; then - PKG_CHECK_MODULES([libxml2], libxml-2.0) - PKG_CHECK_MODULES([libcurl], libcurl) - conky_CFLAGS="$conky_CFLAGS $libxml2_CFLAGS $libcurl_CFLAGS" - conky_LIBS="$conky_LIBS $libxml2_LIBS $libcurl_LIBS" + want_curl=yes + want_libxml2=yes AC_DEFINE(EVE, 1, [Define if you want Eve-Online Skill monitor support]) AC_DEFINE(EVEURL_TRAINING, "http://api.eve-online.com/char/SkillInTraining.xml.aspx", [Eve training URL]) AC_DEFINE(EVEURL_SKILLTREE, "http://api.eve-online.com/eve/Skilltree.xml.aspx", [Eve skilltree URL]) @@ -339,11 +345,9 @@ AC_ARG_ENABLE([rss], AM_CONDITIONAL(BUILD_RSS, test x$want_rss = xyes) if test x$want_rss = xyes; then WANT_GLIB=yes - PKG_CHECK_MODULES([libxml2], libxml-2.0) - PKG_CHECK_MODULES([libcurl], libcurl) - conky_CFLAGS="$conky_CFLAGS $libxml2_CFLAGS $libcurl_CFLAGS" - conky_LIBS="$conky_LIBS $libxml2_LIBS $libcurl_LIBS" - AC_DEFINE(RSS, 1, [Define if you want rss support]) + want_curl=yes + want_libxml2=yes + AC_DEFINE(RSS, 1, [Define if you want Curl support]) fi dnl @@ -360,17 +364,13 @@ AC_ARG_ENABLE([xoap], # AM_CONDITIONAL(BUILD_WEATHER, test x$want_weather = xyes) if test x$want_weather = xyes; then - AM_CONDITIONAL(BUILD_XOAP, test x$want_xoap = xyes) - if test x$want_xoap = xyes; then - PKG_CHECK_MODULES([libxml2], libxml-2.0) - conky_CFLAGS="$conky_CFLAGS $libxml2_CFLAGS" - conky_LIBS="$conky_LIBS $libxml2_LIBS" - AC_DEFINE(XOAP, 1, [Define if you want weather xoap support]) - AC_DEFINE(XOAP_FILE, "$HOME/.xoaprc", [User xoap keys file]) + AM_CONDITIONAL(BUILD_XOAP, test x$want_xoap = xyes) + if test x$want_xoap = xyes; then + want_libxml2=yes + AC_DEFINE(XOAP, 1, [Define if you want weather xoap support]) + AC_DEFINE(XOAP_FILE, "$HOME/.xoaprc", [User xoap keys file]) fi - PKG_CHECK_MODULES([libcurl], libcurl) - conky_CFLAGS="$conky_CFLAGS $libcurl_CFLAGS" - conky_LIBS="$conky_LIBS $libcurl_LIBS" + want_curl=yes AC_DEFINE(WEATHER, 1, [Define if you want weather support]) fi @@ -649,6 +649,28 @@ if test x$WANT_GLIB = xyes; then fi dnl +dnl libcurl +dnl + +if test x$want_curl = xyes; then + PKG_CHECK_MODULES([libcurl], libcurl) + conky_CFLAGS="$conky_CFLAGS $libcurl_CFLAGS" + conky_LIBS="$conky_LIBS $libcurl_LIBS" + AC_DEFINE(HAVE_CURL, 1, [Define if you want Curl support]) +fi +AM_CONDITIONAL(BUILD_CURL, test x$want_curl = xyes) + +dnl +dnl libx +dnl + +if test x$want_libxml2 = xyes; then + PKG_CHECK_MODULES([libxml2], libxml-2.0) + conky_CFLAGS="$conky_CFLAGS $libxml2_CFLAGS" + conky_LIBS="$conky_LIBS $libxml2_LIBS" +fi + +dnl dnl KVM dnl @@ -907,9 +929,10 @@ $PACKAGE $VERSION configured successfully: hddtemp: $want_hddtemp portmon: $want_portmon RSS: $want_rss - Weather (METAR) - NOAA: $want_weather - XOAP: $want_xoap + Curl: $want_curl + Weather + NOAA: $want_weather + XOAP: $want_xoap wireless: $want_wlan IBM: $want_ibm nvidia: $want_nvidia diff --git a/doc/docs.xml b/doc/docs.xml index 7387128..ff978dd 100644 --- a/doc/docs.xml +++ b/doc/docs.xml @@ -194,6 +194,16 @@ Colour can be also in #rrggbb format (hex). + + Some objects may create threads, and sometimes these threads will + not be destroyed until Conky terminates. There is no way to + destroy or clean up threads while Conky is running. For example, + if you use an MPD variable, the MPD thread will keep running until + Conky dies. Some threaded objects will use one of the parameters + as a 'key', so that you only have 1 relevant thread running (for + example, the $curl, $rss and $weather objects launch one thread per + URI). + &variables; @@ -210,6 +220,11 @@ hooks. + Be careful when creating threaded objects through the Lua API. You + could wind up with a whole bunch of threads running if a thread is + created with each iteration. + + At this time, the Lua API should not be considered stable and may change drastically from one release to another as it matures. diff --git a/doc/variables.xml b/doc/variables.xml index a8ca92c..44e201c 100644 --- a/doc/variables.xml +++ b/doc/variables.xml @@ -2549,19 +2549,45 @@ + + + + + + + Download data from URI using Curl at the specified interval. + The interval may be a floating point value greater than 0, + otherwise defaults to 15 minutes. Most useful when used in + conjunction with Lua and the Lua API. This object is threaded, + and once a thread is created it can't be explicitely destroyed. + One thread will run for each URI specified. You can use any + protocol that Curl supports. + + + + + + - - Download and parse RSS feeds. Action may be one - of the following: feed_title, item_title (with num par), - item_desc (with num par) and item_titles (when using this - action and spaces_in_front is given conky places that many - spaces in front of each item). - - - + + + Download and parse RSS feeds. The interval may be a floating + point value greater than 0, otherwise defaults to 15 minutes. + Action may be one of the following: feed_title, item_title + (with num par), item_desc (with num par) and item_titles (when + using this action and spaces_in_front is given conky places + that many spaces in front of each item). This object is + threaded, and once a thread is created it can't be explicitely + destroyed. One thread will run for each URI specified. You + can use any protocol that Curl supports. + + + + @@ -2963,7 +2989,9 @@ longer then the time it takes your script to execute. For example, if you have a script that take 5 seconds to execute, you should make the interval at least 6 seconds. - See also $execi. + See also $execi. This object will clean up the thread when it is + destroyed, so it can safely be used in a nested fashion, though it may + not produce the desired behaviour if used this way. @@ -3288,7 +3316,7 @@ - + Download, parse and display METAR data. @@ -3363,6 +3391,11 @@ 'delay_in_minutes' (optional, default 30) cannot be lower than 30 min. + + This object is threaded, and once a thread is created it can't be + explicitely destroyed. One thread will run for each URI specified. + You can use any protocol that Curl supports. + Note that these variables are still EXPERIMENTAL and can be subject to many future changes. diff --git a/src/Makefile.am b/src/Makefile.am index dbbec2e..0301788 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -110,6 +110,10 @@ if BUILD_EVE eve = eve.c eve.h endif +if BUILD_CURL +ccurl_thread = ccurl_thread.c ccurl_thread.h +endif + if BUILD_RSS rss = rss.c prss.c prss.h endif @@ -161,7 +165,7 @@ conky_SOURCES = \ $(eve) \ $(rss) \ $(weather) \ - $(lua) \ + $(lua) \ $(solaris) \ timed_thread.c \ timed_thread.h \ @@ -179,8 +183,9 @@ conky_SOURCES = \ text_object.h \ text_object.c \ algebra.h \ - algebra.c \ - $(imlib2) + algebra.c \ + $(imlib2) \ + $(ccurl_thread) conky_LDFLAGS = \ $(PTHREAD_LIBS) \ @@ -211,8 +216,9 @@ EXTRA_DIST = \ libtcp-portmon.c \ libtcp-portmon.h \ rss.h \ - weather.h \ - llua.h \ + prss.h \ + weather.h \ + llua.h \ mail.h \ mixer.h \ moc.h \ @@ -240,9 +246,10 @@ EXTRA_DIST = \ ibm.c \ ibm.h \ sony.h \ - users.c \ - imlib2.c \ - imlib2.h + users.c \ + imlib2.c \ + imlib2.h \ + ccurl_thread.h # vi:set ts=4 sw=4 noet ai nocindent syntax=automake: diff --git a/src/common.c b/src/common.c index dab8f36..2a852f7 100644 --- a/src/common.c +++ b/src/common.c @@ -513,20 +513,3 @@ unsigned int round_to_int(float f) } } -/* utility function used by RSS and Weather stuff for a curl callback. - */ -size_t WriteMemoryCallback(void *ptr, size_t size, size_t nmemb, void *data) -{ - size_t realsize = size * nmemb; - struct MemoryStruct *mem = (struct MemoryStruct *) data; - - mem->memory = (char *) realloc(mem->memory, mem->size + realsize + 1); - if (mem->memory) { - memcpy(&(mem->memory[mem->size]), ptr, realsize); - mem->size += realsize; - mem->memory[mem->size] = 0; - } - return realsize; -} - - diff --git a/src/common.h b/src/common.h index ba2bb17..ddda4ab 100644 --- a/src/common.h +++ b/src/common.h @@ -89,14 +89,4 @@ int get_battery_perct(const char *bat); int get_battery_perct_bar(const char *bat); void get_battery_short_status(char *buf, unsigned int n, const char *bat); -/* - * used by RSS and Weather - */ -struct MemoryStruct { - char *memory; - size_t size; -}; - -size_t WriteMemoryCallback(void *ptr, size_t size, size_t nmemb, void *data); - #endif /* _COMMON_H */ diff --git a/src/conky.c b/src/conky.c index ed77172..d1fb1fd 100644 --- a/src/conky.c +++ b/src/conky.c @@ -158,7 +158,7 @@ static void reload_config(void); static void generate_text_internal(char *, int, struct text_object, struct information *); static int extract_variable_text_internal(struct text_object *, - const char *, char); + const char *); static void print_version(void) { @@ -208,6 +208,9 @@ static void print_version(void) #ifdef TCP_PORT_MONITOR " * portmon\n" #endif /* TCP_PORT_MONITOR */ +#ifdef HAVE_CURL + " * Curl\n" +#endif /* HAVE_CURL */ #ifdef RSS " * RSS\n" #endif /* RSS */ @@ -908,6 +911,11 @@ static void free_text_objects(struct text_object *root, int internal) case OBJ_eve: break; #endif +#ifdef HAVE_CURL + case OBJ_curl: + free(data.curl.uri); + break; +#endif #ifdef RSS case OBJ_rss: free(data.rss.uri); @@ -954,6 +962,7 @@ static void free_text_objects(struct text_object *root, int internal) free(data.execi.buffer); break; case OBJ_texeci: + if (data.texeci.p_timed_thread) timed_thread_destroy(data.texeci.p_timed_thread, &data.texeci.p_timed_thread); free(data.texeci.cmd); free(data.texeci.buffer); break; @@ -1245,7 +1254,7 @@ long current_text_color; /* construct_text_object() creates a new text_object */ static struct text_object *construct_text_object(const char *s, - const char *arg, long line, char allow_threaded, void **ifblock_opaque, void *free_at_crash) + const char *arg, long line, void **ifblock_opaque, void *free_at_crash) { // struct text_object *obj = new_text_object(); struct text_object *obj = new_text_object_internal(); @@ -1257,8 +1266,6 @@ static struct text_object *construct_text_object(const char *s, #define OBJ_IF(a, n) if (strcmp(s, #a) == 0) { \ obj->type = OBJ_##a; need_mask |= (1ULL << n); \ obj_be_ifblock_if(ifblock_opaque, obj); { -#define OBJ_THREAD(a, n) if (strcmp(s, #a) == 0 && allow_threaded) { \ - obj->type = OBJ_##a; need_mask |= (1ULL << n); { #define END } } else #define SIZE_DEFAULTS(arg) { \ @@ -1821,7 +1828,7 @@ static struct text_object *construct_text_object(const char *s, obj->data.execi.cmd = strndup(arg + n, text_buffer_size); obj->data.execi.buffer = malloc(text_buffer_size); } - END OBJ_THREAD(texeci, 0) + END OBJ(texeci, 0) int n; if (!arg || sscanf(arg, "%f %n", &obj->data.texeci.interval, &n) <= 0) { @@ -2110,7 +2117,7 @@ static struct text_object *construct_text_object(const char *s, obj->data.ifblock.s = strndup(arg, text_buffer_size); obj->sub = malloc(sizeof(struct text_object)); extract_variable_text_internal(obj->sub, - obj->data.ifblock.s, 0); + obj->data.ifblock.s); } END OBJ_IF(if_match, 0) if (!arg) { @@ -2120,7 +2127,7 @@ static struct text_object *construct_text_object(const char *s, obj->data.ifblock.s = strndup(arg, text_buffer_size); obj->sub = malloc(sizeof(struct text_object)); extract_variable_text_internal(obj->sub, - obj->data.ifblock.s, 0); + obj->data.ifblock.s); } END OBJ_IF(if_existing, 0) if (!arg) { @@ -2595,7 +2602,7 @@ static struct text_object *construct_text_object(const char *s, END OBJ(apm_battery_life, 0) END OBJ(apm_battery_time, 0) #endif /* __FreeBSD__ */ - END OBJ_THREAD(imap_unseen, 0) + END OBJ(imap_unseen, 0) if (arg) { // proccss obj->data.mail = parse_mail_args(IMAP_TYPE, arg); @@ -2603,7 +2610,7 @@ static struct text_object *construct_text_object(const char *s, } else { obj->char_b = 1; } - END OBJ_THREAD(imap_messages, 0) + END OBJ(imap_messages, 0) if (arg) { // proccss obj->data.mail = parse_mail_args(IMAP_TYPE, arg); @@ -2611,7 +2618,7 @@ static struct text_object *construct_text_object(const char *s, } else { obj->char_b = 1; } - END OBJ_THREAD(pop3_unseen, 0) + END OBJ(pop3_unseen, 0) if (arg) { // proccss obj->data.mail = parse_mail_args(POP3_TYPE, arg); @@ -2619,7 +2626,7 @@ static struct text_object *construct_text_object(const char *s, } else { obj->char_b = 1; } - END OBJ_THREAD(pop3_used, 0) + END OBJ(pop3_used, 0) if (arg) { // proccss obj->data.mail = parse_mail_args(POP3_TYPE, arg); @@ -2816,30 +2823,43 @@ static struct text_object *construct_text_object(const char *s, CRIT_ERR(obj, free_at_crash, "eve needs arguments: "); } #endif +#ifdef HAVE_CURL + END OBJ(curl, 0) + if (arg) { + int argc; + float interval; + char *uri = (char *) malloc(128 * sizeof(char)); + + argc = sscanf(arg, "%127s %f", uri, &interval); + obj->data.curl.uri = uri; + obj->data.curl.interval = interval > 0 ? interval * 60 : 15*60; + } else { + CRIT_ERR(obj, free_at_crash, "curl needs arguments: "); + } +#endif #ifdef RSS END OBJ(rss, 0) if (arg) { - int argc, delay, act_par; + float interval; + int argc, act_par; unsigned int nrspaces = 0; char *uri = (char *) malloc(128 * sizeof(char)); char *action = (char *) malloc(64 * sizeof(char)); - argc = sscanf(arg, "%127s %d %63s %d %u", uri, &delay, action, + argc = sscanf(arg, "%127s %f %63s %d %u", uri, &interval, action, &act_par, &nrspaces); obj->data.rss.uri = uri; - obj->data.rss.delay = delay; + obj->data.rss.interval = interval > 0 ? interval * 60 : 15*60; obj->data.rss.action = action; obj->data.rss.act_par = act_par; obj->data.rss.nrspaces = nrspaces; - - init_rss_info(); } else { - CRIT_ERR(obj, free_at_crash, "rss needs arguments: " + CRIT_ERR(obj, free_at_crash, "rss needs arguments: " "[act_par] [spaces in front]"); } #endif #ifdef WEATHER - END OBJ_THREAD(weather, 0) + END OBJ(weather, 0) if (arg) { int argc, interval; char *locID = (char *) malloc(9 * sizeof(char)); @@ -2849,14 +2869,14 @@ static struct text_object *construct_text_object(const char *s, argc = sscanf(arg, "%119s %8s %31s %d", uri, locID, data_type, &interval); - //locID MUST BE upper-case + /* locID MUST BE upper-case */ tmp_p = locID; while (*tmp_p) { *tmp_p = toupper(*tmp_p); tmp_p++; } - //Construct complete uri + /* Construct complete uri */ if (strstr(uri, "xoap.weather.com")) { if(xoap != NULL) { strcat(uri, locID); @@ -2876,12 +2896,12 @@ static struct text_object *construct_text_object(const char *s, obj->data.weather.uri = uri; obj->data.weather.data_type = data_type; - //Limit the data retrieval interval to half hour min + /* Limit the data retrieval interval to half hour min */ if (interval < 30) { interval = 30; } - //Convert to seconds + /* Convert to seconds */ obj->data.weather.interval = interval * 60; free(locID); @@ -2969,14 +2989,14 @@ static struct text_object *construct_text_object(const char *s, END OBJ(blink, 0) if(arg) { obj->sub = malloc(sizeof(struct text_object)); - extract_variable_text_internal(obj->sub, arg, 0); + extract_variable_text_internal(obj->sub, arg); }else{ CRIT_ERR(obj, free_at_crash, "blink needs a argument"); } END OBJ(to_bytes, 0) if(arg) { obj->sub = malloc(sizeof(struct text_object)); - extract_variable_text_internal(obj->sub, arg, 0); + extract_variable_text_internal(obj->sub, arg); }else{ CRIT_ERR(obj, free_at_crash, "to_bytes needs a argument"); } @@ -3001,7 +3021,7 @@ static struct text_object *construct_text_object(const char *s, obj->data.scroll.start = 0; obj->sub = malloc(sizeof(struct text_object)); extract_variable_text_internal(obj->sub, - obj->data.scroll.text, 0); + obj->data.scroll.text); } else { CRIT_ERR(obj, free_at_crash, "scroll needs arguments: [] "); } @@ -3045,9 +3065,9 @@ static struct text_object *construct_text_object(const char *s, obj->data.combine.right[endvar[1] - startvar[1]] = 0; obj->sub = malloc(sizeof(struct text_object)); - extract_variable_text_internal(obj->sub, obj->data.combine.left, 0); + extract_variable_text_internal(obj->sub, obj->data.combine.left); obj->sub->sub = malloc(sizeof(struct text_object)); - extract_variable_text_internal(obj->sub->sub, obj->data.combine.right, 0); + extract_variable_text_internal(obj->sub->sub, obj->data.combine.right); } else { CRIT_ERR(obj, free_at_crash, "combine needs arguments: "); } @@ -3371,7 +3391,7 @@ static size_t remove_comments(char *string) return folded; } -static int extract_variable_text_internal(struct text_object *retval, const char *const_p, char allow_threaded) +static int extract_variable_text_internal(struct text_object *retval, const char *const_p) { struct text_object *obj; char *p, *s, *orig_p; @@ -3490,8 +3510,7 @@ static int extract_variable_text_internal(struct text_object *retval, const char } obj = construct_text_object(buf, arg, - line, allow_threaded, - &ifblock_opaque, orig_p); + line, &ifblock_opaque, orig_p); if (obj != NULL) { append_object(retval, obj); } @@ -3543,12 +3562,12 @@ static void extract_variable_text(const char *p) text_buffer = 0; } - extract_variable_text_internal(&global_root_object, p, 1); + extract_variable_text_internal(&global_root_object, p); } void parse_conky_vars(struct text_object *root, char *txt, char *p, struct information *cur) { - extract_variable_text_internal(root, txt, 0); + extract_variable_text_internal(root, txt); generate_text_internal(p, max_user_text, *root, cur); return; } @@ -4439,8 +4458,10 @@ static void generate_text_internal(char *p, int p_max_size, if (!obj->data.texeci.p_timed_thread) { ERR("Error creating texeci timed thread"); } - timed_thread_register(obj->data.texeci.p_timed_thread, - &obj->data.texeci.p_timed_thread); + /* + * note that we don't register this thread with the + * timed_thread list, because we destroy it manually + */ if (timed_thread_run(obj->data.texeci.p_timed_thread)) { ERR("Error running texeci timed thread"); } @@ -4631,87 +4652,30 @@ static void generate_text_internal(char *p, int p_max_size, snprintf(p, p_max_size, "%s", skill); } #endif +#ifdef HAVE_CURL + OBJ(curl) { + if (obj->data.curl.uri != NULL) { + ccurl_process_info(p, p_max_size, obj->data.curl.uri, obj->data.curl.interval); + } else { + ERR("error processing Curl data"); + } + } +#endif #ifdef RSS OBJ(rss) { - PRSS *data = get_rss_info(obj->data.rss.uri, - obj->data.rss.delay); - char *str; - - if (data == NULL) { - snprintf(p, p_max_size, "prss: Error reading RSS data\n"); + if (obj->data.rss.uri != NULL) { + rss_process_info(p, p_max_size, obj->data.rss.uri, obj->data.rss.action, obj->data.rss.act_par, obj->data.rss.interval, obj->data.rss.nrspaces); } else { - if (strcmp(obj->data.rss.action, "feed_title") == EQUAL) { - str = data->title; - // remove trailing new line if one exists - if (str[strlen(str) - 1] == '\n') { - str[strlen(str) - 1] = 0; - } - snprintf(p, p_max_size, "%s", str); - } else if (strcmp(obj->data.rss.action, "item_title") == EQUAL) { - if (obj->data.rss.act_par < data->item_count) { - str = data->items[obj->data.rss.act_par].title; - // remove trailing new line if one exists - if (str[strlen(str) - 1] == '\n') { - str[strlen(str) - 1] = 0; - } - snprintf(p, p_max_size, "%s", str); - } - } else if (strcmp(obj->data.rss.action, "item_desc") == EQUAL) { - if (obj->data.rss.act_par < data->item_count) { - str = - data->items[obj->data.rss.act_par].description; - // remove trailing new line if one exists - if (str[strlen(str) - 1] == '\n') { - str[strlen(str) - 1] = 0; - } - snprintf(p, p_max_size, "%s", str); - } - } else if (strcmp(obj->data.rss.action, "item_titles") == EQUAL) { - if (data->item_count > 0) { - int itmp; - int show; - //'tmpspaces' is a string with spaces too be placed in front of each title - char *tmpspaces = malloc(obj->data.rss.nrspaces + 1); - memset(tmpspaces, ' ', obj->data.rss.nrspaces); - tmpspaces[obj->data.rss.nrspaces]=0; - - p[0] = 0; - - if (obj->data.rss.act_par > data->item_count) { - show = data->item_count; - } else { - show = obj->data.rss.act_par; - } - for (itmp = 0; itmp < show; itmp++) { - PRSS_Item *item = &data->items[itmp]; - - str = item->title; - if (str) { - // don't add new line before first item - if (itmp > 0) { - strncat(p, "\n", p_max_size); - } - /* remove trailing new line if one exists, - * we have our own */ - if (str[strlen(str) - 1] == '\n') { - str[strlen(str) - 1] = 0; - } - strncat(p, tmpspaces, p_max_size); - strncat(p, str, p_max_size); - } - } - free(tmpspaces); - } - } + ERR("error processing RSS data"); } } #endif #ifdef WEATHER OBJ(weather) { - if( obj->data.weather.uri != NULL ) { - process_weather_info(p, p_max_size, obj->data.weather.uri, obj->data.weather.data_type, obj->data.weather.interval); - } else { - strncpy(p, "either invalid xoap keys file or compiled without xoap support", p_max_size); + if (obj->data.weather.uri != NULL) { + weather_process_info(p, p_max_size, obj->data.weather.uri, obj->data.weather.data_type, obj->data.weather.interval); + } else { + ERR("error processing weather data, check that you have a valid XOAP key if using XOAP."); } } #endif @@ -7636,11 +7600,14 @@ void clean_up(void *memtofree1, void* memtofree2) #ifdef TCP_PORT_MONITOR tcp_portmon_clear(); #endif +#ifdef HAVE_CURL + ccurl_free_info(); +#endif #ifdef RSS - free_rss_info(); + rss_free_info(); #endif #ifdef WEATHER - free_weather_info(); + weather_free_info(); #endif #ifdef HAVE_LUA llua_close(); diff --git a/src/conky.h b/src/conky.h index 59e0dcc..859ad54 100644 --- a/src/conky.h +++ b/src/conky.h @@ -87,17 +87,21 @@ char *strndup(const char *s, size_t n); #include "nvidia.h" #endif +#ifdef HAVE_CURL +#include "ccurl_thread.h" +#endif /* HAVE_CURL */ + #ifdef RSS #include "rss.h" -#endif +#endif /* RSS */ #ifdef WEATHER #include "weather.h" -#endif +#endif /* WEATHER */ #ifdef HAVE_LUA #include "llua.h" -#endif +#endif /* HAVE_LUA */ #ifdef TCP_PORT_MONITOR #include "tcp-portmon.h" @@ -196,9 +200,6 @@ enum { INFO_XMMS2 = 22, #endif INFO_ENTROPY = 23, -#ifdef RSS - INFO_RSS = 24, -#endif #ifdef IBM INFO_SMAPI = 25, #endif diff --git a/src/prss.c b/src/prss.c index 562f549..2bbe589 100644 --- a/src/prss.c +++ b/src/prss.c @@ -24,29 +24,19 @@ #define PARSE_OPTIONS 0 #endif -PRSS *prss_parse_doc(xmlDocPtr doc); +void prss_parse_doc(PRSS *result, xmlDocPtr doc); -PRSS *prss_parse_data(const char *xml_data) +void prss_parse_data(void *result, const char *xml_data) { + PRSS *data = (PRSS*)result; xmlDocPtr doc = xmlReadMemory(xml_data, strlen(xml_data), "", NULL, PARSE_OPTIONS); if (!doc) { - return NULL; - } - - return prss_parse_doc(doc); -} - -PRSS *prss_parse_file(const char *xml_file) -{ - xmlDocPtr doc = xmlReadFile(xml_file, NULL, PARSE_OPTIONS); - - if (!doc) { - return NULL; + return; } - return prss_parse_doc(doc); + prss_parse_doc(data, doc); } void prss_free(PRSS *data) @@ -57,7 +47,6 @@ void prss_free(PRSS *data) xmlFreeDoc(data->_data); free(data->version); free(data->items); - free(data); } static inline void prss_null(PRSS *p) @@ -169,6 +158,7 @@ static inline int parse_rss_2_0(PRSS *res, xmlNodePtr root) } res->version = strndup("2.0", text_buffer_size); + if (res->items) free(res->items); res->items = malloc(items * sizeof(PRSS_Item)); res->item_count = 0; @@ -198,6 +188,7 @@ static inline int parse_rss_1_0(PRSS *res, xmlNodePtr root) } res->version = strndup("1.0", text_buffer_size); + if (res->items) free(res->items); res->items = malloc(items * sizeof(PRSS_Item)); res->item_count = 0; @@ -216,13 +207,12 @@ static inline int parse_rss_0_9x(PRSS *res, xmlNodePtr root) return parse_rss_2_0(res, root); } -PRSS *prss_parse_doc(xmlDocPtr doc) +void prss_parse_doc(PRSS *result, xmlDocPtr doc) { /* FIXME: doc shouldn't be freed after failure when called explicitly from * program! */ xmlNodePtr root = xmlDocGetRootElement(doc); - PRSS *result = malloc(sizeof(PRSS)); prss_null(result); result->_data = doc; @@ -230,24 +220,15 @@ PRSS *prss_parse_doc(xmlDocPtr doc) if (root->type == XML_ELEMENT_NODE) { if (!strcmp((const char *) root->name, "RDF")) { // RSS 1.0 document - if (!parse_rss_1_0(result, root)) { - free(result); - xmlFreeDoc(doc); - return NULL; - } - return result; + parse_rss_1_0(result, root); + return; } else if (!strcmp((const char *) root->name, "rss")) { // RSS 2.0 or <1.0 document - if (!parse_rss_2_0(result, root)) { - free(result); - xmlFreeDoc(doc); - return NULL; - } - return result; + parse_rss_2_0(result, root); + return; } } root = root->next; } while (root); - free(result); - return NULL; + return; } diff --git a/src/prss.h b/src/prss.h index ff7079a..12843b0 100644 --- a/src/prss.h +++ b/src/prss.h @@ -51,8 +51,7 @@ typedef struct PRSS_ { } PRSS; /* Functions for parsing RSS-data */ -PRSS *prss_parse_data(const char *xml_data); -PRSS *prss_parse_file(const char *xml_file); +void prss_parse_data(void *result, const char *xml_data); /* // Works wrong currently when called from application! PRSS *prss_parse_doc(xmlDocPtr doc); */ diff --git a/src/rss.c b/src/rss.c index 5bdbc8a..4603b9c 100644 --- a/src/rss.c +++ b/src/rss.c @@ -24,137 +24,110 @@ #include "conky.h" #include "logging.h" #include "prss.h" +#include "ccurl_thread.h" #include #include -#include -#include -#include -#define MAX_FEEDS 16 +static ccurl_location_t *locations_head = 0; -typedef struct feed_ { - char *uri; - int last_update; - PRSS *data; -} feed; - -int num_feeds = 0; -feed feeds[MAX_FEEDS]; - -int rss_delay(int *wait_time, int delay) +void rss_free_info(void) { - time_t now = time(NULL); + ccurl_location_t *tail = locations_head; - // make it minutes - if (delay < 1) { - delay = 1; + while (tail) { + if (tail->result) prss_free((PRSS*)tail->result); /* clean up old data */ + tail = tail->next; } - delay *= 60; - - if (!*wait_time) { - *wait_time = now + delay; - return 1; - } - - if (now >= *wait_time + delay) { - *wait_time = now + delay; - return 1; - } - - return 0; + ccurl_free_locations(&locations_head); } -void init_rss_info(void) +void rss_process_info(char *p, int p_max_size, char *uri, char *action, int + act_par, int interval, unsigned int nrspaces) { - int i; - - for (i = 0; i < MAX_FEEDS; i++) { - feeds[i].uri = NULL; - feeds[i].data = NULL; - feeds[i].last_update = 0; - } -} - -void free_rss_info(void) -{ - int i; - - for (i = 0; i < num_feeds; i++) { - if (feeds[i].uri != NULL) { - free(feeds[i].uri); + PRSS *data; + char *str; + + ccurl_location_t *curloc = ccurl_find_location(&locations_head, uri); + if (!curloc->p_timed_thread) { + curloc->result = malloc(sizeof(PRSS)); + memset(curloc->result, 0, sizeof(PRSS)); + curloc->process_function = &prss_parse_data; + ccurl_init_thread(curloc, interval); + if (!curloc->p_timed_thread) { + ERR("error setting up weather thread"); } } -} - -PRSS *get_rss_info(char *uri, int delay) -{ - CURL *curl = NULL; - CURLcode res; - - // pointers to struct - feed *curfeed = NULL; - PRSS *curdata = NULL; - int *last_update = 0; - - int i; - - // curl temps - struct MemoryStruct chunk; - chunk.memory = NULL; - chunk.size = 0; - - // first seek for the uri in list - for (i = 0; i < num_feeds; i++) { - if (feeds[i].uri != NULL) { - if (!strcmp(feeds[i].uri, uri)) { - curfeed = &feeds[i]; - break; + timed_thread_lock(curloc->p_timed_thread); + data = (PRSS*)curloc->result; + + if (data == NULL) { + snprintf(p, p_max_size, "prss: Error reading RSS data\n"); + } else { + if (strcmp(action, "feed_title") == EQUAL) { + str = data->title; + // remove trailing new line if one exists + if (str[strlen(str) - 1] == '\n') { + str[strlen(str) - 1] = 0; + } + snprintf(p, p_max_size, "%s", str); + } else if (strcmp(action, "item_title") == EQUAL) { + if (act_par < data->item_count) { + str = data->items[act_par].title; + // remove trailing new line if one exists + if (str[strlen(str) - 1] == '\n') { + str[strlen(str) - 1] = 0; + } + snprintf(p, p_max_size, "%s", str); + } + } else if (strcmp(action, "item_desc") == EQUAL) { + if (act_par < data->item_count) { + str = + data->items[act_par].description; + // remove trailing new line if one exists + if (str[strlen(str) - 1] == '\n') { + str[strlen(str) - 1] = 0; + } + snprintf(p, p_max_size, "%s", str); + } + } else if (strcmp(action, "item_titles") == EQUAL) { + if (data->item_count > 0) { + int itmp; + int show; + //'tmpspaces' is a string with spaces too be placed in front of each title + char *tmpspaces = malloc(nrspaces + 1); + memset(tmpspaces, ' ', nrspaces); + tmpspaces[nrspaces]=0; + + p[0] = 0; + + if (act_par > data->item_count) { + show = data->item_count; + } else { + show = act_par; + } + for (itmp = 0; itmp < show; itmp++) { + PRSS_Item *item = &data->items[itmp]; + + str = item->title; + if (str) { + // don't add new line before first item + if (itmp > 0) { + strncat(p, "\n", p_max_size); + } + /* remove trailing new line if one exists, + * we have our own */ + if (str[strlen(str) - 1] == '\n') { + str[strlen(str) - 1] = 0; + } + strncat(p, tmpspaces, p_max_size); + strncat(p, str, p_max_size); + } + } + free(tmpspaces); } } } - - if (!curfeed) { // new feed - if (num_feeds == MAX_FEEDS - 1) { - return NULL; - } - curfeed = &feeds[num_feeds]; - curfeed->uri = strndup(uri, text_buffer_size); - num_feeds++; - } - - last_update = &curfeed->last_update; - curdata = curfeed->data; - - if (!rss_delay(last_update, delay)) { - return curdata; // wait for delay to pass - } - - if (curdata != NULL) { - prss_free(curdata); // clean up old data - curdata = NULL; - } - - curl = curl_easy_init(); - if (curl) { - curl_easy_setopt(curl, CURLOPT_URL, uri); - curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 1); - curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback); - curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *) &chunk); - curl_easy_setopt(curl, CURLOPT_USERAGENT, "conky-rss/1.0"); - - res = curl_easy_perform(curl); - if (res == CURLE_OK && chunk.size) { - curdata = prss_parse_data(chunk.memory); - free(chunk.memory); - } else { - ERR("No data from server"); - } - - curl_easy_cleanup(curl); - } - - curfeed->data = curdata; - - return curdata; + timed_thread_unlock(curloc->p_timed_thread); } + diff --git a/src/rss.h b/src/rss.h index 9391c5a..16fd9ac 100644 --- a/src/rss.h +++ b/src/rss.h @@ -3,8 +3,8 @@ #include "prss.h" -PRSS *get_rss_info(char *uri, int delay); -void init_rss_info(void); -void free_rss_info(void); +void rss_free_info(void); +void rss_process_info(char *p, int p_max_size, char *uri, char *action, int + act_par, int interval, unsigned int nrspaces); #endif /*RSS_H_*/ diff --git a/src/text_object.h b/src/text_object.h index 4d759a2..9c74e88 100644 --- a/src/text_object.h +++ b/src/text_object.h @@ -375,6 +375,9 @@ enum text_object_type { #ifdef EVE OBJ_eve, #endif /* EVE */ +#ifdef HAVE_CURL + OBJ_curl, +#endif /* HAVE_CURL */ #ifdef RSS OBJ_rss, #endif /* RSS */ @@ -538,22 +541,26 @@ struct text_object { char *userid; } eve; #endif +#ifdef HAVE_CURL + struct { + char *uri; + float interval; + } curl; +#endif #ifdef RSS struct { char *uri; char *action; int act_par; - int delay; + float interval; unsigned int nrspaces; - timed_thread *p_timed_thread; } rss; #endif #ifdef WEATHER struct { char *uri; - char *data_type; - int interval; - timed_thread *p_timed_thread; + char *data_type; + int interval; } weather; #endif struct { diff --git a/src/weather.c b/src/weather.c index 868737a..c8de446 100644 --- a/src/weather.c +++ b/src/weather.c @@ -30,14 +30,12 @@ #include "logging.h" #include "weather.h" #include "temphelper.h" +#include "ccurl_thread.h" #include #include #ifdef MATH #include #endif /* MATH */ -#include -#include -#include #ifdef XOAP #include #endif /* XOAP */ @@ -63,57 +61,11 @@ const char *WC_CODES[NUM_WC_CODES] = { "FC", "PO", "SQ", "SS", "DS" }; -typedef struct location_ { - char *uri; - int last_update; - PWEATHER data; - timed_thread *p_timed_thread; - struct location_ *next; -} location; +static ccurl_location_t *locations_head = 0; -static location *locations_head = 0; - -location *find_location(char *uri) -{ - location *tail = locations_head; - location *new = 0; - while (tail) { - if (tail->uri && - strcmp(tail->uri, uri) == EQUAL) { - return tail; - } - tail = tail->next; - } - if (!tail) { // new location!!!!!!! - new = malloc(sizeof(location)); - memset(new, 0, sizeof(location)); - new->uri = strndup(uri, text_buffer_size); - tail = locations_head; - while (tail && tail->next) { - tail = tail->next; - } - if (!tail) { - // omg the first one!!!!!!! - locations_head = new; - } else { - tail->next = new; - } - } - return new; -} - -void free_weather_info(void) +void weather_free_info(void) { - location *tail = locations_head; - location *last = 0; - - while (tail) { - if (tail->uri) free(tail->uri); - last = tail; - tail = tail->next; - free(last); - } - locations_head = 0; + ccurl_free_locations(&locations_head); } int rel_humidity(int dew_point, int air) { @@ -489,9 +441,10 @@ static inline void parse_token(PWEATHER *res, char *token) { } } -static void parse_weather(PWEATHER *res, const char *data) +void parse_weather(void *result, const char *data) { - //Reset results + PWEATHER *res = (PWEATHER*)result; + /* Reset results */ memset(res, 0, sizeof(PWEATHER)); #ifdef XOAP @@ -532,60 +485,7 @@ static void parse_weather(PWEATHER *res, const char *data) } } -void fetch_weather_info(location *curloc) -{ - CURL *curl = NULL; - CURLcode res; - - // curl temps - struct MemoryStruct chunk; - - chunk.memory = NULL; - chunk.size = 0; - - curl = curl_easy_init(); - if (curl) { - curl_easy_setopt(curl, CURLOPT_URL, curloc->uri); - curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 1); - curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback); - curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *) &chunk); - curl_easy_setopt(curl, CURLOPT_USERAGENT, "conky-weather/1.0"); - - res = curl_easy_perform(curl); - if (res == CURLE_OK && chunk.size) { - timed_thread_lock(curloc->p_timed_thread); - parse_weather(&curloc->data, chunk.memory); - timed_thread_unlock(curloc->p_timed_thread); - free(chunk.memory); - } else { - ERR("weather: no data from server"); - } - - curl_easy_cleanup(curl); - } - - return; -} - -void *weather_thread(void *) __attribute__((noreturn)); - -void init_thread(location *curloc, int interval) -{ - curloc->p_timed_thread = - timed_thread_create(&weather_thread, - (void *)curloc, interval * 1000000); - if (!curloc->p_timed_thread) { - ERR("weather: error creating timed thread"); - } - timed_thread_register(curloc->p_timed_thread, - &curloc->p_timed_thread); - if (timed_thread_run(curloc->p_timed_thread)) { - ERR("weather: error running timed thread"); - } -} - - -void process_weather_info(char *p, int p_max_size, char *uri, char *data_type, int interval) +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", @@ -593,96 +493,93 @@ void process_weather_info(char *p, int p_max_size, char *uri, char *data_type, i "mist", "dust", "sand", "funnel cloud tornado", "dust/sand", "squall", "sand storm", "dust storm" }; + PWEATHER *data; - location *curloc = find_location(uri); - if (!curloc->p_timed_thread) init_thread(curloc, interval); + ccurl_location_t *curloc = ccurl_find_location(&locations_head, uri); + if (!curloc->p_timed_thread) { + curloc->result = malloc(sizeof(PWEATHER)); + memset(curloc->result, 0, sizeof(PWEATHER)); + curloc->process_function = &parse_weather; + ccurl_init_thread(curloc, interval); + if (!curloc->p_timed_thread) { + ERR("error setting up weather thread"); + } + } timed_thread_lock(curloc->p_timed_thread); + data = (PWEATHER*)curloc->result; if (strcmp(data_type, "last_update") == EQUAL) { - strncpy(p, curloc->data.lastupd, p_max_size); + strncpy(p, data->lastupd, p_max_size); } else if (strcmp(data_type, "temperature") == EQUAL) { - temp_print(p, p_max_size, curloc->data.temp, TEMP_CELSIUS); + temp_print(p, p_max_size, data->temp, TEMP_CELSIUS); } else if (strcmp(data_type, "cloud_cover") == EQUAL) { #ifdef XOAP - if (curloc->data.xoap_t[0] != '\0') { - strncpy(p, curloc->data.xoap_t, p_max_size); + if (data->xoap_t[0] != '\0') { + strncpy(p, data->xoap_t, p_max_size); } else #endif /* XOAP */ - if (curloc->data.cc == 0) { + if (data->cc == 0) { strncpy(p, "", p_max_size); - } else if (curloc->data.cc < 3) { + } else if (data->cc < 3) { strncpy(p, "clear", p_max_size); - } else if (curloc->data.cc < 5) { + } else if (data->cc < 5) { strncpy(p, "partly cloudy", p_max_size); - } else if (curloc->data.cc == 5) { + } else if (data->cc == 5) { strncpy(p, "cloudy", p_max_size); - } else if (curloc->data.cc == 6) { + } else if (data->cc == 6) { strncpy(p, "overcast", p_max_size); - } else if (curloc->data.cc == 7) { + } else if (data->cc == 7) { strncpy(p, "towering cumulus", p_max_size); } else { strncpy(p, "cumulonimbus", p_max_size); } } else if (strcmp(data_type, "pressure") == EQUAL) { - snprintf(p, p_max_size, "%d", curloc->data.bar); + snprintf(p, p_max_size, "%d", data->bar); } else if (strcmp(data_type, "wind_speed") == EQUAL) { - snprintf(p, p_max_size, "%d", curloc->data.wind_s); + snprintf(p, p_max_size, "%d", data->wind_s); } else if (strcmp(data_type, "wind_dir") == EQUAL) { - if ((curloc->data.wind_d >= 349) || (curloc->data.wind_d < 12)) { + if ((data->wind_d >= 349) || (data->wind_d < 12)) { strncpy(p, "N", p_max_size); - } else if (curloc->data.wind_d < 33) { + } else if (data->wind_d < 33) { strncpy(p, "NNE", p_max_size); - } else if (curloc->data.wind_d < 57) { + } else if (data->wind_d < 57) { strncpy(p, "NE", p_max_size); - } else if (curloc->data.wind_d < 79) { + } else if (data->wind_d < 79) { strncpy(p, "ENE", p_max_size); - } else if (curloc->data.wind_d < 102) { + } else if (data->wind_d < 102) { strncpy(p, "E", p_max_size); - } else if (curloc->data.wind_d < 124) { + } else if (data->wind_d < 124) { strncpy(p, "ESE", p_max_size); - } else if (curloc->data.wind_d < 147) { + } else if (data->wind_d < 147) { strncpy(p, "SE", p_max_size); - } else if (curloc->data.wind_d < 169) { + } else if (data->wind_d < 169) { strncpy(p, "SSE", p_max_size); - } else if (curloc->data.wind_d < 192) { + } else if (data->wind_d < 192) { strncpy(p, "S", p_max_size); - } else if (curloc->data.wind_d < 214) { + } else if (data->wind_d < 214) { strncpy(p, "SSW", p_max_size); - } else if (curloc->data.wind_d < 237) { + } else if (data->wind_d < 237) { strncpy(p, "SW", p_max_size); - } else if (curloc->data.wind_d < 259) { + } else if (data->wind_d < 259) { strncpy(p, "WSW", p_max_size); - } else if (curloc->data.wind_d < 282) { + } else if (data->wind_d < 282) { strncpy(p, "W", p_max_size); - } else if (curloc->data.wind_d < 304) { + } else if (data->wind_d < 304) { strncpy(p, "WNW", p_max_size); - } else if (curloc->data.wind_d < 327) { + } else if (data->wind_d < 327) { strncpy(p, "NW", p_max_size); - } else if (curloc->data.wind_d < 349) { + } else if (data->wind_d < 349) { strncpy(p, "NNW", p_max_size); }; } else if (strcmp(data_type, "wind_dir_DEG") == EQUAL) { - snprintf(p, p_max_size, "%d", curloc->data.wind_d); + snprintf(p, p_max_size, "%d", data->wind_d); } else if (strcmp(data_type, "humidity") == EQUAL) { - snprintf(p, p_max_size, "%d", curloc->data.hmid); + snprintf(p, p_max_size, "%d", data->hmid); } else if (strcmp(data_type, "weather") == EQUAL) { - strncpy(p, wc[curloc->data.wc], p_max_size); + strncpy(p, wc[data->wc], p_max_size); } timed_thread_unlock(curloc->p_timed_thread); } -void *weather_thread(void *arg) -{ - location *curloc = (location*)arg; - - while (1) { - fetch_weather_info(curloc); - if (timed_thread_test(curloc->p_timed_thread, 0)) { - timed_thread_exit(curloc->p_timed_thread); - } - } - /* never reached */ -} - diff --git a/src/weather.h b/src/weather.h index bff17c5..8730a58 100644 --- a/src/weather.h +++ b/src/weather.h @@ -55,8 +55,7 @@ typedef struct PWEATHER_ { } PWEATHER; /* Prototypes */ -void init_weather_info(void); -void free_weather_info(void); -void process_weather_info(char *p, int p_max_size, char *uri, char *data_type, int interval); +void weather_free_info(void); +void weather_process_info(char *p, int p_max_size, char *uri, char *data_type, int interval); #endif /*WEATHER_H_*/ -- 1.7.9.5