the big relocation patch
[monky] / src / conky.c
index 5ceac4a..8edbc24 100644 (file)
 /* #define SIGNAL_BLOCKING */
 #undef SIGNAL_BLOCKING
 
-static void print_version()
+static void print_version(void)
 {
        printf("Conky %s compiled %s for %s\n", VERSION, BUILD_DATE, BUILD_ARCH);
 
        printf("\nCompiled in features:\n\n"
-                  "system config file: %s\n\n"
+                  "System config file: %s\n\n"
 #ifdef X11
                   " X11:\n"
 # ifdef HAVE_XDAMAGE
@@ -117,13 +117,18 @@ static void print_version()
 #endif /* RSS */
 #ifdef HAVE_IWLIB
                   "  * wireless\n"
-#endif
-                  "", SYSTEM_CONFIG_FILE
+#endif /* HAVE_IWLIB */
+#ifdef SMAPI
+       "  * smapi\n"
+#endif /* SMAPI */
+       "", SYSTEM_CONFIG_FILE
        );
 
        exit(0);
 }
 
+static const char *suffixes[] = { "B", "kiB", "MiB", "GiB", "TiB", "PiB", "" };
+
 #ifdef X11
 
 /* text size */
@@ -135,15 +140,19 @@ static int text_width, text_height;
 enum alignment {
        TOP_LEFT = 1,
        TOP_RIGHT,
+       TOP_MIDDLE,
        BOTTOM_LEFT,
        BOTTOM_RIGHT,
+       BOTTOM_MIDDLE,
+       MIDDLE_LEFT,
+       MIDDLE_RIGHT,
        NONE
 };
 
 /* for fonts */
 struct font_list {
 
-       char name[TEXT_BUFFER_SIZE];
+       char name[DEFAULT_TEXT_BUFFER_SIZE];
        int num;
        XFontStruct *font;
 
@@ -157,8 +166,6 @@ static int selected_font = 0;
 static int font_count = -1;
 struct font_list *fonts = NULL;
 
-static char *suffixes[] = { "B", "kiB", "MiB", "GiB", "TiB", "PiB", "" };
-
 #ifdef XFT
 
 #define font_height() (use_xft ? (fonts[selected_font].xftfont->ascent + \
@@ -181,7 +188,7 @@ static char *suffixes[] = { "B", "kiB", "MiB", "GiB", "TiB", "PiB", "" };
 
 #define MAX_FONTS 64 // hmm, no particular reason, just makes sense.
 
-static void set_font();
+static void set_font(void);
 
 int addfont(const char *data_in)
 {
@@ -197,14 +204,16 @@ int addfont(const char *data_in)
                                == NULL) {
                        CRIT_ERR("malloc");
                }
+               memset(fonts, 0, sizeof(struct font_list));
        }
        fonts = realloc(fonts, (sizeof(struct font_list) * (font_count + 1)));
+       memset(&fonts[font_count], 0, sizeof(struct font_list));
        if (fonts == NULL) {
                CRIT_ERR("realloc in addfont");
        }
        // must account for null terminator
-       if (strlen(data_in) < TEXT_BUFFER_SIZE) {
-               strncpy(fonts[font_count].name, data_in, TEXT_BUFFER_SIZE);
+       if (strlen(data_in) < DEFAULT_TEXT_BUFFER_SIZE) {
+               strncpy(fonts[font_count].name, data_in, DEFAULT_TEXT_BUFFER_SIZE);
 #ifdef XFT
                fonts[font_count].font_alpha = 0xffff;
 #endif
@@ -221,17 +230,18 @@ void set_first_font(const char *data_in)
                                == NULL) {
                        CRIT_ERR("malloc");
                }
+               memset(fonts, 0, sizeof(struct font_list));
                font_count++;
        }
        if (strlen(data_in) > 1) {
-               strncpy(fonts[0].name, data_in, TEXT_BUFFER_SIZE - 1);
+               strncpy(fonts[0].name, data_in, DEFAULT_TEXT_BUFFER_SIZE - 1);
 #ifdef XFT
                fonts[0].font_alpha = 0xffff;
 #endif
        }
 }
 
-void free_fonts()
+void free_fonts(void)
 {
        int i;
 
@@ -239,10 +249,12 @@ void free_fonts()
 #ifdef XFT
                if (use_xft) {
                        XftFontClose(display, fonts[i].xftfont);
+                       fonts[i].xftfont = 0;
                } else
 #endif
                {
                        XFreeFont(display, fonts[i].font);
+                       fonts[i].font = 0;
                }
        }
        free(fonts);
@@ -251,19 +263,22 @@ void free_fonts()
        selected_font = 0;
 }
 
-static void load_fonts()
+static void load_fonts(void)
 {
        int i;
 
        for (i = 0; i <= font_count; i++) {
 #ifdef XFT
                /* load Xft font */
-               if (use_xft) {
+               if (use_xft && fonts[i].xftfont) {
+                       continue;
+               } else if (use_xft) {
                        /* if (fonts[i].xftfont != NULL && selected_font == 0) {
                                XftFontClose(display, fonts[i].xftfont);
                        } */
-                       if ((fonts[i].xftfont = XftFontOpenName(display, screen,
-                                       fonts[i].name)) != NULL) {
+                       fonts[i].xftfont = XftFontOpenName(display, screen,
+                                       fonts[i].name);
+                       if (fonts[i].xftfont != NULL) {
                                continue;
                        }
 
@@ -288,7 +303,7 @@ static void load_fonts()
                        XFreeFont(display, fonts[i].font);
                } */
 
-               if ((fonts[i].font = XLoadQueryFont(display, fonts[i].name)) == NULL) {
+               if (fonts[i].font || (fonts[i].font = XLoadQueryFont(display, fonts[i].name)) == NULL) {
                        ERR("can't load font '%s'", fonts[i].name);
                        if ((fonts[i].font = XLoadQueryFont(display, "fixed")) == NULL) {
                                CRIT_ERR("can't load font '%s'", "fixed");
@@ -361,7 +376,7 @@ static unsigned int max_specials = MAX_SPECIALS_DEFAULT;
 static unsigned int max_user_text = MAX_USER_TEXT_DEFAULT;
 
 /* maximum size of individual text buffers, ie $exec buffer size */
-unsigned int text_buffer_size = TEXT_BUFFER_SIZE;
+unsigned int text_buffer_size = DEFAULT_TEXT_BUFFER_SIZE;
 
 #ifdef HAVE_ICONV
 #define CODEPAGE_LENGTH 20
@@ -461,10 +476,10 @@ static inline int calc_text_width(const char *s, int l)
 
                if (utf8_mode) {
                        XftTextExtentsUtf8(display, fonts[selected_font].xftfont,
-                               (FcChar8 *) s, l, &gi);
+                               (const FcChar8 *) s, l, &gi);
                } else {
                        XftTextExtents8(display, fonts[selected_font].xftfont,
-                               (FcChar8 *) s, l, &gi);
+                               (const FcChar8 *) s, l, &gi);
                }
                return gi.xOff;
        } else
@@ -478,7 +493,7 @@ static inline int calc_text_width(const char *s, int l)
 /* formatted text to render on screen, generated in generate_text(),
  * drawn in draw_stuff() */
 
-static char text_buffer[TEXT_BUFFER_SIZE * 4];
+static char *text_buffer;
 
 /* special stuff in text_buffer */
 
@@ -673,7 +688,7 @@ static void new_font(char *buf, char *args)
        if (args) {
                struct special_t *s = new_special(buf, FONT);
 
-               if (!s->font_added || strcmp(args, fonts[s->font_added].name)) {
+               if (s->font_added > font_count || !s->font_added || strncmp(args, fonts[s->font_added].name, DEFAULT_TEXT_BUFFER_SIZE)) {
                        int tmp = selected_font;
 
                        selected_font = s->font_added = addfont(args);
@@ -692,10 +707,11 @@ static void new_font(char *buf, char *args)
 
 inline void graph_append(struct special_t *graph, double f)
 {
+       int i;
+
        if (!graph->scaled && f > graph->graph_scale) {
                f = graph->graph_scale;
        }
-       int i;
 
        if (graph->scaled) {
                graph->graph_scale = 1;
@@ -712,7 +728,7 @@ inline void graph_append(struct special_t *graph, double f)
 }
 
 short colour_depth = 0;
-void set_up_gradient();
+void set_up_gradient(void);
 
 /* precalculated: 31/255, and 63/255 */
 #define CONST_8_TO_5_BITS 0.12156862745098
@@ -789,7 +805,7 @@ static char *scan_graph(const char *args, int *w, int *h,
        *scale = 0;
        /* graph's argument is either height or height,width */
        if (args) {
-               if (sscanf(args, "%d,%d %x %x %i", h, w, first_colour, last_colour,
+               if (sscanf(args, "%d,%d %x %x %u", h, w, first_colour, last_colour,
                                scale) == 5) {
                        return NULL;
                }
@@ -797,7 +813,7 @@ static char *scan_graph(const char *args, int *w, int *h,
                if (sscanf(args, "%d,%d %x %x", h, w, first_colour, last_colour) == 4) {
                        return NULL;
                }
-               if (sscanf(args, "%63s %d,%d %x %x %i", buf, h, w, first_colour,
+               if (sscanf(args, "%63s %d,%d %x %x %u", buf, h, w, first_colour,
                                last_colour, scale) == 6) {
                        return strdup(buf);
                }
@@ -809,14 +825,14 @@ static char *scan_graph(const char *args, int *w, int *h,
                buf[0] = '\0';
                *h = 25;
                *w = 0;
-               if (sscanf(args, "%x %x %i", first_colour, last_colour, scale) == 3) {
+               if (sscanf(args, "%x %x %u", first_colour, last_colour, scale) == 3) {
                        return NULL;
                }
                *scale = 0;
                if (sscanf(args, "%x %x", first_colour, last_colour) == 2) {
                        return NULL;
                }
-               if (sscanf(args, "%63s %x %x %i", buf, first_colour, last_colour,
+               if (sscanf(args, "%63s %x %x %u", buf, first_colour, last_colour,
                                scale) == 4) {
                        return strdup(buf);
                }
@@ -827,14 +843,14 @@ static char *scan_graph(const char *args, int *w, int *h,
                buf[0] = '\0';
                *first_colour = 0;
                *last_colour = 0;
-               if (sscanf(args, "%d,%d %i", h, w, scale) == 3) {
+               if (sscanf(args, "%d,%d %u", h, w, scale) == 3) {
                        return NULL;
                }
                *scale = 0;
                if (sscanf(args, "%d,%d", h, w) == 2) {
                        return NULL;
                }
-               if (sscanf(args, "%63s %d,%d %i", buf, h, w, scale) < 4) {
+               if (sscanf(args, "%63s %d,%d %u", buf, h, w, scale) < 4) {
                        *scale = 0;
                        //TODO: check the return value and throw an error?
                        sscanf(args, "%63s %d,%d", buf, h, w);
@@ -954,11 +970,16 @@ static void convert_escapes(char *buf)
 /* Prints anything normally printed with snprintf according to the current value
  * of use_spacer.  Actually slightly more flexible than snprintf, as you can
  * safely specify the destination buffer as one of your inputs.  */
-static int spaced_print(char *buf, int size, char *format, int width,
-               char *func_name, ...) {
+static int spaced_print(char *buf, int size, const char *format, int width,
+               const char *func_name, ...) {
        int len;
        va_list argp;
-       char *tempbuf = malloc(size * sizeof(char));
+       char *tempbuf;
+
+       if (size < 1) {
+               return 0;
+       }
+       tempbuf = malloc(size * sizeof(char));
 
        // Passes the varargs along to vsnprintf
        va_start(argp, func_name);
@@ -970,10 +991,10 @@ static int spaced_print(char *buf, int size, char *format, int width,
                        len = snprintf(buf, size, "%s", tempbuf);
                        break;
                case LEFT_SPACER:
-                       len = snprintf(buf, width, "%*s", width - 1, tempbuf);
+                       len = snprintf(buf, size, "%*s", width - 1, tempbuf);
                        break;
                case RIGHT_SPACER:
-                       len = snprintf(buf, width, "%-*s", width - 1, tempbuf);
+                       len = snprintf(buf, size, "%-*s", width - 1, tempbuf);
                        break;
                default:
                        CRIT_ERR("%s encountered invalid use_spacer value (%d)", func_name,
@@ -986,9 +1007,9 @@ static int spaced_print(char *buf, int size, char *format, int width,
 }
 
 /* converts from bytes to human readable format (k, M, G, T) */
-static void human_readable(long long num, char *buf, int size, char *func_name)
+static void human_readable(long long num, char *buf, int size, const char *func_name)
 {
-       char **suffix = suffixes;
+       const char **suffix = suffixes;
        float fnum;
        int precision, len;
        static const int WIDTH = 10, SHORT_WIDTH = 8;
@@ -1031,6 +1052,9 @@ static void human_readable(long long num, char *buf, int size, char *func_name)
 
 enum text_object_type {
        OBJ_addr,
+#if defined(__linux__)
+    OBJ_addrs,
+#endif /* __linux__ */
 #ifndef __OpenBSD__
        OBJ_acpiacadapter,
        OBJ_adt746xcpu,
@@ -1056,6 +1080,9 @@ enum text_object_type {
        OBJ_color7,
        OBJ_color8,
        OBJ_color9,
+       OBJ_conky_version,
+       OBJ_conky_build_date,
+       OBJ_conky_build_arch,
        OBJ_font,
        OBJ_cpu,
        OBJ_cpubar,
@@ -1079,6 +1106,8 @@ enum text_object_type {
        OBJ_execgraph,
        OBJ_execibar,
        OBJ_execigraph,
+       OBJ_execp,
+       OBJ_execpi,
        OBJ_freq,
        OBJ_freq_g,
        OBJ_freq_dyn,
@@ -1088,6 +1117,7 @@ enum text_object_type {
        OBJ_fs_free,
        OBJ_fs_free_perc,
        OBJ_fs_size,
+       OBJ_fs_type,
        OBJ_fs_used,
        OBJ_fs_used_perc,
        OBJ_goto,
@@ -1101,6 +1131,7 @@ enum text_object_type {
        OBJ_platform,
        OBJ_hwmon,
 #if defined(__linux__)
+       OBJ_disk_protect,
        OBJ_i8k_version,
        OBJ_i8k_bios,
        OBJ_i8k_serial,
@@ -1116,6 +1147,12 @@ enum text_object_type {
        OBJ_ibm_temps,
        OBJ_ibm_volume,
        OBJ_ibm_brightness,
+       OBJ_if_up,
+       OBJ_if_gw,
+       OBJ_ioscheduler,
+       OBJ_gw_iface,
+       OBJ_gw_ip,
+       OBJ_laptop_mode,
        OBJ_pb_battery,
        OBJ_voltage_mv,
        OBJ_voltage_v,
@@ -1152,6 +1189,7 @@ enum text_object_type {
        OBJ_mixerbar,
        OBJ_mixerlbar,
        OBJ_mixerrbar,
+       OBJ_nameserver,
        OBJ_new_mails,
        OBJ_nodename,
        OBJ_pre_exec,
@@ -1179,6 +1217,10 @@ enum text_object_type {
        OBJ_upspeedgraph,
        OBJ_uptime,
        OBJ_uptime_short,
+       OBJ_user_names,
+       OBJ_user_terms,
+       OBJ_user_times,
+       OBJ_user_number,
        OBJ_imap,
        OBJ_imap_messages,
        OBJ_imap_unseen,
@@ -1226,8 +1268,6 @@ enum text_object_type {
        OBJ_xmms2_title,
        OBJ_xmms2_genre,
        OBJ_xmms2_comment,
-       OBJ_xmms2_decoder,
-       OBJ_xmms2_transport,
        OBJ_xmms2_url,
        OBJ_xmms2_date,
        OBJ_xmms2_tracknr,
@@ -1240,6 +1280,8 @@ enum text_object_type {
        OBJ_xmms2_status,
        OBJ_xmms2_bar,
        OBJ_xmms2_smart,
+       OBJ_xmms2_playlist,
+       OBJ_xmms2_timesplayed,
 #endif
 #ifdef AUDACIOUS
        OBJ_audacious_status,
@@ -1277,6 +1319,12 @@ enum text_object_type {
 #ifdef HDDTEMP
        OBJ_hddtemp,
 #endif
+#ifdef SMAPI
+       OBJ_smapi,
+       OBJ_smapi_bat_bar,
+       OBJ_smapi_bat_perc,
+       OBJ_if_smapi_bat_installed,
+#endif
        OBJ_entropy_avail,
        OBJ_entropy_poolsize,
        OBJ_entropy_bar
@@ -1406,8 +1454,8 @@ struct text_object_list {
        struct text_object *text_objects;
 };
 
-static unsigned int text_object_count;
-static struct text_object *text_objects;
+static unsigned int global_text_object_count;
+static struct text_object *global_text_objects;
 static void generate_text_internal(char *p, int p_max_size,
        struct text_object *objs, unsigned int object_count,
        struct information *cur);
@@ -1419,9 +1467,10 @@ static void generate_text_internal(char *p, int p_max_size,
 struct mail_s *parse_mail_args(char type, const char *arg)
 {
        struct mail_s *mail;
+       char *tmp;
+
        mail = malloc(sizeof(struct mail_s));
        memset(mail, 0, sizeof(struct mail_s));
-       char *tmp;
 
        if (sscanf(arg, "%128s %128s %128s", mail->host, mail->user, mail->pass)
                        != 3) {
@@ -1475,8 +1524,8 @@ struct mail_s *parse_mail_args(char type, const char *arg)
        }
        tmp = strstr(arg, "-e ");
        if (tmp) {
-               tmp += 3;
                int len = 1024;
+               tmp += 3;
 
                if (tmp[0] == '\'') {
                        len = strstr(tmp + 1, "'") - tmp - 1;
@@ -1492,7 +1541,7 @@ struct mail_s *parse_mail_args(char type, const char *arg)
        return mail;
 }
 
-void *imap_thread(struct mail_s *mail)
+void *imap_thread(void *arg)
 {
        int sockfd, numbytes;
        char recvbuf[MAXDATASIZE];
@@ -1504,12 +1553,17 @@ void *imap_thread(struct mail_s *mail)
        struct stat stat_buf;
        struct hostent *he;
        struct sockaddr_in their_addr;  // connector's address information
+       struct mail_s *mail = (struct mail_s *)arg;
 
        if ((he = gethostbyname(mail->host)) == NULL) { // get the host info
                herror("gethostbyname");
                exit(1);
        }
        while (fail < 5) {
+               struct timeval timeout;
+               int res;
+               fd_set fdset;
+
                if (fail > 0) {
                        ERR("Trying IMAP connection again for %s@%s (try %i/5)",
                                mail->user, mail->host, fail + 1);
@@ -1534,9 +1588,6 @@ void *imap_thread(struct mail_s *mail)
                        fail++;
                        goto next_iteration;
                }
-               struct timeval timeout;
-               int res;
-               fd_set fdset;
 
                timeout.tv_sec = 60;    // 60 second timeout i guess
                timeout.tv_usec = 0;
@@ -1564,7 +1615,7 @@ void *imap_thread(struct mail_s *mail)
                strncat(sendbuf, mail->user, MAXDATASIZE - strlen(sendbuf) - 1);
                strncat(sendbuf, " ", MAXDATASIZE - strlen(sendbuf) - 1);
                strncat(sendbuf, mail->pass, MAXDATASIZE - strlen(sendbuf) - 1);
-               strncat(sendbuf, "\n", MAXDATASIZE - strlen(sendbuf) - 1);
+               strncat(sendbuf, "\r\n", MAXDATASIZE - strlen(sendbuf) - 1);
                if (send(sockfd, sendbuf, strlen(sendbuf), 0) == -1) {
                        perror("send a1");
                        fail++;
@@ -1590,7 +1641,7 @@ void *imap_thread(struct mail_s *mail)
                }
                strncpy(sendbuf, "a2 STATUS ", MAXDATASIZE);
                strncat(sendbuf, mail->folder, MAXDATASIZE - strlen(sendbuf) - 1);
-               strncat(sendbuf, " (MESSAGES UNSEEN)\n",
+               strncat(sendbuf, " (MESSAGES UNSEEN)\r\n",
                        MAXDATASIZE - strlen(sendbuf) - 1);
                if (send(sockfd, sendbuf, strlen(sendbuf), 0) == -1) {
                        perror("send a2");
@@ -1629,7 +1680,7 @@ void *imap_thread(struct mail_s *mail)
                                &mail->unseen);
                        timed_thread_unlock(mail->p_timed_thread);
                }
-               strncpy(sendbuf, "a3 logout\n", MAXDATASIZE);
+               strncpy(sendbuf, "a3 logout\r\n", MAXDATASIZE);
                if (send(sockfd, sendbuf, strlen(sendbuf), 0) == -1) {
                        perror("send a3");
                        fail++;
@@ -1677,7 +1728,7 @@ next_iteration:
        return 0;
 }
 
-void *pop3_thread(struct mail_s *mail)
+void *pop3_thread(void *arg)
 {
        int sockfd, numbytes;
        char recvbuf[MAXDATASIZE];
@@ -1688,12 +1739,17 @@ void *pop3_thread(struct mail_s *mail)
        struct stat stat_buf;
        struct hostent *he;
        struct sockaddr_in their_addr;  // connector's address information
+       struct mail_s *mail = (struct mail_s *)arg;
 
        if ((he = gethostbyname(mail->host)) == NULL) { // get the host info
                herror("gethostbyname");
                exit(1);
        }
        while (fail < 5) {
+               struct timeval timeout;
+               int res;
+               fd_set fdset;
+
                if (fail > 0) {
                        ERR("Trying POP3 connection again for %s@%s (try %i/5)",
                                mail->user, mail->host, fail + 1);
@@ -1718,9 +1774,6 @@ void *pop3_thread(struct mail_s *mail)
                        fail++;
                        goto next_iteration;
                }
-               struct timeval timeout;
-               int res;
-               fd_set fdset;
 
                timeout.tv_sec = 60;    // 60 second timeout i guess
                timeout.tv_usec = 0;
@@ -1746,7 +1799,7 @@ void *pop3_thread(struct mail_s *mail)
                }
                strncpy(sendbuf, "USER ", MAXDATASIZE);
                strncat(sendbuf, mail->user, MAXDATASIZE - strlen(sendbuf) - 1);
-               strncat(sendbuf, "\n", MAXDATASIZE - strlen(sendbuf) - 1);
+               strncat(sendbuf, "\r\n", MAXDATASIZE - strlen(sendbuf) - 1);
                if (send(sockfd, sendbuf, strlen(sendbuf), 0) == -1) {
                        perror("send USER");
                        fail++;
@@ -1772,7 +1825,7 @@ void *pop3_thread(struct mail_s *mail)
                }
                strncpy(sendbuf, "PASS ", MAXDATASIZE);
                strncat(sendbuf, mail->pass, MAXDATASIZE - strlen(sendbuf) - 1);
-               strncat(sendbuf, "\n", MAXDATASIZE - strlen(sendbuf) - 1);
+               strncat(sendbuf, "\r\n", MAXDATASIZE - strlen(sendbuf) - 1);
                if (send(sockfd, sendbuf, strlen(sendbuf), 0) == -1) {
                        perror("send PASS");
                        fail++;
@@ -1796,7 +1849,7 @@ void *pop3_thread(struct mail_s *mail)
                        fail++;
                        goto next_iteration;
                }
-               strncpy(sendbuf, "STAT\n", MAXDATASIZE);
+               strncpy(sendbuf, "STAT\r\n", MAXDATASIZE);
                if (send(sockfd, sendbuf, strlen(sendbuf), 0) == -1) {
                        perror("send STAT");
                        fail++;
@@ -1831,7 +1884,7 @@ void *pop3_thread(struct mail_s *mail)
                        sscanf(reply, "%lu %lu", &mail->unseen, &mail->used);
                        timed_thread_unlock(mail->p_timed_thread);
                }
-               strncpy(sendbuf, "QUIT\n", MAXDATASIZE);
+               strncpy(sendbuf, "QUIT\r\n", MAXDATASIZE);
                if (send(sockfd, sendbuf, strlen(sendbuf), 0) == -1) {
                        perror("send QUIT");
                        fail++;
@@ -1877,14 +1930,18 @@ next_iteration:
        return 0;
 }
 
-void *threaded_exec(struct text_object *obj)
+void *threaded_exec(void *arg)
 {
+       FILE *fp;
+       char *p2;
+       int n2;
+       struct text_object *obj = (struct text_object *)arg;
        while (1) {
-               char *p2 = obj->data.texeci.buffer;
-               FILE *fp = popen(obj->data.texeci.cmd, "r");
+               p2 = obj->data.texeci.buffer;
+               fp = popen(obj->data.texeci.cmd, "r");
 
                timed_thread_lock(obj->data.texeci.p_timed_thread);
-               int n2 = fread(p2, 1, text_buffer_size, fp);
+               n2 = fread(p2, 1, text_buffer_size, fp);
 
                pclose(fp);
                p2[n2] = '\0';
@@ -1905,7 +1962,7 @@ void *threaded_exec(struct text_object *obj)
        return 0;
 }
 
-static struct text_object *new_text_object_internal()
+static struct text_object *new_text_object_internal(void)
 {
        struct text_object *obj = malloc(sizeof(struct text_object));
        memset(obj, 0, sizeof(struct text_object));
@@ -1920,24 +1977,16 @@ static void free_text_objects(unsigned int count, struct text_object *objs)
                switch (objs[i].type) {
 #ifndef __OpenBSD__
                        case OBJ_acpitemp:
-                               close(objs[i].data.i);
-                               break;
                        case OBJ_acpitempf:
                                close(objs[i].data.i);
                                break;
                        case OBJ_i2c:
-                               close(objs[i].data.sysfs.fd);
-                               break;
                        case OBJ_platform:
-                               close(objs[i].data.sysfs.fd);
-                               break;
                        case OBJ_hwmon:
                                close(objs[i].data.sysfs.fd);
                                break;
 #endif /* !__OpenBSD__ */
                        case OBJ_time:
-                               free(objs[i].data.s);
-                               break;
                        case OBJ_utime:
                                free(objs[i].data.s);
                                break;
@@ -1992,31 +2041,45 @@ static void free_text_objects(unsigned int count, struct text_object *objs)
                                break;
                        case OBJ_text:
                        case OBJ_font:
-                               free(objs[i].data.s);
-                               break;
                        case OBJ_image:
-                               free(objs[i].data.s);
-                               break;
                        case OBJ_exec:
-                               free(objs[i].data.s);
-                               break;
                        case OBJ_execbar:
-                               free(objs[i].data.s);
-                               break;
                        case OBJ_execgraph:
+                       case OBJ_execp:
                                free(objs[i].data.s);
                                break;
-                       /* case OBJ_execibar:
-                               free(objs[i].data.s);
-                               break;
-                       case OBJ_execigraph:
-                               free(objs[i].data.s);
-                               break; */
 #ifdef HAVE_ICONV
                        case OBJ_iconv_start:
                                free_iconv();
                                break;
 #endif
+#ifdef __LINUX__
+                       case OBJ_disk_protect:
+                               free(objs[i].data.s);
+                               break;
+                       case OBJ_if_up:
+                               free(objs[i].data.ifblock.s);
+                               free(objs[i].data.ifblock.str);
+                               break;
+                       case OBJ_if_gw:
+                               free(objs[i].data.ifblock.s);
+                               free(objs[i].data.ifblock.str);
+                       case OBJ_gw_iface:
+                       case OBJ_gw_ip:
+                               if (info.gw_info.iface) {
+                                       free(info.gw_info.iface);
+                                       info.gw_info.iface = 0;
+                               }
+                               if (info.gw_info.ip) {
+                                       free(info.gw_info.ip);
+                                       info.gw_info.ip = 0;
+                               }
+                               break;
+                       case OBJ_ioscheduler:
+                               if(objs[i].data.s)
+                                       free(objs[i].data.s);
+                               break;
+#endif
 #ifdef XMMS2
                        case OBJ_xmms2_artist:
                                if (info.xmms2.artist) {
@@ -2048,18 +2111,6 @@ static void free_text_objects(unsigned int count, struct text_object *objs)
                                        info.xmms2.comment = 0;
                                }
                                break;
-                       case OBJ_xmms2_decoder:
-                               if (info.xmms2.decoder) {
-                                       free(info.xmms2.decoder);
-                                       info.xmms2.url = 0;
-                               }
-                               break;
-                       case OBJ_xmms2_transport:
-                               if (info.xmms2.transport) {
-                                       free(info.xmms2.transport);
-                                       info.xmms2.url = 0;
-                               }
-                               break;
                        case OBJ_xmms2_url:
                                if (info.xmms2.url) {
                                        free(info.xmms2.url);
@@ -2078,6 +2129,12 @@ static void free_text_objects(unsigned int count, struct text_object *objs)
                                        info.xmms2.status = 0;
                                }
                                break;
+                       case OBJ_xmms2_playlist:
+                               if (info.xmms2.playlist) {
+                                       free(info.xmms2.playlist);
+                                       info.xmms2.playlist = 0;
+                               }
+                               break;
                        case OBJ_xmms2_smart:
                                if (info.xmms2.artist) {
                                        free(info.xmms2.artist);
@@ -2118,7 +2175,10 @@ static void free_text_objects(unsigned int count, struct text_object *objs)
                                free(objs[i].data.s);
                                break;
 #endif /* !__OpenBSD__ */
+                       case OBJ_execpi:
                        case OBJ_execi:
+                       case OBJ_execibar:
+                       case OBJ_execigraph:
                                free(objs[i].data.execi.cmd);
                                free(objs[i].data.execi.buffer);
                                break;
@@ -2126,12 +2186,10 @@ static void free_text_objects(unsigned int count, struct text_object *objs)
                                free(objs[i].data.texeci.cmd);
                                free(objs[i].data.texeci.buffer);
                                break;
-                       case OBJ_top:
-                               if (info.first_process) {
-                                       free_all_processes();
-                                       info.first_process = NULL;
-                               }
+                       case OBJ_nameserver:
+                               free_dns_data();
                                break;
+                       case OBJ_top:
                        case OBJ_top_mem:
                                if (info.first_process) {
                                        free_all_processes();
@@ -2148,49 +2206,62 @@ static void free_text_objects(unsigned int count, struct text_object *objs)
                        case OBJ_entropy_poolsize:
                        case OBJ_entropy_bar:
                                break;
+                       case OBJ_user_names:
+                               if (info.users.names) {
+                                       free(info.users.names);
+                                       info.users.names = 0;
+                               }
+                               break;
+                       case OBJ_user_terms:
+                               if (info.users.terms) {
+                                       free(info.users.terms);
+                                       info.users.terms = 0;
+                               }
+                               break;
+                       case OBJ_user_times:
+                               if (info.users.times) {
+                                       free(info.users.times);
+                                       info.users.times = 0;
+                               }
+                               break;
+#ifdef SMAPI
+                       case OBJ_smapi:
+                       case OBJ_smapi_bat_perc:
+                               free(objs[i].data.s);
+                               break;
+                       case OBJ_if_smapi_bat_installed:
+                               free(objs[i].data.ifblock.s);
+                               free(objs[i].data.ifblock.str);
+                               break;
+#endif
+#ifdef MPD
+                       case OBJ_mpd_title:
+                       case OBJ_mpd_artist:
+                       case OBJ_mpd_album:
+                       case OBJ_mpd_random:
+                       case OBJ_mpd_repeat:
+                       case OBJ_mpd_vol:
+                       case OBJ_mpd_bitrate:
+                       case OBJ_mpd_status:
+                       case OBJ_mpd_host:
+                       case OBJ_mpd_port:
+                       case OBJ_mpd_password:
+                       case OBJ_mpd_bar:
+                       case OBJ_mpd_elapsed:
+                       case OBJ_mpd_length:
+                       case OBJ_mpd_track:
+                       case OBJ_mpd_name:
+                       case OBJ_mpd_file:
+                       case OBJ_mpd_percent:
+                       case OBJ_mpd_smart:
+                               free_mpd_vars(&info);
+                               break;
+#endif
                }
        }
        free(objs);
-#ifdef MPD
-       if (info.mpd.title) {
-               free(info.mpd.title);
-               info.mpd.title = NULL;
-       }
-       if (info.mpd.artist) {
-               free(info.mpd.artist);
-               info.mpd.artist = NULL;
-       }
-       if (info.mpd.album) {
-               free(info.mpd.album);
-               info.mpd.album = NULL;
-       }
-       if (info.mpd.random) {
-               free(info.mpd.random);
-               info.mpd.random = NULL;
-       }
-       if (info.mpd.repeat) {
-               free(info.mpd.repeat);
-               info.mpd.repeat = NULL;
-       }
-       if (info.mpd.track) {
-               free(info.mpd.track);
-               info.mpd.track = NULL;
-       }
-       if (info.mpd.name) {
-               free(info.mpd.name);
-               info.mpd.name = NULL;
-       }
-       if (info.mpd.file) {
-               free(info.mpd.file);
-               info.mpd.file = NULL;
-       }
-       if (info.mpd.status) {
-               free(info.mpd.status);
-               info.mpd.status = NULL;
-       }
-#endif
        /* text_objects = NULL;
-       text_object_count = 0; */
+          text_object_count = 0; */
 }
 
 void scan_mixer_bar(const char *arg, int *a, int *w, int *h)
@@ -2369,7 +2440,7 @@ static struct text_object *construct_text_object(const char *s,
                obj->data.s = strdup(bat);
        END OBJ(battery_bar, 0)
                char bat[64];
-
+               obj->b = 6;
                if (arg) {
                        arg = scan_bar(arg, &obj->a, &obj->b);
                        sscanf(arg, "%63s", bat);
@@ -2380,6 +2451,11 @@ static struct text_object *construct_text_object(const char *s,
 #endif /* !__OpenBSD__ */
 
 #if defined(__linux__)
+       END OBJ(disk_protect, 0)
+               if (arg)
+                       obj->data.s = strdup(arg);
+               else
+                       CRIT_ERR("disk_protect needs an argument");
        END OBJ(i8k_version, INFO_I8K)
        END OBJ(i8k_bios, INFO_I8K)
        END OBJ(i8k_serial, INFO_I8K)
@@ -2404,6 +2480,32 @@ static struct text_object *construct_text_object(const char *s,
                obj->data.sensor = atoi(&arg[0]);
        END OBJ(ibm_volume, 0)
        END OBJ(ibm_brightness, 0)
+       END OBJ(if_up, 0)
+               if (blockdepth >= MAX_IF_BLOCK_DEPTH) {
+                       CRIT_ERR("MAX_IF_BLOCK_DEPTH exceeded");
+               }
+               if (!arg) {
+                       ERR("if_up needs an argument");
+                       obj->data.ifblock.s = 0;
+               } else
+                       obj->data.ifblock.s = strdup(arg);
+               blockstart[blockdepth] = object_count;
+               obj->data.ifblock.pos = object_count + 2;
+               blockdepth++;
+       END OBJ(if_gw, 0)
+               if (blockdepth >= MAX_IF_BLOCK_DEPTH) {
+                       CRIT_ERR("MAX_IF_BLOCK_DEPTH exceeded");
+               }
+               blockstart[blockdepth] = object_count;
+               obj->data.ifblock.pos = object_count + 2;
+               blockdepth++;
+       END OBJ(ioscheduler, 0)
+               if (!arg) {
+                       CRIT_ERR("get_ioscheduler needs an argument (e.g. hda)");
+                       obj->data.s = 0;
+               } else
+                       obj->data.s = strdup(arg);
+       END OBJ(laptop_mode, 0)
        END OBJ(pb_battery, 0)
                if (arg && strcmp(arg, "status") == 0) {
                        obj->data.i = PB_BATT_STATUS;
@@ -2566,6 +2668,9 @@ static struct text_object *construct_text_object(const char *s,
                obj->data.l = color9;
        END OBJ(font, 0)
                obj->data.s = scan_font(arg);
+       END OBJ(conky_version, 0)
+       END OBJ(conky_build_date, 0)
+       END OBJ(conky_build_arch, 0)
        END OBJ(downspeed, INFO_NET)
                if (arg) {
                        obj->data.net = get_net_stat(arg);
@@ -2608,12 +2713,14 @@ static struct text_object *construct_text_object(const char *s,
 #ifdef HAVE_POPEN
        END OBJ(exec, 0)
                obj->data.s = strdup(arg ? arg : "");
+       END OBJ(execp, 0)
+               obj->data.s = strdup(arg ? arg : "");
        END OBJ(execbar, 0)
                obj->data.s = strdup(arg ? arg : "");
        END OBJ(execgraph, 0)
                obj->data.s = strdup(arg ? arg : "");
        END OBJ(execibar, 0)
-               unsigned int n;
+               int n;
 
                if (!arg || sscanf(arg, "%f %n", &obj->data.execi.interval, &n) <= 0) {
                        char buf[256];
@@ -2626,7 +2733,7 @@ static struct text_object *construct_text_object(const char *s,
                        obj->data.execi.cmd = strdup(arg + n);
                }
        END OBJ(execigraph, 0)
-               unsigned int n;
+               int n;
 
                if (!arg || sscanf(arg, "%f %n", &obj->data.execi.interval, &n) <= 0) {
                        char buf[256];
@@ -2639,7 +2746,21 @@ static struct text_object *construct_text_object(const char *s,
                        obj->data.execi.cmd = strdup(arg + n);
                }
        END OBJ(execi, 0)
-               unsigned int n;
+               int n;
+
+               if (!arg || sscanf(arg, "%f %n", &obj->data.execi.interval, &n) <= 0) {
+                       char buf[256];
+
+                       ERR("${execi <interval> command}");
+                       obj->type = OBJ_text;
+                       snprintf(buf, 256, "${%s}", s);
+                       obj->data.s = strdup(buf);
+               } else {
+                       obj->data.execi.cmd = strdup(arg + n);
+                       obj->data.execi.buffer = malloc(text_buffer_size);
+               }
+       END OBJ(execpi, 0)
+               int n;
 
                if (!arg || sscanf(arg, "%f %n", &obj->data.execi.interval, &n) <= 0) {
                        char buf[256];
@@ -2650,10 +2771,10 @@ static struct text_object *construct_text_object(const char *s,
                        obj->data.s = strdup(buf);
                } else {
                        obj->data.execi.cmd = strdup(arg + n);
-                       obj->data.execi.buffer = (char *) calloc(1, text_buffer_size);
+                       obj->data.execi.buffer = malloc(text_buffer_size);
                }
        END OBJ(texeci, 0)
-               unsigned int n;
+               int n;
 
                if (!arg || sscanf(arg, "%f %n", &obj->data.texeci.interval, &n) <= 0) {
                        char buf[256];
@@ -2664,7 +2785,7 @@ static struct text_object *construct_text_object(const char *s,
                        obj->data.s = strdup(buf);
                } else {
                        obj->data.texeci.cmd = strdup(arg + n);
-                       obj->data.texeci.buffer = (char *) calloc(1, text_buffer_size);
+                       obj->data.texeci.buffer = malloc(text_buffer_size);
                }
                obj->data.texeci.p_timed_thread = NULL;
        END OBJ(pre_exec, 0)
@@ -2689,7 +2810,6 @@ static struct text_object *construct_text_object(const char *s,
                }
 #endif
        END OBJ(fs_bar, INFO_FS)
-               obj->data.fsbar.h = 4;
                arg = scan_bar(arg, &obj->data.fsbar.w, &obj->data.fsbar.h);
                if (arg) {
                        while (isspace(*arg)) {
@@ -2703,16 +2823,18 @@ static struct text_object *construct_text_object(const char *s,
                }
                obj->data.fsbar.fs = prepare_fs_stat(arg);
        END OBJ(fs_bar_free, INFO_FS)
-               obj->data.fsbar.h = 4;
+               arg = scan_bar(arg, &obj->data.fsbar.w, &obj->data.fsbar.h);
                if (arg) {
-                       unsigned int n;
-
-                       if (sscanf(arg, "%d %n", &obj->data.fsbar.h, &n) >= 1) {
-                               arg += n;
+                       while (isspace(*arg)) {
+                               arg++;
+                       }
+                       if (*arg == '\0') {
+                               arg = "/";
                        }
                } else {
                        arg = "/";
                }
+
                obj->data.fsbar.fs = prepare_fs_stat(arg);
        END OBJ(fs_free, INFO_FS)
                if (!arg) {
@@ -2734,6 +2856,11 @@ static struct text_object *construct_text_object(const char *s,
                        arg = "/";
                }
                obj->data.fs = prepare_fs_stat(arg);
+       END OBJ(fs_type, INFO_FS)
+               if (!arg) {
+                       arg = "/";
+               }
+               obj->data.fs = prepare_fs_stat(arg);
        END OBJ(fs_used, INFO_FS)
                if (!arg) {
                        arg = "/";
@@ -2741,6 +2868,8 @@ static struct text_object *construct_text_object(const char *s,
                obj->data.fs = prepare_fs_stat(arg);
        END OBJ(hr, 0)
                obj->data.i = arg ? atoi(arg) : 1;
+       END OBJ(nameserver, INFO_DNS)
+               obj->data.i = arg ? atoi(arg) : 0;
        END OBJ(offset, 0)
                obj->data.i = arg ? atoi(arg) : 1;
        END OBJ(voffset, 0)
@@ -2920,6 +3049,14 @@ static struct text_object *construct_text_object(const char *s,
                } else {
                        CRIT_ERR("addr needs argument");
                }
+#if defined(__linux__)
+     END OBJ(addrs, INFO_NET)
+        if (arg) {
+            obj->data.net = get_net_stat(arg);
+        } else {
+             CRIT_ERR("addrs needs argument");
+        }
+#endif /* __linux__ */
        END OBJ(tail, 0)
                char buf[64];
                int n1, n2;
@@ -3188,11 +3325,11 @@ static struct text_object *construct_text_object(const char *s,
                obj->data.local_mail.box = strdup(dst);
                obj->data.local_mail.interval = n1;
        END OBJ(mboxscan, 0)
-               obj->data.mboxscan.args = (char *) malloc(TEXT_BUFFER_SIZE);
+               obj->data.mboxscan.args = (char *) malloc(text_buffer_size);
                obj->data.mboxscan.output = (char *) malloc(text_buffer_size);
                /* if '1' (in mboxscan.c) then there was SIGUSR1, hmm */
                obj->data.mboxscan.output[0] = 1;
-               strncpy(obj->data.mboxscan.args, arg, TEXT_BUFFER_SIZE);
+               strncpy(obj->data.mboxscan.args, arg, text_buffer_size);
        END OBJ(mem, INFO_MEM)
        END OBJ(memmax, INFO_MEM)
        END OBJ(memperc, INFO_MEM)
@@ -3371,6 +3508,13 @@ static struct text_object *construct_text_object(const char *s,
                }
        END OBJ(uptime_short, INFO_UPTIME)
        END OBJ(uptime, INFO_UPTIME)
+       END OBJ(user_names, INFO_USERS)
+       END OBJ(user_times, INFO_USERS)
+       END OBJ(user_terms, INFO_USERS)
+       END OBJ(user_number, INFO_USERS)
+       END OBJ(gw_iface, INFO_GW)
+       END OBJ(gw_ip, INFO_GW)
+       END OBJ(if_gw, INFO_GW)
 #ifndef __OpenBSD__
        END OBJ(adt746xcpu, 0)
        END OBJ(adt746xfan, 0)
@@ -3413,16 +3557,52 @@ static struct text_object *construct_text_object(const char *s,
                } else {
                        obj->global_mode = 1;
                }
-#ifdef MPD
-       END OBJ(mpd_artist, INFO_MPD)
-       END OBJ(mpd_title, INFO_MPD)
-               if (arg) {
-                       sscanf(arg, "%d", &info.mpd.max_title_len);
-                       if (info.mpd.max_title_len > 0) {
-                               info.mpd.max_title_len++;
+#ifdef SMAPI
+       END OBJ(smapi, 0)
+               if (arg)
+                       obj->data.s = strdup(arg);
+               else
+                       ERR("smapi needs an argument");
+       END OBJ(if_smapi_bat_installed, 0)
+               if (blockdepth >= MAX_IF_BLOCK_DEPTH) {
+                       CRIT_ERR("MAX_IF_BLOCK_DEPTH exceeded");
+               }
+               if (!arg) {
+                       ERR("if_smapi_bat_installed needs an argument");
+                       obj->data.ifblock.s = 0;
+               } else
+                       obj->data.ifblock.s = strdup(arg);
+               blockstart[blockdepth] = object_count;
+               obj->data.ifblock.pos = object_count + 2;
+               blockdepth++;
+       END OBJ(smapi_bat_perc, 0)
+               if (arg)
+                       obj->data.s = strdup(arg);
+               else
+                       ERR("smapi_bat_perc needs an argument");
+       END OBJ(smapi_bat_bar, 0)
+               if(arg) {
+                       int cnt;
+                       if(sscanf(arg, "%i %n", &obj->data.i, &cnt) <= 0) {
+                               ERR("first argument to smapi_bat_bar must be an integer value");
+                               obj->data.i = -1;
                        } else {
-                               CRIT_ERR("mpd_title: invalid length argument");
+                               obj->b = 4;
+                               arg = scan_bar(arg + cnt, &obj->a, &obj->b);
                        }
+               } else
+                       ERR("if_smapi_bat_bar needs an argument");
+#endif /* SMAPI */
+#ifdef MPD
+                       END OBJ(mpd_artist, INFO_MPD)
+                       END OBJ(mpd_title, INFO_MPD)
+                       if (arg) {
+                               sscanf(arg, "%d", &info.mpd.max_title_len);
+                               if (info.mpd.max_title_len > 0) {
+                                       info.mpd.max_title_len++;
+                               } else {
+                                       CRIT_ERR("mpd_title: invalid length argument");
+                               }
                } else {
                        info.mpd.max_title_len = 0;
                }
@@ -3448,8 +3628,6 @@ static struct text_object *construct_text_object(const char *s,
        END OBJ(xmms2_title, INFO_XMMS2)
        END OBJ(xmms2_genre, INFO_XMMS2)
        END OBJ(xmms2_comment, INFO_XMMS2)
-       END OBJ(xmms2_decoder, INFO_XMMS2)
-       END OBJ(xmms2_transport, INFO_XMMS2)
        END OBJ(xmms2_url, INFO_XMMS2)
        END OBJ(xmms2_tracknr, INFO_XMMS2)
        END OBJ(xmms2_bitrate, INFO_XMMS2)
@@ -3463,6 +3641,8 @@ static struct text_object *construct_text_object(const char *s,
        END OBJ(xmms2_bar, INFO_XMMS2)
                scan_bar(arg, &obj->data.pair.a, &obj->data.pair.b);
        END OBJ(xmms2_smart, INFO_XMMS2)
+       END OBJ(xmms2_playlist, INFO_XMMS2)
+       END OBJ(xmms2_timesplayed, INFO_XMMS2)
 #endif
 #ifdef AUDACIOUS
        END OBJ(audacious_status, INFO_AUDACIOUS)
@@ -3650,24 +3830,28 @@ static struct text_object *create_plain_text(const char *s)
        return obj;
 }
 
-static struct text_object_list *extract_variable_text_internal(const char *p)
+static struct text_object_list *extract_variable_text_internal(const char *const_p)
 {
        struct text_object_list *retval;
        struct text_object *obj;
-       const char *s = p;
+       char *p, *s, *orig_p;
+       long line;
+
+       p = strdup(const_p);
+       s = orig_p = p;
 
        retval = malloc(sizeof(struct text_object_list));
        memset(retval, 0, sizeof(struct text_object_list));
        retval->text_object_count = 0;
 
-       long line = text_lines;
+       line = text_lines;
 
        while (*p) {
                if (*p == '\n') {
                        line++;
                }
                if (*p == '$') {
-                       *(char *) p = '\0';
+                       *p = '\0';
                        obj = create_plain_text(s);
                        if (obj != NULL) {
                                // allocate memory for the object
@@ -3679,7 +3863,7 @@ static struct text_object_list *extract_variable_text_internal(const char *p)
                                        sizeof(struct text_object));
                                free(obj);
                        }
-                       *(char *) p = '$';
+                       *p = '$';
                        p++;
                        s = p;
 
@@ -3728,7 +3912,7 @@ static struct text_object_list *extract_variable_text_internal(const char *p)
 
                                /* if variable wasn't found in environment, use some special */
                                if (!var) {
-                                       char *p;
+                                       char *tmp_p;
                                        char *arg = 0;
 
                                        /* split arg */
@@ -3745,10 +3929,10 @@ static struct text_object_list *extract_variable_text_internal(const char *p)
                                        }
 
                                        /* lowercase variable name */
-                                       p = buf;
-                                       while (*p) {
-                                               *p = tolower(*p);
-                                               p++;
+                                       tmp_p = buf;
+                                       while (*tmp_p) {
+                                               *tmp_p = tolower(*tmp_p);
+                                               tmp_p++;
                                        }
 
                                        // create new object
@@ -3798,6 +3982,7 @@ static struct text_object_list *extract_variable_text_internal(const char *p)
                ERR("one or more $endif's are missing");
        }
 
+       free(orig_p);
        return retval;
 }
 
@@ -3805,25 +3990,37 @@ static void extract_variable_text(const char *p)
 {
        struct text_object_list *list;
 
-       free_text_objects(text_object_count, text_objects);
-       text_object_count = 0;
-       text_objects = NULL;
+       free_text_objects(global_text_object_count, global_text_objects);
+       if (tmpstring1) {
+               free(tmpstring1);
+               tmpstring1 = 0;
+       }
+       if (tmpstring2) {
+               free(tmpstring2);
+               tmpstring2 = 0;
+       }
+       if (text_buffer) {
+               free(text_buffer);
+               text_buffer = 0;
+       }
+       global_text_object_count = 0;
+       global_text_objects = NULL;
 
        list = extract_variable_text_internal(p);
-       text_objects = list->text_objects;
-       text_object_count = list->text_object_count;
+       global_text_objects = list->text_objects;
+       global_text_object_count = list->text_object_count;
 
        free(list);
 }
 
-void parse_conky_vars(char *text, char *p, struct information *cur)
+struct text_object_list *parse_conky_vars(char *text, char *p, struct information *cur)
 {
        struct text_object_list *object_list =
                extract_variable_text_internal(text);
 
-       generate_text_internal(p, P_MAX_SIZE, object_list->text_objects,
+       generate_text_internal(p, max_user_text, object_list->text_objects,
                object_list->text_object_count, cur);
-       free(object_list);
+       return object_list;
 }
 
 /* Allows reading from a FIFO (i.e., /dev/xconsole).
@@ -3907,6 +4104,46 @@ static void tail_pipe(struct text_object *obj, char *dst, size_t dst_size)
        snprintf(dst, dst_size, "%s", obj->data.tail.buffer);
 }
 
+char *format_time(unsigned long time, const int width)
+{
+       char buf[10];
+       unsigned long nt;       // narrow time, for speed on 32-bit
+       unsigned cc;            // centiseconds
+       unsigned nn;            // multi-purpose whatever
+
+       nt = time;
+       cc = nt % 100;          // centiseconds past second
+       nt /= 100;                      // total seconds
+       nn = nt % 60;           // seconds past the minute
+       nt /= 60;                       // total minutes
+       if (width >= snprintf(buf, sizeof buf, "%lu:%02u.%02u",
+                               nt, nn, cc)) {
+               return strdup(buf);
+       }
+       if (width >= snprintf(buf, sizeof buf, "%lu:%02u", nt, nn)) {
+               return strdup(buf);
+       }
+       nn = nt % 60;           // minutes past the hour
+       nt /= 60;                       // total hours
+       if (width >= snprintf(buf, sizeof buf, "%lu,%02u", nt, nn)) {
+               return strdup(buf);
+       }
+       nn = nt;                        // now also hours
+       if (width >= snprintf(buf, sizeof buf, "%uh", nn)) {
+               return strdup(buf);
+       }
+       nn /= 24;                       // now days
+       if (width >= snprintf(buf, sizeof buf, "%ud", nn)) {
+               return strdup(buf);
+       }
+       nn /= 7;                        // now weeks
+       if (width >= snprintf(buf, sizeof buf, "%uw", nn)) {
+               return strdup(buf);
+       }
+       // well shoot, this outta' fit...
+       return strdup("<inf>");
+}
+
 static void generate_text_internal(char *p, int p_max_size,
                struct text_object *objs, unsigned int object_count,
                struct information *cur)
@@ -3914,13 +4151,18 @@ static void generate_text_internal(char *p, int p_max_size,
        unsigned int i;
 
 #ifdef HAVE_ICONV
-       char buff_in[P_MAX_SIZE] = { 0 };
+       char buff_in[p_max_size];
+       buff_in[0] = 0;
        iconv_converting = 0;
 #endif
 
        for (i = 0; i < object_count; i++) {
                struct text_object *obj = &objs[i];
 
+               if (p_max_size < 1) {
+                       break;
+               };
+
 #define OBJ(a) break; case OBJ_##a:
 
                switch (obj->type) {
@@ -3994,7 +4236,7 @@ static void generate_text_internal(char *p, int p_max_size,
                        }
                        OBJ(wireless_link_qual_perc) {
                                if (obj->data.net->link_qual_max > 0) {
-                                       spaced_print(p, p_max_size, "%.0f%%", 5,
+                                       spaced_print(p, p_max_size, "%.0f", 5,
                                                "wireless_link_qual_perc",
                                                (double) obj->data.net->link_qual /
                                                obj->data.net->link_qual_max * 100);
@@ -4044,7 +4286,8 @@ static void generate_text_internal(char *p, int p_max_size,
                                get_battery_stuff(p, p_max_size, obj->data.s, BATTERY_TIME);
                        }
                        OBJ(battery_percent) {
-                               snprintf(p, p_max_size, "%d", get_battery_perct(obj->data.s));
+                               spaced_print(p, p_max_size, "%*d", 4, "battery_percent",
+                                               pad_percents, get_battery_perct(obj->data.s));
                        }
                        OBJ(battery_bar) {
                                new_bar(p, obj->a, obj->b, get_battery_perct_bar(obj->data.s));
@@ -4108,7 +4351,20 @@ static void generate_text_internal(char *p, int p_max_size,
                        OBJ(color9) {
                                new_fg(p, color9);
                        }
+                       OBJ(conky_version) {
+                               snprintf(p, p_max_size, "%s", VERSION);
+                       }
+                       OBJ(conky_build_date) {
+                               snprintf(p, p_max_size, "%s", BUILD_DATE);
+                       }
+                       OBJ(conky_build_arch) {
+                               snprintf(p, p_max_size, "%s", BUILD_ARCH);
+                       }
 #if defined(__linux__)
+                       OBJ(disk_protect) {
+                               snprintf(p, p_max_size, "%s",
+                                       get_disk_protect_queue(obj->data.s));
+                       }
                        OBJ(i8k_version) {
                                snprintf(p, p_max_size, "%s", i8k.version);
                        }
@@ -4191,6 +4447,32 @@ static void generate_text_internal(char *p, int p_max_size,
                        OBJ(ibm_brightness) {
                                get_ibm_acpi_brightness(p, p_max_size);
                        }
+                       OBJ(if_up) {
+                               if ((obj->data.ifblock.s)
+                                               && (!interface_up(obj->data.ifblock.s))) {
+                                       i = obj->data.ifblock.pos;
+                                       if_jumped = 1;
+                               } else {
+                                       if_jumped = 0;
+                               }
+                       }
+                       OBJ(if_gw) {
+                               if (!cur->gw_info.count) {
+                                       i = obj->data.ifblock.pos;
+                                       if_jumped = 1;
+                               } else {
+                                       if_jumped = 0;
+                               }
+                       }
+                       OBJ(gw_iface) {
+                               snprintf(p, p_max_size, "%s", cur->gw_info.iface);
+                       }
+                       OBJ(gw_ip) {
+                               snprintf(p, p_max_size, "%s", cur->gw_info.ip);
+                       }
+                       OBJ(laptop_mode) {
+                               snprintf(p, p_max_size, "%d", get_laptop_mode());
+                       }
                        OBJ(pb_battery) {
                                get_powerbook_batt_info(p, p_max_size, obj->data.i);
                        }
@@ -4316,6 +4598,18 @@ static void generate_text_internal(char *p, int p_max_size,
                                        obj->data.net->addr.sa_data[5] & 255);
                        }
 
+#if defined(__linux__)
+           OBJ(addrs) {
+                                    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");
+           }
+#endif /* __linux__ */
+
 #if defined(IMLIB2) && defined(X11)
                        OBJ(image) {
                                if (obj->a < 1) {
@@ -4355,20 +4649,42 @@ static void generate_text_internal(char *p, int p_max_size,
                                int length = fread(p, 1, p_max_size, fp);
 
                                pclose(fp);
-                               /* output[length] = '\0';
-                               if (length > 0 && output[length - 1] == '\n') {
-                                       output[length - 1] = '\0';
-                               } */
+
                                p[length] = '\0';
                                if (length > 0 && p[length - 1] == '\n') {
                                        p[length - 1] = '\0';
                                }
-                               // parse_conky_vars(output, p, cur);
+                       }
+                       OBJ(execp) {
+                               FILE *fp;
+                               struct information *my_info;
+                               struct text_object_list *text_objects;
+                               int length;
+
+                               fp = popen(obj->data.s, "r");
+                               fread(p, 1, p_max_size, fp);
+                               pclose(fp);
+
+                               my_info = malloc(sizeof(struct information));
+                               memcpy(my_info, cur, sizeof(struct information));
+                               text_objects = parse_conky_vars(p, p, my_info);
+
+                               length = strlen(p);
+
+                               p[length] = '\0';
+                               if (length > 0 && p[length - 1] == '\n') {
+                                       p[length - 1] = '\0';
+                               }
+
+                               free_text_objects(text_objects->text_object_count, text_objects->text_objects);
+                               free(text_objects);
+                               free(my_info);
                        }
                        OBJ(execbar) {
                                char *p2 = p;
                                FILE *fp = popen(obj->data.s, "r");
                                int n2 = fread(p, 1, p_max_size, fp);
+                               double barnum;
 
                                pclose(fp);
                                p[n2] = '\0';
@@ -4382,7 +4698,6 @@ static void generate_text_internal(char *p, int p_max_size,
                                        }
                                        p2++;
                                }
-                               double barnum;
 
                                if (sscanf(p, "%lf", &barnum) == 0) {
                                        ERR("reading execbar value failed (perhaps it's not the "
@@ -4400,6 +4715,7 @@ static void generate_text_internal(char *p, int p_max_size,
                                char *p2 = p;
                                FILE *fp = popen(obj->data.s, "r");
                                int n2 = fread(p, 1, p_max_size, fp);
+                               double barnum;
 
                                pclose(fp);
                                p[n2] = '\0';
@@ -4412,7 +4728,6 @@ static void generate_text_internal(char *p, int p_max_size,
                                        }
                                        p2++;
                                }
-                               double barnum;
 
                                if (sscanf(p, "%lf", &barnum) == 0) {
                                        ERR("reading execgraph value failed (perhaps it's not the "
@@ -4434,6 +4749,7 @@ static void generate_text_internal(char *p, int p_max_size,
                                        char *p2 = p;
                                        FILE *fp = popen(obj->data.execi.cmd, "r");
                                        int n2 = fread(p, 1, p_max_size, fp);
+                                       float barnum;
 
                                        pclose(fp);
                                        p[n2] = '\0';
@@ -4447,7 +4763,6 @@ static void generate_text_internal(char *p, int p_max_size,
                                                }
                                                p2++;
                                        }
-                                       float barnum;
 
                                        if (sscanf(p, "%f", &barnum) == 0) {
                                                ERR("reading execibar value failed (perhaps it's not "
@@ -4471,6 +4786,7 @@ static void generate_text_internal(char *p, int p_max_size,
                                        char *p2 = p;
                                        FILE *fp = popen(obj->data.execi.cmd, "r");
                                        int n2 = fread(p, 1, p_max_size, fp);
+                                       float barnum;
 
                                        pclose(fp);
                                        p[n2] = '\0';
@@ -4484,7 +4800,6 @@ static void generate_text_internal(char *p, int p_max_size,
                                                }
                                                p2++;
                                        }
-                                       float barnum;
 
                                        if (sscanf(p, "%f", &barnum) == 0) {
                                                ERR("reading execigraph value failed (perhaps it's not "
@@ -4510,7 +4825,6 @@ static void generate_text_internal(char *p, int p_max_size,
                                        char *output = obj->data.execi.buffer;
                                        FILE *fp = popen(obj->data.execi.cmd, "r");
 
-                                       // int length = fread(output, 1, text_buffer_size, fp);
                                        int length = fread(output, 1, text_buffer_size, fp);
 
                                        pclose(fp);
@@ -4523,10 +4837,39 @@ static void generate_text_internal(char *p, int p_max_size,
                                }
                                // parse_conky_vars(output, p, cur);
                        }
+                       OBJ(execpi) {
+                               struct text_object_list *text_objects = 0;
+                               struct information *my_info =
+                                       malloc(sizeof(struct information));
+                               memcpy(my_info, cur, sizeof(struct information));
+
+                               if (current_update_time - obj->data.execi.last_update
+                                               < obj->data.execi.interval
+                                               || obj->data.execi.interval == 0) {
+                                       text_objects = parse_conky_vars(obj->data.execi.buffer, p, my_info);
+                               } else {
+                                       char *output = obj->data.execi.buffer;
+                                       FILE *fp = popen(obj->data.execi.cmd, "r");
+                                       int length = fread(output, 1, text_buffer_size, fp);
+
+                                       pclose(fp);
+
+                                       output[length] = '\0';
+                                       if (length > 0 && output[length - 1] == '\n') {
+                                               output[length - 1] = '\0';
+                                       }
+                                       
+                                       text_objects = parse_conky_vars(obj->data.execi.buffer, p, my_info);
+                                       obj->data.execi.last_update = current_update_time;
+                               }
+                               free_text_objects(text_objects->text_object_count, text_objects->text_objects);
+                               free(text_objects);
+                               free(my_info);
+                       }
                        OBJ(texeci) {
                                if (!obj->data.texeci.p_timed_thread) {
                                        obj->data.texeci.p_timed_thread =
-                                               timed_thread_create((void *) threaded_exec,
+                                               timed_thread_create(&threaded_exec,
                                                (void *) obj, obj->data.texeci.interval * 1000000);
                                        if (!obj->data.texeci.p_timed_thread) {
                                                ERR("Error creating texeci timed thread");
@@ -4547,7 +4890,7 @@ static void generate_text_internal(char *p, int p_max_size,
                                        // this means we use info
                                        if (!info.mail->p_timed_thread) {
                                                info.mail->p_timed_thread =
-                                                       timed_thread_create((void *) imap_thread,
+                                                       timed_thread_create(&imap_thread,
                                                        (void *) info.mail, info.mail->interval * 1000000);
                                                if (!info.mail->p_timed_thread) {
                                                        ERR("Error creating imap timed thread");
@@ -4565,7 +4908,7 @@ static void generate_text_internal(char *p, int p_max_size,
                                        // this means we use obj
                                        if (!obj->data.mail->p_timed_thread) {
                                                obj->data.mail->p_timed_thread =
-                                                       timed_thread_create((void *) imap_thread,
+                                                       timed_thread_create(&imap_thread,
                                                        (void *) obj->data.mail,
                                                        obj->data.mail->interval * 1000000);
                                                if (!obj->data.mail->p_timed_thread) {
@@ -4593,7 +4936,7 @@ static void generate_text_internal(char *p, int p_max_size,
                                        // this means we use info
                                        if (!info.mail->p_timed_thread) {
                                                info.mail->p_timed_thread =
-                                                       timed_thread_create((void *) imap_thread,
+                                                       timed_thread_create(&imap_thread,
                                                        (void *) info.mail, info.mail->interval * 1000000);
                                                if (!info.mail->p_timed_thread) {
                                                        ERR("Error creating imap timed thread");
@@ -4611,7 +4954,7 @@ static void generate_text_internal(char *p, int p_max_size,
                                        // this means we use obj
                                        if (!obj->data.mail->p_timed_thread) {
                                                obj->data.mail->p_timed_thread =
-                                                       timed_thread_create((void *) imap_thread,
+                                                       timed_thread_create(&imap_thread,
                                                        (void *) obj->data.mail,
                                                        obj->data.mail->interval * 1000000);
                                                if (!obj->data.mail->p_timed_thread) {
@@ -4639,7 +4982,7 @@ static void generate_text_internal(char *p, int p_max_size,
                                        // this means we use info
                                        if (!info.mail->p_timed_thread) {
                                                info.mail->p_timed_thread =
-                                                       timed_thread_create((void *) pop3_thread,
+                                                       timed_thread_create(&pop3_thread,
                                                        (void *) info.mail, info.mail->interval * 1000000);
                                                if (!info.mail->p_timed_thread) {
                                                        ERR("Error creating pop3 timed thread");
@@ -4657,7 +5000,7 @@ static void generate_text_internal(char *p, int p_max_size,
                                        // this means we use obj
                                        if (!obj->data.mail->p_timed_thread) {
                                                obj->data.mail->p_timed_thread =
-                                                       timed_thread_create((void *) pop3_thread,
+                                                       timed_thread_create(&pop3_thread,
                                                        (void *) obj->data.mail,
                                                        obj->data.mail->interval * 1000000);
                                                if (!obj->data.mail->p_timed_thread) {
@@ -4685,7 +5028,7 @@ static void generate_text_internal(char *p, int p_max_size,
                                        // this means we use info
                                        if (!info.mail->p_timed_thread) {
                                                info.mail->p_timed_thread =
-                                                       timed_thread_create((void *) pop3_thread,
+                                                       timed_thread_create(&pop3_thread,
                                                        (void *) info.mail, info.mail->interval * 1000000);
                                                if (!info.mail->p_timed_thread) {
                                                        ERR("Error creating pop3 timed thread");
@@ -4704,7 +5047,7 @@ static void generate_text_internal(char *p, int p_max_size,
                                        // this means we use obj
                                        if (!obj->data.mail->p_timed_thread) {
                                                obj->data.mail->p_timed_thread =
-                                                       timed_thread_create((void *) pop3_thread,
+                                                       timed_thread_create(&pop3_thread,
                                                        (void *) obj->data.mail,
                                                        obj->data.mail->interval * 1000000);
                                                if (!obj->data.mail->p_timed_thread) {
@@ -4747,9 +5090,9 @@ static void generate_text_internal(char *p, int p_max_size,
                        OBJ(fs_free_perc) {
                                if (obj->data.fs != NULL) {
                                        if (obj->data.fs->size) {
-                                               snprintf(p, p_max_size, "%*d", pad_percents,
-                                                       (int) ((obj->data.fs->avail * 100) /
-                                                       obj->data.fs->size));
+                                               spaced_print(p, p_max_size, "%*d", 4, "fs_free_perc",
+                                                               pad_percents, (int) ((obj->data.fs->avail * 100) /
+                                                                       obj->data.fs->size));
                                        } else {
                                                snprintf(p, p_max_size, "0");
                                        }
@@ -4760,6 +5103,10 @@ static void generate_text_internal(char *p, int p_max_size,
                                        human_readable(obj->data.fs->size, p, 255, "fs_size");
                                }
                        }
+                       OBJ(fs_type) {
+                               if (obj->data.fs != NULL)
+                                       snprintf(p, p_max_size, "%s", obj->data.fs->type);
+                       }
                        OBJ(fs_used) {
                                if (obj->data.fs != NULL) {
                                        human_readable(obj->data.fs->size - (obj->data.fs->free
@@ -4781,9 +5128,9 @@ static void generate_text_internal(char *p, int p_max_size,
                        OBJ(fs_used_perc) {
                                if (obj->data.fs != NULL) {
                                        if (obj->data.fs->size) {
-                                               snprintf(p, 4, "%d",
-                                                       100 - ((int) ((obj->data.fs->avail * 100) /
-                                                       obj->data.fs->size)));
+                                               spaced_print(p, 4, "%*d", 4, "fs_used_perc",
+                                                               pad_percents, 100 - ((int) ((obj->data.fs->avail * 100) /
+                                                                               obj->data.fs->size)));
                                        } else {
                                                snprintf(p, p_max_size, "0");
                                        }
@@ -4815,6 +5162,11 @@ static void generate_text_internal(char *p, int p_max_size,
                        OBJ(hr) {
                                new_hr(p, obj->data.i);
                        }
+                       OBJ(nameserver) {
+                               if (cur->nameserver_info.nscount > obj->data.i)
+                                       snprintf(p, p_max_size, "%s",
+                                                       cur->nameserver_info.ns_list[obj->data.i]);
+                       }
 #ifdef RSS
                        OBJ(rss) {
                                PRSS *data = get_rss_info(obj->data.rss.uri,
@@ -4853,9 +5205,9 @@ static void generate_text_internal(char *p, int p_max_size,
                                        } else if (!strcmp(obj->data.rss.action, "item_titles")) {
                                                if (data->item_count > 0) {
                                                        int itmp;
+                                                       int show;
 
                                                        p[0] = 0;
-                                                       int show;
 
                                                        if (obj->data.rss.act_par > data->item_count) {
                                                                show = data->item_count;
@@ -4951,11 +5303,12 @@ static void generate_text_internal(char *p, int p_max_size,
                                new_alignc(p, obj->data.i);
                        }
                        OBJ(if_empty) {
+                               struct text_object_list *text_objects;
                                struct information *my_info =
                                        malloc(sizeof(struct information));
-
                                memcpy(my_info, cur, sizeof(struct information));
-                               parse_conky_vars(obj->data.ifblock.s, p, my_info);
+                               text_objects = parse_conky_vars(obj->data.ifblock.s, p, my_info);
+
                                if (strlen(p) != 0) {
                                        i = obj->data.ifblock.pos;
                                        if_jumped = 1;
@@ -4963,6 +5316,8 @@ static void generate_text_internal(char *p, int p_max_size,
                                        if_jumped = 0;
                                }
                                p[0] = '\0';
+                               free_text_objects(text_objects->text_object_count, text_objects->text_objects);
+                               free(text_objects);
                                free(my_info);
                        }
                        OBJ(if_existing) {
@@ -5003,6 +5358,9 @@ static void generate_text_internal(char *p, int p_max_size,
                                        if_jumped = 0;
                                }
                        }
+                       OBJ(ioscheduler) {
+                               snprintf(p, p_max_size, "%s", get_ioscheduler(obj->data.s));
+                       }
                        OBJ(kernel) {
                                snprintf(p, p_max_size, "%s", cur->uname_s.release);
                        }
@@ -5019,7 +5377,7 @@ static void generate_text_internal(char *p, int p_max_size,
                        }
                        OBJ(memperc) {
                                if (cur->memmax) {
-                                       spaced_print(p, p_max_size, "%*Lu", 4, "memperc",
+                                       spaced_print(p, p_max_size, "%*llu", 4, "memperc",
                                                pad_percents, cur->mem * 100 / cur->memmax);
                                }
                        }
@@ -5063,7 +5421,7 @@ static void generate_text_internal(char *p, int p_max_size,
                        }
                        OBJ(mboxscan) {
                                mbox_scan(obj->data.mboxscan.args, obj->data.mboxscan.output,
-                                       TEXT_BUFFER_SIZE);
+                                       text_buffer_size);
                                snprintf(p, p_max_size, "%s", obj->data.mboxscan.output);
                        }
                        OBJ(new_mails) {
@@ -5102,7 +5460,7 @@ static void generate_text_internal(char *p, int p_max_size,
                                if (cur->swapmax == 0) {
                                        strncpy(p, "No swap", p_max_size);
                                } else {
-                                       spaced_print(p, p_max_size, "%*Lu", 4, "swapperc",
+                                       spaced_print(p, p_max_size, "%*llu", 4, "swapperc",
                                                pad_percents, cur->swap * 100 / cur->swapmax);
                                }
                        }
@@ -5128,14 +5486,16 @@ static void generate_text_internal(char *p, int p_max_size,
                        }
                        OBJ(tztime) {
                                char *oldTZ = NULL;
+                               time_t t;
+                               struct tm *tm;
 
                                if (obj->data.tztime.tz) {
                                        oldTZ = getenv("TZ");
                                        setenv("TZ", obj->data.tztime.tz, 1);
                                        tzset();
                                }
-                               time_t t = time(NULL);
-                               struct tm *tm = localtime(&t);
+                               t = time(NULL);
+                               tm = localtime(&t);
 
                                setlocale(LC_TIME, "");
                                strftime(p, p_max_size, obj->data.tztime.fmt, tm);
@@ -5174,7 +5534,18 @@ static void generate_text_internal(char *p, int p_max_size,
                        OBJ(uptime) {
                                format_seconds(p, p_max_size, (int) cur->uptime);
                        }
-
+                       OBJ(user_names) {
+                               snprintf(p, p_max_size, "%s", cur->users.names);
+                       }
+                       OBJ(user_terms) {
+                               snprintf(p, p_max_size, "%s", cur->users.terms);
+                       }
+                       OBJ(user_times) {
+                               snprintf(p, p_max_size, "%s", cur->users.times);
+                       }
+                       OBJ(user_number) {
+                               snprintf(p, p_max_size, "%d", cur->users.number);
+                       }
 #if (defined(__FreeBSD__) || defined(__FreeBSD_kernel__) \
                || defined(__OpenBSD__)) && (defined(i386) || defined(__i386__))
                        OBJ(apm_adapter) {
@@ -5291,7 +5662,8 @@ static void generate_text_internal(char *p, int p_max_size,
                                }
                        }
                        OBJ(mpd_percent) {
-                               snprintf(p, p_max_size, "%2.0f", cur->mpd.progress * 100);
+                               spaced_print(p, p_max_size, "%*d", 4, "mpd_percent",
+                                               pad_percents, (int) (cur->mpd.progress * 100));
                        }
                        OBJ(mpd_bar) {
                                new_bar(p, obj->data.pair.a, obj->data.pair.b,
@@ -5331,12 +5703,6 @@ static void generate_text_internal(char *p, int p_max_size,
                        OBJ(xmms2_comment) {
                                snprintf(p, p_max_size, "%s", cur->xmms2.comment);
                        }
-                       OBJ(xmms2_decoder) {
-                               snprintf(p, p_max_size, "%s", cur->xmms2.decoder);
-                       }
-                       OBJ(xmms2_transport) {
-                               snprintf(p, p_max_size, "%s", cur->xmms2.transport);
-                       }
                        OBJ(xmms2_url) {
                                snprintf(p, p_max_size, "%s", cur->xmms2.url);
                        }
@@ -5376,6 +5742,12 @@ static void generate_text_internal(char *p, int p_max_size,
                                new_bar(p, obj->data.pair.a, obj->data.pair.b,
                                        (int) (cur->xmms2.progress * 255.0f));
                        }
+                       OBJ(xmms2_playlist) {
+                               snprintf(p, p_max_size, "%s", cur->xmms2.playlist);
+                       }
+                       OBJ(xmms2_timesplayed) {
+                               snprintf(p, p_max_size, "%i", cur->xmms2.timesplayed);
+                       }
                        OBJ(xmms2_smart) {
                                if (strlen(cur->xmms2.title) < 2
                                                && strlen(cur->xmms2.title) < 2) {
@@ -5466,47 +5838,6 @@ static void generate_text_internal(char *p, int p_max_size,
                                snprintf(p, p_max_size, "%i", cur->bmpx.bitrate);
                        }
 #endif
-
-                       char *format_time(unsigned long time, const int width)
-                       {
-                               char buf[10];
-                               unsigned long nt;       // narrow time, for speed on 32-bit
-                               unsigned cc;            // centiseconds
-                               unsigned nn;            // multi-purpose whatever
-
-                               nt = time;
-                               cc = nt % 100;          // centiseconds past second
-                               nt /= 100;                      // total seconds
-                               nn = nt % 60;           // seconds past the minute
-                               nt /= 60;                       // total minutes
-                               if (width >= snprintf(buf, sizeof buf, "%lu:%02u.%02u",
-                                               nt, nn, cc)) {
-                                       return strdup(buf);
-                               }
-                               if (width >= snprintf(buf, sizeof buf, "%lu:%02u", nt, nn)) {
-                                       return strdup(buf);
-                               }
-                               nn = nt % 60;           // minutes past the hour
-                               nt /= 60;                       // total hours
-                               if (width >= snprintf(buf, sizeof buf, "%lu,%02u", nt, nn)) {
-                                       return strdup(buf);
-                               }
-                               nn = nt;                        // now also hours
-                               if (width >= snprintf(buf, sizeof buf, "%uh", nn)) {
-                                       return strdup(buf);
-                               }
-                               nn /= 24;                       // now days
-                               if (width >= snprintf(buf, sizeof buf, "%ud", nn)) {
-                                       return strdup(buf);
-                               }
-                               nn /= 7;                        // now weeks
-                               if (width >= snprintf(buf, sizeof buf, "%uw", nn)) {
-                                       return strdup(buf);
-                               }
-                               // well shoot, this outta' fit...
-                               return strdup("<inf>");
-                       }
-
                        OBJ(top) {
                                if (obj->data.top.num >= 0 && obj->data.top.num < 10) {
                                        char *time;
@@ -5553,7 +5884,7 @@ static void generate_text_internal(char *p, int p_max_size,
                                                        break;
                                                case TOP_CPU:
                                                        snprintf(p, 7, "%6.2f",
-                                                               cur->memu[obj->data.top.num]->cpu_perc);
+                                                               cur->memu[obj->data.top.num]->amount);
                                                        break;
                                                case TOP_PID:
                                                        snprintf(p, 6, "%5i",
@@ -5583,11 +5914,12 @@ static void generate_text_internal(char *p, int p_max_size,
                                                < obj->data.tail.interval) {
                                        snprintf(p, p_max_size, "%s", obj->data.tail.buffer);
                                } else {
-                                       obj->data.tail.last_update = current_update_time;
                                        FILE *fp;
                                        long nl = 0, bsize;
                                        int iter;
 
+                                       obj->data.tail.last_update = current_update_time;
+
                                        if (obj->data.tail.fd != -1) {
                                                tail_pipe(obj, p, p_max_size);
                                                goto head;
@@ -5659,11 +5991,12 @@ head:
                                                < obj->data.tail.interval) {
                                        snprintf(p, p_max_size, "%s", obj->data.tail.buffer);
                                } else {
-                                       obj->data.tail.last_update = current_update_time;
                                        FILE *fp;
                                        long nl = 0;
                                        int iter;
 
+                                       obj->data.tail.last_update = current_update_time;
+
                                        fp = fopen(obj->data.tail.logfile, "rt");
                                        if (fp == NULL) {
                                                /* Send one message, but do not consistently spam
@@ -5758,6 +6091,43 @@ head:
                                        (double) cur->entropy.poolsize;
                                new_bar(p, obj->a, obj->b, (int) (entropy_perc * 255.0f));
                        }
+#ifdef SMAPI
+                       OBJ(smapi) {
+                               char *s;
+                               if(obj->data.s) {
+                                       s = smapi_get_val(obj->data.s);
+                                       snprintf(p, p_max_size, "%s", s);
+                                       free(s);
+                               }
+                       }
+                       OBJ(if_smapi_bat_installed) {
+                               int idx;
+                               if(obj->data.ifblock.s && sscanf(obj->data.ifblock.s, "%i", &idx) == 1) {
+                                       if(!smapi_bat_installed(idx)) {
+                                               i = obj->data.ifblock.pos;
+                                               if_jumped = 1;
+                                       } else
+                                               if_jumped = 0;
+                               } else
+                                       ERR("argument to if_smapi_bat_installed must be an integer");
+                       }
+                       OBJ(smapi_bat_perc) {
+                               int idx, val;
+                               if(obj->data.s && sscanf(obj->data.s, "%i", &idx) == 1) {
+                                       val = smapi_bat_installed(idx) ?
+                                               smapi_get_bat_int(idx, "remaining_percent") : 0;
+                                       spaced_print(p, p_max_size, "%*d", 4, "smapi_bat_perc", pad_percents, val);
+                               } else
+                                       ERR("argument to smapi_bat_perc must be an integer");
+                       }
+                       OBJ(smapi_bat_bar) {
+                               if(obj->data.i >= 0 && smapi_bat_installed(obj->data.i))
+                                       new_bar(p, obj->a, obj->b, (int)
+                                                       (255 * smapi_get_bat_int(obj->data.i, "remaining_percent") / 100));
+                               else
+                                       new_bar(p, obj->a, obj->b, 0);
+                       }
+#endif /* SMAPI */
 
                        break;
                }
@@ -5775,12 +6145,12 @@ head:
 
                                dummy1 = dummy2 = a;
 
-                               strncpy(buff_in, p, P_MAX_SIZE);
+                               strncpy(buff_in, p, p_max_size);
 
                                iconv(*iconv_cd[iconv_selected - 1], NULL, NULL, NULL, NULL);
                                while (dummy1 > 0) {
                                        bytes = iconv(*iconv_cd[iconv_selected - 1], &ptr, &dummy1,
-                                               &outptr, &dummy2);
+                                                       &outptr, &dummy2);
                                        if (bytes == -1) {
                                                ERR("Iconv codeset conversion failed");
                                                break;
@@ -5791,7 +6161,7 @@ head:
                                 * singlebyte codepage */
                                a = outptr - p;
                        }
-#endif
+#endif /* HAVE_ICONV */
                        p += a;
                        p_max_size -= a;
                }
@@ -5800,7 +6170,7 @@ head:
 
 double current_update_time, last_update_time;
 
-static void generate_text()
+static void generate_text(void)
 {
        struct information *cur = &info;
        char *p;
@@ -5811,7 +6181,7 @@ static void generate_text()
 
        current_update_time = get_time();
 
-       update_stuff(cur);
+       update_stuff();
        /* fix diskio rates to b/s (use update_interval */
        diskio_read_value = diskio_read_value / update_interval;
        diskio_write_value = diskio_write_value / update_interval;
@@ -5823,7 +6193,8 @@ static void generate_text()
 
        p = text_buffer;
 
-       generate_text_internal(p, P_MAX_SIZE, text_objects, text_object_count, cur);
+       generate_text_internal(p, max_user_text, global_text_objects,
+                       global_text_object_count, cur);
 
        if (stuff_in_upper_case) {
                char *p;
@@ -5841,7 +6212,7 @@ static void generate_text()
 }
 
 #ifdef X11
-static void set_font()
+static void set_font(void)
 {
 #ifdef XFT
        if (use_xft) {
@@ -5870,17 +6241,18 @@ static inline int get_string_width(const char *s)
 
 static inline int get_string_width_special(char *s)
 {
+#ifdef X11
+       char *p, *final;
+       int index = 1;
+       int width = 0;
+       unsigned int i;
+
        if (!s) {
                return 0;
        }
-#ifdef X11
-       char *p, *final;
 
        p = strdup(s);
        final = p;
-       int index = 1;
-       int width = 0;
-       unsigned int i;
 
        while (*p) {
                if (*p == SPECIAL_CHAR) {
@@ -5904,7 +6276,7 @@ static inline int get_string_width_special(char *s)
        free(final);
        return width;
 #else
-       return strlen(s);
+       return (s) ? strlen(s) : 0;
 #endif /* X11 */
 }
 
@@ -5912,7 +6284,7 @@ static inline int get_string_width_special(char *s)
 static void text_size_updater(char *s);
 
 int last_font_height;
-static void update_text_area()
+static void update_text_area(void)
 {
        int x, y;
 
@@ -5947,6 +6319,11 @@ static void update_text_area()
                        y = gap_y;
                        break;
 
+               case TOP_MIDDLE:
+                       x = workarea[2] / 2 - text_width / 2 - gap_x;
+                       y = gap_y;
+                       break;
+
                default:
                case BOTTOM_LEFT:
                        x = gap_x;
@@ -5958,6 +6335,21 @@ static void update_text_area()
                        y = workarea[3] - text_height - gap_y;
                        break;
 
+               case BOTTOM_MIDDLE:
+                       x = workarea[2] / 2 - text_width / 2 - gap_x;
+                       y = workarea[3] - text_height - gap_y;
+                       break;
+
+               case MIDDLE_LEFT:
+                       x = gap_x;
+                       y = workarea[3] / 2 - text_height / 2 - gap_y;
+                       break;
+
+               case MIDDLE_RIGHT:
+                       x = workarea[2] - text_width - gap_x;
+                       y = workarea[3] / 2 - text_height / 2 - gap_y;
+                       break;
+
 #ifdef OWN_WINDOW
                case NONE:      // Let the WM manage the window
                        x = window.x;
@@ -6072,24 +6464,25 @@ static inline void set_foreground_color(long c)
 
 static void draw_string(const char *s)
 {
-       if (s[0] == '\0') {
-               return;
-       }
        int i, i2, pos, width_of_s;
        int max = 0;
        int added;
+       char space[2];
+
+       if (s[0] == '\0') {
+               return;
+       }
 
        width_of_s = get_string_width(s);
        if (out_to_console) {
                printf("%s\n", s);
                fflush(stdout); /* output immediately, don't buffer */
        }
-       memset(tmpstring1, 0, TEXT_BUFFER_SIZE);
-       memset(tmpstring2, 0, TEXT_BUFFER_SIZE);
-       strncpy(tmpstring1, s, TEXT_BUFFER_SIZE - 1);
+       memset(tmpstring1, 0, text_buffer_size);
+       memset(tmpstring2, 0, text_buffer_size);
+       strncpy(tmpstring1, s, text_buffer_size - 1);
        pos = 0;
        added = 0;
-       char space[2];
 
        snprintf(space, 2, " ");
 #ifdef X11
@@ -6098,25 +6491,19 @@ static void draw_string(const char *s)
        /* This code looks for tabs in the text and coverts them to spaces.
         * The trick is getting the correct number of spaces, and not going
         * over the window's size without forcing the window larger. */
-       for (i = 0; i < TEXT_BUFFER_SIZE; i++) {
+       for (i = 0; i < (int)text_buffer_size; i++) {
                if (tmpstring1[i] == '\t') {    // 9 is ascii tab
                        i2 = 0;
                        for (i2 = 0; i2 < (8 - (1 + pos) % 8) && added <= max; i2++) {
-                               /* if (pos + i2 > TEXT_BUFFER_SIZE - 1) {
-                                       fprintf(stderr, "buffer overrun detected\n");
-                               } */
                                /* guard against overrun */
-                               tmpstring2[MIN(pos + i2, TEXT_BUFFER_SIZE - 1)] = ' ';
+                               tmpstring2[MIN(pos + i2, (int)text_buffer_size - 1)] = ' ';
                                added++;
                        }
                        pos += i2;
                } else {
                        if (tmpstring1[i] != 9) {
-                               /* if (pos > TEXT_BUFFER_SIZE - 1) {
-                                       fprintf(stderr, "buffer overrun detected\n");
-                               } */
                                /* guard against overrun */
-                               tmpstring2[MIN(pos, TEXT_BUFFER_SIZE - 1)] = tmpstring1[i];
+                               tmpstring2[MIN(pos, (int)text_buffer_size - 1)] = tmpstring1[i];
                                pos++;
                        }
                }
@@ -6148,10 +6535,10 @@ static void draw_string(const char *s)
                c2.color.alpha = fonts[selected_font].font_alpha;
                if (utf8_mode) {
                        XftDrawStringUtf8(window.xftdraw, &c2, fonts[selected_font].xftfont,
-                               cur_x, cur_y, (XftChar8 *) s, strlen(s));
+                               cur_x, cur_y, (const XftChar8 *) s, strlen(s));
                } else {
                        XftDrawString8(window.xftdraw, &c2, fonts[selected_font].xftfont,
-                               cur_x, cur_y, (XftChar8 *) s, strlen(s));
+                               cur_x, cur_y, (const XftChar8 *) s, strlen(s));
                }
        } else
 #endif
@@ -6161,13 +6548,14 @@ static void draw_string(const char *s)
        }
        cur_x += width_of_s;
 #endif /* X11 */
-       memcpy(tmpstring1, s, TEXT_BUFFER_SIZE);
+       memcpy(tmpstring1, s, text_buffer_size);
 }
 
 long redmask, greenmask, bluemask;
 
-void set_up_gradient()
+void set_up_gradient(void)
 {
+       int i;
 #ifdef X11
        colour_depth = DisplayPlanes(display, screen);
 #else
@@ -6177,7 +6565,6 @@ void set_up_gradient()
                ERR("using non-standard colour depth, gradients may look like a "
                        "lolly-pop");
        }
-       int i;
 
        redmask = 0;
        greenmask = 0;
@@ -6258,14 +6645,17 @@ inline unsigned long do_gradient(unsigned long first_colour,
 inline unsigned long gradient_max(unsigned long first_colour,
                unsigned long last_colour)
 {
+       int red1, green1, blue1;                                // first colour
+       int red2, green2, blue2;                                // second colour
+       int red3 = 0, green3 = 0, blue3 = 0;                    // difference
+       long redshift, greenshift;
+       int max;
+
        if (colour_depth == 0) {
                set_up_gradient();
        }
-       int red1, green1, blue1;                                // first colour
-       int red2, green2, blue2;                                // second colour
-       long redshift = (2 * colour_depth / 3 + colour_depth % 3);
-       long greenshift = (colour_depth / 3);
-       int red3 = 0, green3 = 0, blue3 = 0;    // difference
+       redshift = (2 * colour_depth / 3 + colour_depth % 3);
+       greenshift = (colour_depth / 3);
 
        red1 = (first_colour & redmask) >> redshift;
        green1 = (first_colour & greenmask) >> greenshift;
@@ -6276,7 +6666,7 @@ inline unsigned long gradient_max(unsigned long first_colour,
        red3 = abs(red1 - red2);
        green3 = abs(green1 - green2);
        blue3 = abs(blue1 - blue2);
-       int max = red3;
+       max = red3;
 
        if (green3 > max) {
                max = green3;
@@ -6291,11 +6681,12 @@ static void draw_line(char *s)
 {
 #ifdef X11
        char *p;
+       int cur_y_add = 0;
+       short font_h;
 
        cur_x = text_start_x;
        cur_y += font_ascent();
-       int cur_y_add = 0;
-       short font_h = font_height();
+       font_h = font_height();
 
        /* find specials and draw stuff */
        p = s;
@@ -6343,13 +6734,14 @@ static void draw_line(char *s)
 
                                case BAR:
                                {
+                                       int h, bar_usage, by;
                                        if (cur_x - text_start_x > maximum_width
                                                        && maximum_width > 0) {
                                                break;
                                        }
-                                       int h = specials[special_index].height;
-                                       int bar_usage = specials[special_index].arg;
-                                       int by = cur_y - (font_ascent() / 2) - 1;
+                                       h = specials[special_index].height;
+                                       bar_usage = specials[special_index].arg;
+                                       by = cur_y - (font_ascent() / 2) - 1;
 
                                        if (h < font_height()) {
                                                by -= h / 2 - 1;
@@ -6378,13 +6770,18 @@ static void draw_line(char *s)
 
                                case GRAPH:
                                {
+                                       int h, by, i, j = 0;
+                                       int gradient_size = 0;
+                                       float gradient_factor = 0;
+                                       float gradient_update = 0;
+                                       unsigned long last_colour = current_color;
+                                       unsigned long tmpcolour = current_color;
                                        if (cur_x - text_start_x > maximum_width
                                                        && maximum_width > 0) {
                                                break;
                                        }
-                                       int h = specials[special_index].height;
-                                       unsigned long last_colour = current_color;
-                                       int by = cur_y - (font_ascent() / 2) - 1;
+                                       h = specials[special_index].height;
+                                       by = cur_y - (font_ascent() / 2) - 1;
 
                                        if (h < font_height()) {
                                                by -= h / 2 - 1;
@@ -6404,12 +6801,6 @@ static void draw_line(char *s)
                                        }
                                        XSetLineAttributes(display, window.gc, 1, LineSolid,
                                                CapButt, JoinMiter);
-                                       int i;
-                                       int j = 0;
-                                       int gradient_size = 0;
-                                       float gradient_factor = 0;
-                                       float gradient_update = 0;
-                                       unsigned long tmpcolour = current_color;
 
                                        if (specials[special_index].last_colour != 0
                                                        || specials[special_index].first_colour != 0) {
@@ -6575,7 +6966,7 @@ static void draw_line(char *s)
 #endif /* X11 */
 }
 
-static void draw_text()
+static void draw_text(void)
 {
 #ifdef X11
        cur_y = text_start_y;
@@ -6606,7 +6997,7 @@ static void draw_text()
        for_each_line(text_buffer, draw_line);
 }
 
-static void draw_stuff()
+static void draw_stuff(void)
 {
 #ifdef X11
        selected_font = 0;
@@ -6621,8 +7012,8 @@ static void draw_stuff()
        }
 
        if (draw_outline) {
-               selected_font = 0;
                int i, j;
+               selected_font = 0;
 
                for (i = -1; i < 2; i++) {
                        for (j = -1; j < 2; j++) {
@@ -6679,7 +7070,7 @@ static void clear_text(int exposures)
 static int need_to_update;
 
 /* update_text() generates new text and clears old text area */
-static void update_text()
+static void update_text(void)
 {
        generate_text();
 #ifdef X11
@@ -6688,35 +7079,35 @@ static void update_text()
        need_to_update = 1;
 }
 
-static void main_loop()
+static void main_loop(void)
 {
 #ifdef SIGNAL_BLOCKING
        sigset_t newmask, oldmask;
-
-       sigemptyset(&newmask);
-       sigaddset(&newmask, SIGINT);
-       sigaddset(&newmask, SIGTERM);
-       sigaddset(&newmask, SIGUSR1);
 #endif
-
 #ifdef X11
        Region region = XCreateRegion();
 
 #ifdef HAVE_XDAMAGE
+       Damage damage;
+       XserverRegion region2, part;
        int event_base, error_base;
 
        if (!XDamageQueryExtension(display, &event_base, &error_base)) {
                ERR("Xdamage extension unavailable");
        }
-       Damage damage = XDamageCreate(display, window.window,
-               XDamageReportNonEmpty);
-       XserverRegion region2 = XFixesCreateRegionFromWindow(display,
-               window.window, 0);
-       XserverRegion part = XFixesCreateRegionFromWindow(display,
-               window.window, 0);
+       damage = XDamageCreate(display, window.window, XDamageReportNonEmpty);
+       region2 = XFixesCreateRegionFromWindow(display, window.window, 0);
+       part = XFixesCreateRegionFromWindow(display, window.window, 0);
 #endif /* HAVE_XDAMAGE */
 #endif /* X11 */
 
+#ifdef SIGNAL_BLOCKING
+       sigemptyset(&newmask);
+       sigaddset(&newmask, SIGINT);
+       sigaddset(&newmask, SIGTERM);
+       sigaddset(&newmask, SIGUSR1);
+#endif
+
        info.looped = 0;
        while (total_run_times == 0 || info.looped < total_run_times) {
                info.looped++;
@@ -6981,8 +7372,9 @@ static void main_loop()
 #endif
 
                switch (g_signal_pending) {
+                       case SIGHUP:
                        case SIGUSR1:
-                               ERR("received SIGUSR1. reloading the config file.");
+                               ERR("received SIGHUP or SIGUSR1. reloading the config file.");
                                reload_config();
                                break;
                        case SIGINT:
@@ -6992,6 +7384,11 @@ static void main_loop()
 #ifdef X11
                                XDestroyRegion(region);
                                region = NULL;
+#ifdef HAVE_XDAMAGE
+                               XDamageDestroy(display, damage);
+                               XFixesDestroyRegion(display, region2);
+                               XFixesDestroyRegion(display, part);
+#endif /* HAVE_XDAMAGE */
 #endif /* X11 */
                                return; /* return from main_loop */
                                /* break; */
@@ -7075,6 +7472,8 @@ void reload_config(void)
 
 #ifdef X11
        free_fonts();
+       load_fonts();
+       set_font();
 #endif /* X11 */
 
 #ifdef TCP_PORT_MONITOR
@@ -7092,9 +7491,6 @@ void reload_config(void)
                }
 
 #ifdef X11
-               load_fonts();
-               set_font();
-
                // clear the window first
                XClearWindow(display, RootWindow(display, screen));
 
@@ -7102,16 +7498,24 @@ void reload_config(void)
 #ifdef TCP_PORT_MONITOR
                info.p_tcp_port_monitor_collection = NULL;
 #endif
-#ifdef AUDACIOUS
-               if (create_audacious_thread() != 0) {
-                       CRIT_ERR("unable to create audacious thread!");
-               }
-               timed_thread_register(info.audacious.p_timed_thread,
-                       &info.audacious.p_timed_thread);
-#endif
                extract_variable_text(text);
                free(text);
                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);
                update_text();
        }
 }
@@ -7147,12 +7551,25 @@ void clean_up(void)
        free_fonts();
 #endif /* X11 */
 
-       free_text_objects(text_object_count, text_objects);
-       text_object_count = 0;
-       text_objects = NULL;
+       free_text_objects(global_text_object_count, global_text_objects);
+       if (tmpstring1) {
+               free(tmpstring1);
+               tmpstring1 = 0;
+       }
+       if (tmpstring2) {
+               free(tmpstring2);
+               tmpstring2 = 0;
+       }
+       if (text_buffer) {
+               free(text_buffer);
+               text_buffer = 0;
+       }
+       global_text_object_count = 0;
+       global_text_objects = NULL;
 
-       if (!text) {
+       if (text) {
                free(text);
+               text = 0;
        }
 
        free(current_config);
@@ -7183,15 +7600,15 @@ void clean_up(void)
 static int string_to_bool(const char *s)
 {
        if (!s) {
-               return TRUE;
+               return 1;
        } else if (strcasecmp(s, "yes") == 0) {
-               return TRUE;
+               return 1;
        } else if (strcasecmp(s, "true") == 0) {
-               return TRUE;
+               return 1;
        } else if (strcasecmp(s, "1") == 0) {
-               return TRUE;
+               return 1;
        }
-       return FALSE;
+       return 0;
 }
 
 #ifdef X11
@@ -7201,18 +7618,34 @@ static enum alignment string_to_alignment(const char *s)
                return TOP_LEFT;
        } else if (strcasecmp(s, "top_right") == 0) {
                return TOP_RIGHT;
+       } else if (strcasecmp(s, "top_middle") == 0) {
+               return TOP_MIDDLE;
        } else if (strcasecmp(s, "bottom_left") == 0) {
                return BOTTOM_LEFT;
        } else if (strcasecmp(s, "bottom_right") == 0) {
                return BOTTOM_RIGHT;
+       } else if (strcasecmp(s, "bottom_middle") == 0) {
+               return BOTTOM_MIDDLE;
+       } else if (strcasecmp(s, "middle_left") == 0) {
+               return MIDDLE_LEFT;
+       } else if (strcasecmp(s, "middle_right") == 0) {
+               return MIDDLE_RIGHT;
        } else if (strcasecmp(s, "tl") == 0) {
                return TOP_LEFT;
        } else if (strcasecmp(s, "tr") == 0) {
                return TOP_RIGHT;
+       } else if (strcasecmp(s, "tm") == 0) {
+               return TOP_MIDDLE;
        } else if (strcasecmp(s, "bl") == 0) {
                return BOTTOM_LEFT;
        } else if (strcasecmp(s, "br") == 0) {
                return BOTTOM_RIGHT;
+       } else if (strcasecmp(s, "bm") == 0) {
+               return BOTTOM_MIDDLE;
+       } else if (strcasecmp(s, "ml") == 0) {
+               return MIDDLE_LEFT;
+       } else if (strcasecmp(s, "mr") == 0) {
+               return MIDDLE_RIGHT;
        } else if (strcasecmp(s, "none") == 0) {
                return NONE;
        }
@@ -7249,10 +7682,9 @@ static void set_default_configurations(void)
        info.xmms2.title = NULL;
        info.xmms2.genre = NULL;
        info.xmms2.comment = NULL;
-       info.xmms2.decoder = NULL;
-       info.xmms2.transport = NULL;
        info.xmms2.url = NULL;
        info.xmms2.status = NULL;
+       info.xmms2.playlist = NULL;
 #endif
        use_spacer = NO_SPACER;
 #ifdef X11
@@ -7312,6 +7744,7 @@ static void set_default_configurations(void)
        update_interval = 3.0;
        info.music_player_interval = 1.0;
        stuff_in_upper_case = 0;
+       info.users.number = 1;
 
 #ifdef TCP_PORT_MONITOR
        tcp_port_monitor_args.max_port_monitor_connections =
@@ -7901,13 +8334,18 @@ static void load_config_file(const char *f)
                CONF("text_buffer_size") {
                        if (value) {
                                text_buffer_size = atoi(value);
+                               if (text_buffer_size < DEFAULT_TEXT_BUFFER_SIZE) {
+                                       ERR("text_buffer_size must be >=%i bytes", DEFAULT_TEXT_BUFFER_SIZE);
+                                       text_buffer_size = DEFAULT_TEXT_BUFFER_SIZE;
+                               }
                        } else {
                                CONF_ERR;
                        }
                }
                CONF("text") {
-                       if (!text) {
+                       if (text) {
                                free(text);
+                               text = 0;
                        }
 
                        text = (char *) malloc(1);
@@ -8003,6 +8441,10 @@ static const struct option longopts[] = {
 
 int main(int argc, char **argv)
 {
+#ifdef X11
+       char *s, *temp;
+       unsigned int x;
+#endif
        struct sigaction act, oact;
 
        g_signal_pending = 0;
@@ -8015,9 +8457,6 @@ int main(int argc, char **argv)
 
        /* handle command line parameters that don't change configs */
 #ifdef X11
-       char *s, *temp;
-       unsigned int x;
-
        if (((s = getenv("LC_ALL")) && *s) || ((s = getenv("LC_CTYPE")) && *s)
                        || ((s = getenv("LANG")) && *s)) {
                temp = (char *) malloc((strlen(s) + 1) * sizeof(char));
@@ -8100,6 +8539,17 @@ int main(int argc, char **argv)
        init_X11();
 #endif /* X11 */
 
+       /* 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) {
@@ -8147,7 +8597,7 @@ int main(int argc, char **argv)
 
        /* handle other command line arguments */
 
-#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__OpenBSD__)
+#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__OpenBSD__) \
                || defined(__NetBSD__)
        optind = optreset = 1;
 #else
@@ -8193,8 +8643,9 @@ int main(int argc, char **argv)
 #endif
 #endif /* X11 */
                        case 't':
-                               if (!text) {
+                               if (text) {
                                        free(text);
+                                       text = 0;
                                }
                                text = strdup(optarg);
                                convert_escapes(text);
@@ -8233,8 +8684,9 @@ int main(int argc, char **argv)
 
        /* generate text and get initial size */
        extract_variable_text(text);
-       if (!text) {
+       if (text) {
                free(text);
+               text = 0;
        }
        text = NULL;
        /* fork */
@@ -8263,13 +8715,26 @@ int main(int argc, char **argv)
                }
        }
 
+       text_buffer = malloc(max_user_text);
+       memset(text_buffer, 0, max_user_text);
+       tmpstring1 = malloc(text_buffer_size);
+       memset(tmpstring1, 0, text_buffer_size);
+       tmpstring2 = malloc(text_buffer_size);
+       memset(tmpstring2, 0, text_buffer_size);
+
 #ifdef X11
        selected_font = 0;
        update_text_area();     /* to get initial size of the window */
 
+#ifdef OWN_WINDOW
        init_window(own_window, text_width + border_margin * 2 + 1,
                text_height + border_margin * 2 + 1, set_transparent, background_colour,
                argv, argc);
+#else /* OWN_WINDOW */
+       init_window(0, text_width + border_margin * 2 + 1,
+               text_height + border_margin * 2 + 1, set_transparent, 0,
+               argv, argc);
+#endif /* OWN_WINDOW */
 
        selected_font = 0;
        update_text_area();     /* to position text/window on screen */
@@ -8301,18 +8766,11 @@ int main(int argc, char **argv)
 
        if (sigaction(SIGINT, &act, &oact) < 0
                        || sigaction(SIGUSR1, &act, &oact) < 0
+                       || sigaction(SIGHUP,&act,&oact) < 0
                        || sigaction(SIGTERM, &act, &oact) < 0) {
                ERR("error setting signal handler: %s", strerror(errno));
        }
 
-#ifdef AUDACIOUS
-       if (create_audacious_thread() != 0) {
-               CRIT_ERR("unable to create audacious thread!");
-       }
-       timed_thread_register(info.audacious.p_timed_thread,
-               &info.audacious.p_timed_thread);
-#endif
-
        /* *************** *
         * MAIN CONKY LOOP *
         * *************** */