here comes the big header include rewrite
[monky] / src / conky.c
index 3aaa092..d9c82d6 100644 (file)
  * You should have received a copy of the GNU General Public License
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  *
- * $Id$ */
+ */
 
+#include "config.h"
+#include "text_object.h"
 #include "conky.h"
+#include "common.h"
 #include <stdarg.h>
 #include <math.h>
 #include <ctype.h>
 #include <time.h>
 #include <locale.h>
 #include <signal.h>
-#include <unistd.h>
 #include <errno.h>
-#include <termios.h>
 #include <limits.h>
 #if HAVE_DIRENT_H
 #include <dirent.h>
 #endif
 #include <sys/time.h>
 #ifdef X11
+#include "x11.h"
 #include <X11/Xutil.h>
 #ifdef HAVE_XDAMAGE
 #include <X11/extensions/Xdamage.h>
 #include <fcntl.h>
 #include <getopt.h>
 
+/* local headers */
+#include "build.h"
+#include "diskio.h"
+#include "fs.h"
+#include "logging.h"
+#include "mixer.h"
+#include "mail.h"
+#include "mboxscan.h"
+#include "temphelper.h"
+#include "top.h"
+
+/* check for OS and include appropriate headers */
+#if defined(__linux__)
+#include "linux.h"
+#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
+#include "freebsd.h"
+#elif defined(__OpenBSD__)
+#include "openbsd.h"
+#endif
+
+/* FIXME: apm_getinfo is unused here. maybe it's meant for common.c */
+#if (defined(__FreeBSD__) || defined(__FreeBSD_kernel__) \
+               || defined(__OpenBSD__)) && (defined(i386) || defined(__i386__))
+int apm_getinfo(int fd, apm_info_t aip);
+char *get_apm_adapter(void);
+char *get_apm_battery_life(void);
+char *get_apm_battery_time(void);
+#endif
+
 #ifdef HAVE_ICONV
 #include <iconv.h>
 #endif
 
-#include "build.h"
+#ifdef CONFIG_OUTPUT
+#include "defconfig.h"
+#ifdef HAVE_FOPENCOOKIE
+#include "conf_cookie.h"
+#endif
+#endif
 
 #ifndef S_ISSOCK
 #define S_ISSOCK(x)   ((x & S_IFMT) == S_IFSOCK)
 #define MAX_IF_BLOCK_DEPTH 5
 #define MAX_TAIL_LINES 100
 
-#define SIGNAL_BLOCKING
-//#undef SIGNAL_BLOCKING
-sigset_t oldmask;
+//#define SIGNAL_BLOCKING
+#undef SIGNAL_BLOCKING
+
+/* debugging level, used by logging.h */
+int global_debug_level = 0;
+
+/* two strings for internal use */
+static char *tmpstring1, *tmpstring2;
+
+/* variables holding various config settings */
+int short_units;
+int cpu_separate;
+static int use_spacer;
+int top_cpu, top_mem;
+#define TO_X 1
+#define TO_STDOUT 2
+static int output_methods;
+static volatile int g_signal_pending;
+/* Update interval */
+static double update_interval;
+
 
+/* prototypes for internally used functions */
+static void signal_handler(int);
 static void print_version(void) __attribute__((noreturn));
+static void reload_config(void);
+static void clean_up(void);
 
 static void print_version(void)
 {
@@ -329,6 +387,10 @@ static void load_fonts(void)
 
 #endif /* X11 */
 
+/* struct that has all info to be shared between
+ * instances of the same text object */
+struct information info;
+
 /* default config file */
 static char *current_config;
 
@@ -386,6 +448,8 @@ static int sensor_device;
 static long color0, color1, color2, color3, color4, color5, color6, color7,
        color8, color9;
 
+static char *template[10];
+
 /* maximum number of special things, e.g. fonts, offsets, aligns, etc. */
 static unsigned int max_specials = MAX_SPECIALS_DEFAULT;
 
@@ -444,20 +508,11 @@ int no_buffers;
 /* pad percentages to decimals? */
 static int pad_percents = 0;
 
-#ifdef TCP_PORT_MONITOR
-tcp_port_monitor_args_t tcp_port_monitor_args;
-#endif
-
 static char *global_text = 0;
 long global_text_lines;
 
 static int total_updates;
 
-/* if-blocks */
-static int blockdepth = 0;
-static int if_jumped = 0;
-static int blockstart[MAX_IF_BLOCK_DEPTH];
-
 int check_contains(char *f, char *s)
 {
        int ret = 0;
@@ -1094,1081 +1149,11 @@ static void human_readable(long long num, char *buf, int size, const char *func_
        } while (len >= (short_units ? SHORT_WIDTH : WIDTH) || len >= size);
 }
 
-/* text handling */
-
-enum text_object_type {
-       OBJ_addr,
-#if defined(__linux__)
-    OBJ_addrs,
-#endif /* __linux__ */
-#ifndef __OpenBSD__
-       OBJ_acpiacadapter,
-       OBJ_adt746xcpu,
-       OBJ_adt746xfan,
-       OBJ_acpifan,
-       OBJ_acpitemp,
-       OBJ_acpitempf,
-       OBJ_battery,
-       OBJ_battery_time,
-       OBJ_battery_percent,
-       OBJ_battery_bar,
-#endif /* !__OpenBSD__ */
-       OBJ_buffers,
-       OBJ_cached,
-       OBJ_color,
-       OBJ_color0,
-       OBJ_color1,
-       OBJ_color2,
-       OBJ_color3,
-       OBJ_color4,
-       OBJ_color5,
-       OBJ_color6,
-       OBJ_color7,
-       OBJ_color8,
-       OBJ_color9,
-       OBJ_conky_version,
-       OBJ_conky_build_date,
-       OBJ_conky_build_arch,
-       OBJ_font,
-       OBJ_cpu,
-       OBJ_cpubar,
-       OBJ_cpugraph,
-       OBJ_loadgraph,
-       OBJ_diskio,
-       OBJ_diskio_read,
-       OBJ_diskio_write,
-       OBJ_diskiograph,
-       OBJ_diskiograph_read,
-       OBJ_diskiograph_write,
-       OBJ_downspeed,
-       OBJ_downspeedf,
-       OBJ_downspeedgraph,
-       OBJ_else,
-       OBJ_endif,
-       OBJ_image,
-       OBJ_exec,
-       OBJ_execi,
-       OBJ_texeci,
-       OBJ_execbar,
-       OBJ_execgraph,
-       OBJ_execibar,
-       OBJ_execigraph,
-       OBJ_execp,
-       OBJ_execpi,
-       OBJ_freq,
-       OBJ_freq_g,
-       OBJ_freq_dyn,
-       OBJ_freq_dyn_g,
-       OBJ_fs_bar,
-       OBJ_fs_bar_free,
-       OBJ_fs_free,
-       OBJ_fs_free_perc,
-       OBJ_fs_size,
-       OBJ_fs_type,
-       OBJ_fs_used,
-       OBJ_fs_used_perc,
-       OBJ_goto,
-       OBJ_tab,
-       OBJ_hr,
-       OBJ_offset,
-       OBJ_voffset,
-       OBJ_alignr,
-       OBJ_alignc,
-       OBJ_i2c,
-       OBJ_platform,
-       OBJ_hwmon,
-#if defined(__linux__)
-       OBJ_disk_protect,
-       OBJ_i8k_version,
-       OBJ_i8k_bios,
-       OBJ_i8k_serial,
-       OBJ_i8k_cpu_temp,
-       OBJ_i8k_cpu_tempf,
-       OBJ_i8k_left_fan_status,
-       OBJ_i8k_right_fan_status,
-       OBJ_i8k_left_fan_rpm,
-       OBJ_i8k_right_fan_rpm,
-       OBJ_i8k_ac_status,
-       OBJ_i8k_buttons_status,
-       OBJ_ibm_fan,
-       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,
-       OBJ_wireless_essid,
-       OBJ_wireless_mode,
-       OBJ_wireless_bitrate,
-       OBJ_wireless_ap,
-       OBJ_wireless_link_qual,
-       OBJ_wireless_link_qual_max,
-       OBJ_wireless_link_qual_perc,
-       OBJ_wireless_link_bar,
-#endif /* __linux__ */
-       OBJ_if_empty,
-       OBJ_if_existing,
-       OBJ_if_mounted,
-       OBJ_if_running,
-       OBJ_top,
-       OBJ_top_mem,
-       OBJ_tail,
-       OBJ_head,
-       OBJ_lines,
-       OBJ_words,
-       OBJ_kernel,
-       OBJ_loadavg,
-       OBJ_machine,
-       OBJ_mails,
-       OBJ_mboxscan,
-       OBJ_mem,
-       OBJ_memeasyfree,
-       OBJ_memfree,
-       OBJ_membar,
-       OBJ_memgraph,
-       OBJ_memmax,
-       OBJ_memperc,
-       OBJ_mem_res,
-       OBJ_mem_vsize,
-       OBJ_mixer,
-       OBJ_mixerl,
-       OBJ_mixerr,
-       OBJ_mixerbar,
-       OBJ_mixerlbar,
-       OBJ_mixerrbar,
-#ifdef X11
-       OBJ_monitor,
-       OBJ_monitor_number,
-#endif
-       OBJ_nameserver,
-       OBJ_new_mails,
-       OBJ_nodename,
-       OBJ_nvidia,
-       OBJ_pre_exec,
-       OBJ_processes,
-       OBJ_running_processes,
-       OBJ_shadecolor,
-       OBJ_outlinecolor,
-       OBJ_stippled_hr,
-       OBJ_swap,
-       OBJ_swapbar,
-       OBJ_swapmax,
-       OBJ_swapperc,
-       OBJ_sysname,
-       OBJ_temp1,      /* i2c is used instead in these */
-       OBJ_temp2,
-       OBJ_text,
-       OBJ_time,
-       OBJ_utime,
-       OBJ_tztime,
-       OBJ_totaldown,
-       OBJ_totalup,
-       OBJ_updates,
-       OBJ_upspeed,
-       OBJ_upspeedf,
-       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,
-       OBJ_pop3,
-       OBJ_pop3_unseen,
-       OBJ_pop3_used,
-#if (defined(__FreeBSD__) || defined(__FreeBSD_kernel__) \
-               || defined(__OpenBSD__)) && (defined(i386) || defined(__i386__))
-       OBJ_apm_adapter,
-       OBJ_apm_battery_time,
-       OBJ_apm_battery_life,
-#endif /* __FreeBSD__ __OpenBSD__ */
-#ifdef __OpenBSD__
-       OBJ_obsd_sensors_temp,
-       OBJ_obsd_sensors_fan,
-       OBJ_obsd_sensors_volt,
-       OBJ_obsd_vendor,
-       OBJ_obsd_product,
-#endif /* __OpenBSD__ */
-#ifdef MPD
-       OBJ_mpd_title,
-       OBJ_mpd_artist,
-       OBJ_mpd_album,
-       OBJ_mpd_random,
-       OBJ_mpd_repeat,
-       OBJ_mpd_vol,
-       OBJ_mpd_bitrate,
-       OBJ_mpd_status,
-       OBJ_mpd_host,
-       OBJ_mpd_port,
-       OBJ_mpd_password,
-       OBJ_mpd_bar,
-       OBJ_mpd_elapsed,
-       OBJ_mpd_length,
-       OBJ_mpd_track,
-       OBJ_mpd_name,
-       OBJ_mpd_file,
-       OBJ_mpd_percent,
-       OBJ_mpd_smart,
-#endif
-#ifdef MOC
-  OBJ_moc_state,
-  OBJ_moc_file,
-  OBJ_moc_title,
-  OBJ_moc_artist,
-  OBJ_moc_song,
-  OBJ_moc_album,
-  OBJ_moc_totaltime,
-  OBJ_moc_timeleft,
-  OBJ_moc_curtime,
-  OBJ_moc_bitrate,
-  OBJ_moc_rate,
-#endif
-       OBJ_music_player_interval,
-#ifdef XMMS2
-       OBJ_xmms2_artist,
-       OBJ_xmms2_album,
-       OBJ_xmms2_title,
-       OBJ_xmms2_genre,
-       OBJ_xmms2_comment,
-       OBJ_xmms2_url,
-       OBJ_xmms2_date,
-       OBJ_xmms2_tracknr,
-       OBJ_xmms2_bitrate,
-       OBJ_xmms2_id,
-       OBJ_xmms2_duration,
-       OBJ_xmms2_elapsed,
-       OBJ_xmms2_size,
-       OBJ_xmms2_percent,
-       OBJ_xmms2_status,
-       OBJ_xmms2_bar,
-       OBJ_xmms2_smart,
-       OBJ_xmms2_playlist,
-       OBJ_xmms2_timesplayed,
-#endif
-#ifdef AUDACIOUS
-       OBJ_audacious_status,
-       OBJ_audacious_title,
-       OBJ_audacious_length,
-       OBJ_audacious_length_seconds,
-       OBJ_audacious_position,
-       OBJ_audacious_position_seconds,
-       OBJ_audacious_bitrate,
-       OBJ_audacious_frequency,
-       OBJ_audacious_channels,
-       OBJ_audacious_filename,
-       OBJ_audacious_playlist_length,
-       OBJ_audacious_playlist_position,
-       OBJ_audacious_bar,
-#endif
-#ifdef BMPX
-       OBJ_bmpx_title,
-       OBJ_bmpx_artist,
-       OBJ_bmpx_album,
-       OBJ_bmpx_track,
-       OBJ_bmpx_uri,
-       OBJ_bmpx_bitrate,
-#endif
-#ifdef EVE
-       OBJ_eve,
-#endif
-#ifdef RSS
-       OBJ_rss,
-#endif
-#ifdef TCP_PORT_MONITOR
-       OBJ_tcp_portmon,
-#endif
-#ifdef HAVE_ICONV
-       OBJ_iconv_start,
-       OBJ_iconv_stop,
-#endif
-#ifdef HDDTEMP
-       OBJ_hddtemp,
-#endif
-#ifdef SMAPI
-       OBJ_smapi,
-       OBJ_smapi_bat_bar,
-       OBJ_smapi_bat_perc,
-       OBJ_smapi_bat_temp,
-       OBJ_smapi_bat_power,
-       OBJ_if_smapi_bat_installed,
-#endif
-       OBJ_scroll,
-       OBJ_entropy_avail,
-       OBJ_entropy_poolsize,
-       OBJ_entropy_bar
-};
-
-struct text_object {
-       union {
-               char *s;                /* some string */
-               int i;                  /* some integer */
-               long l;                 /* some other integer */
-               unsigned int sensor;
-               struct net_stat *net;
-               struct fs_stat *fs;
-               struct diskio_stat *diskio;
-               unsigned char loadavg[3];
-               unsigned int cpu_index;
-               struct mail_s *mail;
-
-               struct {
-                       char *args;
-                       char *output;
-               } mboxscan;
-
-               struct {
-                       char *tz;       /* timezone variable */
-                       char *fmt;      /* time display formatting */
-               } tztime;
-
-               struct {
-                       struct fs_stat *fs;
-                       int w, h;
-               } fsbar;                /* 3 */
-
-               struct {
-                       int l;
-                       int w, h;
-               } mixerbar;             /* 3 */
-
-               struct {
-                       int fd;
-                       int arg;
-                       char devtype[256];
-                       char type[64];
-               } sysfs;                /* 2 */
-
-               struct {
-                       int pos;
-                       char *s;
-                       char *str;
-               } ifblock;
-
-               struct {
-                       int num;
-                       int type;
-               } top;
-
-               struct {
-                       int wantedlines;
-                       int readlines;
-                       char *logfile;
-                       double last_update;
-                       float interval;
-                       char *buffer;
-                       /* If not -1, a file descriptor to read from when
-                        * logfile is a FIFO. */
-                       int fd;
-               } tail;
-
-               struct {
-                       double last_update;
-                       float interval;
-                       char *cmd;
-                       char *buffer;
-                       double data;
-               } execi;                /* 5 */
-
-               struct {
-                       float interval;
-                       char *cmd;
-                       char *buffer;
-                       double data;
-                       timed_thread *p_timed_thread;
-               } texeci;
-
-               struct {
-                       int a, b;
-               } pair;                 /* 2 */
-#ifdef TCP_PORT_MONITOR
-               struct {
-                       /* starting port to monitor */
-                       in_port_t port_range_begin;
-                       /* ending port to monitor */
-                       in_port_t port_range_end;
-                       /* enum from libtcp-portmon.h, e.g. COUNT, etc. */
-                       int item;
-                       /* 0 to n-1 connections. */
-                       int connection_index;
-               } tcp_port_monitor;
-#endif
-#ifdef HDDTEMP
-               struct {
-                       char *addr;
-                       int port;
-                       char *dev;
-                       double update_time;
-                       char *temp;
-                       char unit;
-               } hddtemp;              /* 2 */
-#endif
-#ifdef EVE
-               struct {
-                       char *apikey;
-                       char *charid;
-                       char *userid;
-               } eve;
-#endif
-#ifdef RSS
-               struct {
-                       char *uri;
-                       char *action;
-                       int act_par;
-                       int delay;
-               } rss;
-#endif
-               struct {
-                       char *text;
-                       unsigned int show;
-                       unsigned int step;
-                       unsigned int start;
-               } scroll;
-               
-               struct local_mail_s local_mail;
-#ifdef NVIDIA
-               struct nvidia_s nvidia;
-#endif /* NVIDIA */
-
-       } data;
-       int type;
-       int a, b;
-       long line;
-       unsigned int c, d, e;
-       float f;
-       char showaslog;
-       char global_mode;
-};
-
-struct text_object_list {
-       unsigned int text_object_count;
-       struct text_object *text_objects;
-};
-
-static struct text_object_list *global_text_object_list;
+/* global object list root element */
+static struct text_object global_root_object;
 
 static void generate_text_internal(char *p, int p_max_size,
-       struct text_object_list *text_object_list,
-       struct information *cur);
-
-#define MAXDATASIZE 1000
-#define POP3 1
-#define IMAP 2
-
-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));
-
-       if (sscanf(arg, "%128s %128s %128s", mail->host, mail->user, mail->pass)
-                       != 3) {
-               if (type == POP3) {
-                       ERR("Scanning IMAP args failed");
-               } else if (type == IMAP) {
-                       ERR("Scanning POP3 args failed");
-               }
-       }
-       // see if password needs prompting
-       if (mail->pass[0] == '*' && mail->pass[1] == '\0') {
-               int fp = fileno(stdin);
-               struct termios term;
-
-               tcgetattr(fp, &term);
-               term.c_lflag &= ~ECHO;
-               tcsetattr(fp, TCSANOW, &term);
-               printf("Enter mailbox password (%s@%s): ", mail->user, mail->host);
-               scanf("%128s", mail->pass);
-               printf("\n");
-               term.c_lflag |= ECHO;
-               tcsetattr(fp, TCSANOW, &term);
-       }
-       // now we check for optional args
-       tmp = strstr(arg, "-r ");
-       if (tmp) {
-               tmp += 3;
-               sscanf(tmp, "%u", &mail->retries);
-       } else {
-               mail->retries = 5;      // 5 retries after failure
-       }
-       tmp = strstr(arg, "-i ");
-       if (tmp) {
-               tmp += 3;
-               sscanf(tmp, "%f", &mail->interval);
-       } else {
-               mail->interval = 300;   // 5 minutes
-       }
-       tmp = strstr(arg, "-p ");
-       if (tmp) {
-               tmp += 3;
-               sscanf(tmp, "%lu", &mail->port);
-       } else {
-               if (type == POP3) {
-                       mail->port = 110;       // default pop3 port
-               } else if (type == IMAP) {
-                       mail->port = 143;       // default imap port
-               }
-       }
-       if (type == IMAP) {
-               tmp = strstr(arg, "-f ");
-               if (tmp) {
-                       tmp += 3;
-                       sscanf(tmp, "%s", mail->folder);
-               } else {
-                       strncpy(mail->folder, "INBOX", 128);    // default imap inbox
-               }
-       }
-       tmp = strstr(arg, "-e ");
-       if (tmp) {
-               int len = 1024;
-               tmp += 3;
-
-               if (tmp[0] == '\'') {
-                       len = strstr(tmp + 1, "'") - tmp - 1;
-                       if (len > 1024) {
-                               len = 1024;
-                       }
-               }
-               strncpy(mail->command, tmp + 1, len);
-       } else {
-               mail->command[0] = '\0';
-       }
-       mail->p_timed_thread = NULL;
-       return mail;
-}
-
-int imap_command(int sockfd, const char *command, char *response, const char *verify)
-{
-       struct timeval timeout;
-       fd_set fdset;
-       int res, numbytes = 0;
-       if (send(sockfd, command, strlen(command), 0) == -1) {
-               perror("send");
-               return -1;
-       }
-       timeout.tv_sec = 60;    // 60 second timeout i guess
-       timeout.tv_usec = 0;
-       FD_ZERO(&fdset);
-       FD_SET(sockfd, &fdset);
-       res = select(sockfd + 1, &fdset, NULL, NULL, &timeout);
-       if (res > 0) {
-               if ((numbytes = recv(sockfd, response, MAXDATASIZE - 1, 0)) == -1) {
-                       perror("recv");
-                       return -1;
-               }
-       }
-       response[numbytes] = '\0';
-       if (strstr(response, verify) == NULL) {
-               return -1;
-       }
-       return 0;
-}
-
-int imap_check_status(char *recvbuf, struct mail_s *mail)
-{
-       char *reply;
-       reply = strstr(recvbuf, " (MESSAGES ");
-       if (!reply || strlen(reply) < 2) {
-               return -1;
-       }
-       reply += 2;
-       *strchr(reply, ')') = '\0';
-       if (reply == NULL) {
-               ERR("Error parsing IMAP response: %s", recvbuf);
-               return -1;
-       } else {
-               timed_thread_lock(mail->p_timed_thread);
-               sscanf(reply, "MESSAGES %lu UNSEEN %lu", &mail->messages,
-                               &mail->unseen);
-               timed_thread_unlock(mail->p_timed_thread);
-       }
-       return 0;
-}
-
-void imap_unseen_command(struct mail_s *mail, unsigned long old_unseen, unsigned long old_messages)
-{
-       if (strlen(mail->command) > 1 && (mail->unseen > old_unseen
-                               || (mail->messages > old_messages && mail->unseen > 0))) {
-               // new mail goodie
-               if (system(mail->command) == -1) {
-                       perror("system()");
-               }
-       }
-}
-
-void *imap_thread(void *arg)
-{
-       int sockfd, numbytes;
-       char recvbuf[MAXDATASIZE];
-       char sendbuf[MAXDATASIZE];
-       unsigned int fail = 0;
-       unsigned long old_unseen = ULONG_MAX;
-       unsigned long old_messages = ULONG_MAX;
-       struct stat stat_buf;
-       struct hostent he, *he_res = 0;
-       int he_errno;
-       char hostbuff[2048];
-       struct sockaddr_in their_addr;  // connector's address information
-       struct mail_s *mail = (struct mail_s *)arg;
-       int has_idle = 0;
-       int threadfd = timed_thread_readfd(mail->p_timed_thread);
-
-#ifdef HAVE_GETHOSTBYNAME_R
-       if (gethostbyname_r(mail->host, &he, hostbuff, sizeof(hostbuff), &he_res, &he_errno)) { // get the host info
-               ERR("IMAP gethostbyname_r: %s", hstrerror(h_errno));
-               exit(1);
-       }
-#else /* HAVE_GETHOSTBYNAME_R */
-       if ((he_res = gethostbyname(mail->host)) == NULL) {     // get the host info
-               herror("gethostbyname");
-               exit(1);
-       }
-#endif /* HAVE_GETHOSTBYNAME_R */
-       while (fail < mail->retries) {
-               struct timeval timeout;
-               int res;
-               fd_set fdset;
-
-               if (fail > 0) {
-                       ERR("Trying IMAP connection again for %s@%s (try %u/%u)",
-                                       mail->user, mail->host, fail + 1, mail->retries);
-               }
-               do {
-                       if ((sockfd = socket(PF_INET, SOCK_STREAM, 0)) == -1) {
-                               perror("socket");
-                               fail++;
-                               break;
-                       }
-
-                       // host byte order
-                       their_addr.sin_family = AF_INET;
-                       // short, network byte order
-                       their_addr.sin_port = htons(mail->port);
-                       their_addr.sin_addr = *((struct in_addr *) he_res->h_addr);
-                       // zero the rest of the struct
-                       memset(&(their_addr.sin_zero), '\0', 8);
-
-                       if (connect(sockfd, (struct sockaddr *) &their_addr,
-                                               sizeof(struct sockaddr)) == -1) {
-                               perror("connect");
-                               fail++;
-                               break;
-                       }
-
-                       timeout.tv_sec = 60;    // 60 second timeout i guess
-                       timeout.tv_usec = 0;
-                       FD_ZERO(&fdset);
-                       FD_SET(sockfd, &fdset);
-                       res = select(sockfd + 1, &fdset, NULL, NULL, &timeout);
-                       if (res > 0) {
-                               if ((numbytes = recv(sockfd, recvbuf, MAXDATASIZE - 1, 0)) == -1) {
-                                       perror("recv");
-                                       fail++;
-                                       break;
-                               }
-                       } else {
-                               ERR("IMAP connection failed: timeout");
-                               fail++;
-                               break;
-                       }
-                       recvbuf[numbytes] = '\0';
-                       if (strstr(recvbuf, "* OK") != recvbuf) {
-                               ERR("IMAP connection failed, probably not an IMAP server");
-                               fail++;
-                               break;
-                       }
-                       strncpy(sendbuf, "a1 login ", MAXDATASIZE);
-                       strncat(sendbuf, mail->user, MAXDATASIZE - strlen(sendbuf) - 1);
-                       strncat(sendbuf, " ", MAXDATASIZE - strlen(sendbuf) - 1);
-                       strncat(sendbuf, mail->pass, MAXDATASIZE - strlen(sendbuf) - 1);
-                       strncat(sendbuf, "\r\n", MAXDATASIZE - strlen(sendbuf) - 1);
-                       if (imap_command(sockfd, sendbuf, recvbuf, "a1 OK")) {
-                               fail++;
-                               break;
-                       }
-                       if (strstr(recvbuf, " IDLE ") != NULL) {
-                               has_idle = 1;
-                       }
-
-                       strncpy(sendbuf, "a2 STATUS ", MAXDATASIZE);
-                       strncat(sendbuf, mail->folder, MAXDATASIZE - strlen(sendbuf) - 1);
-                       strncat(sendbuf, " (MESSAGES UNSEEN)\r\n",
-                                       MAXDATASIZE - strlen(sendbuf) - 1);
-                       if (imap_command(sockfd, sendbuf, recvbuf, "a2 OK")) {
-                               fail++;
-                               break;
-                       }
-
-                       if (imap_check_status(recvbuf, mail)) {
-                               fail++;
-                               break;
-                       }
-                       imap_unseen_command(mail, old_unseen, old_messages);
-                       fail = 0;
-                       old_unseen = mail->unseen;
-                       old_messages = mail->messages;
-
-                       if (has_idle) {
-                               strncpy(sendbuf, "a4 SELECT ", MAXDATASIZE);
-                               strncat(sendbuf, mail->folder, MAXDATASIZE - strlen(sendbuf) - 1);
-                               strncat(sendbuf, "\r\n", MAXDATASIZE - strlen(sendbuf) - 1);
-                               if (imap_command(sockfd, sendbuf, recvbuf, "a4 OK")) {
-                                       fail++;
-                                       break;
-                               }
-
-                               strncpy(sendbuf, "a5 IDLE\r\n", MAXDATASIZE);
-                               if (imap_command(sockfd, sendbuf, recvbuf, "+ idling")) {
-                                       fail++;
-                                       break;
-                               }
-                               recvbuf[0] = '\0';
-
-                               while (1) {
-                                       FD_ZERO(&fdset);
-                                       FD_SET(sockfd, &fdset);
-                                       FD_SET(threadfd, &fdset);
-                                       res = pselect(MAX(sockfd + 1, threadfd + 1), &fdset, NULL, NULL, NULL, &oldmask);
-                                       if (timed_thread_test(mail->p_timed_thread)) {
-                                               timed_thread_exit(mail->p_timed_thread);
-                                       }
-                                       if ((res == -1 && errno == EINTR) || FD_ISSET(threadfd, &fdset)) {
-                                               timed_thread_exit(mail->p_timed_thread);
-                                       } else if (res > 0) {
-                                               if ((numbytes = recv(sockfd, recvbuf, MAXDATASIZE - 1, 0)) == -1) {
-                                                       perror("recv idling");
-                                                       fail++;
-                                                       break;
-                                               }
-                                       } else {
-                                               break;
-                                       }
-                                       recvbuf[numbytes] = '\0';
-                                       if (strlen(recvbuf) > 2) {
-                                               unsigned long messages, recent;
-                                               char *buf = recvbuf;
-                                               buf = strstr(buf, "EXISTS");
-                                               while (buf && strlen(buf) > 1 && strstr(buf + 1, "EXISTS")) {
-                                                       buf = strstr(buf + 1, "EXISTS");
-                                               }
-                                               if (buf) {
-                                                       // back up until we reach '*'
-                                                       while (buf >= recvbuf && buf[0] != '*') {
-                                                               buf--;
-                                                       }
-                                                       if (sscanf(buf, "* %lu EXISTS\r\n", &messages) == 1) {
-                                                               timed_thread_lock(mail->p_timed_thread);
-                                                               mail->messages = messages;
-                                                               timed_thread_unlock(mail->p_timed_thread);
-                                                       }
-                                               }
-                                               buf = recvbuf;
-                                               buf = strstr(buf, "RECENT");
-                                               while (buf && strlen(buf) > 1 && strstr(buf + 1, "RECENT")) {
-                                                       buf = strstr(buf + 1, "RECENT");
-                                               }
-                                               if (buf) {
-                                                       // back up until we reach '*'
-                                                       while (buf >= recvbuf && buf[0] != '*') {
-                                                               buf--;
-                                                       }
-                                                       if (sscanf(buf, "* %lu RECENT\r\n", &recent) != 1) {
-                                                               recent = 0;
-                                                       }
-                                               }
-                                               // check if we got a FETCH from server
-                                               buf = recvbuf;
-                                               if (recent > 0 || (buf && strstr(buf, " FETCH "))) {
-                                                       // re-check messages and unseen
-                                                       if (imap_command(sockfd, "DONE\r\n", recvbuf, "a5 OK")) {
-                                                               fail++;
-                                                               break;
-                                                       }
-                                                       strncpy(sendbuf, "a2 STATUS ", MAXDATASIZE);
-                                                       strncat(sendbuf, mail->folder, MAXDATASIZE - strlen(sendbuf) - 1);
-                                                       strncat(sendbuf, " (MESSAGES UNSEEN)\r\n",
-                                                                       MAXDATASIZE - strlen(sendbuf) - 1);
-                                                       if (imap_command(sockfd, sendbuf, recvbuf, "a2 OK")) {
-                                                               fail++;
-                                                               break;
-                                                       }
-                                                       if (imap_check_status(recvbuf, mail)) {
-                                                               fail++;
-                                                               break;
-                                                       }
-                                                       strncpy(sendbuf, "a5 IDLE\r\n", MAXDATASIZE);
-                                                       if (imap_command(sockfd, sendbuf, recvbuf, "+ idling")) {
-                                                               fail++;
-                                                               break;
-                                                       }
-                                               }
-                                       }
-                                       imap_unseen_command(mail, old_unseen, old_messages);
-                                       fail = 0;
-                                       old_unseen = mail->unseen;
-                                       old_messages = mail->messages;
-                               }
-                       } else {
-                               strncpy(sendbuf, "a3 logout\r\n", MAXDATASIZE);
-                               if (send(sockfd, sendbuf, strlen(sendbuf), 0) == -1) {
-                                       perror("send a3");
-                                       fail++;
-                                       break;
-                               }
-                               timeout.tv_sec = 60;    // 60 second timeout i guess
-                               timeout.tv_usec = 0;
-                               FD_ZERO(&fdset);
-                               FD_SET(sockfd, &fdset);
-                               res = select(sockfd + 1, &fdset, NULL, NULL, &timeout);
-                               if (res > 0) {
-                                       if ((numbytes = recv(sockfd, recvbuf, MAXDATASIZE - 1, 0)) == -1) {
-                                               perror("recv a3");
-                                               fail++;
-                                               break;
-                                       }
-                               }
-                               recvbuf[numbytes] = '\0';
-                               if (strstr(recvbuf, "a3 OK") == NULL) {
-                                       ERR("IMAP logout failed: %s", recvbuf);
-                                       fail++;
-                                       break;
-                               }
-                       }
-               } while (0);
-               if ((fstat(sockfd, &stat_buf) == 0) && S_ISSOCK(stat_buf.st_mode)) {
-                       /* if a valid socket, close it */
-                       close(sockfd);
-               }
-               if (timed_thread_test(mail->p_timed_thread)) {
-                       timed_thread_exit(mail->p_timed_thread);
-               }
-       }
-       mail->unseen = 0;
-       mail->messages = 0;
-       return 0;
-}
-
-void *pop3_thread(void *arg)
-{
-       int sockfd, numbytes;
-       char recvbuf[MAXDATASIZE];
-       char sendbuf[MAXDATASIZE];
-       char *reply;
-       unsigned int fail = 0;
-       unsigned long old_unseen = ULONG_MAX;
-       struct stat stat_buf;
-       struct hostent he, *he_res = 0;
-       int he_errno;
-       char hostbuff[2048];
-       struct sockaddr_in their_addr;  // connector's address information
-       struct mail_s *mail = (struct mail_s *)arg;
-
-#ifdef HAVE_GETHOSTBYNAME_R
-       if (gethostbyname_r(mail->host, &he, hostbuff, sizeof(hostbuff), &he_res, &he_errno)) { // get the host info
-               ERR("POP3 gethostbyname_r: %s", hstrerror(h_errno));
-               exit(1);
-       }
-#else /* HAVE_GETHOSTBYNAME_R */
-       if ((he_res = gethostbyname(mail->host)) == NULL) {     // get the host info
-               herror("gethostbyname");
-               exit(1);
-       }
-#endif /* HAVE_GETHOSTBYNAME_R */
-       while (fail < mail->retries) {
-               struct timeval timeout;
-               int res;
-               fd_set fdset;
-
-               if (fail > 0) {
-                       ERR("Trying POP3 connection again for %s@%s (try %u/%u)",
-                                       mail->user, mail->host, fail + 1, mail->retries);
-               }
-               do {
-                       if ((sockfd = socket(PF_INET, SOCK_STREAM, 0)) == -1) {
-                               perror("socket");
-                               fail++;
-                               break;
-                       }
-
-                       // host byte order
-                       their_addr.sin_family = AF_INET;
-                       // short, network byte order
-                       their_addr.sin_port = htons(mail->port);
-                       their_addr.sin_addr = *((struct in_addr *) he_res->h_addr);
-                       // zero the rest of the struct
-                       memset(&(their_addr.sin_zero), '\0', 8);
-
-                       if (connect(sockfd, (struct sockaddr *) &their_addr,
-                                               sizeof(struct sockaddr)) == -1) {
-                               perror("connect");
-                               fail++;
-                               break;
-                       }
-
-                       timeout.tv_sec = 60;    // 60 second timeout i guess
-                       timeout.tv_usec = 0;
-                       FD_ZERO(&fdset);
-                       FD_SET(sockfd, &fdset);
-                       res = select(sockfd + 1, &fdset, NULL, NULL, &timeout);
-                       if (res > 0) {
-                               if ((numbytes = recv(sockfd, recvbuf, MAXDATASIZE - 1, 0)) == -1) {
-                                       perror("recv");
-                                       fail++;
-                                       break;
-                               }
-                       } else {
-                               ERR("POP3 connection failed: timeout\n");
-                               fail++;
-                               break;
-                       }
-                       recvbuf[numbytes] = '\0';
-                       if (strstr(recvbuf, "+OK ") != recvbuf) {
-                               ERR("POP3 connection failed, probably not a POP3 server");
-                               fail++;
-                               break;
-                       }
-                       strncpy(sendbuf, "USER ", MAXDATASIZE);
-                       strncat(sendbuf, mail->user, MAXDATASIZE - strlen(sendbuf) - 1);
-                       strncat(sendbuf, "\r\n", MAXDATASIZE - strlen(sendbuf) - 1);
-                       if (send(sockfd, sendbuf, strlen(sendbuf), 0) == -1) {
-                               perror("send USER");
-                               fail++;
-                               break;
-                       }
-                       timeout.tv_sec = 60;    // 60 second timeout i guess
-                       timeout.tv_usec = 0;
-                       FD_ZERO(&fdset);
-                       FD_SET(sockfd, &fdset);
-                       res = select(sockfd + 1, &fdset, NULL, NULL, &timeout);
-                       if (res > 0) {
-                               if ((numbytes = recv(sockfd, recvbuf, MAXDATASIZE - 1, 0)) == -1) {
-                                       perror("recv USER");
-                                       fail++;
-                                       break;
-                               }
-                       }
-                       recvbuf[numbytes] = '\0';
-                       if (strstr(recvbuf, "+OK ") == NULL) {
-                               ERR("POP3 server login failed: %s", recvbuf);
-                               fail++;
-                               break;
-                       }
-                       strncpy(sendbuf, "PASS ", MAXDATASIZE);
-                       strncat(sendbuf, mail->pass, MAXDATASIZE - strlen(sendbuf) - 1);
-                       strncat(sendbuf, "\r\n", MAXDATASIZE - strlen(sendbuf) - 1);
-                       if (send(sockfd, sendbuf, strlen(sendbuf), 0) == -1) {
-                               perror("send PASS");
-                               fail++;
-                               break;
-                       }
-                       timeout.tv_sec = 60;    // 60 second timeout i guess
-                       timeout.tv_usec = 0;
-                       FD_ZERO(&fdset);
-                       FD_SET(sockfd, &fdset);
-                       res = select(sockfd + 1, &fdset, NULL, NULL, &timeout);
-                       if (res > 0) {
-                               if ((numbytes = recv(sockfd, recvbuf, MAXDATASIZE - 1, 0)) == -1) {
-                                       perror("recv PASS");
-                                       fail++;
-                                       break;
-                               }
-                       }
-                       recvbuf[numbytes] = '\0';
-                       if (strstr(recvbuf, "+OK ") == NULL) {
-                               ERR("POP3 server login failed: %s", recvbuf);
-                               fail++;
-                               break;
-                       }
-                       strncpy(sendbuf, "STAT\r\n", MAXDATASIZE);
-                       if (send(sockfd, sendbuf, strlen(sendbuf), 0) == -1) {
-                               perror("send STAT");
-                               fail++;
-                               break;
-                       }
-                       timeout.tv_sec = 60;    // 60 second timeout i guess
-                       timeout.tv_usec = 0;
-                       FD_ZERO(&fdset);
-                       FD_SET(sockfd, &fdset);
-                       res = select(sockfd + 1, &fdset, NULL, NULL, &timeout);
-                       if (res > 0) {
-                               if ((numbytes = recv(sockfd, recvbuf, MAXDATASIZE - 1, 0)) == -1) {
-                                       perror("recv STAT");
-                                       fail++;
-                                       break;
-                               }
-                       }
-                       recvbuf[numbytes] = '\0';
-                       if (strstr(recvbuf, "+OK ") == NULL) {
-                               ERR("POP3 status failed: %s", recvbuf);
-                               fail++;
-                               break;
-                       }
-                       // now we get the data
-                       reply = recvbuf + 4;
-                       if (reply == NULL) {
-                               ERR("Error parsing POP3 response: %s", recvbuf);
-                               fail++;
-                               break;
-                       } else {
-                               timed_thread_lock(mail->p_timed_thread);
-                               sscanf(reply, "%lu %lu", &mail->unseen, &mail->used);
-                               timed_thread_unlock(mail->p_timed_thread);
-                       }
-                       strncpy(sendbuf, "QUIT\r\n", MAXDATASIZE);
-                       if (send(sockfd, sendbuf, strlen(sendbuf), 0) == -1) {
-                               perror("send QUIT");
-                               fail++;
-                               break;
-                       }
-                       timeout.tv_sec = 60;    // 60 second timeout i guess
-                       timeout.tv_usec = 0;
-                       FD_ZERO(&fdset);
-                       FD_SET(sockfd, &fdset);
-                       res = select(sockfd + 1, &fdset, NULL, NULL, &timeout);
-                       if (res > 0) {
-                               if ((numbytes = recv(sockfd, recvbuf, MAXDATASIZE - 1, 0)) == -1) {
-                                       perror("recv QUIT");
-                                       fail++;
-                                       break;
-                               }
-                       }
-                       recvbuf[numbytes] = '\0';
-                       if (strstr(recvbuf, "+OK") == NULL) {
-                               ERR("POP3 logout failed: %s", recvbuf);
-                               fail++;
-                               break;
-                       }
-                       if (strlen(mail->command) > 1 && mail->unseen > old_unseen) {
-                               // new mail goodie
-                               if (system(mail->command) == -1) {
-                                       perror("system()");
-                               }
-                       }
-                       fail = 0;
-                       old_unseen = mail->unseen;
-               } while (0);
-               if ((fstat(sockfd, &stat_buf) == 0) && S_ISSOCK(stat_buf.st_mode)) {
-                       /* if a valid socket, close it */
-                       close(sockfd);
-               }
-               if (timed_thread_test(mail->p_timed_thread)) {
-                       timed_thread_exit(mail->p_timed_thread);
-               }
-       }
-       mail->unseen = 0;
-       mail->used = 0;
-       return 0;
-}
+       struct text_object text_object, struct information *cur);
 
 static inline void read_exec(const char *data, char *buf, const int size)
 {
@@ -2201,7 +1186,7 @@ void *threaded_exec(void *arg)
                        p2++;
                }
                timed_thread_unlock(obj->data.texeci.p_timed_thread);
-               if (timed_thread_test(obj->data.texeci.p_timed_thread)) {
+               if (timed_thread_test(obj->data.texeci.p_timed_thread, 0)) {
                        timed_thread_exit(obj->data.texeci.p_timed_thread);
                }
        }
@@ -2218,56 +1203,55 @@ static struct text_object *new_text_object_internal(void)
 /*
  * call with full == 0 when freeing after 'internal' evaluation of objects
  */
-static void free_text_objects(struct text_object_list *text_object_list, char full)
+static void free_text_objects(struct text_object *root, char full)
 {
-       unsigned int i;
        struct text_object *obj;
 
-       if (text_object_list == NULL) {
+       if (!root->prev) {
                return;
        }
 
-       for (i = 0; i < text_object_list->text_object_count; i++) {
-               obj = &text_object_list->text_objects[i];
+#define data obj->data
+       for (obj = root->prev; obj; obj = root->prev) {
+               root->prev = obj->prev;
                switch (obj->type) {
 #ifndef __OpenBSD__
                        case OBJ_acpitemp:
-                       case OBJ_acpitempf:
-                               close(obj->data.i);
+                               close(data.i);
                                break;
                        case OBJ_i2c:
                        case OBJ_platform:
                        case OBJ_hwmon:
-                               close(obj->data.sysfs.fd);
+                               close(data.sysfs.fd);
                                break;
 #endif /* !__OpenBSD__ */
                        case OBJ_time:
                        case OBJ_utime:
-                               free(obj->data.s);
+                               free(data.s);
                                break;
                        case OBJ_tztime:
-                               free(obj->data.tztime.tz);
-                               free(obj->data.tztime.fmt);
+                               free(data.tztime.tz);
+                               free(data.tztime.fmt);
                                break;
                        case OBJ_mboxscan:
-                               free(obj->data.mboxscan.args);
-                               free(obj->data.mboxscan.output);
+                               free(data.mboxscan.args);
+                               free(data.mboxscan.output);
                                break;
                        case OBJ_mails:
                        case OBJ_new_mails:
-                               free(obj->data.local_mail.box);
+                               free(data.local_mail.box);
                                break;
                        case OBJ_imap:
                                free(info.mail);
                                break;
                        case OBJ_imap_unseen:
                                if (!obj->global_mode) {
-                                       free(obj->data.mail);
+                                       free(data.mail);
                                }
                                break;
                        case OBJ_imap_messages:
                                if (!obj->global_mode) {
-                                       free(obj->data.mail);
+                                       free(data.mail);
                                }
                                break;
                        case OBJ_pop3:
@@ -2275,24 +1259,24 @@ static void free_text_objects(struct text_object_list *text_object_list, char fu
                                break;
                        case OBJ_pop3_unseen:
                                if (!obj->global_mode) {
-                                       free(obj->data.mail);
+                                       free(data.mail);
                                }
                                break;
                        case OBJ_pop3_used:
                                if (!obj->global_mode) {
-                                       free(obj->data.mail);
+                                       free(data.mail);
                                }
                                break;
                        case OBJ_if_empty:
                        case OBJ_if_existing:
                        case OBJ_if_mounted:
                        case OBJ_if_running:
-                               free(obj->data.ifblock.s);
-                               free(obj->data.ifblock.str);
+                               free(data.ifblock.s);
+                               free(data.ifblock.str);
                                break;
                        case OBJ_tail:
-                               free(obj->data.tail.logfile);
-                               free(obj->data.tail.buffer);
+                               free(data.tail.logfile);
+                               free(data.tail.buffer);
                                break;
                        case OBJ_text:
                        case OBJ_font:
@@ -2301,7 +1285,7 @@ static void free_text_objects(struct text_object_list *text_object_list, char fu
                        case OBJ_execbar:
                        case OBJ_execgraph:
                        case OBJ_execp:
-                               free(obj->data.s);
+                               free(data.s);
                                break;
 #ifdef HAVE_ICONV
                        case OBJ_iconv_start:
@@ -2310,15 +1294,15 @@ static void free_text_objects(struct text_object_list *text_object_list, char fu
 #endif
 #ifdef __LINUX__
                        case OBJ_disk_protect:
-                               free(objs[i].data.s);
+                               free(obj->data.s);
                                break;
                        case OBJ_if_up:
-                               free(objs[i].data.ifblock.s);
-                               free(objs[i].data.ifblock.str);
+                               free(obj->data.ifblock.s);
+                               free(obj->data.ifblock.str);
                                break;
                        case OBJ_if_gw:
-                               free(objs[i].data.ifblock.s);
-                               free(objs[i].data.ifblock.str);
+                               free(obj->data.ifblock.s);
+                               free(obj->data.ifblock.str);
                        case OBJ_gw_iface:
                        case OBJ_gw_ip:
                                if (info.gw_info.iface) {
@@ -2331,8 +1315,8 @@ static void free_text_objects(struct text_object_list *text_object_list, char fu
                                }
                                break;
                        case OBJ_ioscheduler:
-                               if(objs[i].data.s)
-                                       free(objs[i].data.s);
+                               if(obj->data.s)
+                                       free(obj->data.s);
                                break;
 #endif
 #ifdef XMMS2
@@ -2420,30 +1404,30 @@ static void free_text_objects(struct text_object_list *text_object_list, char fu
 #endif
 #ifdef RSS
                        case OBJ_rss:
-                               free(obj->data.rss.uri);
-                               free(obj->data.rss.action);
+                               free(data.rss.uri);
+                               free(data.rss.action);
                                break;
 #endif
                        case OBJ_pre_exec:
                                break;
 #ifndef __OpenBSD__
                        case OBJ_battery:
-                               free(obj->data.s);
+                               free(data.s);
                                break;
                        case OBJ_battery_time:
-                               free(obj->data.s);
+                               free(data.s);
                                break;
 #endif /* !__OpenBSD__ */
                        case OBJ_execpi:
                        case OBJ_execi:
                        case OBJ_execibar:
                        case OBJ_execigraph:
-                               free(obj->data.execi.cmd);
-                               free(obj->data.execi.buffer);
+                               free(data.execi.cmd);
+                               free(data.execi.buffer);
                                break;
                        case OBJ_texeci:
-                               free(obj->data.texeci.cmd);
-                               free(obj->data.texeci.buffer);
+                               free(data.texeci.cmd);
+                               free(data.texeci.buffer);
                                break;
                        case OBJ_nameserver:
                                free_dns_data();
@@ -2457,9 +1441,10 @@ static void free_text_objects(struct text_object_list *text_object_list, char fu
                                break;
 #ifdef HDDTEMP
                        case OBJ_hddtemp:
-                               free(obj->data.hddtemp.dev);
-                               free(obj->data.hddtemp.addr);
-                               free(obj->data.hddtemp.temp);
+                               free(data.hddtemp.dev);
+                               free(data.hddtemp.addr);
+                               if (data.hddtemp.temp)
+                                       free(data.hddtemp.temp);
                                break;
 #endif
                        case OBJ_entropy_avail:
@@ -2489,11 +1474,11 @@ static void free_text_objects(struct text_object_list *text_object_list, char fu
                        case OBJ_smapi_bat_perc:
                        case OBJ_smapi_bat_temp:
                        case OBJ_smapi_bat_power:
-                               free(obj->data.s);
+                               free(data.s);
                                break;
                        case OBJ_if_smapi_bat_installed:
-                               free(obj->data.ifblock.s);
-                               free(obj->data.ifblock.str);
+                               free(data.ifblock.s);
+                               free(data.ifblock.str);
                                break;
 #endif
 #ifdef NVIDIA
@@ -2520,6 +1505,7 @@ static void free_text_objects(struct text_object_list *text_object_list, char fu
                        case OBJ_mpd_file:
                        case OBJ_mpd_percent:
                        case OBJ_mpd_smart:
+                       case OBJ_if_mpd_playing:
                                if (full) {
                                        free_mpd_vars(&info.mpd);
                                }
@@ -2541,14 +1527,14 @@ static void free_text_objects(struct text_object_list *text_object_list, char fu
       break;
 #endif
                        case OBJ_scroll:
-                               free(obj->data.scroll.text);
+                               free(data.scroll.text);
                                break;
                }
+               free(obj);
        }
+#undef data
+       /* FIXME: below is surely useless */
        if (full) {} // disable warning when MPD !defined
-       free(text_object_list->text_objects);
-       text_object_list->text_objects = NULL;
-       text_object_list->text_object_count = 0;
 }
 
 void scan_mixer_bar(const char *arg, int *a, int *w, int *h)
@@ -2565,14 +1551,29 @@ void scan_mixer_bar(const char *arg, int *a, int *w, int *h)
        }
 }
 
-/* strip a leading /dev/ if any */
-#define DEV_NAME(x) x != NULL && strlen(x) > 5 && strncmp(x, "/dev/", 5) == 0 \
-       ? x + 5 : x
+/* strip a leading /dev/ if any, following symlinks first
+ *
+ * BEWARE: this function returns a pointer to static content
+ *         which gets overwritten in consecutive calls. I.e.:
+ *         this function is NOT reentrant.
+ */
+const char *dev_name(const char *path)
+{
+       static char buf[255];   /* should be enough for pathnames */
+       ssize_t buflen;
+
+#define DEV_NAME(x) \
+  x != NULL && strlen(x) > 5 && strncmp(x, "/dev/", 5) == 0 ? x + 5 : x
+       if ((buflen = readlink(path, buf, 254)) == -1)
+               return DEV_NAME(path);
+       buf[buflen] = '\0';
+       return DEV_NAME(buf);
+#undef DEV_NAME
+}
 
 /* construct_text_object() creates a new text_object */
 static struct text_object *construct_text_object(const char *s,
-               const char *arg, unsigned int object_count,
-               struct text_object *text_objects, long line, char allow_threaded)
+               const char *arg, long line, char allow_threaded)
 {
        // struct text_object *obj = new_text_object();
        struct text_object *obj = new_text_object_internal();
@@ -2596,8 +1597,6 @@ static struct text_object *construct_text_object(const char *s,
 #else
        OBJ(acpitemp, 0)
                obj->data.i = open_acpi_temperature(arg);
-       END OBJ(acpitempf, 0)
-               obj->data.i = open_acpi_temperature(arg);
        END OBJ(acpiacadapter, 0)
        END OBJ(freq, INFO_FREQ)
 #endif /* !__OpenBSD__ */
@@ -2699,8 +1698,6 @@ static struct text_object *construct_text_object(const char *s,
 #endif /* HAVE_IWLIB */
 
 #endif /* __linux__ */
-       END OBJ(freq_dyn, 0)
-       END OBJ(freq_dyn_g, 0)
 
 #ifndef __OpenBSD__
        END OBJ(acpifan, 0)
@@ -2746,14 +1743,13 @@ static struct text_object *construct_text_object(const char *s,
 #if defined(__linux__)
        END OBJ(disk_protect, 0)
                if (arg)
-                       obj->data.s = strndup(DEV_NAME(arg), text_buffer_size);
+                       obj->data.s = strndup(dev_name(arg), text_buffer_size);
                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)
        END OBJ(i8k_cpu_temp, INFO_I8K)
-       END OBJ(i8k_cpu_tempf, INFO_I8K)
        END OBJ(i8k_left_fan_status, INFO_I8K)
        END OBJ(i8k_right_fan_status, INFO_I8K)
        END OBJ(i8k_left_fan_rpm, INFO_I8K)
@@ -2774,30 +1770,20 @@ static struct text_object *construct_text_object(const char *s,
        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 = strndup(arg, text_buffer_size);
-               blockstart[blockdepth] = object_count;
-               obj->data.ifblock.pos = object_count + 2;
-               blockdepth++;
+               obj_be_ifblock_if(obj);
        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++;
+               obj_be_ifblock_if(obj);
        END OBJ(ioscheduler, 0)
                if (!arg) {
                        CRIT_ERR("get_ioscheduler needs an argument (e.g. hda)");
                        obj->data.s = 0;
                } else
-                       obj->data.s = strndup(DEV_NAME(arg), text_buffer_size);
+                       obj->data.s = strndup(dev_name(arg), text_buffer_size);
        END OBJ(laptop_mode, 0)
        END OBJ(pb_battery, 0)
                if (arg && strcmp(arg, "status") == EQUAL) {
@@ -2859,6 +1845,7 @@ static struct text_object *construct_text_object(const char *s,
                        } else {
                                obj->data.cpu_index = 0;
                        }
+                       DBGP2("Adding $cpu for CPU %d", obj->data.cpu_index);
                } else {
                        obj->data.cpu_index = 0;
                }
@@ -2875,6 +1862,7 @@ static struct text_object *construct_text_object(const char *s,
                        scan_bar(arg, &obj->a, &obj->b);
                        obj->data.cpu_index = 0;
                }
+               DBGP2("Adding $cpubar for CPU %d", obj->data.cpu_index);
        END OBJ(cpugraph, INFO_CPU)
                char *buf = scan_graph(arg, &obj->a, &obj->b, &obj->c, &obj->d,
                        &obj->e, &obj->showaslog);
@@ -2887,6 +1875,7 @@ static struct text_object *construct_text_object(const char *s,
                        }
                        free(buf);
                }
+               DBGP2("Adding $cpugraph for CPU %d", obj->data.cpu_index);
        END OBJ(loadgraph, INFO_LOADAVG)
                char *buf = scan_graph(arg, &obj->a, &obj->b, &obj->c, &obj->d,
                                &obj->e, &obj->showaslog);
@@ -2901,24 +1890,24 @@ static struct text_object *construct_text_object(const char *s,
 #if defined(__linux__)
        END OBJ(diskio, INFO_DISKIO)
                if (arg) {
-                       obj->data.diskio = prepare_diskio_stat(DEV_NAME(arg));
+                       obj->data.diskio = prepare_diskio_stat(dev_name(arg));
                } else {
                        obj->data.diskio = NULL;
                }
        END OBJ(diskio_read, INFO_DISKIO)
                if (arg) {
-                       obj->data.diskio = prepare_diskio_stat(DEV_NAME(arg));
+                       obj->data.diskio = prepare_diskio_stat(dev_name(arg));
                } else {
                        obj->data.diskio = NULL;
                }
        END OBJ(diskio_write, INFO_DISKIO)
                if (arg) {
-                       obj->data.diskio = prepare_diskio_stat(DEV_NAME(arg));
+                       obj->data.diskio = prepare_diskio_stat(dev_name(arg));
                } else {
                        obj->data.diskio = NULL;
                }
        END OBJ(diskiograph, INFO_DISKIO)
-               char *buf = scan_graph(DEV_NAME(arg), &obj->a, &obj->b, &obj->c, &obj->d,
+               char *buf = scan_graph(dev_name(arg), &obj->a, &obj->b, &obj->c, &obj->d,
                        &obj->e, &obj->showaslog);
 
                if (buf) {
@@ -2928,7 +1917,7 @@ static struct text_object *construct_text_object(const char *s,
                        obj->data.diskio = NULL;
                }
        END OBJ(diskiograph_read, INFO_DISKIO)
-               char *buf = scan_graph(DEV_NAME(arg), &obj->a, &obj->b, &obj->c, &obj->d,
+               char *buf = scan_graph(dev_name(arg), &obj->a, &obj->b, &obj->c, &obj->d,
                        &obj->e, &obj->showaslog);
 
                if (buf) {
@@ -2938,7 +1927,7 @@ static struct text_object *construct_text_object(const char *s,
                        obj->data.diskio = NULL;
                }
        END OBJ(diskiograph_write, INFO_DISKIO)
-               char *buf = scan_graph(DEV_NAME(arg), &obj->a, &obj->b, &obj->c, &obj->d,
+               char *buf = scan_graph(dev_name(arg), &obj->a, &obj->b, &obj->c, &obj->d,
                        &obj->e, &obj->showaslog);
 
                if (buf) {
@@ -2998,22 +1987,9 @@ static struct text_object *construct_text_object(const char *s,
                obj->data.net = get_net_stat(buf);
                free(buf);
        END OBJ(else, 0)
-               if (blockdepth) {
-                       (text_objects[blockstart[blockdepth - 1]]).data.ifblock.pos =
-                               object_count;
-                       blockstart[blockdepth - 1] = object_count;
-                       obj->data.ifblock.pos = object_count + 2;
-               } else {
-                       ERR("$else: no matching $if_*");
-               }
+               obj_be_ifblock_else(obj);
        END OBJ(endif, 0)
-               if (blockdepth) {
-                       blockdepth--;
-                       text_objects[blockstart[blockdepth]].data.ifblock.pos =
-                               object_count;
-               } else {
-                       ERR("$endif: no matching $if_*");
-               }
+               obj_be_ifblock_endif(obj);
        END OBJ(image, 0)
                obj->data.s = strndup(arg ? arg : "", text_buffer_size);
 #ifdef HAVE_POPEN
@@ -3557,22 +2533,14 @@ static struct text_object *construct_text_object(const char *s,
                obj->data.loadavg[1] = (r >= 2) ? (unsigned char) b : 0;
                obj->data.loadavg[2] = (r >= 3) ? (unsigned char) c : 0;
        END OBJ(if_empty, 0)
-               if (blockdepth >= MAX_IF_BLOCK_DEPTH) {
-                       CRIT_ERR("MAX_IF_BLOCK_DEPTH exceeded");
-               }
                if (!arg) {
                        ERR("if_empty needs an argument");
                        obj->data.ifblock.s = 0;
                } else {
                        obj->data.ifblock.s = strndup(arg, text_buffer_size);
                }
-               blockstart[blockdepth] = object_count;
-               obj->data.ifblock.pos = object_count + 2;
-               blockdepth++;
+               obj_be_ifblock_if(obj);
        END OBJ(if_existing, 0)
-               if (blockdepth >= MAX_IF_BLOCK_DEPTH) {
-                       CRIT_ERR("MAX_IF_BLOCK_DEPTH exceeded");
-               }
                if (!arg) {
                        ERR("if_existing needs an argument or two");
                        obj->data.ifblock.s = NULL;
@@ -3589,26 +2557,17 @@ static struct text_object *construct_text_object(const char *s,
                                obj->data.ifblock.str = strndup(buf2, text_buffer_size);
                        }
                }
-               blockstart[blockdepth] = object_count;
-               obj->data.ifblock.pos = object_count + 2;
-               blockdepth++;
+               DBGP("if_existing: '%s' '%s'", obj->data.ifblock.s, obj->data.ifblock.str);
+               obj_be_ifblock_if(obj);
        END OBJ(if_mounted, 0)
-               if (blockdepth >= MAX_IF_BLOCK_DEPTH) {
-                       CRIT_ERR("MAX_IF_BLOCK_DEPTH exceeded");
-               }
                if (!arg) {
                        ERR("if_mounted needs an argument");
                        obj->data.ifblock.s = 0;
                } else {
                        obj->data.ifblock.s = strndup(arg, text_buffer_size);
                }
-               blockstart[blockdepth] = object_count;
-               obj->data.ifblock.pos = object_count + 2;
-               blockdepth++;
+               obj_be_ifblock_if(obj);
        END OBJ(if_running, 0)
-               if (blockdepth >= MAX_IF_BLOCK_DEPTH) {
-                       CRIT_ERR("MAX_IF_BLOCK_DEPTH exceeded");
-               }
                if (arg) {
                        char buf[256];
 
@@ -3618,9 +2577,7 @@ static struct text_object *construct_text_object(const char *s,
                        ERR("if_running needs an argument");
                        obj->data.ifblock.s = 0;
                }
-               blockstart[blockdepth] = object_count;
-               obj->data.ifblock.pos = object_count + 2;
-               blockdepth++;
+               obj_be_ifblock_if(obj);
        END OBJ(kernel, 0)
        END OBJ(machine, 0)
        END OBJ(mails, 0)
@@ -3862,7 +2819,7 @@ static struct text_object *construct_text_object(const char *s,
        END OBJ_THREAD(imap_unseen, 0)
                if (arg) {
                        // proccss
-                       obj->data.mail = parse_mail_args(IMAP, arg);
+                       obj->data.mail = parse_mail_args(IMAP_TYPE, arg);
                        obj->global_mode = 0;
                } else {
                        obj->global_mode = 1;
@@ -3870,7 +2827,7 @@ static struct text_object *construct_text_object(const char *s,
        END OBJ_THREAD(imap_messages, 0)
                if (arg) {
                        // proccss
-                       obj->data.mail = parse_mail_args(IMAP, arg);
+                       obj->data.mail = parse_mail_args(IMAP_TYPE, arg);
                        obj->global_mode = 0;
                } else {
                        obj->global_mode = 1;
@@ -3878,7 +2835,7 @@ static struct text_object *construct_text_object(const char *s,
        END OBJ_THREAD(pop3_unseen, 0)
                if (arg) {
                        // proccss
-                       obj->data.mail = parse_mail_args(POP3, arg);
+                       obj->data.mail = parse_mail_args(POP3_TYPE, arg);
                        obj->global_mode = 0;
                } else {
                        obj->global_mode = 1;
@@ -3886,7 +2843,7 @@ static struct text_object *construct_text_object(const char *s,
        END OBJ_THREAD(pop3_used, 0)
                if (arg) {
                        // proccss
-                       obj->data.mail = parse_mail_args(POP3, arg);
+                       obj->data.mail = parse_mail_args(POP3_TYPE, arg);
                        obj->global_mode = 0;
                } else {
                        obj->global_mode = 1;
@@ -3898,17 +2855,12 @@ static struct text_object *construct_text_object(const char *s,
                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 = strndup(arg, text_buffer_size);
-               blockstart[blockdepth] = object_count;
-               obj->data.ifblock.pos = object_count + 2;
-               blockdepth++;
+               obj_be_ifblock_if(obj);
        END OBJ(smapi_bat_perc, 0)
                if (arg)
                        obj->data.s = strndup(arg, text_buffer_size);
@@ -3935,17 +2887,29 @@ static struct text_object *construct_text_object(const char *s,
                                arg = scan_bar(arg + cnt, &obj->a, &obj->b);
                        }
                } else
-                       ERR("if_smapi_bat_bar needs an argument");
+                       ERR("smapi_bat_bar needs an argument");
 #endif /* SMAPI */
 #ifdef MPD
        END OBJ_THREAD(mpd_artist, INFO_MPD)
+               if (arg) {
+                       sscanf(arg, "%d", &obj->data.i);
+                       if (obj->data.i > 0) {
+                               obj->data.i++;
+                       } else {
+                               ERR("mpd_artist: invalid length argument");
+                               obj->data.i = 0;
+                       }
+               } else {
+                       obj->data.i = 0;
+               }
        END OBJ_THREAD(mpd_title, INFO_MPD)
                if (arg) {
                        sscanf(arg, "%d", &obj->data.i);
                        if (obj->data.i > 0) {
                                obj->data.i++;
                        } else {
-                               CRIT_ERR("mpd_title: invalid length argument");
+                               ERR("mpd_title: invalid length argument");
+                               obj->data.i = 0;
                        }
                } else {
                        obj->data.i = 0;
@@ -3955,10 +2919,54 @@ static struct text_object *construct_text_object(const char *s,
        END OBJ_THREAD(mpd_elapsed, INFO_MPD)
        END OBJ_THREAD(mpd_length, INFO_MPD)
        END OBJ_THREAD(mpd_track, INFO_MPD)
+               if (arg) {
+                       sscanf(arg, "%d", &obj->data.i);
+                       if (obj->data.i > 0) {
+                               obj->data.i++;
+                       } else {
+                               ERR("mpd_track: invalid length argument");
+                               obj->data.i = 0;
+                       }
+               } else {
+                       obj->data.i = 0;
+               }
        END OBJ_THREAD(mpd_name, INFO_MPD)
+               if (arg) {
+                       sscanf(arg, "%d", &obj->data.i);
+                       if (obj->data.i > 0) {
+                               obj->data.i++;
+                       } else {
+                               ERR("mpd_name: invalid length argument");
+                               obj->data.i = 0;
+                       }
+               } else {
+                       obj->data.i = 0;
+               }
        END OBJ_THREAD(mpd_file, INFO_MPD)
+               if (arg) {
+                       sscanf(arg, "%d", &obj->data.i);
+                       if (obj->data.i > 0) {
+                               obj->data.i++;
+                       } else {
+                               ERR("mpd_file: invalid length argument");
+                               obj->data.i = 0;
+                       }
+               } else {
+                       obj->data.i = 0;
+               }
        END OBJ_THREAD(mpd_percent, INFO_MPD)
        END OBJ_THREAD(mpd_album, INFO_MPD)
+               if (arg) {
+                       sscanf(arg, "%d", &obj->data.i);
+                       if (obj->data.i > 0) {
+                               obj->data.i++;
+                       } else {
+                               ERR("mpd_album: invalid length argument");
+                               obj->data.i = 0;
+                       }
+               } else {
+                       obj->data.i = 0;
+               }
        END OBJ_THREAD(mpd_vol, INFO_MPD)
        END OBJ_THREAD(mpd_bitrate, INFO_MPD)
        END OBJ_THREAD(mpd_status, INFO_MPD)
@@ -3970,11 +2978,14 @@ static struct text_object *construct_text_object(const char *s,
                        if (obj->data.i > 0) {
                                obj->data.i++;
                        } else {
-                               CRIT_ERR("mpd_smart: invalid length argument");
+                               ERR("mpd_smart: invalid length argument");
+                               obj->data.i = 0;
                        }
                } else {
                        obj->data.i = 0;
                }
+       END OBJ_THREAD(if_mpd_playing, INFO_MPD)
+               obj_be_ifblock_if(obj);
 #endif /* MPD */
 #ifdef MOC
   END OBJ_THREAD(moc_state, INFO_MOC)
@@ -4010,6 +3021,8 @@ static struct text_object *construct_text_object(const char *s,
        END OBJ(xmms2_smart, INFO_XMMS2)
        END OBJ(xmms2_playlist, INFO_XMMS2)
        END OBJ(xmms2_timesplayed, INFO_XMMS2)
+       END OBJ(if_xmms2_connected, INFO_XMMS2)
+               obj_be_ifblock_if(obj);
 #endif
 #ifdef AUDACIOUS
        END OBJ(audacious_status, INFO_AUDACIOUS)
@@ -4032,6 +3045,7 @@ static struct text_object *construct_text_object(const char *s,
        END OBJ(audacious_filename, INFO_AUDACIOUS)
        END OBJ(audacious_playlist_length, INFO_AUDACIOUS)
        END OBJ(audacious_playlist_position, INFO_AUDACIOUS)
+       END OBJ(audacious_main_volume, INFO_AUDACIOUS)
        END OBJ(audacious_bar, INFO_AUDACIOUS)
                scan_bar(arg, &obj->a, &obj->b);
 #endif
@@ -4089,111 +3103,31 @@ static struct text_object *construct_text_object(const char *s,
 #endif
 #ifdef HDDTEMP
        END OBJ(hddtemp, 0)
-               if (!arg || scan_hddtemp(arg, &obj->data.hddtemp.dev,
-                                       &obj->data.hddtemp.addr, &obj->data.hddtemp.port, &obj->data.hddtemp.temp)) {
+               if (scan_hddtemp(arg, &obj->data.hddtemp.dev,
+                                &obj->data.hddtemp.addr, &obj->data.hddtemp.port)) {
                        ERR("hddtemp needs arguments");
                        obj->type = OBJ_text;
                        obj->data.s = strndup("${hddtemp}", text_buffer_size);
                        obj->data.hddtemp.update_time = 0;
-                       return NULL;
-               }
+               } else
+                       obj->data.hddtemp.temp = NULL;
 #endif
 #ifdef TCP_PORT_MONITOR
        END OBJ(tcp_portmon, INFO_TCP_PORT_MONITOR)
-               int argc, port_begin, port_end, item, connection_index;
-               char itembuf[32];
-
-               memset(itembuf, 0, sizeof(itembuf));
-               connection_index = 0;
-               /* massive argument checking */
-               if (!arg) {
-                       CRIT_ERR("tcp_portmon: needs arguments");
-               }
-               argc = sscanf(arg, "%d %d %31s %d", &port_begin, &port_end, itembuf,
-                               &connection_index);
-               if ((argc != 3) && (argc != 4)) {
-                       CRIT_ERR("tcp_portmon: requires 3 or 4 arguments");
-               }
-               if ((port_begin < 1) || (port_begin > 65535) || (port_end < 1)
-                               || (port_end > 65535)) {
-                       CRIT_ERR("tcp_portmon: port values must be from 1 to 65535");
-               }
-               if (port_begin > port_end) {
-                       CRIT_ERR("tcp_portmon: starting port must be <= ending port");
-               }
-               if (strncmp(itembuf, "count", 31) == EQUAL) {
-                       item = COUNT;
-               } else if (strncmp(itembuf, "rip", 31) == EQUAL) {
-                       item = REMOTEIP;
-               } else if (strncmp(itembuf, "rhost", 31) == EQUAL) {
-                       item = REMOTEHOST;
-               } else if (strncmp(itembuf, "rport", 31) == EQUAL) {
-                       item = REMOTEPORT;
-               } else if (strncmp(itembuf, "rservice", 31) == EQUAL) {
-                       item = REMOTESERVICE;
-               } else if (strncmp(itembuf, "lip", 31) == EQUAL) {
-                       item = LOCALIP;
-               } else if (strncmp(itembuf, "lhost", 31) == EQUAL) {
-                       item = LOCALHOST;
-               } else if (strncmp(itembuf, "lport", 31) == EQUAL) {
-                       item = LOCALPORT;
-               } else if (strncmp(itembuf, "lservice", 31) == EQUAL) {
-                       item = LOCALSERVICE;
-               } else {
-                       CRIT_ERR("tcp_portmon: invalid item specified");
-               }
-               if ((argc == 3) && (item != COUNT)) {
-                       CRIT_ERR("tcp_portmon: 3 argument form valid only for \"count\" "
-                                       "item");
-               }
-               if ((argc == 4) && (connection_index < 0)) {
-                       CRIT_ERR("tcp_portmon: connection index must be non-negative");
-               }
-               /* ok, args looks good. save the text object data */
-               obj->data.tcp_port_monitor.port_range_begin = (in_port_t) port_begin;
-               obj->data.tcp_port_monitor.port_range_end = (in_port_t) port_end;
-               obj->data.tcp_port_monitor.item = item;
-               obj->data.tcp_port_monitor.connection_index = connection_index;
-
-               /* if the port monitor collection hasn't been created,
-                * we must create it */
-               if (!info.p_tcp_port_monitor_collection) {
-                       info.p_tcp_port_monitor_collection =
-                               create_tcp_port_monitor_collection();
-                       if (!info.p_tcp_port_monitor_collection) {
-                               CRIT_ERR("tcp_portmon: unable to create port monitor "
-                                               "collection");
-                       }
-               }
-
-               /* if a port monitor for this port does not exist,
-                * create one and add it to the collection */
-               if (find_tcp_port_monitor(info.p_tcp_port_monitor_collection,
-                                       port_begin, port_end) == NULL) {
-                       tcp_port_monitor_t *p_monitor = create_tcp_port_monitor(port_begin,
-                                       port_end, &tcp_port_monitor_args);
-
-                       if (!p_monitor) {
-                               CRIT_ERR("tcp_portmon: unable to create port monitor");
-                       }
-                       /* add the newly created monitor to the collection */
-                       if (insert_tcp_port_monitor_into_collection(
-                                               info.p_tcp_port_monitor_collection, p_monitor) != 0) {
-                               CRIT_ERR("tcp_portmon: unable to add port monitor to "
-                                               "collection");
-                       }
-               }
+               tcp_portmon_init(arg, &obj->data.tcp_port_monitor);
 #endif
        END OBJ(entropy_avail, INFO_ENTROPY)
                END OBJ(entropy_poolsize, INFO_ENTROPY)
                END OBJ(entropy_bar, INFO_ENTROPY)
                scan_bar(arg, &obj->a, &obj->b);
        END OBJ(scroll, 0)
-               int n;
+               int n1, n2;
 
                obj->data.scroll.step = 1;
-               if (arg && sscanf(arg, "%u %u %n", &obj->data.scroll.show, &obj->data.scroll.step, &n) > 0) {
-                       obj->data.scroll.text = strndup(arg + n, text_buffer_size);
+               if (arg && sscanf(arg, "%u %n", &obj->data.scroll.show, &n1) > 0) {
+                       if (sscanf(arg + n1, "%u %n", &obj->data.scroll.step, &n2) > 0)
+                               n1 += n2;
+                       obj->data.scroll.text = strndup(arg + n1, text_buffer_size);
                        obj->data.scroll.start = 0;
                } else {
                        CRIT_ERR("scroll needs arguments: <length> [<step>] <text>");
@@ -4235,19 +3169,206 @@ static struct text_object *create_plain_text(const char *s)
        return obj;
 }
 
-static struct text_object_list *extract_variable_text_internal(const char *const_p, char allow_threaded)
+/* backslash_escape - do the actual substitution task for template objects
+ *
+ * The field templates is used for substituting the \N occurences. Set it to
+ * NULL to leave them as they are.
+ */
+static char *backslash_escape(const char *src, char **templates, unsigned int template_count)
+{
+       char *src_dup;
+       const char *p;
+       unsigned int dup_idx = 0, dup_len;
+
+       dup_len = strlen(src);
+       src_dup = malloc(dup_len * sizeof(char));
+
+       p = src;
+       while (*p) {
+               switch (*p) {
+               case '\\':
+                       if (!*(p + 1))
+                               break;
+                       if (*(p + 1) == '\\') {
+                               src_dup[dup_idx++] = '\\';
+                               p++;
+                       } else if (*(p + 1) == ' ') {
+                               src_dup[dup_idx++] = ' ';
+                               p++;
+                       } else if (*(p + 1) == 'n') {
+                               src_dup[dup_idx++] = '\n';
+                               p++;
+                       } else if (templates) {
+                               unsigned int tmpl_num;
+                               int digits;
+                               if ((sscanf(p + 1, "%u%n", &tmpl_num, &digits) <= 0) ||
+                                   (tmpl_num > template_count))
+                                       break;
+                               dup_len += strlen(templates[tmpl_num - 1]);
+                               src_dup = realloc(src_dup, dup_len * sizeof(char));
+                               sprintf(src_dup + dup_idx, "%s", templates[tmpl_num - 1]);
+                               dup_idx += strlen(templates[tmpl_num - 1]);
+                               p += digits;
+                       }
+                       break;
+               default:
+                       src_dup[dup_idx++] = *p;
+                       break;
+               }
+               p++;
+       }
+       src_dup[dup_idx] = '\0';
+       src_dup = realloc(src_dup, (strlen(src_dup) + 1) * sizeof(char));
+       return src_dup;
+}
+
+/* handle_template_object - core logic of the template object
+ *
+ * use config variables like this:
+ * template1 = "$\1\2"
+ * template2 = "\1: ${fs_bar 4,100 \2} ${fs_used \2} / ${fs_size \2}"
+ *
+ * and use them like this:
+ * ${template1 node name}
+ * ${template2 root /}
+ * ${template2 cdrom /mnt/cdrom}
+ */
+static char *handle_template(const char *tmpl, const char *args)
+{
+       char *args_dup, *p, *p_old;
+       char **argsp = NULL;
+       unsigned int argcnt = 0, template_idx, i;
+       char *eval_text;
+
+       if ((sscanf(tmpl, "template%u", &template_idx) != 1) ||
+           (template_idx > 9))
+               return NULL;
+
+       args_dup = strdup(args);
+       p = args_dup;
+       while (*p) {
+               while (*p && (*p == ' ' && *(p - 1) != '\\'))
+                       p++;
+               if (*(p - 1) == '\\')
+                       p--;
+               p_old = p;
+               while (*p && (*p != ' ' || *(p - 1) == '\\'))
+                       p++;
+               if (*p) {
+                       (*p) = '\0';
+                       p++;
+               }
+               argsp = realloc(argsp, ++argcnt * sizeof(char *));
+               argsp[argcnt - 1] = p_old;
+       }
+       for (i = 0; i < argcnt; i++) {
+               char *tmp;
+               tmp = backslash_escape(argsp[i], NULL, 0);
+               DBGP2("%s: substituted arg '%s' to '%s'", tmpl, argsp[i], tmp);
+               argsp[i] = tmp;
+       }
+
+       eval_text = backslash_escape(template[template_idx], argsp, argcnt);
+       DBGP("substituted %s, output is '%s'", tmpl, eval_text);
+       free(args_dup);
+       for (i = 0; i < argcnt; i++)
+               free(argsp[i]);
+       free(argsp);
+       return eval_text;
+}
+
+static char *find_and_replace_templates(const char *inbuf)
+{
+       char *outbuf, *indup, *p, *o, *templ, *args, *tmpl_out;
+       int stack, outlen;
+
+       outlen = strlen(inbuf) + 1;
+       o = outbuf = calloc(outlen, sizeof(char));
+       memset(outbuf, 0, outlen * sizeof(char));
+
+       p = indup = strdup(inbuf);
+       while (*p) {
+               while (*p && *p != '$')
+                       *(o++) = *(p++);
+
+               if (!(*p))
+                       break;
+
+               if (strncmp(p, "$template", 9) && strncmp(p, "${template", 10)) {
+                       *(o++) = *(p++);
+                       continue;
+               }
+
+               if (*(p + 1) == '{') {
+                       templ = p + 2;
+                       while (*p != ' ')
+                               p++;
+                       *(p++) = '\0';
+                       args = p;
+                       stack = 1;
+                       while (stack > 0) {
+                               p++;
+                               if (*p == '{')
+                                       stack++;
+                               else if (*p == '}')
+                                       stack--;
+                       }
+                       *(p++) = '\0';
+               } else {
+                       templ = p + 1;
+                       while (*p != ' ')
+                               p++;
+                       *(p++) = '\0';
+                       args = NULL;
+               }
+               tmpl_out = handle_template(templ, args);
+               if (tmpl_out) {
+                       outlen += strlen(tmpl_out);
+                       outbuf = realloc(outbuf, outlen * sizeof(char));
+                       strcat (outbuf, tmpl_out);
+                       free(tmpl_out);
+                       o = outbuf + strlen(outbuf);
+               } else {
+                       ERR("failed to handle template '%s' with args '%s'", templ, args);
+               }
+       }
+       *o = '\0';
+       outbuf = realloc(outbuf, (strlen(outbuf) + 1) * sizeof(char));
+       free(indup);
+       return outbuf;
+}
+
+static int text_contains_templates(const char *text)
+{
+       if (strcasestr(text, "${template") != NULL)
+               return 1;
+       if (strcasestr(text, "$template") != NULL)
+               return 1;
+       return 0;
+}
+
+static int extract_variable_text_internal(struct text_object *retval, const char *const_p, char allow_threaded)
 {
-       struct text_object_list *retval;
        struct text_object *obj;
        char *p, *s, *orig_p;
        long line;
 
-       p = strndup(const_p, max_user_text);
+       p = strndup(const_p, max_user_text - 1);
+       while (text_contains_templates(p)) {
+               char *tmp;
+               tmp = find_and_replace_templates(p);
+               free(p);
+               p = tmp;
+       }
        s = orig_p = p;
 
-       retval = malloc(sizeof(struct text_object_list));
-       memset(retval, 0, sizeof(struct text_object_list));
-       retval->text_object_count = 0;
+       if (strcmp(p, const_p)) {
+               DBGP("replaced all templates in text: input is\n'%s'\noutput is\n'%s'", const_p, p);
+       } else {
+               DBGP("no templates to replace");
+       }
+
+       memset(retval, 0, sizeof(struct text_object));
 
        line = global_text_lines;
 
@@ -4259,14 +3380,7 @@ static struct text_object_list *extract_variable_text_internal(const char *const
                        *p = '\0';
                        obj = create_plain_text(s);
                        if (obj != NULL) {
-                               // allocate memory for the object
-                               retval->text_objects = realloc(retval->text_objects,
-                                               sizeof(struct text_object) *
-                                               (retval->text_object_count + 1));
-                               // assign the new object to the end of the list.
-                               memcpy(&retval->text_objects[retval->text_object_count++], obj,
-                                               sizeof(struct text_object));
-                               free(obj);
+                               append_object(retval, obj);
                        }
                        *p = '$';
                        p++;
@@ -4340,33 +3454,16 @@ static struct text_object_list *extract_variable_text_internal(const char *const
                                                tmp_p++;
                                        }
 
-                                       // create new object
-                                       obj = construct_text_object(buf, arg,
-                                                       retval->text_object_count, retval->text_objects, line, allow_threaded);
+                                       obj = construct_text_object(buf, arg, line, allow_threaded);
                                        if (obj != NULL) {
-                                               // allocate memory for the object
-                                               retval->text_objects = realloc(retval->text_objects,
-                                                               sizeof(struct text_object) *
-                                                               (retval->text_object_count + 1));
-                                               // assign the new object to the end of the list.
-                                               memcpy(
-                                                               &retval->text_objects[retval->text_object_count++],
-                                                               obj, sizeof(struct text_object));
-                                               free(obj);
+                                               append_object(retval, obj);
                                        }
                                }
                                continue;
                        } else {
                                obj = create_plain_text("$");
                                if (obj != NULL) {
-                                       // allocate memory for the object
-                                       retval->text_objects = realloc(retval->text_objects,
-                                                       sizeof(struct text_object) *
-                                                       (retval->text_object_count + 1));
-                                       // assign the new object to the end of the list.
-                                       memcpy(&retval->text_objects[retval->text_object_count++],
-                                                       obj, sizeof(struct text_object));
-                                       free(obj);
+                                       append_object(retval, obj);
                                }
                        }
                }
@@ -4374,27 +3471,20 @@ static struct text_object_list *extract_variable_text_internal(const char *const
        }
        obj = create_plain_text(s);
        if (obj != NULL) {
-               // allocate memory for the object
-               retval->text_objects = realloc(retval->text_objects,
-                               sizeof(struct text_object) * (retval->text_object_count + 1));
-               // assign the new object to the end of the list.
-               memcpy(&retval->text_objects[retval->text_object_count++], obj,
-                               sizeof(struct text_object));
-               free(obj);
+               append_object(retval, obj);
        }
 
-       if (blockdepth) {
+       if (!ifblock_stack_empty()) {
                ERR("one or more $endif's are missing");
        }
 
        free(orig_p);
-       return retval;
+       return 0;
 }
 
 static void extract_variable_text(const char *p)
 {
-       free_text_objects(global_text_object_list, 1);
-       free(global_text_object_list);
+       free_text_objects(&global_root_object, 1);
        if (tmpstring1) {
                free(tmpstring1);
                tmpstring1 = 0;
@@ -4408,16 +3498,14 @@ static void extract_variable_text(const char *p)
                text_buffer = 0;
        }
 
-       global_text_object_list = extract_variable_text_internal(p, 1);
+       extract_variable_text_internal(&global_root_object, p, 1);
 }
 
-struct text_object_list *parse_conky_vars(char *txt, char *p, struct information *cur)
+int parse_conky_vars(struct text_object *root, char *txt, char *p, struct information *cur)
 {
-       struct text_object_list *object_list =
-               extract_variable_text_internal(txt, 0);
-
-       generate_text_internal(p, max_user_text, object_list, cur);
-       return object_list;
+       extract_variable_text_internal(root, txt, 0);
+       generate_text_internal(p, max_user_text, *root, cur);
+       return 0;
 }
 
 /* Allows reading from a FIFO (i.e., /dev/xconsole).
@@ -4651,10 +3739,9 @@ static inline double get_barnum(char *buf)
 }
 
 static void generate_text_internal(char *p, int p_max_size,
-               struct text_object_list *text_object_list,
-               struct information *cur)
+               struct text_object root, struct information *cur)
 {
-       unsigned int i;
+       struct text_object *obj;
 
 #ifdef HAVE_ICONV
        char buff_in[p_max_size];
@@ -4663,12 +3750,31 @@ static void generate_text_internal(char *p, int p_max_size,
 #endif
 
        p[0] = 0;
-       for (i = 0; i < text_object_list->text_object_count; i++) {
-               struct text_object *obj = &(text_object_list->text_objects[i]);
+       for (obj = root.next; obj && p_max_size > 0; obj = obj->next) {
 
-               if (p_max_size < 1) {
-                       break;
-               };
+/* IFBLOCK jumping algorithm
+ *
+ * This is easier as it looks like:
+ * - each IF checks it's condition
+ *   - on FALSE: call DO_JUMP
+ *   - on TRUE: don't care
+ * - each ELSE calls DO_JUMP unconditionally
+ * - each ENDIF is silently being ignored
+ *
+ * Why this works:
+ * DO_JUMP overwrites the "obj" variable of the loop and sets it to the target
+ * (i.e. the corresponding ELSE or ENDIF). After that, processing for the given
+ * object can continue, free()ing stuff e.g., then the for-loop does the rest: as
+ * regularly, "obj" is being updated to point to obj->next, so object parsing
+ * continues right after the corresponding ELSE or ENDIF. This means that if we
+ * find an ELSE, it's corresponding IF must not have jumped, so we need to jump
+ * always. If we encounter an ENDIF, it's corresponding IF or ELSE has not
+ * jumped, and there is nothing to do.
+ */
+#define DO_JUMP { \
+       DBGP2("jumping"); \
+       obj = obj->data.ifblock.next; \
+}
 
 #define OBJ(a) break; case OBJ_##a:
 
@@ -4677,15 +3783,7 @@ static void generate_text_internal(char *p, int p_max_size,
                                ERR("not implemented obj type %d", obj->type);
 #ifndef __OpenBSD__
                        OBJ(acpitemp) {
-                               /* does anyone have decimals in acpi temperature? */
-                               spaced_print(p, p_max_size, "%d", 5, "acpitemp",
-                                               round_to_int(get_acpi_temperature(obj->data.i)));
-                       }
-                       OBJ(acpitempf) {
-                               /* does anyone have decimals in acpi temperature? */
-                               spaced_print(p, p_max_size, "%d", 5, "acpitemp",
-                                               round_to_int((get_acpi_temperature(obj->data.i) + 40) *
-                                                       9.0 / 5 - 40));
+                               temp_print(p, p_max_size, get_acpi_temperature(obj->data.i), TEMP_CELSIUS);
                        }
 #endif /* !__OpenBSD__ */
                        OBJ(freq) {
@@ -4760,19 +3858,6 @@ static void generate_text_internal(char *p, int p_max_size,
 
 #endif /* __linux__ */
 
-                       OBJ(freq_dyn) {
-                               get_freq_dynamic(p, p_max_size, "%.0f", 1);
-                               spaced_print(p, p_max_size, "%s", 6, "freq_dyn", p);
-                       }
-                       OBJ(freq_dyn_g) {
-#ifndef __OpenBSD__
-                               get_freq_dynamic(p, p_max_size, "%'.2f", 1000);
-#else
-                               get_freq_dynamic(p, p_max_size, "%.2f", 1000);
-#endif
-                               spaced_print(p, p_max_size, "%s", 6, "freq_dyn", p);
-                       }
-
 #ifndef __OpenBSD__
                        OBJ(adt746xcpu) {
                                get_adt746x_cpu(p, p_max_size);
@@ -4886,13 +3971,10 @@ static void generate_text_internal(char *p, int p_max_size,
                                snprintf(p, p_max_size, "%s", i8k.serial);
                        }
                        OBJ(i8k_cpu_temp) {
-                               snprintf(p, p_max_size, "%s", i8k.cpu_temp);
-                       }
-                       OBJ(i8k_cpu_tempf) {
                                int cpu_temp;
 
                                sscanf(i8k.cpu_temp, "%d", &cpu_temp);
-                               snprintf(p, p_max_size, "%.1f", cpu_temp * (9.0 / 5.0) + 32.0);
+                               temp_print(p, p_max_size, (double)cpu_temp, TEMP_CELSIUS);
                        }
                        OBJ(i8k_left_fan_status) {
                                int left_fan_status;
@@ -4950,7 +4032,8 @@ static void generate_text_internal(char *p, int p_max_size,
                        }
                        OBJ(ibm_temps) {
                                get_ibm_acpi_temps();
-                               snprintf(p, p_max_size, "%d", ibm_acpi.temps[obj->data.sensor]);
+                               temp_print(p, p_max_size,
+                                          ibm_acpi.temps[obj->data.sensor], TEMP_CELSIUS);
                        }
                        OBJ(ibm_volume) {
                                get_ibm_acpi_volume(p, p_max_size);
@@ -4961,18 +4044,12 @@ static void generate_text_internal(char *p, int 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;
+                                       DO_JUMP;
                                }
                        }
                        OBJ(if_gw) {
                                if (!cur->gw_info.count) {
-                                       i = obj->data.ifblock.pos;
-                                       if_jumped = 1;
-                               } else {
-                                       if_jumped = 0;
+                                       DO_JUMP;
                                }
                        }
                        OBJ(gw_iface) {
@@ -4993,8 +4070,9 @@ static void generate_text_internal(char *p, int p_max_size,
                        OBJ(obsd_sensors_temp) {
                                obsd_sensors.device = sensor_device;
                                update_obsd_sensors();
-                               snprintf(p, p_max_size, "%.1f",
-                                               obsd_sensors.temp[obsd_sensors.device][obj->data.sensor]);
+                               temp_print(p, p_max_size,
+                                          obsd_sensors.temp[obsd_sensors.device][obj->data.sensor],
+                                          TEMP_CELSIUS);
                        }
                        OBJ(obsd_sensors_fan) {
                                obsd_sensors.device = sensor_device;
@@ -5091,14 +4169,15 @@ static void generate_text_internal(char *p, int p_max_size,
                                obj->data.net->recv_speed / 1024.0, obj->e, 1, obj->showaslog);
                        }
                        OBJ(else) {
-                               if (!if_jumped) {
-                                       i = obj->data.ifblock.pos - 1;
-                               } else {
-                                       if_jumped = 0;
-                               }
+                               /* Since we see you, you're if has not jumped.
+                                * Do Ninja jump here: without leaving traces.
+                                * This is to prevent us from stale jumped flags.
+                                */
+                               obj = obj->data.ifblock.next;
+                               continue;
                        }
                        OBJ(endif) {
-                               if_jumped = 0;
+                               /* harmless object, just ignore */
                        }
 #ifdef HAVE_POPEN
                        OBJ(addr) {
@@ -5162,30 +4241,30 @@ static void generate_text_internal(char *p, int p_max_size,
 #endif /* IMLIB2 */
 
                        OBJ(exec) {
-                               read_exec(obj->data.s, p, p_max_size);
+                               read_exec(obj->data.s, p, text_buffer_size);
                                remove_deleted_chars(p);
                        }
                        OBJ(execp) {
                                struct information *tmp_info;
-                               struct text_object_list *text_objects;
+                               struct text_object subroot;
 
-                               read_exec(obj->data.s, p, p_max_size);
+                               read_exec(obj->data.s, p, text_buffer_size);
 
                                tmp_info = malloc(sizeof(struct information));
                                memcpy(tmp_info, cur, sizeof(struct information));
-                               text_objects = parse_conky_vars(p, p, tmp_info);
+                               parse_conky_vars(&subroot, p, p, tmp_info);
 
-                               free_text_objects(text_objects, 0);
-                               free(text_objects);
+                               free_text_objects(&subroot, 0);
                                free(tmp_info);
                        }
                        OBJ(execbar) {
                                double barnum;
 
-                               read_exec(obj->data.s, p, p_max_size);
+                               read_exec(obj->data.s, p, text_buffer_size);
                                barnum = get_barnum(p);
 
                                if (barnum >= 0.0) {
+                                       barnum /= 100;
                                        new_bar(p, 0, 4, round_to_int(barnum * 255.0));
                                }
                        }
@@ -5195,11 +4274,11 @@ static void generate_text_internal(char *p, int p_max_size,
 
                                if(strncasecmp(obj->data.s, LOGGRAPH" ", strlen(LOGGRAPH" ")) == EQUAL) {
                                        showaslog = TRUE;
-                                       read_exec(obj->data.s + strlen(LOGGRAPH" ") * sizeof(char), p, p_max_size);
+                                       read_exec(obj->data.s + strlen(LOGGRAPH" ") * sizeof(char), p, text_buffer_size);
                                } else if(strncasecmp(obj->data.s, NORMGRAPH" ", strlen(NORMGRAPH" ")) == EQUAL) {
-                                       read_exec(obj->data.s + strlen(NORMGRAPH" ") * sizeof(char), p, p_max_size);
+                                       read_exec(obj->data.s + strlen(NORMGRAPH" ") * sizeof(char), p, text_buffer_size);
                                } else {
-                                       read_exec(obj->data.s, p, p_max_size);
+                                       read_exec(obj->data.s, p, text_buffer_size);
                                }
                                barnum = get_barnum(p);
 
@@ -5213,7 +4292,7 @@ static void generate_text_internal(char *p, int p_max_size,
                                                >= obj->data.execi.interval) {
                                        double barnum;
 
-                                       read_exec(obj->data.execi.cmd, p, p_max_size);
+                                       read_exec(obj->data.execi.cmd, p, text_buffer_size);
                                        barnum = get_barnum(p);
 
                                        if (barnum >= 0.0) {
@@ -5228,7 +4307,7 @@ static void generate_text_internal(char *p, int p_max_size,
                                                >= obj->data.execi.interval) {
                                        double barnum;
 
-                                       read_exec(obj->data.execi.cmd, p, p_max_size);
+                                       read_exec(obj->data.execi.cmd, p, text_buffer_size);
                                        barnum = get_barnum(p);
 
                                        if (barnum >= 0.0) {
@@ -5243,13 +4322,13 @@ static void generate_text_internal(char *p, int p_max_size,
                                                >= obj->data.execi.interval
                                                && obj->data.execi.interval != 0) {
                                        read_exec(obj->data.execi.cmd, obj->data.execi.buffer,
-                                               p_max_size);
+                                               text_buffer_size);
                                        obj->data.execi.last_update = current_update_time;
                                }
-                               snprintf(p, p_max_size, "%s", obj->data.execi.buffer);
+                               snprintf(p, text_buffer_size, "%s", obj->data.execi.buffer);
                        }
                        OBJ(execpi) {
-                               struct text_object_list *text_objects = 0;
+                               struct text_object subroot;
                                struct information *tmp_info =
                                        malloc(sizeof(struct information));
                                memcpy(tmp_info, cur, sizeof(struct information));
@@ -5257,7 +4336,7 @@ static void generate_text_internal(char *p, int p_max_size,
                                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, tmp_info);
+                                       parse_conky_vars(&subroot, obj->data.execi.buffer, p, tmp_info);
                                } else {
                                        char *output = obj->data.execi.buffer;
                                        FILE *fp = popen(obj->data.execi.cmd, "r");
@@ -5270,11 +4349,10 @@ static void generate_text_internal(char *p, int p_max_size,
                                                output[length - 1] = '\0';
                                        }
 
-                                       text_objects = parse_conky_vars(obj->data.execi.buffer, p, tmp_info);
+                                       parse_conky_vars(&subroot, obj->data.execi.buffer, p, tmp_info);
                                        obj->data.execi.last_update = current_update_time;
                                }
-                               free_text_objects(text_objects, 0);
-                               free(text_objects);
+                               free_text_objects(&subroot, 0);
                                free(tmp_info);
                        }
                        OBJ(texeci) {
@@ -5292,7 +4370,7 @@ static void generate_text_internal(char *p, int p_max_size,
                                        }
                                }
                                timed_thread_lock(obj->data.texeci.p_timed_thread);
-                               snprintf(p, p_max_size, "%s", obj->data.texeci.buffer);
+                               snprintf(p, text_buffer_size, "%s", obj->data.texeci.buffer);
                                timed_thread_unlock(obj->data.texeci.p_timed_thread);
                        }
 #endif /* HAVE_POPEN */
@@ -5506,22 +4584,29 @@ static void generate_text_internal(char *p, int p_max_size,
 #endif
 #ifdef HDDTEMP
                        OBJ(hddtemp) {
+                               char *endptr, unit;
+                               long val;
                                if (obj->data.hddtemp.update_time < current_update_time - 30) {
-                                       char *str = get_hddtemp_info(obj->data.hddtemp.dev,
-                                                       obj->data.hddtemp.addr, obj->data.hddtemp.port, &obj->data.hddtemp.unit);
-                                       if (str) {
-                                               strncpy(obj->data.hddtemp.temp, str, text_buffer_size);
-                                       } else {
-                                               obj->data.hddtemp.temp[0] = 0;
-                                       }
+                                       if (obj->data.hddtemp.temp)
+                                               free(obj->data.hddtemp.temp);
+                                       obj->data.hddtemp.temp = get_hddtemp_info(obj->data.hddtemp.dev,
+                                                       obj->data.hddtemp.addr, obj->data.hddtemp.port);
                                        obj->data.hddtemp.update_time = current_update_time;
                                }
                                if (!obj->data.hddtemp.temp) {
                                        snprintf(p, p_max_size, "N/A");
-                               } else if (obj->data.hddtemp.unit == '*') {
-                                       snprintf(p, p_max_size, "%s", obj->data.hddtemp.temp);
                                } else {
-                                       snprintf(p, p_max_size, "%s%c", obj->data.hddtemp.temp, obj->data.hddtemp.unit);
+                                       val = strtol(obj->data.hddtemp.temp + 1, &endptr, 10);
+                                       unit = obj->data.hddtemp.temp[0];
+
+                                       if (*endptr != '\0')
+                                               snprintf(p, p_max_size, "N/A");
+                                       else if (unit == 'C')
+                                               temp_print(p, p_max_size, (double)val, TEMP_CELSIUS);
+                                       else if (unit == 'F')
+                                               temp_print(p, p_max_size, (double)val, TEMP_FAHRENHEIT);
+                                       else
+                                               snprintf(p, p_max_size, "N/A");
                                }
                        }
 #endif
@@ -5538,7 +4623,9 @@ static void generate_text_internal(char *p, int p_max_size,
                                r = get_sysfs_info(&obj->data.sysfs.fd, obj->data.sysfs.arg,
                                        obj->data.sysfs.devtype, obj->data.sysfs.type);
 
-                               if (r >= 100.0 || r == 0) {
+                               if (!strncmp(obj->data.sysfs.type, "temp", 4)) {
+                                       temp_print(p, p_max_size, r, TEMP_CELSIUS);
+                               } else if (r >= 100.0 || r == 0) {
                                        snprintf(p, p_max_size, "%d", (int) r);
                                } else {
                                        snprintf(p, p_max_size, "%.1f", r);
@@ -5550,7 +4637,9 @@ static void generate_text_internal(char *p, int p_max_size,
                                r = get_sysfs_info(&obj->data.sysfs.fd, obj->data.sysfs.arg,
                                        obj->data.sysfs.devtype, obj->data.sysfs.type);
 
-                               if (r >= 100.0 || r == 0) {
+                               if (!strncmp(obj->data.sysfs.type, "temp", 4)) {
+                                       temp_print(p, p_max_size, r, TEMP_CELSIUS);
+                               } else if (r >= 100.0 || r == 0) {
                                        snprintf(p, p_max_size, "%d", (int) r);
                                } else {
                                        snprintf(p, p_max_size, "%.1f", r);
@@ -5562,7 +4651,9 @@ static void generate_text_internal(char *p, int p_max_size,
                                r = get_sysfs_info(&obj->data.sysfs.fd, obj->data.sysfs.arg,
                                        obj->data.sysfs.devtype, obj->data.sysfs.type);
 
-                               if (r >= 100.0 || r == 0) {
+                               if (!strncmp(obj->data.sysfs.type, "temp", 4)) {
+                                       temp_print(p, p_max_size, r, TEMP_CELSIUS);
+                               } else if (r >= 100.0 || r == 0) {
                                        snprintf(p, p_max_size, "%d", (int) r);
                                } else {
                                        snprintf(p, p_max_size, "%.1f", r);
@@ -5576,59 +4667,38 @@ 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 text_object subroot;
                                struct information *tmp_info =
                                        malloc(sizeof(struct information));
                                memcpy(tmp_info, cur, sizeof(struct information));
-                               text_objects = parse_conky_vars(obj->data.ifblock.s, p, tmp_info);
+                               parse_conky_vars(&subroot, obj->data.ifblock.s, p, tmp_info);
 
                                if (strlen(p) != 0) {
-                                       i = obj->data.ifblock.pos;
-                                       if_jumped = 1;
-                               } else {
-                                       if_jumped = 0;
+                                       DO_JUMP;
                                }
                                p[0] = '\0';
-                               free_text_objects(text_objects, 0);
-                               free(text_objects);
+                               free_text_objects(&subroot, 0);
                                free(tmp_info);
                        }
                        OBJ(if_existing) {
-                               struct stat tmp;
-
-                               if ((obj->data.ifblock.s)
-                                               && (stat(obj->data.ifblock.s, &tmp) == -1)) {
-                                       i = obj->data.ifblock.pos;
-                                       if_jumped = 1;
-                               } else {
-                                       if (obj->data.ifblock.str) {
-                                               if (!check_contains(obj->data.ifblock.s,
-                                                               obj->data.ifblock.str)) {
-                                                       i = obj->data.ifblock.pos;
-                                                       if_jumped = 1;
-                                               } else {
-                                                       if_jumped = 0;
-                                               }
-                                       } else {
-                                               if_jumped = 0;
-                                       }
+                               if (obj->data.ifblock.str
+                                   && !check_contains(obj->data.ifblock.s,
+                                                      obj->data.ifblock.str)) {
+                                       DO_JUMP;
+                               } else if (obj->data.ifblock.s
+                                          && access(obj->data.ifblock.s, F_OK)) {
+                                       DO_JUMP;
                                }
                        }
                        OBJ(if_mounted) {
                                if ((obj->data.ifblock.s)
                                                && (!check_mount(obj->data.ifblock.s))) {
-                                       i = obj->data.ifblock.pos;
-                                       if_jumped = 1;
-                               } else {
-                                       if_jumped = 0;
+                                       DO_JUMP;
                                }
                        }
                        OBJ(if_running) {
                                if ((obj->data.ifblock.s) && system(obj->data.ifblock.s)) {
-                                       i = obj->data.ifblock.pos;
-                                       if_jumped = 1;
-                               } else {
-                                       if_jumped = 0;
+                                       DO_JUMP;
                                }
                        }
 #if defined(__linux__)
@@ -5868,10 +4938,16 @@ static void generate_text_internal(char *p, int p_max_size,
                                snprintf(p, len, "%s", cur->mpd.title);
                        }
                        OBJ(mpd_artist) {
-                               snprintf(p, p_max_size, "%s", cur->mpd.artist);
+                               int len = obj->data.i;
+                               if (len == 0 || len > p_max_size)
+                                       len = p_max_size;
+                               snprintf(p, len, "%s", cur->mpd.artist);
                        }
                        OBJ(mpd_album) {
-                               snprintf(p, p_max_size, "%s", cur->mpd.album);
+                               int len = obj->data.i;
+                               if (len == 0 || len > p_max_size)
+                                       len = p_max_size;
+                               snprintf(p, len, "%s", cur->mpd.album);
                        }
                        OBJ(mpd_random) {
                                snprintf(p, p_max_size, "%s", cur->mpd.random);
@@ -5880,13 +4956,22 @@ static void generate_text_internal(char *p, int p_max_size,
                                snprintf(p, p_max_size, "%s", cur->mpd.repeat);
                        }
                        OBJ(mpd_track) {
-                               snprintf(p, p_max_size, "%s", cur->mpd.track);
+                               int len = obj->data.i;
+                               if (len == 0 || len > p_max_size)
+                                       len = p_max_size;
+                               snprintf(p, len, "%s", cur->mpd.track);
                        }
                        OBJ(mpd_name) {
-                               snprintf(p, p_max_size, "%s", cur->mpd.name);
+                               int len = obj->data.i;
+                               if (len == 0 || len > p_max_size)
+                                       len = p_max_size;
+                               snprintf(p, len, "%s", cur->mpd.name);
                        }
                        OBJ(mpd_file) {
-                               snprintf(p, p_max_size, "%s", cur->mpd.file);
+                               int len = obj->data.i;
+                               if (len == 0 || len > p_max_size)
+                                       len = p_max_size;
+                               snprintf(p, len, "%s", cur->mpd.file);
                        }
                        OBJ(mpd_vol) {
                                snprintf(p, p_max_size, "%i", cur->mpd.volume);
@@ -5931,6 +5016,11 @@ static void generate_text_internal(char *p, int p_max_size,
                                        *p = 0;
                                }
                        }
+                       OBJ(if_mpd_playing) {
+                               if (!cur->mpd.is_playing) {
+                                       DO_JUMP;
+                               }
+                       }
 #endif
 
 #ifdef MOC
@@ -6038,6 +5128,11 @@ static void generate_text_internal(char *p, int p_max_size,
                                                cur->xmms2.title);
                                }
                        }
+                       OBJ(if_xmms2_connected) {
+                               if (cur->xmms2_conn_state != 1) {
+                                       DO_JUMP;
+                               }
+                       }
 #endif
 #ifdef AUDACIOUS
                        OBJ(audacious_status) {
@@ -6089,6 +5184,10 @@ static void generate_text_internal(char *p, int p_max_size,
                                snprintf(p, p_max_size, "%s",
                                        cur->audacious.items[AUDACIOUS_PLAYLIST_POSITION]);
                        }
+                       OBJ(audacious_main_volume) {
+                               snprintf(p, p_max_size, "%s",
+                                       cur->audacious.items[AUDACIOUS_MAIN_VOLUME]);
+                       }
                        OBJ(audacious_bar) {
                                double progress;
 
@@ -6279,7 +5378,6 @@ static void generate_text_internal(char *p, int p_max_size,
                                                }       /* bsize > 0 */
                                        }               /* fp == NULL */
                                }                       /* if cur_upd_time >= */
-                               // parse_conky_vars(obj->data.tail.buffer, p, cur);
                        }
 head:
                        OBJ(head) {
@@ -6336,7 +5434,6 @@ head:
                                                }       /* nl > 0 */
                                        }               /* if fp == null */
                                }                       /* cur_upd_time >= */
-                               // parse_conky_vars(obj->data.tail.buffer, p, cur);
                        }
 
                        OBJ(lines) {
@@ -6390,25 +5487,8 @@ head:
                        }
 #ifdef TCP_PORT_MONITOR
                        OBJ(tcp_portmon) {
-                               /* grab a pointer to this port monitor */
-                               tcp_port_monitor_t *p_monitor =
-                                       find_tcp_port_monitor(info.p_tcp_port_monitor_collection,
-                                       obj->data.tcp_port_monitor.port_range_begin,
-                                       obj->data.tcp_port_monitor.port_range_end);
-
-                               if (!p_monitor) {
-                                       snprintf(p, p_max_size, "monitor not found");
-                                       break;
-                               }
-
-                               /* now grab the text of interest */
-                               if (peek_tcp_port_monitor(p_monitor,
-                                               obj->data.tcp_port_monitor.item,
-                                               obj->data.tcp_port_monitor.connection_index, p,
-                                               p_max_size) != 0) {
-                                       snprintf(p, p_max_size, "monitor peek error");
-                                       break;
-                               }
+                               tcp_portmon_action(p, p_max_size,
+                                                  &obj->data.tcp_port_monitor);
                        }
 #endif
 
@@ -6449,10 +5529,8 @@ head:
                                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;
+                                               DO_JUMP;
+                                       }
                                } else
                                        ERR("argument to if_smapi_bat_installed must be an integer");
                        }
@@ -6470,8 +5548,8 @@ head:
                                if(obj->data.s && sscanf(obj->data.s, "%i", &idx) == 1) {
                                        val = smapi_bat_installed(idx) ?
                                                smapi_get_bat_int(idx, "temperature") : 0;
-                                       /* temperature is in milli degree celsius, round to degree celsius */
-                                       snprintf(p, p_max_size, "%d", (int)((val / 1000) + 0.5));
+                                       /* temperature is in milli degree celsius */
+                                       temp_print(p, p_max_size, val / 1000, TEMP_CELSIUS);
                                } else
                                        ERR("argument to smapi_bat_temp must be an integer");
                        }
@@ -6496,8 +5574,9 @@ head:
                        OBJ(scroll) {
                                unsigned int j;
                                char *tmp;
-                               parse_conky_vars(obj->data.scroll.text, p, cur);
-                               
+                               struct text_object subroot;
+                               parse_conky_vars(&subroot, obj->data.scroll.text, p, cur);
+
                                if (strlen(p) <= obj->data.scroll.show) {
                                        break;
                                }
@@ -6533,6 +5612,8 @@ head:
                                int value = get_nvidia_value(obj->data.nvidia.type, display);
                                if(value == -1)
                                        snprintf(p, p_max_size, "N/A");
+                               else if (obj->data.nvidia.type == NV_TEMP)
+                                       temp_print(p, p_max_size, (double)value, TEMP_CELSIUS);
                                else if (obj->data.nvidia.print_as_float &&
                                                value > 0 && value < 100)
                                        snprintf(p, p_max_size, "%.1f", (float)value);
@@ -6543,6 +5624,8 @@ head:
 
                        break;
                }
+#undef DO_JUMP
+
 
                {
                        unsigned int a = strlen(p);
@@ -6605,7 +5688,7 @@ static void generate_text(void)
 
        p = text_buffer;
 
-       generate_text_internal(p, max_user_text, global_text_object_list, cur);
+       generate_text_internal(p, max_user_text, global_root_object, cur);
 
        if (stuff_in_upper_case) {
                char *tmp_p;
@@ -7560,7 +6643,7 @@ static void update_text(void)
 static void main_loop(void)
 {
 #ifdef SIGNAL_BLOCKING
-       sigset_t newmask;
+       sigset_t newmask, oldmask;
 #endif
        double t;
 #ifdef X11
@@ -7900,7 +6983,7 @@ static void main_loop(void)
 static void load_config_file(const char *);
 
 /* reload the config file */
-void reload_config(void)
+static void reload_config(void)
 {
        timed_thread_destroy_registered_threads();
 
@@ -7961,7 +7044,7 @@ void reload_config(void)
 #endif /* X11 */
 
 #ifdef TCP_PORT_MONITOR
-       destroy_tcp_port_monitor_collection(info.p_tcp_port_monitor_collection);
+       tcp_portmon_clear();
 #endif
 
        if (current_config) {
@@ -7981,9 +7064,6 @@ void reload_config(void)
                XClearWindow(display, RootWindow(display, screen));
 
 #endif /* X11 */
-#ifdef TCP_PORT_MONITOR
-               info.p_tcp_port_monitor_collection = NULL;
-#endif
                extract_variable_text(global_text);
                free(global_text);
                global_text = NULL;
@@ -8004,10 +7084,9 @@ void reload_config(void)
                memset(text_buffer, 0, max_user_text);
                update_text();
        }
-       sigemptyset(&oldmask);
 }
 
-void clean_up(void)
+static void clean_up(void)
 {
        timed_thread_destroy_registered_threads();
 
@@ -8038,9 +7117,7 @@ void clean_up(void)
        free_fonts();
 #endif /* X11 */
 
-       free_text_objects(global_text_object_list, 1);
-       free(global_text_object_list);
-       global_text_object_list = NULL;
+       free_text_objects(&global_root_object, 1);
        if (tmpstring1) {
                free(tmpstring1);
                tmpstring1 = 0;
@@ -8062,8 +7139,7 @@ void clean_up(void)
        free(current_config);
 
 #ifdef TCP_PORT_MONITOR
-       destroy_tcp_port_monitor_collection(info.p_tcp_port_monitor_collection);
-       info.p_tcp_port_monitor_collection = NULL;
+       tcp_portmon_clear();
 #endif
 #ifdef RSS
        free_rss_info();
@@ -8199,6 +7275,16 @@ static void set_default_configurations(void)
        color7 = default_fg_color;
        color8 = default_fg_color;
        color9 = default_fg_color;
+       template[0] = strdup("");
+       template[1] = strdup("");
+       template[2] = strdup("");
+       template[3] = strdup("");
+       template[4] = strdup("");
+       template[5] = strdup("");
+       template[6] = strdup("");
+       template[7] = strdup("");
+       template[8] = strdup("");
+       template[9] = strdup("");
        draw_shades = 1;
        draw_borders = 0;
        draw_graph_borders = 1;
@@ -8242,8 +7328,8 @@ static void set_default_configurations(void)
        info.users.number = 1;
 
 #ifdef TCP_PORT_MONITOR
-       tcp_port_monitor_args.max_port_monitor_connections =
-               MAX_PORT_MONITOR_CONNECTIONS_DEFAULT;
+       /* set default connection limit */
+       tcp_portmon_set_max_connections(0);
 #endif
 }
 
@@ -8254,10 +7340,19 @@ static void load_config_file(const char *f)
        FILE *fp;
 
        set_default_configurations();
-       fp = fopen(f, "r");
+#ifdef CONFIG_OUTPUT
+       if (!strcmp(f, "==builtin==")) {
+#ifdef HAVE_FOPENCOOKIE
+               fp = fopencookie(NULL, "r", conf_cookie);
+#endif
+       } else
+#endif /* CONFIG_OUTPUT */
+               fp = fopen(f, "r");
+
        if (!fp) {
                return;
        }
+       DBGP("reading contents from config file '%s'", f);
 
        while (!feof(fp)) {
                char buf[256], *p, *p2, *name, *value;
@@ -8319,7 +7414,9 @@ static void load_config_file(const char *f)
 
 #ifdef X11
                CONF2("alignment") {
-                       if (value) {
+                       if (window.type == TYPE_DOCK)
+                               ;
+                       else if (value) {
                                int a = string_to_alignment(value);
 
                                if (a <= 0) {
@@ -8430,6 +7527,25 @@ static void load_config_file(const char *f)
                                CONF_ERR;
                        }
                }
+#define TEMPLATE_CONF(n) \
+               CONF("template"#n) { \
+                       if (value) { \
+                               free(template[n]); \
+                               template[n] = strdup(value); \
+                       } else { \
+                               CONF_ERR; \
+                       } \
+               }
+               TEMPLATE_CONF(0)
+               TEMPLATE_CONF(1)
+               TEMPLATE_CONF(2)
+               TEMPLATE_CONF(3)
+               TEMPLATE_CONF(4)
+               TEMPLATE_CONF(5)
+               TEMPLATE_CONF(6)
+               TEMPLATE_CONF(7)
+               TEMPLATE_CONF(8)
+               TEMPLATE_CONF(9)
                CONF("default_color") {
                        if (value) {
                                default_fg_color = get_x11_color(value);
@@ -8454,14 +7570,14 @@ static void load_config_file(const char *f)
 #endif /* X11 */
                CONF("imap") {
                        if (value) {
-                               info.mail = parse_mail_args(IMAP, value);
+                               info.mail = parse_mail_args(IMAP_TYPE, value);
                        } else {
                                CONF_ERR;
                        }
                }
                CONF("pop3") {
                        if (value) {
-                               info.mail = parse_mail_args(POP3, value);
+                               info.mail = parse_mail_args(POP3_TYPE, value);
                        } else {
                                CONF_ERR;
                        }
@@ -8773,6 +7889,7 @@ static void load_config_file(const char *f)
                                        window.type = TYPE_DESKTOP;
                                } else if (strncmp(value, "dock", 7) == EQUAL) {
                                        window.type = TYPE_DOCK;
+                                       text_alignment = TOP_LEFT;
                                } else if (strncmp(value, "override", 8) == EQUAL) {
                                        window.type = TYPE_OVERRIDE;
                                } else {
@@ -8876,21 +7993,15 @@ static void load_config_file(const char *f)
                }
 #ifdef TCP_PORT_MONITOR
                CONF("max_port_monitor_connections") {
-                       if (!value || (sscanf(value, "%d",
-                                       &tcp_port_monitor_args.max_port_monitor_connections) != 1)
-                                       || tcp_port_monitor_args.max_port_monitor_connections < 0) {
+                       int max;
+                       if (!value || (sscanf(value, "%d", &max) != 1)) {
                                /* an error. use default, warn and continue. */
-                               tcp_port_monitor_args.max_port_monitor_connections =
-                                       MAX_PORT_MONITOR_CONNECTIONS_DEFAULT;
+                               tcp_portmon_set_max_connections(0);
+                               CONF_ERR;
+                       } else if (tcp_portmon_set_max_connections(max)) {
+                               /* max is < 0, default has been set*/
                                CONF_ERR;
-                       } else if (tcp_port_monitor_args.max_port_monitor_connections
-                                       == 0) {
-                               /* no error, just use default */
-                               tcp_port_monitor_args.max_port_monitor_connections =
-                                       MAX_PORT_MONITOR_CONNECTIONS_DEFAULT;
                        }
-                       /* else tcp_port_monitor_args.max_port_monitor_connections > 0
-                        * as per config */
                }
 #endif
                CONF("if_up_strictness") {
@@ -8908,6 +8019,15 @@ static void load_config_file(const char *f)
                                ifup_strictness = IFUP_UP;
                        }
                }
+
+               CONF("temperature_unit") {
+                       if (!value) {
+                               ERR("config option 'temperature_unit' needs an argument");
+                       } else if (set_temp_output_unit(value)) {
+                               ERR("temperature_unit: incorrect argument");
+                       }
+               }
+
                else {
                        ERR("%s: %d: no such configuration: '%s'", f, line, name);
                }
@@ -8936,6 +8056,7 @@ static void print_help(const char *prog_name) {
                        "file.\n"
                        "   -v, --version             version\n"
                        "   -q, --quiet               quiet mode\n"
+                       "   -D, --debug               increase debugging output\n"
                        "   -c, --config=FILE         config file to load\n"
                        "   -d, --daemonize           daemonize, fork to background\n"
                        "   -h, --help                help\n"
@@ -8960,7 +8081,7 @@ static void print_help(const char *prog_name) {
 }
 
 /* : means that character before that takes an argument */
-static const char *getopt_string = "vVqdt:u:i:hc:"
+static const char *getopt_string = "vVqdDt:u:i:hc:"
 #ifdef X11
        "x:y:w:a:f:"
 #ifdef OWN_WINDOW
@@ -8969,13 +8090,20 @@ static const char *getopt_string = "vVqdt:u:i:hc:"
 #ifdef HAVE_XDBE
        "b"
 #endif
+#ifdef CONFIG_OUTPUT
+       "C"
+#endif
 #endif /* X11 */
        ;
 
 static const struct option longopts[] = {
        { "help", 0, NULL, 'h' },
        { "version", 0, NULL, 'V' },
+       { "debug", 0, NULL, 'D' },
        { "config", 1, NULL, 'c' },
+#ifdef CONFIG_OUTPUT
+       { "print-config", 0, NULL, 'C' },
+#endif
        { "daemonize", 0, NULL, 'd' },
 #ifdef X11
        { "alignment", 1, NULL, 'a' },
@@ -9006,8 +8134,8 @@ int main(int argc, char **argv)
        clear_net_stats();
 
 #ifdef TCP_PORT_MONITOR
-       tcp_port_monitor_args.max_port_monitor_connections =
-               MAX_PORT_MONITOR_CONNECTIONS_DEFAULT;
+       /* set default connection limit */
+       tcp_portmon_set_max_connections(0);
 #endif
 
        /* handle command line parameters that don't change configs */
@@ -9055,6 +8183,11 @@ int main(int argc, char **argv)
                        case 'h':
                                print_help(argv[0]);
                                return 0;
+#ifdef CONFIG_OUTPUT
+                       case 'C':
+                               print_defconfig();
+                               return 0;
+#endif
 #ifdef X11
                        case 'w':
                                window.window = strtol(optarg, 0, 0);
@@ -9104,7 +8237,13 @@ int main(int argc, char **argv)
 
                /* No readable config found */
                if (!current_config) {
+#ifdef CONFIG_OUTPUT
+                       current_config = strdup("==builtin==");
+                       ERR("no readable personal or system-wide config file found,"
+                                       " using builtin default");
+#else
                        CRIT_ERR("no readable personal or system-wide config file found");
+#endif /* ! CONF_OUTPUT */
                }
        }
 
@@ -9154,7 +8293,9 @@ int main(int argc, char **argv)
                        case 'd':
                                fork_to_background = 1;
                                break;
-
+                       case 'D':
+                               global_debug_level++;
+                               break;
 #ifdef X11
                        case 'f':
                                set_first_font(optarg);
@@ -9310,7 +8451,7 @@ int main(int argc, char **argv)
        return 0;
 }
 
-void signal_handler(int sig)
+static void signal_handler(int sig)
 {
        /* signal handler is light as a feather, as it should be.
         * we will poll g_signal_pending with each loop of conky