Better argument handling for rss/curl/weather.
[monky] / src / conky.c
index 3303c12..136773c 100644 (file)
@@ -148,6 +148,8 @@ static volatile int g_signal_pending;
 double update_interval;
 void *global_cpu = NULL;
 
+int argc_copy;
+char** argv_copy;
 
 /* prototypes for internally used functions */
 static void signal_handler(int);
@@ -156,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)
 {
@@ -206,11 +208,17 @@ 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 */
 #ifdef WEATHER
-                  "  * Weather (METAR)\n"
+                  "  * Weather (NOAA)\n"
+#ifdef XOAP
+                  "  * Weather (XOAP)\n"
+#endif /* XOAP */
 #endif /* WEATHER */
 #ifdef HAVE_IWLIB
                   "  * wireless\n"
@@ -259,7 +267,6 @@ static const char *suffixes[] = { "B", "KiB", "MiB", "GiB", "TiB", "PiB", "" };
 
 #ifdef X11
 
-static void X11_destroy_window(void);
 static void X11_create_window(void);
 static void X11_initialisation(void);
 
@@ -303,7 +310,7 @@ struct information info;
 char *current_config;
 
 /* set to 1 if you want all text to be in uppercase */
-static unsigned int stuff_in_upper_case;
+static unsigned int stuff_in_uppercase;
 
 /* Run how many times? */
 static unsigned long total_run_times;
@@ -317,6 +324,11 @@ static int cpu_avg_samples, net_avg_samples, diskio_avg_samples;
 char *overwrite_file = NULL; FILE *overwrite_fpointer = NULL;
 char *append_file = NULL; FILE *append_fpointer = NULL;
 
+/* xoap suffix for weather from weather.com */
+#ifdef WEATHER
+static char *xoap = NULL;
+#endif /* WEATHER */
+
 #ifdef X11
 
 static int show_graph_scale;
@@ -378,11 +390,11 @@ int register_iconv(iconv_t *new_iconv)
 {
        iconv_cd = realloc(iconv_cd, sizeof(iconv_t *) * (iconv_count + 1));
        if (!iconv_cd) {
-               CRIT_ERR("Out of memory");
+               CRIT_ERR(NULL, NULL, "Out of memory");
        }
        iconv_cd[iconv_count] = malloc(sizeof(iconv_t));
        if (!iconv_cd[iconv_count]) {
-               CRIT_ERR("Out of memory");
+               CRIT_ERR(NULL, NULL, "Out of memory");
        }
        memcpy(iconv_cd[iconv_count], new_iconv, sizeof(iconv_t));
        iconv_count++;
@@ -443,11 +455,15 @@ int check_contains(char *f, char *s)
        return ret;
 }
 
+#define SECRIT_MULTILINE_CHAR '\x02'
+
 #ifdef X11
+
 static inline int calc_text_width(const char *s, int l)
 {
-       if ((output_methods & TO_X) == 0)
+       if ((output_methods & TO_X) == 0) {
                return 0;
+       }
 #ifdef XFT
        if (use_xft) {
                XGlyphInfo gi;
@@ -473,27 +489,24 @@ static inline int calc_text_width(const char *s, int l)
 
 static char *text_buffer;
 
-#ifdef X11
-static unsigned int special_index;     /* used when drawing */
-#endif /* X11 */
-
 /* quite boring functions */
 
-static inline void for_each_line(char *b, void f(char *))
+static inline void for_each_line(char *b, int f(char *, int))
 {
        char *ps, *pe;
+       int special_index = 0; /* specials index */
 
        for (ps = b, pe = b; *pe; pe++) {
                if (*pe == '\n') {
                        *pe = '\0';
-                       f(ps);
+                       special_index = f(ps, special_index);
                        *pe = '\n';
                        ps = pe + 1;
                }
        }
 
        if (ps < pe) {
-               f(ps);
+               f(ps, special_index);
        }
 }
 
@@ -898,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);
@@ -912,6 +930,7 @@ static void free_text_objects(struct text_object *root, int internal)
 #endif
 #ifdef HAVE_LUA
                        case OBJ_lua:
+                       case OBJ_lua_parse:
                        case OBJ_lua_bar:
 #ifdef X11
                        case OBJ_lua_graph:
@@ -944,6 +963,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;
@@ -1090,6 +1110,10 @@ static void free_text_objects(struct text_object *root, int internal)
                                  free(info.x11.desktop.name);
                                  info.x11.desktop.name = NULL;
                                }
+                               if(info.x11.desktop.all_names) {
+                                 free(info.x11.desktop.all_names);
+                                 info.x11.desktop.all_names = NULL;
+                               }
                                break;
 #endif /* X11 */
                }
@@ -1227,9 +1251,11 @@ static int parse_top_args(const char *s, const char *arg, struct text_object *ob
        return 1;
 }
 
+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)
+               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();
@@ -1241,8 +1267,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) { \
@@ -1296,10 +1320,10 @@ static struct text_object *construct_text_object(const char *s,
                        }
                        obj->data.read_tcp.port = htons(obj->data.read_tcp.port);
                        if(obj->data.read_tcp.port < 1 || obj->data.read_tcp.port > 65535) {
-                               CRIT_ERR("read_tcp: Needs \"(host) port\" as argument(s)");
+                               CRIT_ERR(obj, free_at_crash, "read_tcp: Needs \"(host) port\" as argument(s)");
                        }
                }else{
-                       CRIT_ERR("read_tcp: Needs \"(host) port\" as argument(s)");
+                       CRIT_ERR(obj, free_at_crash, "read_tcp: Needs \"(host) port\" as argument(s)");
                }
 #if defined(__linux__)
        END OBJ(voltage_mv, 0)
@@ -1328,76 +1352,76 @@ static struct text_object *construct_text_object(const char *s,
 #ifdef HAVE_IWLIB
        END OBJ(wireless_essid, INFO_NET)
                if (arg) {
-                       obj->data.net = get_net_stat(arg);
+                       obj->data.net = get_net_stat(arg, obj, free_at_crash);
                } else {
                        // default to DEFAULTNETDEV
                        char *buf = strndup(DEFAULTNETDEV, text_buffer_size);
-                       obj->data.net = get_net_stat(buf);
+                       obj->data.net = get_net_stat(buf, obj, free_at_crash);
                        free(buf);
                }
        END OBJ(wireless_mode, INFO_NET)
                if (arg) {
-                       obj->data.net = get_net_stat(arg);
+                       obj->data.net = get_net_stat(arg, obj, free_at_crash);
                } else {
                        // default to DEFAULTNETDEV
                        char *buf = strndup(DEFAULTNETDEV, text_buffer_size);
-                       obj->data.net = get_net_stat(buf);
+                       obj->data.net = get_net_stat(buf, obj, free_at_crash);
                        free(buf);
                }
        END OBJ(wireless_bitrate, INFO_NET)
                if (arg) {
-                       obj->data.net = get_net_stat(arg);
+                       obj->data.net = get_net_stat(arg, obj, free_at_crash);
                } else {
                        // default to DEFAULTNETDEV
                        char *buf = strndup(DEFAULTNETDEV, text_buffer_size);
-                       obj->data.net = get_net_stat(buf);
+                       obj->data.net = get_net_stat(buf, obj, free_at_crash);
                        free(buf);
                }
        END OBJ(wireless_ap, INFO_NET)
                if (arg) {
-                       obj->data.net = get_net_stat(arg);
+                       obj->data.net = get_net_stat(arg, obj, free_at_crash);
                } else {
                        // default to DEFAULTNETDEV
                        char *buf = strndup(DEFAULTNETDEV, text_buffer_size);
-                       obj->data.net = get_net_stat(buf);
+                       obj->data.net = get_net_stat(buf, obj, free_at_crash);
                        free(buf);
                }
        END OBJ(wireless_link_qual, INFO_NET)
                if (arg) {
-                       obj->data.net = get_net_stat(arg);
+                       obj->data.net = get_net_stat(arg, obj, free_at_crash);
                } else {
                        // default to DEFAULTNETDEV
                        char *buf = strndup(DEFAULTNETDEV, text_buffer_size);
-                       obj->data.net = get_net_stat(buf);
+                       obj->data.net = get_net_stat(buf, obj, free_at_crash);
                        free(buf);
                }
        END OBJ(wireless_link_qual_max, INFO_NET)
                if (arg) {
-                       obj->data.net = get_net_stat(arg);
+                       obj->data.net = get_net_stat(arg, obj, free_at_crash);
                } else {
                        // default to DEFAULTNETDEV
                        char *buf = strndup(DEFAULTNETDEV, text_buffer_size);
-                       obj->data.net = get_net_stat(buf);
+                       obj->data.net = get_net_stat(buf, obj, free_at_crash);
                        free(buf);
                }
        END OBJ(wireless_link_qual_perc, INFO_NET)
                if (arg) {
-                       obj->data.net = get_net_stat(arg);
+                       obj->data.net = get_net_stat(arg, obj, free_at_crash);
                } else {
                        // default to DEFAULTNETDEV
                        char *buf = strndup(DEFAULTNETDEV, text_buffer_size);
-                       obj->data.net = get_net_stat(buf);
+                       obj->data.net = get_net_stat(buf, obj, free_at_crash);
                        free(buf);
                }
        END OBJ(wireless_link_bar, INFO_NET)
                SIZE_DEFAULTS(bar);
                if (arg) {
                        arg = scan_bar(arg, &obj->a, &obj->b);
-                       obj->data.net = get_net_stat(arg);
+                       obj->data.net = get_net_stat(arg, obj, free_at_crash);
                } else {
                        // default to DEFAULTNETDEV
                        char *buf = strndup(DEFAULTNETDEV, text_buffer_size);
-                       obj->data.net = get_net_stat(buf);
+                       obj->data.net = get_net_stat(buf, obj, free_at_crash);
                        free(buf);
                }
 #endif /* HAVE_IWLIB */
@@ -1460,7 +1484,7 @@ static struct text_object *construct_text_object(const char *s,
                if (arg)
                        obj->data.s = strndup(dev_name(arg), text_buffer_size);
                else
-                       CRIT_ERR("disk_protect needs an argument");
+                       CRIT_ERR(obj, free_at_crash, "disk_protect needs an argument");
        END OBJ(i8k_version, INFO_I8K)
        END OBJ(i8k_bios, INFO_I8K)
        END OBJ(i8k_serial, INFO_I8K)
@@ -1475,7 +1499,7 @@ static struct text_object *construct_text_object(const char *s,
        END OBJ(ibm_fan, 0)
        END OBJ(ibm_temps, 0)
                if (!arg) {
-                       CRIT_ERR("ibm_temps: needs an argument");
+                       CRIT_ERR(obj, free_at_crash, "ibm_temps: needs an argument");
                }
                if (!isdigit(arg[0]) || strlen(arg) >= 2 || atoi(&arg[0]) >= 8) {
                        obj->data.sensor = 0;
@@ -1492,7 +1516,7 @@ static struct text_object *construct_text_object(const char *s,
        END OBJ_IF(if_gw, INFO_GW)
        END OBJ(ioscheduler, 0)
                if (!arg) {
-                       CRIT_ERR("get_ioscheduler needs an argument (e.g. hda)");
+                       CRIT_ERR(obj, free_at_crash, "get_ioscheduler needs an argument (e.g. hda)");
                        obj->data.s = 0;
                } else
                        obj->data.s = strndup(dev_name(arg), text_buffer_size);
@@ -1523,7 +1547,7 @@ static struct text_object *construct_text_object(const char *s,
 #if defined(__OpenBSD__)
        END OBJ(obsd_sensors_temp, 0)
                if (!arg) {
-                       CRIT_ERR("obsd_sensors_temp: needs an argument");
+                       CRIT_ERR(obj, free_at_crash, "obsd_sensors_temp: needs an argument");
                }
                if (!isdigit(arg[0]) || atoi(&arg[0]) < 0
                                || atoi(&arg[0]) > OBSD_MAX_SENSORS - 1) {
@@ -1533,7 +1557,7 @@ static struct text_object *construct_text_object(const char *s,
                obj->data.sensor = atoi(&arg[0]);
        END OBJ(obsd_sensors_fan, 0)
                if (!arg) {
-                       CRIT_ERR("obsd_sensors_fan: needs 2 arguments (device and sensor "
+                       CRIT_ERR(obj, free_at_crash, "obsd_sensors_fan: needs 2 arguments (device and sensor "
                                "number)");
                }
                if (!isdigit(arg[0]) || atoi(&arg[0]) < 0
@@ -1544,7 +1568,7 @@ static struct text_object *construct_text_object(const char *s,
                obj->data.sensor = atoi(&arg[0]);
        END OBJ(obsd_sensors_volt, 0)
                if (!arg) {
-                       CRIT_ERR("obsd_sensors_volt: needs 2 arguments (device and sensor "
+                       CRIT_ERR(obj, free_at_crash, "obsd_sensors_volt: needs 2 arguments (device and sensor "
                                "number)");
                }
                if (!isdigit(arg[0]) || atoi(&arg[0]) < 0
@@ -1639,28 +1663,39 @@ static struct text_object *construct_text_object(const char *s,
 #ifdef X11
                if (output_methods & TO_X) {
                        obj->data.l = arg ? get_x11_color(arg) : default_fg_color;
+                       current_text_color = obj->data.l;
                }
 #endif /* X11 */
        END OBJ(color0, 0)
                obj->data.l = color0;
+               current_text_color = obj->data.l;
        END OBJ(color1, 0)
                obj->data.l = color1;
+               current_text_color = obj->data.l;
        END OBJ(color2, 0)
                obj->data.l = color2;
+               current_text_color = obj->data.l;
        END OBJ(color3, 0)
                obj->data.l = color3;
+               current_text_color = obj->data.l;
        END OBJ(color4, 0)
                obj->data.l = color4;
+               current_text_color = obj->data.l;
        END OBJ(color5, 0)
                obj->data.l = color5;
+               current_text_color = obj->data.l;
        END OBJ(color6, 0)
                obj->data.l = color6;
+               current_text_color = obj->data.l;
        END OBJ(color7, 0)
                obj->data.l = color7;
+               current_text_color = obj->data.l;
        END OBJ(color8, 0)
                obj->data.l = color8;
+               current_text_color = obj->data.l;
        END OBJ(color9, 0)
                obj->data.l = color9;
+               current_text_color = obj->data.l;
 #ifdef X11
        END OBJ(font, 0)
                obj->data.s = scan_font(arg);
@@ -1670,20 +1705,20 @@ static struct text_object *construct_text_object(const char *s,
        END OBJ(conky_build_arch, 0)
        END OBJ(downspeed, INFO_NET)
                if (arg) {
-                       obj->data.net = get_net_stat(arg);
+                       obj->data.net = get_net_stat(arg, obj, free_at_crash);
                } else {
                        // default to DEFAULTNETDEV
                        char *buf = strndup(DEFAULTNETDEV, text_buffer_size);
-                       obj->data.net = get_net_stat(buf);
+                       obj->data.net = get_net_stat(buf, obj, free_at_crash);
                        free(buf);
                }
        END OBJ(downspeedf, INFO_NET)
                if (arg) {
-                       obj->data.net = get_net_stat(arg);
+                       obj->data.net = get_net_stat(arg, obj, free_at_crash);
                } else {
                        // default to DEFAULTNETDEV
                        char *buf = strndup(DEFAULTNETDEV, text_buffer_size);
-                       obj->data.net = get_net_stat(buf);
+                       obj->data.net = get_net_stat(buf, obj, free_at_crash);
                        free(buf);
                }
 #ifdef X11
@@ -1695,7 +1730,7 @@ static struct text_object *construct_text_object(const char *s,
 
                // default to DEFAULTNETDEV
                buf = strndup(buf ? buf : DEFAULTNETDEV, text_buffer_size);
-               obj->data.net = get_net_stat(buf);
+               obj->data.net = get_net_stat(buf, obj, free_at_crash);
                free(buf);
 #endif /* X11 */
        END OBJ(else, 0)
@@ -1794,7 +1829,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) {
@@ -2017,21 +2052,21 @@ static struct text_object *construct_text_object(const char *s,
                }
        } else OBJ(addr, INFO_NET)
                if (arg) {
-                       obj->data.net = get_net_stat(arg);
+                       obj->data.net = get_net_stat(arg, obj, free_at_crash);
                } else {
                        // default to DEFAULTNETDEV
                        char *buf = strndup(DEFAULTNETDEV, text_buffer_size);
-                       obj->data.net = get_net_stat(buf);
+                       obj->data.net = get_net_stat(buf, obj, free_at_crash);
                        free(buf);
                }
 #if defined(__linux__)
        END OBJ(addrs, INFO_NET)
                if (arg) {
-                       obj->data.net = get_net_stat(arg);
+                       obj->data.net = get_net_stat(arg, obj, free_at_crash);
                } else {
                        // default to DEFAULTNETDEV
                        char *buf = strndup(DEFAULTNETDEV, text_buffer_size);
-                       obj->data.net = get_net_stat(buf);
+                       obj->data.net = get_net_stat(buf, obj, free_at_crash);
                        free(buf);
                }
 #endif /* __linux__ */
@@ -2049,13 +2084,13 @@ static struct text_object *construct_text_object(const char *s,
                if (arg) {
                        obj->data.s = strndup(arg, text_buffer_size);
                }else{
-                       CRIT_ERR("lines needs a argument");
+                       CRIT_ERR(obj, free_at_crash, "lines needs a argument");
                }
        END OBJ(words, 0)
                if (arg) {
                        obj->data.s = strndup(arg, text_buffer_size);
                }else{
-                       CRIT_ERR("words needs a argument");
+                       CRIT_ERR(obj, free_at_crash, "words needs a argument");
                }
        END OBJ(loadavg, INFO_LOADAVG)
                int a = 1, b = 2, c = 3, r = 3;
@@ -2083,7 +2118,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) {
@@ -2093,7 +2128,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) {
@@ -2462,7 +2497,7 @@ static struct text_object *construct_text_object(const char *s,
 #ifdef HAVE_ICONV
        END OBJ(iconv_start, 0)
                if (iconv_converting) {
-                       CRIT_ERR("You must stop your last iconv conversion before "
+                       CRIT_ERR(obj, free_at_crash, "You must stop your last iconv conversion before "
                                "starting another");
                }
                if (arg) {
@@ -2470,7 +2505,7 @@ static struct text_object *construct_text_object(const char *s,
                        char iconv_to[CODEPAGE_LENGTH];
 
                        if (sscanf(arg, "%s %s", iconv_from, iconv_to) != 2) {
-                               CRIT_ERR("Invalid arguments for iconv_start");
+                               CRIT_ERR(obj, free_at_crash, "Invalid arguments for iconv_start");
                        } else {
                                iconv_t new_iconv;
 
@@ -2483,7 +2518,7 @@ static struct text_object *construct_text_object(const char *s,
                                }
                        }
                } else {
-                       CRIT_ERR("Iconv requires arguments");
+                       CRIT_ERR(obj, free_at_crash, "Iconv requires arguments");
                }
        END OBJ(iconv_stop, 0)
                iconv_converting = 0;
@@ -2491,27 +2526,27 @@ static struct text_object *construct_text_object(const char *s,
 #endif
        END OBJ(totaldown, INFO_NET)
                if (arg) {
-                       obj->data.net = get_net_stat(arg);
+                       obj->data.net = get_net_stat(arg, obj, free_at_crash);
                } else {
                        // default to DEFAULTNETDEV
                        char *buf = strndup(DEFAULTNETDEV, text_buffer_size);
-                       obj->data.net = get_net_stat(buf);
+                       obj->data.net = get_net_stat(buf, obj, free_at_crash);
                        free(buf);
                }
        END OBJ(totalup, INFO_NET)
-               obj->data.net = get_net_stat(arg);
+               obj->data.net = get_net_stat(arg, obj, free_at_crash);
                if (arg) {
-                       obj->data.net = get_net_stat(arg);
+                       obj->data.net = get_net_stat(arg, obj, free_at_crash);
                } else {
                        // default to DEFAULTNETDEV
                        char *buf = strndup(DEFAULTNETDEV, text_buffer_size);
-                       obj->data.net = get_net_stat(buf);
+                       obj->data.net = get_net_stat(buf, obj, free_at_crash);
                        free(buf);
                }
        END OBJ(updates, 0)
        END OBJ_IF(if_updatenr, 0)
                obj->data.ifblock.i = arg ? atoi(arg) : 0;
-               if(obj->data.ifblock.i == 0) CRIT_ERR("if_updatenr needs a number above 0 as argument");
+               if(obj->data.ifblock.i == 0) CRIT_ERR(obj, free_at_crash, "if_updatenr needs a number above 0 as argument");
                updatereset = obj->data.ifblock.i > updatereset ? obj->data.ifblock.i : updatereset;
        END OBJ(alignr, 0)
                obj->data.i = arg ? atoi(arg) : 0;
@@ -2519,20 +2554,20 @@ static struct text_object *construct_text_object(const char *s,
                obj->data.i = arg ? atoi(arg) : 0;
        END OBJ(upspeed, INFO_NET)
                if (arg) {
-                       obj->data.net = get_net_stat(arg);
+                       obj->data.net = get_net_stat(arg, obj, free_at_crash);
                } else {
                        // default to DEFAULTNETDEV
                        char *buf = strndup(DEFAULTNETDEV, text_buffer_size);
-                       obj->data.net = get_net_stat(buf);
+                       obj->data.net = get_net_stat(buf, obj, free_at_crash);
                        free(buf);
                }
        END OBJ(upspeedf, INFO_NET)
                if (arg) {
-                       obj->data.net = get_net_stat(arg);
+                       obj->data.net = get_net_stat(arg, obj, free_at_crash);
                } else {
                        // default to DEFAULTNETDEV
                        char *buf = strndup(DEFAULTNETDEV, text_buffer_size);
-                       obj->data.net = get_net_stat(buf);
+                       obj->data.net = get_net_stat(buf, obj, free_at_crash);
                        free(buf);
                }
 
@@ -2545,7 +2580,7 @@ static struct text_object *construct_text_object(const char *s,
 
                // default to DEFAULTNETDEV
                buf = strndup(buf ? buf : DEFAULTNETDEV, text_buffer_size);
-               obj->data.net = get_net_stat(buf);
+               obj->data.net = get_net_stat(buf, obj, free_at_crash);
                free(buf);
 #endif
        END OBJ(uptime_short, INFO_UPTIME)
@@ -2568,7 +2603,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);
@@ -2576,7 +2611,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);
@@ -2584,7 +2619,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);
@@ -2592,7 +2627,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);
@@ -2737,7 +2772,7 @@ static struct text_object *construct_text_object(const char *s,
                        if (info.audacious.max_title_len > 0) {
                                info.audacious.max_title_len++;
                        } else {
-                               CRIT_ERR("audacious_title: invalid length argument");
+                               CRIT_ERR(obj, free_at_crash, "audacious_title: invalid length argument");
                        }
                }
        END OBJ(audacious_length, INFO_AUDACIOUS)
@@ -2786,64 +2821,108 @@ static struct text_object *construct_text_object(const char *s,
 
                        init_eve();
                } else {
-                       CRIT_ERR("eve needs arguments: <userid> <apikey> <characterid>");
+                       CRIT_ERR(obj, free_at_crash, "eve needs arguments: <userid> <apikey> <characterid>");
+               }
+#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);
+                       if (argc == 2) {
+                               obj->data.curl.uri = uri;
+                               obj->data.curl.interval = interval > 0 ? interval * 60 : 15*60;
+                       } else {
+                               ERR("wrong number of arguments for $curl");
+                       }
+               } else {
+                       CRIT_ERR(obj, free_at_crash, "curl needs arguments: <uri> <interval in minutes>");
                }
 #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.action = action;
-                       obj->data.rss.act_par = act_par;
-                       obj->data.rss.nrspaces = nrspaces;
-
-                       init_rss_info();
+                       if (argc == 5) {
+                               obj->data.rss.uri = uri;
+                               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;
+                       } else {
+                               ERR("wrong number of arguments for $rss");
+                       }
                } else {
-                       CRIT_ERR("rss needs arguments: <uri> <delay in minutes> <action> "
+                       CRIT_ERR(obj, free_at_crash, "rss needs arguments: <uri> <interval in minutes> <action> "
                                        "[act_par] [spaces in front]");
                }
 #endif
 #ifdef WEATHER
-       END OBJ_THREAD(weather, 0)
+       END OBJ(weather, 0)
                if (arg) {
-                       int argc, interval;
-                       char *icao = (char *) malloc(5 * sizeof(char));
+                       int argc;
+                       float interval;
+                       char *locID = (char *) malloc(9 * sizeof(char));
                        char *uri = (char *) malloc(128 * sizeof(char));
                        char *data_type = (char *) malloc(32 * sizeof(char));
                        char *tmp_p;
 
-                       argc = sscanf(arg, "%119s %4s %31s %d", uri, icao, data_type, &interval);
+                       argc = sscanf(arg, "%119s %8s %31s %f", uri, locID, data_type, &interval);
 
-                       //icao MUST BE upper-case
-                       tmp_p = icao;
-                       while (*tmp_p) {
-                               *tmp_p = toupper(*tmp_p);
-                               tmp_p++;
-                       }
+                       if (argc >= 3) {
+                               /* locID MUST BE upper-case */
+                               tmp_p = locID;
+                               while (*tmp_p) {
+                                       *tmp_p = toupper(*tmp_p);
+                                       tmp_p++;
+                               }
+
+                               /* Construct complete uri */
+                               if (strstr(uri, "xoap.weather.com")) {
+                                       if(xoap != NULL) {
+                                               strcat(uri, locID);
+                                               strcat(uri, xoap);
+                                       } else {
+                                               free(uri);
+                                               uri = NULL;
+                                       }
+                               } else if (strstr(uri, "weather.noaa.gov")) {
+                                       strcat(uri, locID);
+                                       strcat(uri, ".TXT");
+                               } else  if (!strstr(uri, "localhost") && !strstr(uri, "127.0.0.1")) {
+                                       CRIT_ERR(obj, free_at_crash, \
+                                                       "could not recognize the weather uri");
+                               }
 
+                               obj->data.weather.uri = uri;
+                               obj->data.weather.data_type = data_type;
 
-                       strcat(uri, icao);
-                       strcat(uri, ".TXT");
-                       obj->data.weather.uri = uri;
+                               /* Limit the data retrieval interval to half hour min */
+                               if (interval < 30) {
+                                       interval = 30;
+                               }
 
-                       obj->data.weather.data_type = data_type;
+                               /* Convert to seconds */
+                               obj->data.weather.interval = interval * 60;
+                               free(locID);
 
-                       // The data retrieval interval is limited to half an hour
-                       if (interval < 30) {
-                               interval = 30;
+                               DBGP("weather: fetching %s from %s every %d seconds", \
+                                               data_type, uri, obj->data.weather.interval);
+                       } else {
+                               ERR("wrong number of arguments for $weather");
                        }
-                       obj->data.weather.interval = interval * 60; // convert to seconds
-                       free(icao);
                } else {
-                       CRIT_ERR("weather needs arguments: <uri> <icao> <data_type> [interval in minutes]");
+                       CRIT_ERR(obj, free_at_crash, "weather needs arguments: <uri> <locID> <data_type> [interval in minutes]");
                }
 #endif
 #ifdef HAVE_LUA
@@ -2851,13 +2930,13 @@ static struct text_object *construct_text_object(const char *s,
                if (arg) {
                        obj->data.s = strndup(arg, text_buffer_size);
                } else {
-                       CRIT_ERR("lua needs arguments: <function name> [function parameters]");
+                       CRIT_ERR(obj, free_at_crash, "lua needs arguments: <function name> [function parameters]");
                }
        END OBJ(lua_parse, 0)
                if (arg) {
                        obj->data.s = strndup(arg, text_buffer_size);
                } else {
-                       CRIT_ERR("lua_parse needs arguments: <function name> [function parameters]");
+                       CRIT_ERR(obj, free_at_crash, "lua_parse needs arguments: <function name> [function parameters]");
                }
        END OBJ(lua_bar, 0)
                SIZE_DEFAULTS(bar);
@@ -2866,10 +2945,10 @@ static struct text_object *construct_text_object(const char *s,
                        if(arg) {
                                obj->data.s = strndup(arg, text_buffer_size);
                        } else {
-                               CRIT_ERR("lua_bar needs arguments: <height>,<width> <function name> [function parameters]");
+                               CRIT_ERR(obj, free_at_crash, "lua_bar needs arguments: <height>,<width> <function name> [function parameters]");
                        }
                } else {
-                       CRIT_ERR("lua_bar needs arguments: <height>,<width> <function name> [function parameters]");
+                       CRIT_ERR(obj, free_at_crash, "lua_bar needs arguments: <height>,<width> <function name> [function parameters]");
                }
 #ifdef X11
        END OBJ(lua_graph, 0)
@@ -2881,10 +2960,10 @@ static struct text_object *construct_text_object(const char *s,
                        if (buf) {
                                obj->data.s = buf;
                        } else {
-                               CRIT_ERR("lua_graph needs arguments: <function name> [height],[width] [gradient colour 1] [gradient colour 2] [scale] [-t] [-l]");
+                               CRIT_ERR(obj, free_at_crash, "lua_graph needs arguments: <function name> [height],[width] [gradient colour 1] [gradient colour 2] [scale] [-t] [-l]");
                        }
                } else {
-                       CRIT_ERR("lua_graph needs arguments: <function name> [height],[width] [gradient colour 1] [gradient colour 2] [scale] [-t] [-l]");
+                       CRIT_ERR(obj, free_at_crash, "lua_graph needs arguments: <function name> [height],[width] [gradient colour 1] [gradient colour 2] [scale] [-t] [-l]");
        }
        END OBJ(lua_gauge, 0)
                SIZE_DEFAULTS(gauge);
@@ -2893,10 +2972,10 @@ static struct text_object *construct_text_object(const char *s,
                        if (arg) {
                                obj->data.s = strndup(arg, text_buffer_size);
                        } else {
-                               CRIT_ERR("lua_gauge needs arguments: <height>,<width> <function name> [function parameters]");
+                               CRIT_ERR(obj, free_at_crash, "lua_gauge needs arguments: <height>,<width> <function name> [function parameters]");
                        }
                } else {
-                       CRIT_ERR("lua_gauge needs arguments: <height>,<width> <function name> [function parameters]");
+                       CRIT_ERR(obj, free_at_crash, "lua_gauge needs arguments: <height>,<width> <function name> [function parameters]");
                }
 #endif /* X11 */
 #endif /* HAVE_LUA */
@@ -2924,31 +3003,41 @@ 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("blink needs a argument");
+                       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("to_bytes needs a argument");
+                       CRIT_ERR(obj, free_at_crash, "to_bytes needs a argument");
                }
        END OBJ(scroll, 0)
-               int n1, n2;
+               int n1 = 0, n2 = 0;
 
+               obj->data.scroll.resetcolor = current_text_color;
                obj->data.scroll.step = 1;
                if (arg && sscanf(arg, "%u %n", &obj->data.scroll.show, &n1) > 0) {
-                       if (sscanf(arg + n1, "%u %n", &obj->data.scroll.step, &n2) > 0)
+                       sscanf(arg + n1, "%u %n", &obj->data.scroll.step, &n2);
+                       if (*(arg + n1 + n2)) {
                                n1 += n2;
-                       obj->data.scroll.text = strndup(arg + n1, text_buffer_size);
+                       } else {
+                               obj->data.scroll.step = 1;
+                       }
+                       obj->data.scroll.text = malloc(strlen(arg + n1) + obj->data.scroll.show + 1);
+                       for(n2 = 0; (unsigned int) n2 < obj->data.scroll.show; n2++) {
+                               obj->data.scroll.text[n2] = ' ';
+                       }
+                       obj->data.scroll.text[n2] = 0;
+                       strcat(obj->data.scroll.text, arg + n1);
                        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("scroll needs arguments: <length> [<step>] <text>");
+                       CRIT_ERR(obj, free_at_crash, "scroll needs arguments: <length> [<step>] <text>");
                }
        END OBJ(combine, 0)
                if(arg) {
@@ -2990,21 +3079,21 @@ 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("combine needs arguments: <text1> <text2>");
+                               CRIT_ERR(obj, free_at_crash, "combine needs arguments: <text1> <text2>");
                        }
                } else {
-                       CRIT_ERR("combine needs arguments: <text1> <text2>");
+                       CRIT_ERR(obj, free_at_crash, "combine needs arguments: <text1> <text2>");
                }
 #ifdef NVIDIA
        END OBJ(nvidia, 0)
                if (!arg) {
-                       CRIT_ERR("nvidia needs an argument\n");
+                       CRIT_ERR(obj, free_at_crash, "nvidia needs an argument\n");
                } else if (set_nvidia_type(&obj->data.nvidia, arg)) {
-                       CRIT_ERR("nvidia: invalid argument"
+                       CRIT_ERR(obj, free_at_crash, "nvidia: invalid argument"
                                 " specified: '%s'\n", arg);
                }
 #endif /* NVIDIA */
@@ -3015,13 +3104,13 @@ static struct text_object *construct_text_object(const char *s,
                                char host[64];
                                int port;
                                if (sscanf(arg, "%63s %d", host, &port) != 2) {
-                                       CRIT_ERR("apcupsd needs arguments: <host> <port>");
+                                       CRIT_ERR(obj, free_at_crash, "apcupsd needs arguments: <host> <port>");
                                } else {
                                        info.apcupsd.port = htons(port);
                                        strncpy(info.apcupsd.host, host, sizeof(info.apcupsd.host));
                                }
                        } else {
-                               CRIT_ERR("apcupsd needs arguments: <host> <port>");
+                               CRIT_ERR(obj, free_at_crash, "apcupsd needs arguments: <host> <port>");
                        }
                        END OBJ(apcupsd_name, INFO_APCUPSD)
                        END OBJ(apcupsd_model, INFO_APCUPSD)
@@ -3233,7 +3322,7 @@ static char *find_and_replace_templates(const char *inbuf)
                                *(p - 1) = '\0';
                        } else {
                                // we ran into the end of string without finding a closing }, bark
-                               CRIT_ERR("cannot find a closing '}' in template expansion");
+                               CRIT_ERR(NULL, NULL, "cannot find a closing '}' in template expansion");
                        }
                } else {
                        templ = p + 1;
@@ -3316,7 +3405,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;
@@ -3435,8 +3524,7 @@ static int extract_variable_text_internal(struct text_object *retval, const char
                                }
 
                                obj = construct_text_object(buf, arg,
-                                               line, allow_threaded,
-                                               &ifblock_opaque);
+                                               line, &ifblock_opaque, orig_p);
                                if (obj != NULL) {
                                        append_object(retval, obj);
                                }
@@ -3488,12 +3576,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;
 }
@@ -3647,6 +3735,22 @@ static inline double get_barnum(char *buf)
        return barnum;
 }
 
+/* substitutes all occurrences of '\n' with SECRIT_MULTILINE_CHAR, which allows
+ * multiline objects like $exec work with $align[rc] and friends
+ */
+void substitute_newlines(char *p, long l)
+{
+       char *s = p;
+       if (l < 0) return;
+       while (p && *p && p < s + l) {
+               if (*p == '\n') {
+                       /* only substitute if it's not the last newline */
+                       *p = SECRIT_MULTILINE_CHAR;
+               }
+               p++;
+       }
+}
+
 static void generate_text_internal(char *p, int p_max_size,
                struct text_object root, struct information *cur)
 {
@@ -3667,7 +3771,7 @@ static void generate_text_internal(char *p, int p_max_size,
        p[0] = 0;
        obj = root.next;
        while (obj && p_max_size > 0) {
-               needed = 0; // reset for top stuff
+               needed = 0; /* reset for top stuff */
 
 /* IFBLOCK jumping algorithm
  *
@@ -3865,7 +3969,7 @@ static void generate_text_internal(char *p, int p_max_size,
                                if (obj->data.cpu_index > info.cpu_count) {
                                        ERR("obj->data.cpu_index %i info.cpu_count %i",
                                                        obj->data.cpu_index, info.cpu_count);
-                                       CRIT_ERR("attempting to use more CPUs than you have!");
+                                       CRIT_ERR(NULL, NULL, "attempting to use more CPUs than you have!");
                                }
                                percent_print(p, p_max_size,
                                              round_to_int(cur->cpu_usage[obj->data.cpu_index] * 100.0));
@@ -4161,14 +4265,13 @@ static void generate_text_internal(char *p, int p_max_size,
                        }
 #if defined(__linux__)
                        OBJ(addrs) {
-                               if(NULL != obj->data.net->addrs && strlen(obj->data.net->addrs) > 2)
-                               {
+                               if (NULL != obj->data.net->addrs && strlen(obj->data.net->addrs) > 2) {
                                        obj->data.net->addrs[strlen(obj->data.net->addrs) - 2] = 0; /* remove ", " from end of string */
                                        strcpy(p, obj->data.net->addrs);
+                               } else {
+                                       strcpy(p, "0.0.0.0");
                                }
-                               else
-                                        strcpy(p, "0.0.0.0");
-           }
+                       }
 #endif /* __linux__ */
 #if defined(IMLIB2) && defined(X11)
                        OBJ(image) {
@@ -4369,8 +4472,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");
                                        }
@@ -4561,84 +4666,31 @@ 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) {
-                               process_weather_info(p, p_max_size, obj->data.weather.uri, obj->data.weather.data_type, obj->data.weather.interval);
+                               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
 #ifdef HAVE_LUA
@@ -4653,6 +4705,7 @@ static void generate_text_internal(char *p, int p_max_size,
                                char *str = llua_getstring(obj->data.s);
                                if (str) {
                                        evaluate(str, p);
+                                       free(str);
                                }
                        }
                        OBJ(lua_bar) {
@@ -4919,22 +4972,41 @@ static void generate_text_internal(char *p, int p_max_size,
                                }
                        }
 #ifdef X11
+#define NOT_IN_X "Not running in X"
                        OBJ(monitor) {
-                               snprintf(p, p_max_size, "%d", cur->x11.monitor.current);
+                               if(x_initialised != YES) {
+                                       strncpy(p, NOT_IN_X, p_max_size);
+                               }else{
+                                       snprintf(p, p_max_size, "%d", cur->x11.monitor.current);
+                               }
                        }
                        OBJ(monitor_number) {
-                               snprintf(p, p_max_size, "%d", cur->x11.monitor.number);
+                               if(x_initialised != YES) {
+                                       strncpy(p, NOT_IN_X, p_max_size);
+                               }else{
+                                       snprintf(p, p_max_size, "%d", cur->x11.monitor.number);
+                               }
                        }
                        OBJ(desktop) {
-                               snprintf(p, p_max_size, "%d", cur->x11.desktop.current);
+                               if(x_initialised != YES) {
+                                       strncpy(p, NOT_IN_X, p_max_size);
+                               }else{
+                                       snprintf(p, p_max_size, "%d", cur->x11.desktop.current);
+                               }
                        }
                        OBJ(desktop_number) {
-                               snprintf(p, p_max_size, "%d", cur->x11.desktop.number);
+                               if(x_initialised != YES) {
+                                       strncpy(p, NOT_IN_X, p_max_size);
+                               }else{
+                                       snprintf(p, p_max_size, "%d", cur->x11.desktop.number);
+                               }
                        }
                        OBJ(desktop_name) {
-                         if(cur->x11.desktop.name != NULL) {
-                               strncpy(p, cur->x11.desktop.name, p_max_size);
-                         }
+                               if(x_initialised != YES) {
+                                       strncpy(p, NOT_IN_X, p_max_size);
+                               }else if(cur->x11.desktop.name != NULL) {
+                                       strncpy(p, cur->x11.desktop.name, p_max_size);
+                               }
                        }
 #endif /* X11 */
 
@@ -5691,7 +5763,7 @@ static void generate_text_internal(char *p, int p_max_size,
                        OBJ(to_bytes) {
                                char buf[max_user_text];
                                long long bytes;
-                               char unit[16];  //16 because we can also have long names (like mega-bytes)
+                               char unit[16];  // 16 because we can also have long names (like mega-bytes)
 
                                generate_text_internal(buf, max_user_text, *obj->sub, cur);
                                if(sscanf(buf, "%lli%s", &bytes, unit) == 2 && strlen(unit) < 16){
@@ -5704,42 +5776,71 @@ static void generate_text_internal(char *p, int p_max_size,
                                snprintf(p, p_max_size, "%s", buf);
                        }
                        OBJ(scroll) {
-                               unsigned int j;
-                               char *tmp, buf[max_user_text];
+                               unsigned int j, colorchanges = 0, frontcolorchanges = 0, visibcolorchanges = 0, strend;
+                               char *pwithcolors;
+                               char buf[max_user_text];
                                generate_text_internal(buf, max_user_text,
                                                       *obj->sub, cur);
-
-                               if (strlen(buf) <= obj->data.scroll.show) {
-                                       snprintf(p, p_max_size, "%s", buf);
-                                       break;
-                               }
-#define LINESEPARATOR '|'
-                               //place all the lines behind each other with LINESEPARATOR between them
                                for(j = 0; buf[j] != 0; j++) {
-                                       if(buf[j]=='\n') {
+                                       switch(buf[j]) {
+                                       case '\n':      //place all the lines behind each other with LINESEPARATOR between them
+#define LINESEPARATOR '|'
                                                buf[j]=LINESEPARATOR;
+                                               break;
+                                       case SPECIAL_CHAR:
+                                               colorchanges++;
+                                               break;
                                        }
                                }
-                               //scroll the output obj->data.scroll.start places by copying that many chars from
-                               //the front of the string to tmp, scrolling the rest to the front and placing tmp
-                               //at the back of the string
-                               tmp = calloc(obj->data.scroll.start + 1, sizeof(char));
-                               strncpy(tmp, buf, obj->data.scroll.start); tmp[obj->data.scroll.start] = 0;
-                               for(j = obj->data.scroll.start; buf[j] != 0; j++){
-                                       buf[j - obj->data.scroll.start] = buf[j];
-                               }
-                               strcpy(&buf[j - obj->data.scroll.start], tmp);
-                               free(tmp);
-                               //only show the requested number of chars
-                               if(obj->data.scroll.show < j) {
-                                       buf[obj->data.scroll.show] = 0;
-                               }
-                               //next time, scroll a place more or reset scrolling if we are at the end
+                               //no scrolling necessary if the length of the text to scroll is too short
+                               if (strlen(buf) - colorchanges <= obj->data.scroll.show) {
+                                       snprintf(p, p_max_size, "%s", buf);
+                                       break;
+                               }
+                               //make sure a colorchange at the front is not part of the string we are going to show
+                               while(*(buf + obj->data.scroll.start) == SPECIAL_CHAR) {
+                                       obj->data.scroll.start++;
+                               }
+                               //place all chars that should be visible in p, including colorchanges
+                               for(j=0; j < obj->data.scroll.show + visibcolorchanges; j++) {
+                                       p[j] = *(buf + obj->data.scroll.start + j);
+                                       if(p[j] == SPECIAL_CHAR) {
+                                               visibcolorchanges++;
+                                       }
+                                       //if there is still room fill it with spaces
+                                       if( ! p[j]) break;
+                               }
+                               for(; j < obj->data.scroll.show + visibcolorchanges; j++) {
+                                       p[j] = ' ';
+                               }
+                               p[j] = 0;
+                               //count colorchanges in front of the visible part and place that many colorchanges in front of the visible part
+                               for(j = 0; j < obj->data.scroll.start; j++) {
+                                       if(buf[j] == SPECIAL_CHAR) frontcolorchanges++;
+                               }
+                               pwithcolors=malloc(strlen(p) + 1 + colorchanges - visibcolorchanges);
+                               for(j = 0; j < frontcolorchanges; j++) {
+                                       pwithcolors[j] = SPECIAL_CHAR;
+                               }
+                               pwithcolors[j] = 0;
+                               strcat(pwithcolors,p);
+                               strend = strlen(pwithcolors);
+                               //and place the colorchanges not in front or in the visible part behind the visible part
+                               for(j = 0; j < colorchanges - frontcolorchanges - visibcolorchanges; j++) {
+                                       pwithcolors[strend + j] = SPECIAL_CHAR;
+                               }
+                               pwithcolors[strend + j] = 0;
+                               strcpy(p, pwithcolors);
+                               free(pwithcolors);
+                               //scroll
                                obj->data.scroll.start += obj->data.scroll.step;
-                               if(obj->data.scroll.start >= j){
+                               if(buf[obj->data.scroll.start] == 0){
                                         obj->data.scroll.start = 0;
                                }
-                               snprintf(p, p_max_size, "%s", buf);
+#ifdef X11
+                               //reset color when scroll is finished
+                               new_fg(p + strlen(p), obj->data.scroll.resetcolor);
+#endif
                        }
                        OBJ(combine) {
                                char buf[2][max_user_text];
@@ -5794,12 +5895,12 @@ static void generate_text_internal(char *p, int p_max_size,
                                        }
                                        strcat(p, "\n");
                                        #ifdef HAVE_OPENMP
-                                       #pragma omp parallel for
+                                       #pragma omp parallel for schedule(dynamic,10)
                                        #endif /* HAVE_OPENMP */
                                        for(i=0; i<2; i++) if(current[i]) current[i]=current[i]->next;
                                }
                                #ifdef HAVE_OPENMP
-                               #pragma omp parallel for
+                               #pragma omp parallel for schedule(dynamic,10)
                                #endif /* HAVE_OPENMP */
                                for(i=0; i<2; i++) {
                                        while(ll_rows[i] != NULL) {
@@ -5941,6 +6042,9 @@ static void generate_text_internal(char *p, int p_max_size,
                                a = outptr - p;
                        }
 #endif /* HAVE_ICONV */
+                       if (obj->type != OBJ_text) {
+                               substitute_newlines(p, a - 2);
+                       }
                        p += a;
                        p_max_size -= a;
                }
@@ -5991,7 +6095,7 @@ static void generate_text(void)
 
        generate_text_internal(p, max_user_text, global_root_object, cur);
 
-       if (stuff_in_upper_case) {
+       if (stuff_in_uppercase) {
                char *tmp_p;
 
                tmp_p = text_buffer;
@@ -6009,7 +6113,6 @@ static void generate_text(void)
        }
        last_update_time = current_update_time;
        total_updates++;
-       // free(p);
 }
 
 static inline int get_string_width(const char *s)
@@ -6022,18 +6125,16 @@ static inline int get_string_width(const char *s)
        return strlen(s);
 }
 
-static inline int get_string_width_special(char *s)
-{
 #ifdef X11
+static int get_string_width_special(char *s, int special_index)
+{
        char *p, *final;
        int idx = 1;
        int width = 0;
        long i;
 
        if ((output_methods & TO_X) == 0) {
-#endif
                return (s) ? strlen(s) : 0;
-#ifdef X11
        }
 
        if (!s) {
@@ -6056,6 +6157,9 @@ static inline int get_string_width_special(char *s)
                                width += specials[special_index + idx].width;
                        }
                        idx++;
+               } else if (*p == SECRIT_MULTILINE_CHAR) {
+                       *p = 0;
+                       break;
                } else {
                        p++;
                }
@@ -6065,11 +6169,9 @@ static inline int get_string_width_special(char *s)
        }
        free(final);
        return width;
-#endif /* X11 */
 }
 
-#ifdef X11
-static void text_size_updater(char *s);
+static int text_size_updater(char *s, int special_index);
 
 int last_font_height;
 static void update_text_area(void)
@@ -6085,7 +6187,6 @@ static void update_text_area(void)
        {
                text_width = minimum_width;
                text_height = 0;
-               special_index = 0;
                last_font_height = font_height();
                for_each_line(text_buffer, text_size_updater);
                text_width += 1;
@@ -6188,13 +6289,13 @@ static int draw_mode;           /* FG, BG or OUTLINE */
 #ifdef X11
 static long current_color;
 
-static void text_size_updater(char *s)
+static int text_size_updater(char *s, int special_index)
 {
        int w = 0;
        char *p;
 
        if ((output_methods & TO_X) == 0)
-               return;
+               return 0;
        /* get string widths and skip specials */
        p = s;
        while (*p) {
@@ -6238,6 +6339,14 @@ static void text_size_updater(char *s)
 
                        special_index++;
                        s = p + 1;
+               } else if (*p == SECRIT_MULTILINE_CHAR) {
+                       int lw;
+                       *p = '\0';
+                       lw = get_string_width(s);
+                       *p = SECRIT_MULTILINE_CHAR;
+                       s = p + 1;
+                       w = lw > w ? lw : w;
+                       text_height += last_font_height;
                }
                p++;
        }
@@ -6251,6 +6360,7 @@ static void text_size_updater(char *s)
 
        text_height += last_font_height;
        last_font_height = font_height();
+       return special_index;
 }
 
 static inline void set_foreground_color(long c)
@@ -6363,36 +6473,39 @@ static void draw_string(const char *s)
        memcpy(tmpstring1, s, text_buffer_size);
 }
 
-static void draw_line(char *s)
-{
 #ifdef X11
-       char *p;
+int draw_each_line_inner(char *s, int special_index, int last_special_applied)
+{
+       int font_h = font_height();
        int cur_y_add = 0;
-       int font_h;
-       char *tmp_str;
+       char *recurse = 0;
+       char *p = s;
+       int last_special_needed = -1;
+       int orig_special_index = special_index;
 
-       if ((output_methods & TO_X) == 0) {
-#endif /* X11 */
-               draw_string(s);
-               return;
-#ifdef X11
-       }
        cur_x = text_start_x;
        cur_y += font_ascent();
-       font_h = font_height();
 
-       /* find specials and draw stuff */
-       p = s;
        while (*p) {
-               if (*p == SPECIAL_CHAR) {
-                       int w = 0;
-
-                       /* draw string before special */
+               if (*p == SECRIT_MULTILINE_CHAR) {
+                       /* special newline marker for multiline objects */
+                       recurse = p + 1;
                        *p = '\0';
-                       draw_string(s);
-                       *p = SPECIAL_CHAR;
-                       s = p + 1;
+                       break;
+               }
+               if (*p == SPECIAL_CHAR || last_special_applied > -1) {
+                       int w = 0;
 
+                       /* draw string before special, unless we're dealing multiline
+                        * specials */
+                       if (last_special_applied > -1) {
+                               special_index = last_special_applied;
+                       } else {
+                               *p = '\0';
+                               draw_string(s);
+                               *p = SPECIAL_CHAR;
+                               s = p + 1;
+                       }
                        /* draw special */
                        switch (specials[special_index].type) {
                                case HORIZONTAL_LINE:
@@ -6615,6 +6728,7 @@ static void draw_line(char *s)
                                                char *tmp_hour_str;
                                                char *tmp_min_str;
                                                char *tmp_sec_str;
+                                               char *tmp_str;
                                                unsigned short int timeunits;
                                                if (seconds != 0) {
                                                        timeunits = seconds / 86400; seconds %= 86400;
@@ -6656,6 +6770,7 @@ static void draw_line(char *s)
                                        if (show_graph_scale && (specials[special_index].show_scale == 1)) {
                                                int tmp_x = cur_x;
                                                int tmp_y = cur_y;
+                                               char *tmp_str;
                                                cur_x += font_ascent() / 2;
                                                cur_y += font_h / 2;
                                                tmp_str = (char *)
@@ -6707,6 +6822,7 @@ static void draw_line(char *s)
 
                                case OFFSET:
                                        w += specials[special_index].arg;
+                                       last_special_needed = special_index;
                                        break;
 
                                case VOFFSET:
@@ -6717,6 +6833,7 @@ static void draw_line(char *s)
                                        if (specials[special_index].arg >= 0) {
                                                cur_x = (int) specials[special_index].arg;
                                        }
+                                       last_special_needed = special_index;
                                        break;
 
                                case TAB:
@@ -6728,6 +6845,7 @@ static void draw_line(char *s)
                                                step = 10;
                                        }
                                        w = step - (cur_x - text_start_x - start) % step;
+                                       last_special_needed = special_index;
                                        break;
                                }
 
@@ -6736,7 +6854,7 @@ static void draw_line(char *s)
                                        /* TODO: add back in "+ window.border_inner_margin" to the end of
                                         * this line? */
                                        int pos_x = text_start_x + text_width -
-                                               get_string_width_special(s);
+                                               get_string_width_special(s, special_index);
 
                                        /* printf("pos_x %i text_start_x %i text_width %i cur_x %i "
                                                "get_string_width(p) %i gap_x %i "
@@ -6748,13 +6866,15 @@ static void draw_line(char *s)
                                        if (pos_x > specials[special_index].arg && pos_x > cur_x) {
                                                cur_x = pos_x - specials[special_index].arg;
                                        }
+                                       last_special_needed = special_index;
                                        break;
                                }
 
                                case ALIGNC:
                                {
-                                       int pos_x = (text_width) / 2 - get_string_width_special(s) /
-                                               2 - (cur_x - text_start_x);
+                                       int pos_x = (text_width) / 2 - get_string_width_special(s,
+                                                       special_index) / 2 - (cur_x -
+                                                               text_start_x);
                                        /* int pos_x = text_start_x + text_width / 2 -
                                                get_string_width_special(s) / 2; */
 
@@ -6766,24 +6886,47 @@ static void draw_line(char *s)
                                        if (pos_x > specials[special_index].arg) {
                                                w = pos_x - specials[special_index].arg;
                                        }
+                                       last_special_needed = special_index;
                                        break;
                                }
                        }
 
                        cur_x += w;
 
-                       special_index++;
+                       if (special_index != last_special_applied) {
+                               special_index++;
+                       } else {
+                               special_index = orig_special_index;
+                               last_special_applied = -1;
+                       }
                }
-
                p++;
        }
 
-       if (cur_y_add > 0) {
-               cur_y += cur_y_add;
-       }
+       cur_y += cur_y_add;
        draw_string(s);
        cur_y += font_descent();
+       if (recurse && *recurse) {
+               special_index = draw_each_line_inner(recurse, special_index, last_special_needed);
+               *(recurse - 1) = SECRIT_MULTILINE_CHAR;
+       }
+       return special_index;
+}
+#endif /* X11 */
+
+static int draw_line(char *s, int special_index)
+{
+#ifdef X11
+       if ((output_methods & TO_X) == 0) {
+#endif /* X11 */
+               draw_string(s);
+               //'special_index - special_index' instead of 0 otherwise gcc complains about not using special_index when build without X11
+               return special_index - special_index;
+#ifdef X11
+       }
 
+       /* find specials and draw stuff */
+       return draw_each_line_inner(s, special_index, -1);
 #endif /* X11 */
 }
 
@@ -6816,7 +6959,6 @@ static void draw_text(void)
                }
 
                /* draw text */
-               special_index = 0;
        }
        setup_fonts();
 #endif /* X11 */
@@ -6969,7 +7111,7 @@ static void main_loop(void)
 #ifdef SIGNAL_BLOCKING
                /* block signals.  we will inspect for pending signals later */
                if (sigprocmask(SIG_BLOCK, &newmask, &oldmask) < 0) {
-                       CRIT_ERR("unable to sigprocmask()");
+                       CRIT_ERR(NULL, NULL, "unable to sigprocmask()");
                }
 #endif
 
@@ -7111,6 +7253,14 @@ static void main_loop(void)
                                                break;
                                        }
 
+                                       case PropertyNotify:
+                                       {
+                                               if ( ev.xproperty.state == PropertyNewValue ) {
+                                                       get_x11_desktop_info( ev.xproperty.display, ev.xproperty.atom );
+                                               }
+                                               break;
+                                       }
+
 #ifdef OWN_WINDOW
                                        case ReparentNotify:
                                                /* set background to ParentRelative for all parents */
@@ -7269,7 +7419,7 @@ static void main_loop(void)
 #ifdef SIGNAL_BLOCKING
                /* unblock signals of interest and let handler fly */
                if (sigprocmask(SIG_SETMASK, &oldmask, NULL) < 0) {
-                       CRIT_ERR("unable to sigprocmask()");
+                       CRIT_ERR(NULL, NULL, "unable to sigprocmask()");
                }
 #endif
 
@@ -7364,7 +7514,7 @@ static void main_loop(void)
 
                g_signal_pending = 0;
        }
-       clean_up();
+       clean_up(NULL, NULL);
 
 #ifdef HAVE_SYS_INOTIFY_H
        if (inotify_fd != -1) {
@@ -7373,95 +7523,32 @@ static void main_loop(void)
                inotify_fd = inotify_config_wd = 0;
        }
 #endif /* HAVE_SYS_INOTIFY_H */
-
-#ifdef X11
-       X11_destroy_window();
-#endif /* X11 */
 }
 
 static void load_config_file(const char *);
+#ifdef X11
 static void load_config_file_x11(const char *);
+#endif /* X11 */
+void initialisation(int argc, char** argv);
 
        /* reload the config file */
 static void reload_config(void)
 {
-       timed_thread_destroy_registered_threads();
-
-       if (info.cpu_usage) {
-               free(info.cpu_usage);
-               info.cpu_usage = NULL;
-       }
-
-       if (info.mail) {
-               free(info.mail);
-       }
-
-#ifdef X11
-       free_fonts();
-#endif /* X11 */
-
-#ifdef TCP_PORT_MONITOR
-       tcp_portmon_clear();
-#endif
-
-#ifdef RSS
-       free_rss_info();
-#endif
-#ifdef WEATHER
-       free_weather_info();
-#endif
-#ifdef HAVE_LUA
-       llua_close();
-#endif /* HAVE_LUA */
-
-#ifdef X11
-       X11_destroy_window();
-#endif /* X11 */
-
-       if (current_config) {
-               clear_fs_stats();
-               load_config_file(current_config);
-               load_config_file_x11(current_config);
-
-               /* re-init specials array */
-               if ((specials = realloc((void *) specials,
-                               sizeof(struct special_t) * max_specials)) == 0) {
-                       ERR("failed to realloc specials array");
-               }
-
-#ifdef X11
-               if (output_methods & TO_X) {
-                       X11_initialisation();
-               }
-#endif /* X11 */
-               extract_variable_text(global_text);
-               free(global_text);
-               global_text = NULL;
-               if (tmpstring1) {
-                       free(tmpstring1);
-               }
-               tmpstring1 = malloc(text_buffer_size);
-               memset(tmpstring1, 0, text_buffer_size);
-               if (tmpstring2) {
-                       free(tmpstring2);
-               }
-               tmpstring2 = malloc(text_buffer_size);
-               memset(tmpstring2, 0, text_buffer_size);
-               if (text_buffer) {
-                       free(text_buffer);
-               }
-               text_buffer = malloc(max_user_text);
-               memset(text_buffer, 0, max_user_text);
-#ifdef X11
-               X11_create_window();
-#endif /* X11 */
-               update_text();
-       }
+       char *current_config_copy = strdup(current_config);
+       clean_up(NULL, NULL);
+       current_config = current_config_copy;
+       initialisation(argc_copy, argv_copy);
 }
 
-void clean_up(void)
+void clean_up(void *memtofree1, void* memtofree2)
 {
        int i;
+       if(memtofree1) {
+               free(memtofree1);
+       }
+       if(memtofree2) {
+               free(memtofree2);
+       }
        timed_thread_destroy_registered_threads();
 
        if (info.cpu_usage) {
@@ -7470,27 +7557,27 @@ void clean_up(void)
        }
 #ifdef X11
        if (x_initialised == YES) {
-#ifdef HAVE_XDBE
-               if (use_xdbe) {
-                       XdbeDeallocateBackBufferName(display, window.back_buffer);
+               destroy_window();
+               free_fonts();
+               if(x11_stuff.region) {
+                       XDestroyRegion(x11_stuff.region);
+                       x11_stuff.region = NULL;
                }
-#endif
-#ifdef OWN_WINDOW
-               if (own_window) {
-                       XDestroyWindow(display, window.window);
-                       XClearWindow(display, RootWindow(display, screen));
-                       XFlush(display);
-               } else
-#endif
-               {
-                       XClearWindow(display, RootWindow(display, screen));
-                       clear_text(1);
-                       XFlush(display);
+               XClearWindow(display, RootWindow(display, screen));
+               XCloseDisplay(display);
+               display = NULL;
+               if(info.x11.desktop.all_names) {
+                       free(info.x11.desktop.all_names);
+                       info.x11.desktop.all_names = NULL;
                }
-
-               free_fonts();
+               if (info.x11.desktop.name) {
+                       free(info.x11.desktop.name);
+                       info.x11.desktop.name = NULL;
+               }
+               x_initialised = NO;
        }else{
                free(fonts);    //in set_default_configurations a font is set but not loaded
+               font_count = -1;
        }
 
 #endif /* X11 */
@@ -7527,11 +7614,14 @@ void clean_up(void)
 #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();
@@ -7549,7 +7639,10 @@ void clean_up(void)
 
        clear_net_stats();
        clear_diskio_stats();
-       if(global_cpu != NULL) free(global_cpu);
+       if(global_cpu != NULL) {
+               free(global_cpu);
+               global_cpu = NULL;
+       }
 }
 
 static int string_to_bool(const char *s)
@@ -7625,6 +7718,7 @@ static void set_default_configurations_for_x(void)
        color7 = default_fg_color;
        color8 = default_fg_color;
        color9 = default_fg_color;
+       current_text_color = default_fg_color;
 }
 #endif /* X11 */
 
@@ -7728,6 +7822,8 @@ static void set_default_configurations(void)
        info.x11.monitor.current = 0;
        info.x11.desktop.current = 1; 
        info.x11.desktop.number = 1;
+       info.x11.desktop.nitems = 0;
+       info.x11.desktop.all_names = NULL; 
        info.x11.desktop.name = NULL; 
 #endif /* X11 */
 
@@ -7750,7 +7846,7 @@ static void set_default_configurations(void)
        no_buffers = 1;
        update_interval = 3.0;
        info.music_player_interval = 1.0;
-       stuff_in_upper_case = 0;
+       stuff_in_uppercase = 0;
        info.users.number = 1;
 
 #ifdef TCP_PORT_MONITOR
@@ -7827,24 +7923,6 @@ static void X11_initialisation(void)
 #endif /* DEBUG */
 }
 
-static void X11_destroy_window(void)
-{
-       /* this function only exists for the sake of consistency */
-       if (output_methods & TO_X) {
-#ifdef HAVE_XDAMAGE
-               XDamageDestroy(display, x11_stuff.damage);
-               XFixesDestroyRegion(display, x11_stuff.region2);
-               XFixesDestroyRegion(display, x11_stuff.part);
-               if (x11_stuff.region) {
-                       XDestroyRegion(x11_stuff.region);
-               }
-               x11_stuff.region = NULL;
-#endif /* HAVE_XDAMAGE */
-               destroy_window();
-       }
-       x_initialised = NO;
-}
-
 static char **xargv = 0;
 static int xargc = 0;
 
@@ -7993,13 +8071,12 @@ static void load_config_file(const char *f)
                CONF2("out_to_x") {
                        /* don't listen if X is already initialised or
                         * if we already know we don't want it */
-                       if(x_initialised == NO) {
+                       if(x_initialised != YES) {
                                if (string_to_bool(value)) {
                                        output_methods &= TO_X;
                                } else {
                                        output_methods &= ~TO_X;
                                        x_initialised = NEVER;
-                                       free(fonts);    //in set_default_configurations a font is set but not loaded
                                }
                        }
                }
@@ -8541,7 +8618,7 @@ static void load_config_file(const char *f)
                        }
                }
                CONF("uppercase") {
-                       stuff_in_upper_case = string_to_bool(value);
+                       stuff_in_uppercase = string_to_bool(value);
                }
                CONF("max_specials") {
                        if (value) {
@@ -8617,7 +8694,7 @@ static void load_config_file(const char *f)
                        }
                        fclose(fp);
                        if (strlen(global_text) < 1) {
-                               CRIT_ERR("no text supplied in configuration; exiting");
+                               CRIT_ERR(NULL, NULL, "no text supplied in configuration; exiting");
                        }
                        global_text_lines = line + 1;
                        return;
@@ -8737,10 +8814,11 @@ static void load_config_file(const char *f)
                info.music_player_interval = update_interval;
        }
        if (!global_text) { // didn't supply any text
-               CRIT_ERR("missing text block in configuration; exiting");
+               CRIT_ERR(NULL, NULL, "missing text block in configuration; exiting");
        }
 }
 
+#ifdef X11
 static void load_config_file_x11(const char *f)
 {
        int line = 0;
@@ -8761,7 +8839,6 @@ static void load_config_file_x11(const char *f)
                        continue;
                }
 
-#ifdef X11
                CONF2("color0") {
                        X11_initialisation();
                        if (x_initialised == YES) {
@@ -8906,12 +8983,11 @@ static void load_config_file_x11(const char *f)
                }
 #endif
                CONF("text") {
-                       //initialize X11 if nothing X11-related is mentioned before TEXT (and if X11 is the default outputmethod)
+                       /* initialize X11 if nothing X11-related is mentioned before TEXT (and if X11 is the default outputmethod) */
                        if(output_methods & TO_X) {
                                X11_initialisation();
                        }
                }
-#endif /* X11 */
 #undef CONF
 #undef CONF2
 #undef CONF3
@@ -8925,6 +9001,43 @@ static void load_config_file_x11(const char *f)
        fclose(fp);
 
 }
+#endif /* X11 */
+
+#if defined(WEATHER) && defined(XOAP)
+/*
+ * TODO: make the xoap keys file readable from the config file
+ *       make the keys directly readable from the config file
+ *       make the xoap keys file giveable as a command line option
+ */
+static void load_xoap_keys(void)
+{
+  FILE *fp;
+  char *par = (char *) malloc(11 * sizeof(char));
+  char *key = (char *) malloc(17 * sizeof(char));
+
+  xoap = (char *) malloc(64 * sizeof(char));
+  to_real_path(xoap, XOAP_FILE);
+  fp = fopen(xoap, "r");
+  if (fp != NULL) {
+    if( fscanf(fp, "%10s %16s", par, key) == 2 ) {
+      strcpy(xoap, "?cc=*&link=xoap&prod=xoap&par=");
+      strcat(xoap, par);
+      strcat(xoap, "&key=");
+      strcat(xoap, key);
+      strcat(xoap, "&unit=m");
+    } else {
+      free(xoap);
+      xoap = NULL;
+    }
+    fclose(fp);
+  } else {
+    free(xoap);
+    xoap = NULL;
+  }
+  free(par);
+  free(key);
+}
+#endif /* WEATHER && XOAP */
 
 static void print_help(const char *prog_name) {
        printf("Usage: %s [OPTION]...\n"
@@ -9004,133 +9117,9 @@ static const struct option longopts[] = {
        { 0, 0, 0, 0 }
 };
 
-int main(int argc, char **argv)
-{
-#ifdef X11
-       char *s, *temp;
-       unsigned int x;
-#endif
+void initialisation(int argc, char **argv) {
        struct sigaction act, oact;
 
-       g_signal_pending = 0;
-       max_user_text = MAX_USER_TEXT_DEFAULT;
-       current_config = 0;
-       memset(&info, 0, sizeof(info));
-       memset(template, 0, sizeof(template));
-       clear_net_stats();
-
-#ifdef TCP_PORT_MONITOR
-       /* set default connection limit */
-       tcp_portmon_set_max_connections(0);
-#endif
-
-       /* handle command line parameters that don't change configs */
-#ifdef X11
-       if (((s = getenv("LC_ALL")) && *s) || ((s = getenv("LC_CTYPE")) && *s)
-                       || ((s = getenv("LANG")) && *s)) {
-               temp = (char *) malloc((strlen(s) + 1) * sizeof(char));
-               if (temp == NULL) {
-                       ERR("malloc failed");
-               }
-               for (x = 0; x < strlen(s); x++) {
-                       temp[x] = tolower(s[x]);
-               }
-               temp[x] = 0;
-               if (strstr(temp, "utf-8") || strstr(temp, "utf8")) {
-                       utf8_mode = 1;
-               }
-
-               free(temp);
-       }
-       if (!setlocale(LC_CTYPE, "")) {
-               ERR("Can't set the specified locale!\nCheck LANG, LC_CTYPE, LC_ALL.");
-       }
-#endif /* X11 */
-       while (1) {
-               int c = getopt_long(argc, argv, getopt_string, longopts, NULL);
-
-               if (c == -1) {
-                       break;
-               }
-
-               switch (c) {
-                       case 'v':
-                       case 'V':
-                               print_version();
-                       case 'c':
-                               if (current_config) {
-                                       free(current_config);
-                               }
-                               current_config = strndup(optarg, max_user_text);
-                               break;
-                       case 'q':
-                               freopen("/dev/null", "w", stderr);
-                               break;
-                       case 'h':
-                               print_help(argv[0]);
-                               return 0;
-#ifdef CONFIG_OUTPUT
-                       case 'C':
-                               print_defconfig();
-                               return 0;
-#endif
-#ifdef X11
-                       case 'w':
-                               window.window = strtol(optarg, 0, 0);
-                               break;
-#endif /* X11 */
-
-                       case '?':
-                               exit(EXIT_FAILURE);
-               }
-       }
-
-       /* check if specified config file is valid */
-       if (current_config) {
-               struct stat sb;
-               if (stat(current_config, &sb) ||
-                               (!S_ISREG(sb.st_mode) && !S_ISLNK(sb.st_mode))) {
-                       ERR("invalid configuration file '%s'\n", current_config);
-                       free(current_config);
-                       current_config = 0;
-               }
-       }
-
-       /* load current_config, CONFIG_FILE or SYSTEM_CONFIG_FILE */
-
-       if (!current_config) {
-               /* load default config file */
-               char buf[DEFAULT_TEXT_BUFFER_SIZE];
-               FILE *fp;
-
-               /* Try to use personal config file first */
-               to_real_path(buf, CONFIG_FILE);
-               if (buf[0] && (fp = fopen(buf, "r"))) {
-                       current_config = strndup(buf, max_user_text);
-                       fclose(fp);
-               }
-
-               /* Try to use system config file if personal config not readable */
-               if (!current_config && (fp = fopen(SYSTEM_CONFIG_FILE, "r"))) {
-                       current_config = strndup(SYSTEM_CONFIG_FILE, max_user_text);
-                       fclose(fp);
-               }
-
-               /* No readable config found */
-               if (!current_config) {
-#ifdef CONFIG_OUTPUT
-                       current_config = strdup("==builtin==");
-                       ERR("no readable personal or system-wide config file found,"
-                                       " using builtin default");
-#else
-                       CRIT_ERR("no readable personal or system-wide config file found");
-#endif /* ! CONF_OUTPUT */
-               }
-       }
-#ifdef HAVE_SYS_INOTIFY_H
-       inotify_fd = inotify_init();
-#endif /* HAVE_SYS_INOTIFY_H */
-
        load_config_file(current_config);
 
        /* init specials array */
@@ -9162,7 +9151,7 @@ int main(int argc, char **argv)
 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
        if ((kd = kvm_open("/dev/null", "/dev/null", "/dev/null", O_RDONLY,
                        "kvm_open")) == NULL) {
-               CRIT_ERR("cannot read kvm");
+               CRIT_ERR(NULL, NULL, "cannot read kvm");
        }
 #endif
 
@@ -9275,7 +9264,7 @@ int main(int argc, char **argv)
                                fprintf(stderr, PACKAGE_NAME": forked to background, pid is %d\n",
                                        pid);
                                fflush(stderr);
-                               return 0;
+                               exit(EXIT_SUCCESS);
                }
        }
 
@@ -9307,6 +9296,144 @@ int main(int argc, char **argv)
                ERR("error setting signal handler: %s", strerror(errno));
        }
 
+}
+
+int main(int argc, char **argv)
+{
+#ifdef X11
+       char *s, *temp;
+       unsigned int x;
+#endif
+
+       argc_copy = argc;
+       argv_copy = argv;
+       g_signal_pending = 0;
+       max_user_text = MAX_USER_TEXT_DEFAULT;
+       current_config = 0;
+       memset(&info, 0, sizeof(info));
+       memset(template, 0, sizeof(template));
+       clear_net_stats();
+
+#ifdef TCP_PORT_MONITOR
+       /* set default connection limit */
+       tcp_portmon_set_max_connections(0);
+#endif
+
+       /* handle command line parameters that don't change configs */
+#ifdef X11
+       if (((s = getenv("LC_ALL")) && *s) || ((s = getenv("LC_CTYPE")) && *s)
+                       || ((s = getenv("LANG")) && *s)) {
+               temp = (char *) malloc((strlen(s) + 1) * sizeof(char));
+               if (temp == NULL) {
+                       ERR("malloc failed");
+               }
+               for (x = 0; x < strlen(s); x++) {
+                       temp[x] = tolower(s[x]);
+               }
+               temp[x] = 0;
+               if (strstr(temp, "utf-8") || strstr(temp, "utf8")) {
+                       utf8_mode = 1;
+               }
+
+               free(temp);
+       }
+       if (!setlocale(LC_CTYPE, "")) {
+               ERR("Can't set the specified locale!\nCheck LANG, LC_CTYPE, LC_ALL.");
+       }
+#endif /* X11 */
+       while (1) {
+               int c = getopt_long(argc, argv, getopt_string, longopts, NULL);
+
+               if (c == -1) {
+                       break;
+               }
+
+               switch (c) {
+                       case 'v':
+                       case 'V':
+                               print_version();
+                       case 'c':
+                               if (current_config) {
+                                       free(current_config);
+                               }
+                               current_config = strndup(optarg, max_user_text);
+                               break;
+                       case 'q':
+                               freopen("/dev/null", "w", stderr);
+                               break;
+                       case 'h':
+                               print_help(argv[0]);
+                               return 0;
+#ifdef CONFIG_OUTPUT
+                       case 'C':
+                               print_defconfig();
+                               return 0;
+#endif
+#ifdef X11
+                       case 'w':
+                               window.window = strtol(optarg, 0, 0);
+                               break;
+#endif /* X11 */
+
+                       case '?':
+                               exit(EXIT_FAILURE);
+               }
+       }
+
+       /* check if specified config file is valid */
+       if (current_config) {
+               struct stat sb;
+               if (stat(current_config, &sb) ||
+                               (!S_ISREG(sb.st_mode) && !S_ISLNK(sb.st_mode))) {
+                       ERR("invalid configuration file '%s'\n", current_config);
+                       free(current_config);
+                       current_config = 0;
+               }
+       }
+
+       /* load current_config, CONFIG_FILE or SYSTEM_CONFIG_FILE */
+
+       if (!current_config) {
+               /* load default config file */
+               char buf[DEFAULT_TEXT_BUFFER_SIZE];
+               FILE *fp;
+
+               /* Try to use personal config file first */
+               to_real_path(buf, CONFIG_FILE);
+               if (buf[0] && (fp = fopen(buf, "r"))) {
+                       current_config = strndup(buf, max_user_text);
+                       fclose(fp);
+               }
+
+               /* Try to use system config file if personal config not readable */
+               if (!current_config && (fp = fopen(SYSTEM_CONFIG_FILE, "r"))) {
+                       current_config = strndup(SYSTEM_CONFIG_FILE, max_user_text);
+                       fclose(fp);
+               }
+
+               /* No readable config found */
+               if (!current_config) {
+#ifdef CONFIG_OUTPUT
+                       current_config = strdup("==builtin==");
+                       ERR("no readable personal or system-wide config file found,"
+                                       " using builtin default");
+#else
+                       CRIT_ERR(NULL, NULL, "no readable personal or system-wide config file found");
+#endif /* ! CONF_OUTPUT */
+               }
+       }
+
+#if defined(WEATHER) && defined(XOAP)
+       /* Load xoap keys, if existing */
+       load_xoap_keys();
+#endif /* WEATHER && XOAP */
+
+#ifdef HAVE_SYS_INOTIFY_H
+       inotify_fd = inotify_init();
+#endif /* HAVE_SYS_INOTIFY_H */
+
+       initialisation(argc, argv);
+
        main_loop();
 
 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
@@ -9323,3 +9450,4 @@ static void signal_handler(int sig)
         * and do any signal processing there, NOT here. */
        g_signal_pending = sig;
 }
+