* Added buffer_text_size option to change the size of the buffer for
[monky] / src / conky.c
1 /*
2  * Conky, a system monitor, based on torsmo
3  *
4  * This program is licensed under BSD license, read COPYING
5  *
6  *  $Id$
7  */
8
9 #include "conky.h"
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <ctype.h>
13 #include <time.h>
14 #include <locale.h>
15 #include <signal.h>
16 #include <unistd.h>
17 #include <errno.h>
18 #include <termios.h>
19 #include <string.h>
20 #include <limits.h>
21 #if HAVE_DIRENT_H
22 #include <dirent.h>
23 #endif
24 #include <sys/time.h>
25 #ifdef X11
26 #include <X11/Xutil.h>
27 #ifdef HAVE_XDAMAGE
28 #include <X11/extensions/Xdamage.h>
29 #endif
30 #ifdef IMLIB2
31 #include <Imlib2.h>
32 #endif /* IMLIB2 */
33 #endif /* X11 */
34 #include <sys/types.h>
35 #include <sys/stat.h>
36 #include <netinet/in.h>
37 #include <netdb.h>
38
39 #ifdef HAVE_ICONV
40 #include <iconv.h>
41 #endif
42
43 #include "build.h"
44
45 #ifndef S_ISSOCK
46 #define S_ISSOCK(x)   ((x & S_IFMT) == S_IFSOCK)
47 #endif
48
49 #define CONFIG_FILE "$HOME/.conkyrc"
50 #define MAIL_FILE "$MAIL"
51 #define MAX_IF_BLOCK_DEPTH 5
52
53 /* #define SIGNAL_BLOCKING */
54 #undef SIGNAL_BLOCKING
55
56 static void print_version()
57 {
58         printf("Conky %s compiled %s for %s\n",
59                         VERSION, BUILD_DATE, BUILD_ARCH);
60
61         printf(
62         "\nCompiled in features:\n\n"
63 #ifdef X11
64         " X11:\n"
65 # ifdef HAVE_XDAMAGE
66         "  * Xdamage extension\n"
67 # endif /* HAVE_XDAMAGE */
68 # ifdef HAVE_XDBE
69         "  * Xdbe extension (double buffer)\n"
70 # endif /* HAVE_XDBE */
71 # ifdef XFT
72         "  * xft\n"
73 # endif /* XFT */
74
75 #endif /* X11 */
76         "\n Music detection:\n"
77 #ifdef AUDACIOUS
78         "  * audacious\n"
79 #endif /* AUDACIOUS */
80 #ifdef BMPX
81         "  * bmpx\n"
82 #endif /* BMPX */
83 #ifdef MPD
84         "  * mpd\n"
85 #endif /* MPD */
86 #ifdef XMMS2
87         "  * xmms2\n"
88 #endif /* XMMS2 */
89         "\n General features:\n"
90 #ifdef HDDTEMP
91         "  * hddtemp\n"
92 #endif /* HDDTEMP */
93 #ifdef TCP_PORT_MONITOR
94         "  * portmon\n"
95 #endif /* TCP_PORT_MONITOR */
96 #ifdef HAVE_LIBDEXTER
97   "  * network\n"
98 #endif
99         "\n");  
100
101         exit(0);
102 }
103
104 #ifdef X11
105
106 /*
107  * text size
108  */
109
110 static int text_start_x, text_start_y;  /* text start position in window */
111 static int text_width, text_height;
112
113 /* alignments */
114 enum alignment {
115         TOP_LEFT = 1,
116         TOP_RIGHT,
117         BOTTOM_LEFT,
118         BOTTOM_RIGHT,
119         NONE
120 };
121
122
123 /* for fonts */
124 struct font_list {
125
126         char name[TEXT_BUFFER_SIZE];
127         int num;
128         XFontStruct *font;
129
130 #ifdef XFT
131         XftFont *xftfont;
132         int font_alpha;
133 #endif  
134
135 };
136 static int selected_font = 0;
137 static int font_count = -1;
138 struct font_list *fonts = NULL;
139
140 #ifdef XFT
141
142 #define font_height() (use_xft ? (fonts[selected_font].xftfont->ascent + fonts[selected_font].xftfont->descent) : \
143 (fonts[selected_font].font->max_bounds.ascent + fonts[selected_font].font->max_bounds.descent))
144 #define font_ascent() (use_xft ? fonts[selected_font].xftfont->ascent : fonts[selected_font].font->max_bounds.ascent)
145 #define font_descent() (use_xft ? fonts[selected_font].xftfont->descent : fonts[selected_font].font->max_bounds.descent)
146
147 #else
148
149 #define font_height() (fonts[selected_font].font->max_bounds.ascent + fonts[selected_font].font->max_bounds.descent)
150 #define font_ascent() fonts[selected_font].font->max_bounds.ascent
151 #define font_descent() fonts[selected_font].font->max_bounds.descent
152
153 #endif
154
155 #define MAX_FONTS 64 // hmm, no particular reason, just makes sense.
156
157
158 static void set_font();
159
160 int addfont(const char *data_in)
161 {
162         if (font_count > MAX_FONTS) {
163                 CRIT_ERR("you don't need that many fonts, sorry.");
164         }
165         font_count++;
166         if (font_count == 0) {
167                 if (fonts != NULL) {
168                         free(fonts);
169                 }
170                 if ((fonts = (struct font_list*)malloc(sizeof(struct font_list))) == NULL) {
171                         CRIT_ERR("malloc");
172                 }
173         }
174         fonts = realloc(fonts, (sizeof(struct font_list) * (font_count+1)));
175         if (fonts == NULL) {
176                 CRIT_ERR("realloc in addfont");
177         }
178         if (strlen(data_in) < TEXT_BUFFER_SIZE) { // must account for null terminator
179                 strncpy(fonts[font_count].name, data_in, TEXT_BUFFER_SIZE);
180 #ifdef XFT
181                 fonts[font_count].font_alpha = 0xffff;
182 #endif
183         } else {
184                 CRIT_ERR("Oops...looks like something overflowed in addfont().");
185         }
186         return font_count;
187 }
188
189 void set_first_font(const char *data_in)
190 {
191         if (font_count < 0) {
192                 if ((fonts = (struct font_list*)malloc(sizeof(struct font_list))) == NULL) {
193                         CRIT_ERR("malloc");
194                 }
195                 font_count++;
196         }
197         if (strlen(data_in) > 1) {
198                 strncpy(fonts[0].name, data_in, TEXT_BUFFER_SIZE-1);
199 #ifdef XFT
200                 fonts[0].font_alpha = 0xffff;
201 #endif
202         }
203 }
204
205 void free_fonts()
206 {
207         int i;
208         for (i=0;i<=font_count;i++) {
209 #ifdef XFT
210                 if (use_xft) {
211                         XftFontClose(display, fonts[i].xftfont);
212                 } else
213 #endif
214                 {
215                         XFreeFont(display, fonts[i].font);
216                 }
217 }
218         free(fonts);
219         fonts = NULL;
220         font_count = -1;
221         selected_font = 0;
222         set_first_font("6x10");
223 }
224
225
226 static void load_fonts()
227 {
228         int i;
229         for (i=0; i <= font_count; i++) {
230 #ifdef XFT
231         /* load Xft font */
232         if (use_xft) {
233         /*if (fonts[i].xftfont != NULL && selected_font == 0) {
234                         XftFontClose(display, fonts[i].xftfont);
235         }*/
236                 if ((fonts[i].xftfont =
237                         XftFontOpenName(display, screen, fonts[i].name)) != NULL)
238                         continue;
239                 
240                 ERR("can't load Xft font '%s'", fonts[i].name);
241                 if ((fonts[i].xftfont =
242                         XftFontOpenName(display, screen,
243                                         "courier-12")) != NULL)
244                         continue;
245                 
246                 ERR("can't load Xft font '%s'", "courier-12");
247                 
248                 if ((fonts[i].font = XLoadQueryFont(display, "fixed")) == NULL) {
249                         CRIT_ERR("can't load font '%s'", "fixed");
250                 }
251                 use_xft = 0;
252                 
253                 continue;
254         }
255 #endif
256         /* load normal font */
257 /*      if (fonts[i].font != NULL)
258                 XFreeFont(display, fonts[i].font);*/
259         
260         if ((fonts[i].font = XLoadQueryFont(display, fonts[i].name)) == NULL) {
261                 ERR("can't load font '%s'", fonts[i].name);
262                 if ((fonts[i].font = XLoadQueryFont(display, "fixed")) == NULL) {
263                         CRIT_ERR("can't load font '%s'", "fixed");
264                         printf("loaded fixed?\n");
265                 }
266         }
267         }
268 }
269
270 #endif /* X11 */
271
272 /* default config file */
273 static char *current_config;
274
275 /* set to 1 if you want all text to be in uppercase */
276 static unsigned int stuff_in_upper_case;
277
278 /* Run how many times? */
279 static unsigned long total_run_times;
280
281 /* fork? */
282 static int fork_to_background;
283
284 static int cpu_avg_samples, net_avg_samples;
285
286 #ifdef X11
287
288 /* Position on the screen */
289 static int text_alignment;
290 static int gap_x, gap_y;
291
292 /* border */
293 static int draw_borders;
294 static int draw_graph_borders;
295 static int stippled_borders;
296
297 static int draw_shades, draw_outline;
298
299 static int border_margin, border_width;
300
301 static long default_fg_color, default_bg_color, default_out_color;
302
303 /* create own window or draw stuff to root? */
304 static int set_transparent = 0;
305
306
307 #ifdef OWN_WINDOW
308 static int own_window = 0;
309 static int background_colour = 0;
310 /* fixed size/pos is set if wm/user changes them */
311 static int fixed_size = 0, fixed_pos = 0;
312 #endif
313
314 static int minimum_width, minimum_height;
315 static int maximum_width;
316
317 #endif /* X11 */
318
319 /* maximum number of special things, e.g. fonts, offsets, aligns, etc. */
320 static unsigned int max_specials = MAX_SPECIALS_DEFAULT;
321
322 /* maximum size of config TEXT buffer, i.e. below TEXT line. */
323 static unsigned int max_user_text = MAX_USER_TEXT_DEFAULT;
324
325 /* maximum size of individual text buffers, ie $exec buffer size */
326 unsigned int text_buffer_size = TEXT_BUFFER_SIZE;
327
328 #ifdef HAVE_ICONV
329 #define CODEPAGE_LENGTH 20
330 long iconv_selected;
331 long iconv_count;
332 char iconv_converting;
333 static iconv_t **iconv_cd = 0;
334
335 int register_iconv(iconv_t *new_iconv)
336 {
337         if (iconv_cd) {
338                 iconv_cd = realloc(iconv, sizeof(iconv_t *) * (iconv_count + 1));
339         } else {
340                 iconv_cd = malloc(sizeof(iconv_t *));
341         }
342         if (!iconv_cd) {
343                 CRIT_ERR("Out of memory");
344         }
345         iconv_cd[iconv_count] = malloc(sizeof(iconv_t));
346         if (!iconv_cd[iconv_count]) {
347                 CRIT_ERR("Out of memory");
348         }
349         memcpy(iconv_cd[iconv_count], new_iconv, sizeof(iconv_t));
350         iconv_count++;
351         return iconv_count;
352 }
353
354 void free_iconv(void)
355 {
356         if (iconv_cd) {
357                 long i;
358                 for (i = iconv_count; i < 0; i++) {
359                         if (iconv_cd[i]) {
360                                 free(iconv_cd[i]);
361                         }
362                 }
363                 free(iconv_cd);
364         }
365         iconv_cd = 0;
366                 
367 }
368
369 #endif
370
371 /* UTF-8 */
372 int utf8_mode = 0;
373
374 /* no buffers in used memory? */
375 int no_buffers;
376
377 /* pad percentages to decimals? */
378 static int pad_percents = 0;
379
380 #ifdef TCP_PORT_MONITOR
381 tcp_port_monitor_args_t         tcp_port_monitor_args;
382 #endif
383
384 #ifdef HAVE_LIBDEXTER
385 /* private config items for libdexter */
386 static char *dexter_config = NULL;
387 #endif
388
389 /* Text that is shown */
390 static char original_text[] =
391     "$nodename - $sysname $kernel on $machine\n"
392     "$hr\n"
393     "${color grey}Uptime:$color $uptime\n"
394     "${color grey}Frequency (in MHz):$color $freq\n"
395     "${color grey}Frequency (in GHz):$color $freq_g\n"
396     "${color grey}RAM Usage:$color $mem/$memmax - $memperc% ${membar 4}\n"
397     "${color grey}Swap Usage:$color $swap/$swapmax - $swapperc% ${swapbar 4}\n"
398     "${color grey}CPU Usage:$color $cpu% ${cpubar 4}\n"
399     "${color grey}Processes:$color $processes  ${color grey}Running:$color $running_processes\n"
400     "$hr\n"
401     "${color grey}File systems:\n"
402     " / $color${fs_free /}/${fs_size /} ${fs_bar 6 /}\n"
403     "${color grey}Networking:\n"
404     " Up:$color ${upspeed eth0} k/s${color grey} - Down:$color ${downspeed eth0} k/s\n"
405     "$hr\n"
406 #ifdef MPD
407     "${color grey}MPD: $mpd_status $mpd_artist - $mpd_title from $mpd_album at $mpd_vol\n"
408     "Bitrate: $mpd_bitrate\n" "Progress: $mpd_bar\n"
409 #endif
410 #ifdef XMMS2
411     "${color grey}XMMS2: $xmms2_status $xmms2_artist - $xmms2_title from $xmms2_album\n"
412     "Progress: $xmms2_bar\n"
413 #endif
414     "${color grey}Name          PID     CPU%    MEM%\n"
415     " ${color lightgrey} ${top name 1} ${top pid 1} ${top cpu 1} ${top mem 1}\n"
416     " ${color lightgrey} ${top name 2} ${top pid 2} ${top cpu 2} ${top mem 2}\n"
417     " ${color lightgrey} ${top name 3} ${top pid 3} ${top cpu 3} ${top mem 3}\n"
418     " ${color lightgrey} ${top name 4} ${top pid 4} ${top cpu 4} ${top mem 4}\n"
419     "${tail /var/log/Xorg.0.log 3}";
420
421 static char *text = original_text;
422 long text_lines;
423
424 static int total_updates;
425
426 /* if-blocks */
427 static int blockdepth = 0;
428 static int if_jumped = 0;
429 static int blockstart[MAX_IF_BLOCK_DEPTH];
430
431 int check_mount(char *s)
432 {
433 #if defined(__linux__)
434         int ret = 0;
435         FILE *mtab = fopen("/etc/mtab", "r");
436         if (mtab) {
437                 char buf1[256], buf2[128];
438                 while (fgets(buf1, 256, mtab)) {
439                         sscanf(buf1, "%*s %128s", buf2);
440                         if (!strcmp(s, buf2)) {
441                                 ret = 1;
442                                 break;
443                         }
444                 }
445                 fclose(mtab);
446         } else {
447                 ERR("Could not open mtab");
448         }
449         return ret;
450 #elif defined(__FreeBSD__)
451         struct statfs *mntbuf;
452         int i, mntsize;
453
454         mntsize = getmntinfo(&mntbuf, MNT_NOWAIT);
455         for (i = mntsize - 1; i >= 0; i--)
456                 if (strcmp(mntbuf[i].f_mntonname, s) == 0)
457                         return 1;
458
459         return 0;
460 #endif
461 }
462
463
464 #ifdef X11
465 static inline int calc_text_width(const char *s, int l)
466 {
467 #ifdef XFT
468         if (use_xft) {
469                 XGlyphInfo gi;
470                 if (utf8_mode) {
471                         XftTextExtentsUtf8(display, fonts[selected_font].xftfont, (FcChar8 *)s, l, &gi);
472                 } else {
473                         XftTextExtents8(display, fonts[selected_font].xftfont, (FcChar8 *)s, l, &gi);
474                 }
475                 return gi.xOff;
476         } else
477 #endif
478         {
479                 return XTextWidth(fonts[selected_font].font, s, l);
480         }
481 }
482 #endif /* X11 */
483
484 /* formatted text to render on screen, generated in generate_text(),
485  * drawn in draw_stuff() */
486
487 static char text_buffer[TEXT_BUFFER_SIZE * 4];
488
489 /* special stuff in text_buffer */
490
491 #define SPECIAL_CHAR '\x01'
492
493 enum {
494         HORIZONTAL_LINE,
495         STIPPLED_HR,
496         BAR,
497         FG,
498         BG,
499         OUTLINE,
500         ALIGNR,
501         ALIGNC,
502         GRAPH,
503         OFFSET,
504         VOFFSET,
505         FONT,
506         GOTO,
507         TAB,
508 };
509
510 struct special_t {
511         int type;
512         short height;
513         short width;
514         long arg;
515         double *graph;
516         double graph_scale;
517         int graph_width;
518         int scaled;
519         short font_added;
520         unsigned long first_colour; // for graph gradient
521         unsigned long last_colour;
522 };
523
524 /* create specials array on heap instead of stack with introduction of max_specials */
525 static struct special_t *specials = NULL;
526
527 static unsigned int special_count;
528 #ifdef X11
529 static unsigned int special_index;      /* used when drawing */
530 #endif /* X11 */
531
532 #define MAX_GRAPH_DEPTH 256     /* why 256? cause an array of more then 256 doubles seems excessive, and who needs that kind of precision anyway? */
533
534 static struct special_t *new_special(char *buf, int t)
535 {
536         if (special_count >= max_specials)
537                 CRIT_ERR("too many special things in text");
538
539         buf[0] = SPECIAL_CHAR;
540         buf[1] = '\0';
541         specials[special_count].type = t;
542         return &specials[special_count++];
543 }
544
545 long fwd_fcharfind(FILE* fp, char val, unsigned int step) {
546 #define BUFSZ 0x1000
547         long ret = -1;
548         unsigned int count = 0;
549         static char buf[BUFSZ];
550         long orig_pos = ftell(fp);
551         long buf_pos = -1;
552         long buf_size = BUFSZ;
553         char* cur_found = NULL;
554         while(count < step) {
555                 if(cur_found == NULL) {
556                         buf_size = fread(buf, 1, buf_size, fp);
557                         buf_pos = 0;
558                 }
559                 cur_found = memchr(buf+buf_pos, val, buf_size-buf_pos);
560                 if(cur_found != NULL) {
561                         buf_pos = cur_found-buf+1;
562                         count++;
563                 }
564                 else {
565                         if(feof(fp))
566                                 break;
567                 }
568         }
569         if(count == step)
570                 ret = ftell(fp) - buf_size + buf_pos - 1;
571         fseek(fp, orig_pos, SEEK_SET);
572         return ret;
573 #undef BUFSZ
574 }
575
576 long rev_fcharfind(FILE* fp, char val, unsigned int step) {
577 #define BUFSZ 0x1000
578         long ret = -1;
579         unsigned int count = 0;
580         static char buf[BUFSZ];
581         long orig_pos = ftell(fp);
582         long buf_pos = -1;
583         long file_pos = orig_pos;
584         long buf_size = BUFSZ;
585         char* cur_found;
586         while(count < step) {
587                 if(buf_pos <= 0) {
588                         if(file_pos > BUFSZ) {
589                                 fseek(fp, file_pos-BUFSZ, SEEK_SET);
590                         }
591                         else {
592                                 buf_size = file_pos;
593                                 fseek(fp, 0, SEEK_SET);
594                         }
595                         file_pos = ftell(fp);
596                         buf_pos = fread(buf, 1, buf_size, fp);
597                 }
598                 cur_found = 
599                         memrchr(
600                                         buf,
601                                         (int)val,
602                                         (size_t)buf_pos);
603                 if(cur_found != NULL) {
604                         buf_pos = cur_found-buf;
605                         count++;
606                 } else {
607                         buf_pos = -1;
608                         if(file_pos == 0) {
609                                 break;
610                         }
611                 }
612         }
613         fseek(fp, orig_pos, SEEK_SET);
614         if(count == step)
615                 ret = file_pos + buf_pos;
616         return ret;
617 #undef BUFSZ
618 }
619
620 static void new_bar(char *buf, int w, int h, int usage)
621 {
622         struct special_t *s = new_special(buf, BAR);
623         s->arg = (usage > 255) ? 255 : ((usage < 0) ? 0 : usage);
624         s->width = w;
625         s->height = h;
626 }
627
628 static const char *scan_bar(const char *args, int *w, int *h)
629 {
630         *w = 0;                 /* zero width means all space that is available */
631         *h = 6;
632         /* bar's argument is either height or height,width */
633         if (args) {
634                 int n = 0;
635                 if (sscanf(args, "%d,%d %n", h, w, &n) <= 1)
636                         sscanf(args, "%d %n", h, &n);
637                 args += n;
638         }
639
640         return args;
641 }
642
643 static char *scan_font(const char *args)
644 {
645         if (args && sizeof(args) < 127) {
646                 return strdup(args);
647         }
648         return NULL;
649 }
650
651 #ifdef X11
652 static void new_font(char *buf, char * args) {
653         if (args) {
654                 struct special_t *s = new_special(buf, FONT);
655                 if (!s->font_added || strcmp(args, fonts[s->font_added].name)) {
656                         int tmp = selected_font;
657                         selected_font = s->font_added = addfont(args);
658                         load_fonts();
659                         selected_font = tmp;
660                 }
661         } else {
662                 struct special_t *s = new_special(buf, FONT);
663                 int tmp = selected_font;
664                 selected_font = s->font_added = 0;
665                 load_fonts();
666                 selected_font = tmp;
667         }
668 }
669 #endif
670
671 inline void graph_append(struct special_t *graph, double f)
672 {
673         if (!graph->scaled && f > graph->graph_scale) {
674                 f = graph->graph_scale;
675         }
676         int i;
677         if (graph->scaled) {
678                 graph->graph_scale = 1;
679         }
680         graph->graph[0] = f; /* add new data */
681         for (i = graph->graph_width - 1; i > 0; i--) { /* shift all the data by 1 */
682                 graph->graph[i] = graph->graph[i - 1];
683                 if (graph->scaled && graph->graph[i] > graph->graph_scale) {
684                         graph->graph_scale = graph->graph[i]; /* check if we need to update the scale */
685                 }
686         }
687 }
688
689 short colour_depth = 0;
690 void set_up_gradient();
691
692 /* precalculated: 31/255, and 63/255 */
693 #define CONST_8_TO_5_BITS 0.12156862745098
694 #define CONST_8_TO_6_BITS 0.247058823529412
695
696 /* adjust color values depending on color depth*/
697 static unsigned int adjust_colors(unsigned int color)
698 {
699         double r, g, b;
700         if (colour_depth == 0) {
701                 set_up_gradient();
702         }
703         if (colour_depth == 16) {
704                 r = (color & 0xff0000) >> 16;
705                 g = (color & 0xff00) >> 8;
706                 b =  color & 0xff;
707                 color  = (int)(r * CONST_8_TO_5_BITS) << 11;
708                 color |= (int)(g * CONST_8_TO_6_BITS) << 5;
709                 color |= (int)(b * CONST_8_TO_5_BITS);
710         }
711         return color;
712 }
713
714 static void new_graph(char *buf, int w, int h, unsigned int first_colour, unsigned int second_colour, double i, int scale, int append)
715 {
716         struct special_t *s = new_special(buf, GRAPH);
717         s->width = w;
718         if (s->graph == NULL) {
719                 if (s->width > 0 && s->width < MAX_GRAPH_DEPTH) {
720                         s->graph_width = s->width/* - 2*/;      // subtract 2 for the box
721                 } else {
722                         s->graph_width = MAX_GRAPH_DEPTH - 2;
723                 }
724                 s->graph = malloc(s->graph_width * sizeof(double));
725                 memset(s->graph, 0, s->graph_width * sizeof(double));
726                 s->graph_scale = 100;
727         }
728         s->height = h;
729         s->first_colour = adjust_colors(first_colour);
730         s->last_colour = adjust_colors(second_colour);
731         if (scale != 0) {
732                 s->scaled = 0;
733         } else {
734                 s->scaled = 1;
735         }
736         /*if (s->width) {
737                 s->graph_width = s->width - 2;  // subtract 2 for rectangle around
738         }*/
739         if (s->scaled) {
740                 s->graph_scale = 1;
741         } else {
742                 s->graph_scale = scale;
743         }
744         if (append) {
745                 graph_append(s, i);
746         }
747 }
748
749 static const char *scan_graph(const char *args, int *w, int *h, unsigned int *first_colour, unsigned int *last_colour, unsigned int *scale)
750 {
751         *w = 0;                 /* zero width means all space that is available */
752         *h = 25;
753         *first_colour = 0;
754         *last_colour = 0;
755         /* graph's argument is either height or height,width */
756         if (args) {
757                 if (sscanf(args, "%*s %d,%d %x %x %i", h, w, first_colour, last_colour, scale) < 5) {
758                         if (sscanf(args, "%*s %d,%d %x %x", h, w, first_colour, last_colour) < 4) {
759                                 *scale = 0;
760                                 if (sscanf(args, "%d,%d %x %x %i", h, w, first_colour, last_colour, scale) < 5) {
761                                         *scale = 0;
762                                         if (sscanf(args, "%d,%d %x %x", h, w, first_colour, last_colour) < 4) {
763                                                 *w = 0;
764                                 *h = 25;                        
765                                 if (sscanf(args, "%*s %x %x %i", first_colour, last_colour, scale) < 3) {
766                                 *w = 0;
767                                 *h = 25;
768                                 *scale = 0;
769                                 if (sscanf(args, "%*s %x %x", first_colour, last_colour) < 2) {
770                                         *w = 0;
771                                         *h = 25;
772                                         if (sscanf(args, "%x %x %i", first_colour, last_colour, scale) < 3) {
773                                                 *first_colour = 0;
774                                                 *last_colour = 0;
775                                                 *scale = 0;
776                                                 if (sscanf(args, "%x %x", first_colour, last_colour) < 2) {
777                                         *first_colour = 0;
778                                         *last_colour = 0;
779                                         if (sscanf(args, "%d,%d %i", h, w, scale) < 3) {
780                                                 *first_colour = 0;
781                                                 *last_colour = 0;
782                                                 *scale = 0;
783                                                 if (sscanf(args, "%d,%d", h, w) < 2) {
784                                                         *first_colour = 0;
785                                                         *last_colour = 0;
786                                                         sscanf(args, "%*s %d,%d", h, w);
787         }}}}}}}}}}} // haha
788         return args;
789 }
790
791
792 static inline void new_hr(char *buf, int a)
793 {
794         new_special(buf, HORIZONTAL_LINE)->height = a;
795 }
796
797 static inline void new_stippled_hr(char *buf, int a, int b)
798 {
799         struct special_t *s = new_special(buf, STIPPLED_HR);
800         s->height = b;
801         s->arg = a;
802 }
803
804 static inline void new_fg(char *buf, long c)
805 {
806         new_special(buf, FG)->arg = c;
807 }
808
809 static inline void new_bg(char *buf, long c)
810 {
811         new_special(buf, BG)->arg = c;
812 }
813
814 static inline void new_outline(char *buf, long c)
815 {
816         new_special(buf, OUTLINE)->arg = c;
817 }
818
819 static inline void new_offset(char *buf, long c)
820 {
821         new_special(buf, OFFSET)->arg = c;
822 }
823
824 static inline void new_voffset(char *buf, long c)
825 {
826         new_special(buf, VOFFSET)->arg = c;
827 }
828
829 static inline void new_alignr(char *buf, long c)
830 {
831         new_special(buf, ALIGNR)->arg = c;
832 }
833
834 static inline void new_alignc(char *buf, long c)
835 {
836         new_special(buf, ALIGNC)->arg = c;
837 }
838
839 static inline void new_goto(char *buf, long c)
840 {
841         new_special(buf, GOTO)->arg = c;
842 }
843
844 static inline void new_tab(char *buf, int a, int b) {
845         struct special_t *s = new_special(buf, TAB);
846         s->width = a;
847         s->arg = b;
848 }
849
850 /* quite boring functions */
851
852 static inline void for_each_line(char *b, void (*f) (char *))
853 {
854         char *ps, *pe;
855
856         for (ps = b, pe = b; *pe; pe++) {
857                 if (*pe == '\n') {
858                         *pe = '\0';
859                         f(ps);
860                         *pe = '\n';
861                         ps = pe + 1;
862                 }
863         }
864
865         if (ps < pe)
866                 f(ps);
867 }
868
869 static void convert_escapes(char *buf)
870 {
871         char *p = buf, *s = buf;
872
873         while (*s) {
874                 if (*s == '\\') {
875                         s++;
876                         if (*s == 'n')
877                                 *p++ = '\n';
878                         else if (*s == '\\')
879                                 *p++ = '\\';
880                         s++;
881                 } else
882                         *p++ = *s++;
883         }
884         *p = '\0';
885 }
886
887 /* converts from bytes to human readable format (k, M, G, T) */
888 static void human_readable(long long a, char *buf, int size)
889 {
890         // Strange conditional due to possible overflows
891         if(a / 1024 / 1024 / 1024.0 > 1024.0){
892                 snprintf(buf, size, "%.2fTiB", (a / 1024 / 1024 / 1024) / 1024.0);
893         }
894         else if (a >= 1024 * 1024 * 1024) {
895                 snprintf(buf, size, "%.2fGiB", (a / 1024 / 1024) / 1024.0);
896         }
897         else if (a >= 1024 * 1024) {
898                 double m = (a / 1024) / 1024.0;
899                 if (m >= 100.0)
900                         snprintf(buf, size, "%.0fMiB", m);
901                 else
902                         snprintf(buf, size, "%.1fMiB", m);
903         } else if (a >= 1024)
904                 snprintf(buf, size, "%LdKiB", a / (long long) 1024);
905         else
906                 snprintf(buf, size, "%LdB", a);
907 }
908
909 /* text handling */
910
911 enum text_object_type {
912         OBJ_acpiacadapter,
913         OBJ_adt746xcpu,
914         OBJ_adt746xfan,
915         OBJ_acpifan,
916         OBJ_addr,
917         OBJ_linkstatus,
918         OBJ_acpitemp,
919         OBJ_acpitempf,
920         OBJ_battery,
921         OBJ_battery_time,
922         OBJ_buffers,
923         OBJ_cached,
924         OBJ_color,
925         OBJ_font,
926         OBJ_cpu,
927         OBJ_cpubar,
928         OBJ_cpugraph,
929         OBJ_diskio,
930         OBJ_diskio_read,
931         OBJ_diskio_write,
932         OBJ_diskiograph,
933         OBJ_diskiograph_read,
934         OBJ_diskiograph_write,
935         OBJ_downspeed,
936         OBJ_downspeedf,
937         OBJ_downspeedgraph,
938         OBJ_else,
939         OBJ_endif,
940         OBJ_image,
941         OBJ_exec,
942         OBJ_execi,
943         OBJ_texeci,
944         OBJ_execbar,
945         OBJ_execgraph,
946         OBJ_execibar,
947         OBJ_execigraph,
948         OBJ_freq,
949         OBJ_freq_g,
950         OBJ_freq_dyn,
951         OBJ_freq_dyn_g,
952         OBJ_fs_bar,
953         OBJ_fs_bar_free,
954         OBJ_fs_free,
955         OBJ_fs_free_perc,
956         OBJ_fs_size,
957         OBJ_fs_used,
958         OBJ_fs_used_perc,
959         OBJ_goto,
960         OBJ_tab,
961         OBJ_hr,
962         OBJ_offset,
963         OBJ_voffset,
964         OBJ_alignr,
965         OBJ_alignc,
966         OBJ_i2c,
967 #if defined(__linux__)
968         OBJ_i8k_version,
969         OBJ_i8k_bios,
970         OBJ_i8k_serial,
971         OBJ_i8k_cpu_temp,
972         OBJ_i8k_cpu_tempf,
973         OBJ_i8k_left_fan_status,
974         OBJ_i8k_right_fan_status,
975         OBJ_i8k_left_fan_rpm,
976         OBJ_i8k_right_fan_rpm,
977         OBJ_i8k_ac_status,      
978         OBJ_i8k_buttons_status,
979         OBJ_ibm_fan,
980         OBJ_ibm_temps,
981         OBJ_ibm_volume,
982         OBJ_ibm_brightness,
983         OBJ_pb_battery,
984         OBJ_voltage_mv,
985         OBJ_voltage_v,
986 #endif /* __linux__ */
987         OBJ_if_existing,
988         OBJ_if_mounted,
989         OBJ_if_running,
990         OBJ_top,
991         OBJ_top_mem,
992         OBJ_tail,
993         OBJ_head,
994         OBJ_kernel,
995         OBJ_loadavg,
996         OBJ_machine,
997         OBJ_mails,
998         OBJ_mboxscan,
999         OBJ_mem,
1000         OBJ_membar,
1001         OBJ_memgraph,
1002         OBJ_memmax,
1003         OBJ_memperc,
1004         OBJ_mixer,
1005         OBJ_mixerl,
1006         OBJ_mixerr,
1007         OBJ_mixerbar,
1008         OBJ_mixerlbar,
1009         OBJ_mixerrbar,
1010         OBJ_new_mails,
1011         OBJ_nodename,
1012         OBJ_pre_exec,
1013         OBJ_processes,
1014         OBJ_running_processes,
1015         OBJ_shadecolor,
1016         OBJ_outlinecolor,
1017         OBJ_stippled_hr,
1018         OBJ_swap,
1019         OBJ_swapbar,
1020         OBJ_swapmax,
1021         OBJ_swapperc,
1022         OBJ_sysname,
1023         OBJ_temp1,              /* i2c is used instead in these */
1024         OBJ_temp2,
1025         OBJ_text,
1026         OBJ_time,
1027         OBJ_utime,
1028         OBJ_tztime,
1029         OBJ_totaldown,
1030         OBJ_totalup,
1031         OBJ_updates,
1032         OBJ_upspeed,
1033         OBJ_upspeedf,
1034         OBJ_upspeedgraph,
1035         OBJ_uptime,
1036         OBJ_uptime_short,
1037         OBJ_imap,
1038         OBJ_imap_messages,
1039         OBJ_imap_unseen,
1040         OBJ_pop3,
1041         OBJ_pop3_unseen,
1042         OBJ_pop3_used,
1043 #if defined(__FreeBSD__) && (defined(i386) || defined(__i386__))
1044         OBJ_apm_adapter,
1045         OBJ_apm_battery_time,
1046         OBJ_apm_battery_life,
1047 #endif /* __FreeBSD__ */
1048 #ifdef MPD
1049         OBJ_mpd_title,
1050         OBJ_mpd_artist,
1051         OBJ_mpd_album,
1052         OBJ_mpd_random,
1053         OBJ_mpd_repeat,
1054         OBJ_mpd_vol,
1055         OBJ_mpd_bitrate,
1056         OBJ_mpd_status,
1057         OBJ_mpd_host,
1058         OBJ_mpd_port,
1059         OBJ_mpd_password,
1060         OBJ_mpd_bar,
1061         OBJ_mpd_elapsed,
1062         OBJ_mpd_length,
1063         OBJ_mpd_track,
1064         OBJ_mpd_name,
1065         OBJ_mpd_file,
1066         OBJ_mpd_percent,
1067         OBJ_mpd_smart,
1068 #endif
1069 #ifdef XMMS2
1070     OBJ_xmms2_artist,
1071     OBJ_xmms2_album,
1072     OBJ_xmms2_title,
1073     OBJ_xmms2_genre,
1074     OBJ_xmms2_comment,
1075     OBJ_xmms2_decoder,
1076     OBJ_xmms2_transport,
1077     OBJ_xmms2_url,
1078     OBJ_xmms2_date,
1079     OBJ_xmms2_tracknr,
1080     OBJ_xmms2_bitrate,
1081     OBJ_xmms2_id,
1082     OBJ_xmms2_duration,
1083     OBJ_xmms2_elapsed,
1084     OBJ_xmms2_size,
1085         OBJ_xmms2_percent,
1086         OBJ_xmms2_status,
1087         OBJ_xmms2_bar,
1088         OBJ_xmms2_smart,
1089 #endif
1090 #ifdef AUDACIOUS
1091         OBJ_audacious_status,
1092         OBJ_audacious_title,
1093         OBJ_audacious_length,
1094         OBJ_audacious_length_seconds,
1095         OBJ_audacious_position,
1096         OBJ_audacious_position_seconds,
1097         OBJ_audacious_bitrate,
1098         OBJ_audacious_frequency,
1099         OBJ_audacious_channels,
1100         OBJ_audacious_filename,
1101         OBJ_audacious_playlist_length,
1102         OBJ_audacious_playlist_position,
1103         OBJ_audacious_bar,
1104 #endif
1105 #ifdef BMPX
1106         OBJ_bmpx_title,
1107         OBJ_bmpx_artist,
1108         OBJ_bmpx_album,
1109         OBJ_bmpx_track,
1110         OBJ_bmpx_uri,
1111         OBJ_bmpx_bitrate,
1112 #endif
1113 #ifdef TCP_PORT_MONITOR
1114         OBJ_tcp_portmon,
1115 #endif
1116 #ifdef HAVE_ICONV
1117         OBJ_iconv_start,
1118         OBJ_iconv_stop,
1119 #endif
1120 #ifdef HDDTEMP
1121         OBJ_hddtemp,
1122 #endif
1123         OBJ_entropy_avail,
1124         OBJ_entropy_poolsize,
1125         OBJ_entropy_bar
1126 };
1127
1128 struct text_object {
1129         int type;
1130         int a, b;
1131         long line;
1132         unsigned int c, d, e;
1133         float f;
1134         char global_mode;
1135         union {
1136                 char *s;        /* some string */
1137                 int i;          /* some integer */
1138                 long l;         /* some other integer */
1139                 unsigned int sensor;
1140                 struct net_stat *net;
1141                 struct fs_stat *fs;
1142                 unsigned char loadavg[3];
1143                 unsigned int cpu_index;
1144                 struct mail_s *mail;
1145
1146                 struct {
1147                         char *args;
1148                         char *output;
1149                 } mboxscan;
1150
1151                 struct {
1152                         char *tz;    /* timezone variable */
1153                         char *fmt;   /* time display formatting */
1154                 } tztime;
1155
1156                 struct {
1157                         struct fs_stat *fs;
1158                         int w, h;
1159                 } fsbar;        /* 3 */
1160
1161                 struct {
1162                         int l;
1163                         int w, h;
1164                 } mixerbar;     /* 3 */
1165
1166                 struct {
1167                         int fd;
1168                         int arg;
1169                         char devtype[256];
1170                         char type[64];
1171                 } i2c;          /* 2 */
1172                 struct {
1173                         int pos;
1174                         char *s;
1175                 } ifblock;
1176                 struct {
1177                         int num;
1178                         int type;
1179                 } top;
1180
1181                 struct {
1182                         int wantedlines;
1183                         int readlines;
1184                         char *logfile;
1185                         double last_update;
1186                         float interval;
1187                         char *buffer;
1188                 } tail;
1189
1190                 struct {
1191                         double last_update;
1192                         float interval;
1193                         char *cmd;
1194                         char *buffer;
1195                         double data;
1196                 } execi;        /* 5 */
1197
1198                 struct {
1199                         float interval;
1200                         char *cmd;
1201                         char *buffer;
1202                         double data;
1203                         timed_thread *p_timed_thread;
1204                 } texeci;
1205
1206                 struct {
1207                         int a, b;
1208                 } pair;         /* 2 */
1209 #ifdef TCP_PORT_MONITOR
1210                 struct {
1211                         in_port_t  port_range_begin;  /* starting port to monitor */
1212                         in_port_t  port_range_end;    /* ending port to monitor */
1213                         int        item;              /* enum from libtcp-portmon.h, e.g. COUNT, etc. */
1214                         int        connection_index;  /* 0 to n-1 connections. */
1215                 } tcp_port_monitor;
1216 #endif
1217 #ifdef HDDTEMP
1218                 struct {
1219                         char *addr;
1220                         int port;
1221                         char *dev;
1222                 } hddtemp; /* 2 */
1223 #endif
1224         } data;
1225 };
1226
1227 struct text_object_list {
1228         unsigned int text_object_count;
1229         struct text_object *text_objects;
1230 };
1231
1232 static unsigned int text_object_count;
1233 static struct text_object *text_objects;
1234 static void generate_text_internal(char *p, int p_max_size, struct text_object *objs, unsigned int object_count, struct information *cur);
1235
1236 #define MAXDATASIZE 1000
1237 #define POP3 1
1238 #define IMAP 2
1239
1240 struct mail_s* parse_mail_args(char type, const char *arg) {
1241         struct mail_s *mail;
1242         mail = malloc(sizeof(struct mail_s));
1243         memset(mail, 0, sizeof(struct mail_s));
1244         char *tmp;
1245         if (sscanf(arg, "%128s %128s %128s", mail->host, mail->user, mail->pass) != 3) {
1246                 if (type == POP3) {
1247                         ERR("Scanning IMAP args failed");
1248                 } else  if (type == IMAP) {
1249                         ERR("Scanning POP3 args failed");
1250                 }
1251         }
1252         // see if password needs prompting
1253         if (mail->pass[0] == '*' && mail->pass[1] == '\0') {
1254                 int fp = fileno(stdin);
1255                 struct termios term;
1256                 tcgetattr(fp, &term);
1257                 term.c_lflag &= ~ECHO;
1258                 tcsetattr(fp, TCSANOW, &term);
1259                 printf("Enter mailbox password (%s@%s): ", mail->user, mail->host);
1260                 scanf("%128s", mail->pass);
1261                 printf("\n");
1262                 term.c_lflag |= ECHO;
1263                 tcsetattr(fp, TCSANOW, &term);
1264         }
1265         // now we check for optional args
1266         tmp = strstr(arg, "-i ");
1267         if (tmp) {
1268                 tmp += 3;
1269                 sscanf(tmp, "%f", &mail->interval);
1270         } else {
1271                 mail->interval = 300;   // 5 minutes
1272         }
1273         tmp = strstr(arg, "-p ");
1274         if (tmp) {
1275                 tmp += 3;
1276                 sscanf(tmp, "%lu", &mail->port);
1277         } else {
1278                 if (type == POP3) {
1279                         mail->port = 110;       // default pop3 port
1280                 } else if (type == IMAP) {
1281                         mail->port = 143;       // default imap port
1282                 }
1283         }
1284         if (type == IMAP) {
1285                 tmp = strstr(arg, "-f ");
1286                 if (tmp) {
1287                         tmp += 3;
1288                         sscanf(tmp, "%s", mail->folder);
1289                 } else {
1290                         strncpy(mail->folder, "INBOX", 128);    // default imap inbox
1291                 }
1292         }
1293         tmp = strstr(arg, "-e ");
1294         if (tmp) {
1295                 tmp += 3;
1296                 int len = 1024;
1297                 if (tmp[0] == '\'') {
1298                         len = strstr(tmp+1, "'") - tmp - 1;
1299                         if (len > 1024) {
1300                                 len = 1024;
1301                         }
1302                 }
1303                 strncpy(mail->command, tmp+1, len);
1304         } else {
1305                 mail->command[0] = '\0';
1306         }
1307         mail->p_timed_thread = NULL;
1308         return mail;
1309 }
1310
1311 void *imap_thread(struct mail_s* mail)
1312 {
1313         int sockfd, numbytes;
1314         char recvbuf[MAXDATASIZE];
1315         char sendbuf[MAXDATASIZE];
1316         char *reply;
1317         int fail = 0;
1318         unsigned int old_unseen = UINT_MAX;
1319         unsigned int old_messages = UINT_MAX;
1320         struct stat stat_buf;
1321         struct hostent *he;
1322         struct sockaddr_in their_addr;  // connector's address information
1323         if ((he = gethostbyname(mail->host)) == NULL) { // get the host info 
1324                 herror("gethostbyname");
1325                 exit(1);
1326         }
1327         while (fail < 5) {
1328                 if (fail > 0) {
1329                     ERR("Trying IMAP connection again for %s@%s (try %i/5)", mail->user, mail->host, fail + 1);
1330                 }
1331                 if ((sockfd = socket(PF_INET, SOCK_STREAM, 0)) == -1) {
1332                         perror("socket");
1333                         fail++;
1334                         goto next_iteration;
1335                 }
1336
1337                 their_addr.sin_family = AF_INET;        // host byte order 
1338                 their_addr.sin_port = htons(mail->port);        // short, network byte order 
1339                 their_addr.sin_addr = *((struct in_addr *) he->h_addr);
1340                 memset(&(their_addr.sin_zero), '\0', 8);        // zero the rest of the struct 
1341
1342                 if (connect
1343                     (sockfd, (struct sockaddr *) &their_addr,
1344                      sizeof(struct sockaddr)) == -1) {
1345                         perror("connect");
1346                         fail++;
1347                         goto next_iteration;
1348                 }
1349                 struct timeval timeout;
1350                 int res;
1351                 fd_set fdset;
1352                 timeout.tv_sec = 60;    // 60 second timeout i guess
1353                 timeout.tv_usec = 0;
1354                 FD_ZERO(&fdset);
1355                 FD_SET(sockfd, &fdset);
1356                 res = select(sockfd + 1, &fdset, NULL, NULL, &timeout);
1357                 if (res > 0) {
1358                         if ((numbytes =
1359                              recv(sockfd, recvbuf, MAXDATASIZE - 1,
1360                                   0)) == -1) {
1361                                 perror("recv");
1362                                 fail++;
1363                                 goto next_iteration;
1364                         }
1365                 } else {
1366                         ERR("IMAP connection failed: timeout");
1367                         fail++;
1368                         goto next_iteration;
1369                 }
1370                 recvbuf[numbytes] = '\0';
1371                 if (strstr(recvbuf, "* OK") != recvbuf) {
1372                         ERR("IMAP connection failed, probably not an IMAP server");
1373                         fail++;
1374                         goto next_iteration;
1375                 }
1376                 strncpy(sendbuf, "a1 login ", MAXDATASIZE);
1377                 strncat(sendbuf, mail->user,
1378                         MAXDATASIZE - strlen(sendbuf) - 1);
1379                 strncat(sendbuf, " ", MAXDATASIZE - strlen(sendbuf) - 1);
1380                 strncat(sendbuf, mail->pass,
1381                         MAXDATASIZE - strlen(sendbuf) - 1);
1382                 strncat(sendbuf, "\n", MAXDATASIZE - strlen(sendbuf) - 1);
1383                 if (send(sockfd, sendbuf, strlen(sendbuf), 0) == -1) {
1384                         perror("send a1");
1385                         fail++;
1386                         goto next_iteration;
1387                 }
1388                 timeout.tv_sec = 60;    // 60 second timeout i guess
1389                 timeout.tv_usec = 0;
1390                 FD_ZERO(&fdset);
1391                 FD_SET(sockfd, &fdset);
1392                 res = select(sockfd + 1, &fdset, NULL, NULL, &timeout);
1393                 if (res > 0) {
1394                         if ((numbytes =
1395                              recv(sockfd, recvbuf, MAXDATASIZE - 1,
1396                                   0)) == -1) {
1397                                 perror("recv a1");
1398                                 fail++;
1399                                 goto next_iteration;
1400                         }
1401                 }
1402                 recvbuf[numbytes] = '\0';
1403                 if (strstr(recvbuf, "a1 OK") == NULL) {
1404                         ERR("IMAP server login failed: %s", recvbuf);
1405                         fail++;
1406                         goto next_iteration;
1407                 }
1408                 strncpy(sendbuf, "a2 STATUS ", MAXDATASIZE);
1409                 strncat(sendbuf, mail->folder,
1410                         MAXDATASIZE - strlen(sendbuf) - 1);
1411                 strncat(sendbuf, " (MESSAGES UNSEEN)\n",
1412                         MAXDATASIZE - strlen(sendbuf) - 1);
1413                 if (send(sockfd, sendbuf, strlen(sendbuf), 0) == -1) {
1414                         perror("send a2");
1415                         fail++;
1416                         goto next_iteration;
1417                 }
1418                 timeout.tv_sec = 60;    // 60 second timeout i guess
1419                 timeout.tv_usec = 0;
1420                 FD_ZERO(&fdset);
1421                 FD_SET(sockfd, &fdset);
1422                 res = select(sockfd + 1, &fdset, NULL, NULL, &timeout);
1423                 if (res > 0) {
1424                         if ((numbytes =
1425                              recv(sockfd, recvbuf, MAXDATASIZE - 1,
1426                                   0)) == -1) {
1427                                 perror("recv a2");
1428                                 fail++;
1429                                 goto next_iteration;
1430                         }
1431                 }
1432                 recvbuf[numbytes] = '\0';
1433                 if (strstr(recvbuf, "a2 OK") == NULL) {
1434                         ERR("IMAP status failed: %s", recvbuf);
1435                         fail++;
1436                         goto next_iteration;
1437                 }
1438                 // now we get the data
1439                 reply = strstr(recvbuf, " (MESSAGES ");
1440                 reply += 2;
1441                 *strchr(reply, ')') = '\0';
1442                 if (reply == NULL) {
1443                         ERR("Error parsing IMAP response: %s", recvbuf);
1444                         fail++;
1445                         goto next_iteration;
1446                 } else {
1447                         timed_thread_lock (mail->p_timed_thread);
1448                         sscanf(reply, "MESSAGES %lu UNSEEN %lu",
1449                                &mail->messages,
1450                                &mail->unseen);
1451                         timed_thread_unlock (mail->p_timed_thread);
1452                 }
1453                 strncpy(sendbuf, "a3 logout\n", MAXDATASIZE);
1454                 if (send(sockfd, sendbuf, strlen(sendbuf), 0) == -1) {
1455                         perror("send a3");
1456                         fail++;
1457                         goto next_iteration;
1458                 }
1459                 timeout.tv_sec = 60;    // 60 second timeout i guess
1460                 timeout.tv_usec = 0;
1461                 FD_ZERO(&fdset);
1462                 FD_SET(sockfd, &fdset);
1463                 res = select(sockfd + 1, &fdset, NULL, NULL, &timeout);
1464                 if (res > 0) {
1465                         if ((numbytes =
1466                              recv(sockfd, recvbuf, MAXDATASIZE - 1,
1467                                   0)) == -1) {
1468                                 perror("recv a3");
1469                                 fail++;
1470                                 goto next_iteration;
1471                         }
1472                 }
1473                 recvbuf[numbytes] = '\0';
1474                 if (strstr(recvbuf, "a3 OK") == NULL) {
1475                         ERR("IMAP logout failed: %s", recvbuf);
1476                         fail++;
1477                         goto next_iteration;
1478                 }
1479                 if (strlen(mail->command) > 1 && (mail->unseen > old_unseen || (mail->messages > old_messages && mail->unseen > 0))) {  // new mail goodie
1480                         if (system(mail->command) == -1) {
1481                                 perror("system()");
1482                         }
1483                 }
1484                 fail = 0;
1485                 old_unseen = mail->unseen;
1486                 old_messages = mail->messages;
1487 next_iteration:
1488                 if ((fstat(sockfd, &stat_buf)==0) && S_ISSOCK(stat_buf.st_mode))
1489                     /* if a valid socket, close it */
1490                     close(sockfd);
1491                 if (timed_thread_test (mail->p_timed_thread))
1492                     timed_thread_exit (mail->p_timed_thread);
1493         }
1494         return 0;
1495 }
1496
1497 void *pop3_thread(struct mail_s *mail)
1498 {
1499         int sockfd, numbytes;
1500         char recvbuf[MAXDATASIZE];
1501         char sendbuf[MAXDATASIZE];
1502         char *reply;
1503         int fail = 0;
1504         unsigned int old_unseen = UINT_MAX;
1505         struct stat stat_buf;
1506         struct hostent *he;
1507         struct sockaddr_in their_addr;  // connector's address information
1508         if ((he = gethostbyname(mail->host)) == NULL) { // get the host info 
1509                 herror("gethostbyname");
1510                 exit(1);
1511         }
1512         while (fail < 5) {
1513                 if (fail > 0) {
1514                     ERR("Trying POP3 connection again for %s@%s (try %i/5)", mail->user, mail->host, fail + 1);
1515                 }
1516                 if ((sockfd = socket(PF_INET, SOCK_STREAM, 0)) == -1) {
1517                         perror("socket");
1518                         fail++;
1519                         goto next_iteration;
1520                 }
1521
1522                 their_addr.sin_family = AF_INET;        // host byte order 
1523                 their_addr.sin_port = htons(mail->port);        // short, network byte order 
1524                 their_addr.sin_addr = *((struct in_addr *) he->h_addr);
1525                 memset(&(their_addr.sin_zero), '\0', 8);        // zero the rest of the struct 
1526
1527                 if (connect
1528                     (sockfd, (struct sockaddr *) &their_addr,
1529                      sizeof(struct sockaddr)) == -1) {
1530                         perror("connect");
1531                         fail++;
1532                         goto next_iteration;
1533                 }
1534                 struct timeval timeout;
1535                 int res;
1536                 fd_set fdset;
1537                 timeout.tv_sec = 60;    // 60 second timeout i guess
1538                 timeout.tv_usec = 0;
1539                 FD_ZERO(&fdset);
1540                 FD_SET(sockfd, &fdset);
1541                 res = select(sockfd + 1, &fdset, NULL, NULL, &timeout);
1542                 if (res > 0) {
1543                         if ((numbytes =
1544                              recv(sockfd, recvbuf, MAXDATASIZE - 1,
1545                                   0)) == -1) {
1546                                 perror("recv");
1547                                 fail++;
1548                                 goto next_iteration;
1549                         }
1550                 } else {
1551                         ERR("POP3 connection failed: timeout\n");
1552                         fail++;
1553                         goto next_iteration;
1554                 }
1555                 recvbuf[numbytes] = '\0';
1556                 if (strstr(recvbuf, "+OK ") != recvbuf) {
1557                         ERR("POP3 connection failed, probably not a POP3 server");
1558                         fail++;
1559                         goto next_iteration;
1560                 }
1561                 strncpy(sendbuf, "USER ", MAXDATASIZE);
1562                 strncat(sendbuf, mail->user,
1563                         MAXDATASIZE - strlen(sendbuf) - 1);
1564                 strncat(sendbuf, "\n", MAXDATASIZE - strlen(sendbuf) - 1);
1565                 if (send(sockfd, sendbuf, strlen(sendbuf), 0) == -1) {
1566                         perror("send USER");
1567                         fail++;
1568                         goto next_iteration;
1569                 }
1570                 timeout.tv_sec = 60;    // 60 second timeout i guess
1571                 timeout.tv_usec = 0;
1572                 FD_ZERO(&fdset);
1573                 FD_SET(sockfd, &fdset);
1574                 res = select(sockfd + 1, &fdset, NULL, NULL, &timeout);
1575                 if (res > 0) {
1576                         if ((numbytes =
1577                              recv(sockfd, recvbuf, MAXDATASIZE - 1,
1578                                   0)) == -1) {
1579                                 perror("recv USER");
1580                                 fail++;
1581                                 goto next_iteration;
1582                         }
1583                 }
1584                 recvbuf[numbytes] = '\0';
1585                 if (strstr(recvbuf, "+OK ") == NULL) {
1586                         ERR("POP3 server login failed: %s", recvbuf);
1587                         fail++;
1588                         goto next_iteration;
1589                 }
1590                 strncpy(sendbuf, "PASS ", MAXDATASIZE);
1591                 strncat(sendbuf, mail->pass,
1592                         MAXDATASIZE - strlen(sendbuf) - 1);
1593                 strncat(sendbuf, "\n", MAXDATASIZE - strlen(sendbuf) - 1);
1594                 if (send(sockfd, sendbuf, strlen(sendbuf), 0) == -1) {
1595                         perror("send PASS");
1596                         fail++;
1597                         goto next_iteration;
1598                 }
1599                 timeout.tv_sec = 60;    // 60 second timeout i guess
1600                 timeout.tv_usec = 0;
1601                 FD_ZERO(&fdset);
1602                 FD_SET(sockfd, &fdset);
1603                 res = select(sockfd + 1, &fdset, NULL, NULL, &timeout);
1604                 if (res > 0) {
1605                         if ((numbytes =
1606                              recv(sockfd, recvbuf, MAXDATASIZE - 1,
1607                                   0)) == -1) {
1608                                 perror("recv PASS");
1609                                 fail++;
1610                                 goto next_iteration;
1611                         }
1612                 }
1613                 recvbuf[numbytes] = '\0';
1614                 if (strstr(recvbuf, "+OK ") == NULL) {
1615                         ERR("POP3 server login failed: %s", recvbuf);
1616                         fail++;
1617                         goto next_iteration;
1618                 }
1619                 strncpy(sendbuf, "STAT\n", MAXDATASIZE);
1620                 if (send(sockfd, sendbuf, strlen(sendbuf), 0) == -1) {
1621                         perror("send STAT");
1622                         fail++;
1623                         goto next_iteration;
1624                 }
1625                 timeout.tv_sec = 60;    // 60 second timeout i guess
1626                 timeout.tv_usec = 0;
1627                 FD_ZERO(&fdset);
1628                 FD_SET(sockfd, &fdset);
1629                 res = select(sockfd + 1, &fdset, NULL, NULL, &timeout);
1630                 if (res > 0) {
1631                         if ((numbytes =
1632                              recv(sockfd, recvbuf, MAXDATASIZE - 1,
1633                                   0)) == -1) {
1634                                 perror("recv STAT");
1635                                 fail++;
1636                                 goto next_iteration;
1637                         }
1638                 }
1639                 recvbuf[numbytes] = '\0';
1640                 if (strstr(recvbuf, "+OK ") == NULL) {
1641                         ERR("POP3 status failed: %s", recvbuf);
1642                         fail++;
1643                         goto next_iteration;
1644                 }
1645                 // now we get the data
1646                 reply = recvbuf + 4;
1647                 if (reply == NULL) {
1648                         ERR("Error parsing POP3 response: %s", recvbuf);
1649                         fail++;
1650                         goto next_iteration;
1651                 } else {
1652                         timed_thread_lock (mail->p_timed_thread);
1653                         sscanf(reply, "%lu %lu", &mail->unseen,
1654                                &mail->used);
1655                         timed_thread_unlock (mail->p_timed_thread);
1656                 }
1657                 strncpy(sendbuf, "QUIT\n", MAXDATASIZE);
1658                 if (send(sockfd, sendbuf, strlen(sendbuf), 0) == -1) {
1659                         perror("send QUIT");
1660                         fail++;
1661                         goto next_iteration;
1662                 }
1663                 timeout.tv_sec = 60;    // 60 second timeout i guess
1664                 timeout.tv_usec = 0;
1665                 FD_ZERO(&fdset);
1666                 FD_SET(sockfd, &fdset);
1667                 res = select(sockfd + 1, &fdset, NULL, NULL, &timeout);
1668                 if (res > 0) {
1669                         if ((numbytes =
1670                              recv(sockfd, recvbuf, MAXDATASIZE - 1,
1671                                   0)) == -1) {
1672                                 perror("recv QUIT");
1673                                 fail++;
1674                                 goto next_iteration;
1675                         }
1676                 }
1677                 recvbuf[numbytes] = '\0';
1678                 if (strstr(recvbuf, "+OK") == NULL) {
1679                         ERR("POP3 logout failed: %s", recvbuf);
1680                         fail++;
1681                         goto next_iteration;
1682                 }
1683                 if (strlen(mail->command) > 1 && mail->unseen > old_unseen) {   // new mail goodie
1684                         if (system(mail->command) == -1) {
1685                                 perror("system()");
1686                         }
1687                 }
1688                 fail = 0;
1689                 old_unseen = mail->unseen;
1690 next_iteration:
1691                 if ((fstat(sockfd, &stat_buf)==0) && S_ISSOCK(stat_buf.st_mode))  
1692                     /* if a valid socket, close it */
1693                     close(sockfd);
1694                 if (timed_thread_test (mail->p_timed_thread))
1695                     timed_thread_exit (mail->p_timed_thread);
1696         }
1697         return 0;
1698 }
1699
1700
1701 void *threaded_exec(struct text_object *obj) { 
1702         while (1) {
1703                 char *p2 = obj->data.texeci.buffer;
1704                 FILE *fp = popen(obj->data.texeci.cmd,"r");
1705                 timed_thread_lock (obj->data.texeci.p_timed_thread);
1706                 int n2 = fread(p2, 1, text_buffer_size, fp);
1707                 (void) pclose(fp);
1708                 p2[n2] = '\0';
1709                 if (n2 && p2[n2 - 1] == '\n') {
1710                         p2[n2 - 1] = '\0';
1711                 }
1712                 while (*p2) {
1713                         if (*p2 == '\001') {
1714                                 *p2 = ' ';
1715                         }
1716                         p2++;
1717                 }
1718                 timed_thread_unlock (obj->data.texeci.p_timed_thread);
1719                 if (timed_thread_test (obj->data.texeci.p_timed_thread))
1720                     timed_thread_exit (obj->data.texeci.p_timed_thread);
1721         }
1722         return 0;
1723 }
1724
1725 static struct text_object *new_text_object_internal()
1726 {
1727         struct text_object *obj = malloc(sizeof(struct text_object));
1728         memset(obj, 0, sizeof(struct text_object));
1729         return obj;
1730 }
1731
1732 static void free_text_objects(unsigned int count, struct text_object *objs)
1733 {
1734         unsigned int i;
1735         for (i = 0; i < count; i++) {
1736                 switch (objs[i].type) {
1737                         case OBJ_acpitemp:
1738                                 close(objs[i].data.i);
1739                                 break;
1740                         case OBJ_acpitempf:
1741                                 close(objs[i].data.i);
1742                                 break;
1743                         case OBJ_i2c:
1744                                 close(objs[i].data.i2c.fd);
1745                                 break;
1746                         case OBJ_time:
1747                                 free(objs[i].data.s);
1748                                 break;
1749                         case OBJ_utime:
1750                                 free(objs[i].data.s);
1751                                 break;
1752                         case OBJ_tztime:
1753                                 free(objs[i].data.tztime.tz);
1754                                 free(objs[i].data.tztime.fmt);
1755                                 break;
1756                         case OBJ_mboxscan:
1757                                 free(objs[i].data.mboxscan.args);
1758                                 free(objs[i].data.mboxscan.output);
1759                                 break;
1760                         case OBJ_imap:
1761                                 free(info.mail);
1762                                 break;
1763                         case OBJ_imap_unseen:
1764                                 if (!objs[i].global_mode) {
1765                                         free(objs[i].data.mail);
1766                                 }
1767                                 break;
1768                         case OBJ_imap_messages:
1769                                 if (!objs[i].global_mode) {
1770                                         free(objs[i].data.mail);
1771                                 }
1772                                 break;
1773                         case OBJ_pop3:
1774                                 free(info.mail);
1775                                 break;
1776                         case OBJ_pop3_unseen:
1777                                 if (!objs[i].global_mode) {
1778                                         free(objs[i].data.mail);
1779                                 }
1780                                 break;
1781                         case OBJ_pop3_used:
1782                                 if (!objs[i].global_mode) {
1783                                         free(objs[i].data.mail);
1784                                 }
1785                                 break;
1786                         case OBJ_if_existing:
1787                         case OBJ_if_mounted:
1788                         case OBJ_if_running:
1789                                 free(objs[i].data.ifblock.s);
1790                                 break;
1791                         case OBJ_tail:
1792                                 free(objs[i].data.tail.logfile);
1793                                 free(objs[i].data.tail.buffer);
1794                                 break;
1795                         case OBJ_text: case OBJ_font:
1796                                 free(objs[i].data.s);
1797                                 break;
1798                         case OBJ_image:
1799                                 free(objs[i].data.s);
1800                                 break;
1801                         case OBJ_exec:
1802                                 free(objs[i].data.s);
1803                                 break;
1804                         case OBJ_execbar:
1805                                 free(objs[i].data.s);
1806                                 break;
1807                         case OBJ_execgraph:
1808                                 free(objs[i].data.s);
1809                                 break;
1810                                 /*              case OBJ_execibar:
1811                                                 free(objs[i].data.s);
1812                                                 break;
1813                                                 case OBJ_execigraph:
1814                                                 free(objs[i].data.s);
1815                                                 break;*/
1816 #ifdef HAVE_ICONV
1817                         case OBJ_iconv_start:
1818                                 free_iconv();
1819                                 break;
1820 #endif
1821 #ifdef MPD
1822                         case OBJ_mpd_title:
1823                                 if (info.mpd.title) {
1824                                         free(info.mpd.title);
1825                                         info.mpd.title = 0;
1826                                 }
1827                                 break;
1828                         case OBJ_mpd_artist:
1829                                 if (info.mpd.artist) {
1830                                         free(info.mpd.artist);
1831                                         info.mpd.artist = 0;
1832                                 }
1833                                 break;
1834                         case OBJ_mpd_album:
1835                                 if (info.mpd.album) {
1836                                         free(info.mpd.album);
1837                                         info.mpd.album = 0;
1838                                 }
1839                                 break;
1840                         case OBJ_mpd_random:
1841                                 if (info.mpd.random) {
1842                                         free(info.mpd.random);
1843                                         info.mpd.random = 0;
1844                                 }
1845                                 break;
1846                         case OBJ_mpd_repeat:
1847                                 if (info.mpd.repeat) {
1848                                         free(info.mpd.repeat);
1849                                         info.mpd.repeat = 0;
1850                                 }
1851                                 break;
1852                         case OBJ_mpd_track:
1853                                 if (info.mpd.track) {
1854                                         free(info.mpd.track);
1855                                         info.mpd.track = 0;
1856                                 }
1857                                 break;
1858                         case OBJ_mpd_name:
1859                                 if (info.mpd.name) {
1860                                         free(info.mpd.name);
1861                                         info.mpd.name = 0;
1862                                 }
1863                                 break;
1864                         case OBJ_mpd_file:
1865                                 if (info.mpd.file) {
1866                                         free(info.mpd.file);
1867                                         info.mpd.file = 0;
1868                                 }
1869                                 break;
1870                         case OBJ_mpd_status:
1871                                 if (info.mpd.status) {
1872                                         free(info.mpd.status);
1873                                         info.mpd.status = 0;
1874                                 }
1875                                 break;
1876                         case OBJ_mpd_smart:
1877                                 if (info.mpd.artist) {
1878                                         free(info.mpd.artist);
1879                                         info.mpd.artist = 0;
1880                                 }
1881                                 if (info.mpd.title) {
1882                                         free(info.mpd.title);
1883                                         info.mpd.title = 0;
1884                                 }
1885                                 if (info.mpd.file) {
1886                                         free(info.mpd.file);
1887                                         info.mpd.file = 0;
1888                                 }
1889                                 break;
1890                         case OBJ_mpd_host:
1891 #endif
1892 #ifdef XMMS2
1893                         case OBJ_xmms2_artist:
1894                                 if (info.xmms2.artist) {
1895                                         free(info.xmms2.artist);
1896                                         info.xmms2.artist = 0;
1897                                 }
1898                                 break;
1899                         case OBJ_xmms2_album:
1900                                 if (info.xmms2.album) {
1901                                         free(info.xmms2.album);
1902                                         info.xmms2.album = 0;
1903                                 }
1904                                 break;
1905                         case OBJ_xmms2_title:
1906                                 if (info.xmms2.title) {
1907                                         free(info.xmms2.title);
1908                                         info.xmms2.title = 0;
1909                                 }
1910                                 break;
1911                         case OBJ_xmms2_genre:
1912                                 if (info.xmms2.genre) {
1913                                         free(info.xmms2.genre);
1914                                         info.xmms2.genre = 0;
1915                                 }
1916                                 break;
1917                         case OBJ_xmms2_comment:
1918                                 if (info.xmms2.comment) {
1919                                         free(info.xmms2.comment);
1920                                         info.xmms2.comment = 0;
1921                                 }
1922                                 break;
1923                         case OBJ_xmms2_decoder:
1924                                 if (info.xmms2.decoder) {
1925                                         free(info.xmms2.decoder);
1926                                         info.xmms2.url = 0;
1927                                 }
1928                                 break;
1929                         case OBJ_xmms2_transport:
1930                                 if (info.xmms2.transport) {
1931                                         free(info.xmms2.transport);
1932                                         info.xmms2.url = 0;
1933                                 }
1934                                 break;
1935                         case OBJ_xmms2_url:
1936                                 if (info.xmms2.url) {
1937                                         free(info.xmms2.url);
1938                                         info.xmms2.url = 0;
1939                                 }
1940                                 break;
1941                         case OBJ_xmms2_date:
1942                                 if (info.xmms2.date) {
1943                                         free(info.xmms2.date);
1944                                         info.xmms2.date = 0;
1945                                 }
1946                                 break;
1947                         case OBJ_xmms2_status:
1948                                 if (info.xmms2.status) {
1949                                         free(info.xmms2.status);
1950                                         info.xmms2.status = 0;
1951                                 }
1952                                 break;
1953                         case OBJ_xmms2_smart:
1954                                 if (info.xmms2.artist) {
1955                                         free(info.xmms2.artist);
1956                                         info.xmms2.artist = 0;
1957                                 }
1958                                 if (info.xmms2.title) {
1959                                         free(info.xmms2.title);
1960                                         info.xmms2.title = 0;
1961                                 }
1962                                 if (info.xmms2.url) {
1963                                         free(info.xmms2.url);
1964                                         info.xmms2.url = 0;
1965                                 }
1966                                 break;
1967 #endif
1968 #ifdef BMPX
1969                         case OBJ_bmpx_title:
1970                         case OBJ_bmpx_artist:
1971                         case OBJ_bmpx_album:
1972                         case OBJ_bmpx_track:
1973                         case OBJ_bmpx_uri:
1974                         case OBJ_bmpx_bitrate:
1975 #endif
1976                         case OBJ_pre_exec:
1977                         case OBJ_battery:
1978                                 free(objs[i].data.s);
1979                                 break;
1980                         case OBJ_battery_time:
1981                                 free(objs[i].data.s);
1982                                 break;
1983                         case OBJ_execi:
1984                                 free(objs[i].data.execi.cmd);
1985                                 free(objs[i].data.execi.buffer);
1986                                 break;
1987                         case OBJ_texeci:
1988                                 free(objs[i].data.texeci.cmd);
1989                                 free(objs[i].data.texeci.buffer);
1990                                 break;
1991                         case OBJ_top:
1992                                 if (info.first_process) {
1993                                         free_all_processes();
1994                                         info.first_process = NULL;
1995                                 }
1996                                 break;
1997                         case OBJ_top_mem:
1998                                 if (info.first_process) {
1999                                         free_all_processes();
2000                                         info.first_process = NULL;
2001                                 }
2002                                 break;
2003 #ifdef HDDTEMP
2004                         case OBJ_hddtemp:
2005                                 free(objs[i].data.hddtemp.dev);
2006                                 free(objs[i].data.hddtemp.addr);
2007                                 break;
2008 #endif
2009                         case OBJ_entropy_avail:
2010                         case OBJ_entropy_poolsize:
2011                         case OBJ_entropy_bar:
2012                                 break;
2013                 }
2014         }
2015         free(objs);
2016         //text_objects = NULL;
2017         //text_object_count = 0;
2018 }
2019
2020 void scan_mixer_bar(const char *arg, int *a, int *w, int *h)
2021 {
2022         char buf1[64];
2023         int n;
2024
2025         if (arg && sscanf(arg, "%63s %n", buf1, &n) >= 1) {
2026                 *a = mixer_init(buf1);
2027                 (void) scan_bar(arg + n, w, h);
2028         } else {
2029                 *a = mixer_init(0);
2030                 (void) scan_bar(arg, w, h);
2031         }
2032 }
2033
2034
2035 /* construct_text_object() creates a new text_object */
2036 static struct text_object *construct_text_object(const char *s, const char *arg, unsigned int object_count, struct text_object *text_objects, long line)
2037 {
2038         //struct text_object *obj = new_text_object();
2039         struct text_object *obj = new_text_object_internal();
2040         obj->line = line;
2041
2042 #define OBJ(a, n) if (strcmp(s, #a) == 0) { obj->type = OBJ_##a; need_mask |= (1 << n); {
2043 #define END ; } } else
2044
2045 #ifdef X11      
2046         if (s[0] == '#') {
2047                 obj->type = OBJ_color;
2048                 obj->data.l = get_x11_color(s);
2049         } else
2050 #endif /* X11 */
2051                 OBJ(acpitemp, 0) obj->data.i = open_acpi_temperature(arg);
2052         END OBJ(acpitempf, 0) obj->data.i = open_acpi_temperature(arg);
2053         END OBJ(acpiacadapter, 0)
2054         END OBJ(freq, INFO_FREQ)
2055             get_cpu_count();
2056         if (!arg
2057             || !isdigit(arg[0])
2058             || strlen(arg) >=2
2059             || atoi(&arg[0])==0
2060             || (unsigned int)atoi(&arg[0])>info.cpu_count)
2061         {
2062             obj->data.cpu_index=1;
2063 //          ERR("freq: Invalid CPU number or you don't have that many CPUs! Displaying the clock for CPU 1.");
2064         }
2065         else 
2066         {
2067             obj->data.cpu_index=atoi(&arg[0]);
2068         }
2069         obj->a = 1;
2070         END OBJ(freq_g, INFO_FREQ)
2071             get_cpu_count();
2072         if (!arg
2073             || !isdigit(arg[0])
2074             || strlen(arg) >=2
2075             || atoi(&arg[0])==0
2076             || (unsigned int)atoi(&arg[0])>info.cpu_count)
2077         {
2078             obj->data.cpu_index=1;
2079 //          ERR("freq_g: Invalid CPU number or you don't have that many CPUs! Displaying the clock for CPU 1.");
2080         }
2081         else 
2082         {
2083             obj->data.cpu_index=atoi(&arg[0]);
2084         }
2085         obj->a = 1;
2086 #if defined(__linux__)
2087         END OBJ(voltage_mv, 0)
2088             get_cpu_count();
2089         if (!arg
2090             || !isdigit(arg[0])
2091             || strlen(arg) >=2
2092             || atoi(&arg[0])==0
2093             || (unsigned int)atoi(&arg[0])>info.cpu_count)
2094         {
2095             obj->data.cpu_index=1;
2096 //          ERR("voltage_mv: Invalid CPU number or you don't have that many CPUs! Displaying voltage for CPU 1.");
2097         }
2098         else 
2099         {
2100             obj->data.cpu_index=atoi(&arg[0]);
2101         }
2102         obj->a = 1;
2103         END OBJ(voltage_v, 0)
2104             get_cpu_count();
2105         if (!arg
2106             || !isdigit(arg[0])
2107             || strlen(arg) >=2
2108             || atoi(&arg[0])==0
2109             || (unsigned int)atoi(&arg[0])>info.cpu_count)
2110         {
2111             obj->data.cpu_index=1;
2112 //          ERR("voltage_v: Invalid CPU number or you don't have that many CPUs! Displaying voltage for CPU 1.");
2113         }
2114         else 
2115         {
2116             obj->data.cpu_index=atoi(&arg[0]);
2117         }
2118         obj->a = 1;
2119 #endif /* __linux__ */
2120         END OBJ(freq_dyn, 0);
2121         END OBJ(freq_dyn_g, 0);
2122         END OBJ(acpifan, 0);
2123         END OBJ(battery, 0);
2124         char bat[64];
2125         if (arg)
2126                 sscanf(arg, "%63s", bat);
2127         else
2128                 strcpy(bat, "BAT0");
2129         obj->data.s = strdup(bat);
2130         END OBJ(battery_time, 0);
2131         char bat[64];
2132         if (arg)
2133                 sscanf(arg, "%63s", bat);
2134         else
2135                 strcpy(bat, "BAT0");
2136         obj->data.s = strdup(bat);
2137 #if defined(__linux__)
2138         END OBJ(i8k_version, INFO_I8K)
2139                 END OBJ(i8k_bios, INFO_I8K)
2140                 END OBJ(i8k_serial, INFO_I8K)
2141                 END OBJ(i8k_cpu_temp, INFO_I8K)
2142                 END OBJ(i8k_cpu_tempf, INFO_I8K)
2143                 END OBJ(i8k_left_fan_status, INFO_I8K)  
2144                 END OBJ(i8k_right_fan_status, INFO_I8K)
2145                 END OBJ(i8k_left_fan_rpm, INFO_I8K)
2146                 END OBJ(i8k_right_fan_rpm, INFO_I8K)
2147                 END OBJ(i8k_ac_status, INFO_I8K)
2148                 END OBJ(i8k_buttons_status, INFO_I8K)
2149         END OBJ(ibm_fan, 0)
2150         END OBJ(ibm_temps, 0)
2151             if (!arg) {
2152                 CRIT_ERR("ibm_temps: needs an argument");
2153             }
2154             if (!isdigit(arg[0])
2155                          || strlen(arg) >=2
2156                          || atoi(&arg[0]) >=8)
2157             {
2158                 obj->data.sensor=0;
2159                 ERR("Invalid temperature sensor! Sensor number must be 0 to 7. Using 0 (CPU temp sensor).");
2160             }
2161                 obj->data.sensor = atoi(&arg[0]);
2162         END OBJ(ibm_volume, 0)
2163         END OBJ(ibm_brightness, 0)
2164         END OBJ(pb_battery, 0)
2165                 if (arg && strcmp(arg, "status") == 0) {
2166                         obj->data.i = PB_BATT_STATUS;
2167                 } else if (arg && strcmp(arg, "percent") == 0) {
2168                         obj->data.i = PB_BATT_PERCENT;
2169                 } else if (arg && strcmp(arg, "time") == 0) {
2170                         obj->data.i = PB_BATT_TIME;
2171                 } else {
2172                         ERR("pb_battery: needs one argument: status, percent or time");
2173                         free(obj);
2174                         return NULL;
2175                 }
2176
2177 #endif /* __linux__ */
2178                 END OBJ(buffers, INFO_BUFFERS)
2179                 END OBJ(cached, INFO_BUFFERS)
2180                 END OBJ(cpu, INFO_CPU)
2181                 if (arg) {
2182                         if (strncmp(arg, "cpu", 3) == 0 && isdigit(arg[3])) {
2183                                 obj->data.cpu_index = atoi(&arg[3]);
2184                                 arg += 4;
2185                         } else {obj->data.cpu_index = 0; }
2186                 } else {
2187                         obj->data.cpu_index = 0;
2188                 }
2189         END OBJ(cpubar, INFO_CPU)
2190                 if (arg) {
2191                         if (strncmp(arg, "cpu", 3) == 0 && isdigit(arg[3])) {
2192                                 obj->data.cpu_index = atoi(&arg[3]);
2193                                 arg += 4;
2194                         }
2195                         else {obj->data.cpu_index = 0;}
2196                         (void) scan_bar(arg, &obj->a, &obj->b);
2197                 } else {
2198                         (void) scan_bar(arg, &obj->a, &obj->b);
2199                         obj->data.cpu_index = 0;
2200                 }
2201         END OBJ(cpugraph, INFO_CPU)
2202                 if (arg) {
2203                         if (strncmp(arg, "cpu", 3) == 0 && isdigit(arg[3])) {
2204                                 obj->data.cpu_index = atoi(&arg[3]);
2205                                 arg += 4;
2206                         }
2207                         (void) scan_graph(arg, &obj->a, &obj->b, &obj->c, &obj->d, &obj->e);
2208                 } else {
2209                         (void) scan_graph(arg, &obj->a, &obj->b, &obj->c, &obj->d, &obj->e);
2210                         obj->data.cpu_index = 0;
2211                 }
2212         END OBJ(diskio, INFO_DISKIO)
2213         END OBJ(diskio_read, INFO_DISKIO)
2214         END OBJ(diskio_write, INFO_DISKIO)
2215         END OBJ(diskiograph, INFO_DISKIO) (void) scan_graph(arg, &obj->a, &obj->b, &obj->c, &obj->d, &obj->e);
2216         END OBJ(diskiograph_read, INFO_DISKIO) (void) scan_graph(arg, &obj->a, &obj->b, &obj->c, &obj->d, &obj->e);
2217         END OBJ(diskiograph_write, INFO_DISKIO) (void) scan_graph(arg, &obj->a, &obj->b, &obj->c, &obj->d, &obj->e);
2218         END OBJ(color, 0) 
2219 #ifdef X11
2220                 obj->data.l = arg ? get_x11_color(arg) : default_fg_color;
2221 #endif /* X11 */
2222         END
2223                 OBJ(font, 0)
2224                 obj->data.s = scan_font(arg);
2225         END
2226                 OBJ(downspeed, INFO_NET) 
2227                 if(arg) {
2228                         obj->data.net = get_net_stat(arg);
2229                 }
2230                 else {
2231                         CRIT_ERR("downspeed needs argument");
2232                 }
2233         END OBJ(downspeedf, INFO_NET)
2234                 if(arg) {
2235                         obj->data.net = get_net_stat(arg);
2236                 }
2237                 else {
2238                         CRIT_ERR("downspeedf needs argument");
2239                 }
2240         END OBJ(downspeedgraph, INFO_NET)
2241                 (void) scan_graph(arg, &obj->a, &obj->b, &obj->c, &obj->d, &obj->e);
2242         char buf[64];
2243         sscanf(arg, "%63s %*i,%*i %*i", buf);
2244         obj->data.net = get_net_stat(buf);
2245         if (sscanf(arg, "%*s %d,%d %*d", &obj->b, &obj->a) <= 1) {
2246                 if (sscanf(arg, "%*s %d,%d", &obj->b, &obj->a) <= 1) {
2247                         obj->a = 0;
2248                         obj->b = 25;
2249                 }
2250         }
2251         END OBJ(else, 0)
2252                 if (blockdepth) {
2253                         (text_objects[blockstart[blockdepth - 1]]).data.ifblock.pos = object_count;
2254                         blockstart[blockdepth - 1] = object_count;
2255                         obj->data.ifblock.pos = object_count + 2;
2256                 } else {
2257                         ERR("$else: no matching $if_*");
2258                 }
2259         END OBJ(endif, 0)
2260                 if (blockdepth) {
2261                         blockdepth--;
2262                         text_objects[blockstart[blockdepth]].data.ifblock.pos = object_count;
2263                 } else {
2264                         ERR("$endif: no matching $if_*");
2265                 }
2266         END
2267         OBJ(image, 0) obj->data.s = strdup(arg ? arg : "");
2268         END
2269 #ifdef HAVE_POPEN
2270         OBJ(exec, 0) obj->data.s = strdup(arg ? arg : "");
2271         END OBJ(execbar, 0) obj->data.s = strdup(arg ? arg : "");
2272         END OBJ(execgraph, 0) obj->data.s = strdup(arg ? arg : "");
2273         END OBJ(execibar, 0) unsigned int n;
2274         if (!arg || sscanf(arg, "%f %n", &obj->data.execi.interval, &n) <= 0) {
2275                 char buf[256];
2276                 ERR("${execibar <interval> command}");
2277                 obj->type = OBJ_text;
2278                 snprintf(buf, 256, "${%s}", s);
2279                 obj->data.s = strdup(buf);
2280         } else {
2281                 obj->data.execi.cmd = strdup(arg + n);
2282         }
2283         END OBJ(execigraph, 0) unsigned int n;
2284         if (!arg || sscanf(arg, "%f %n", &obj->data.execi.interval, &n) <= 0) {
2285                 char buf[256];
2286                 ERR("${execigraph <interval> command}");
2287                 obj->type = OBJ_text;
2288                 snprintf(buf, 256, "${%s}", s);
2289                 obj->data.s = strdup(buf);
2290         } else {
2291                 obj->data.execi.cmd = strdup(arg + n);
2292         }
2293         END OBJ(execi, 0) unsigned int n;
2294         if (!arg || sscanf(arg, "%f %n", &obj->data.execi.interval, &n) <= 0) {
2295                 char buf[256];
2296                 ERR("${execi <interval> command}");
2297                 obj->type = OBJ_text;
2298                 snprintf(buf, 256, "${%s}", s);
2299                 obj->data.s = strdup(buf);
2300         } else {
2301                 obj->data.execi.cmd = strdup(arg + n);
2302                 obj->data.execi.buffer =
2303                         (char *) calloc(1, text_buffer_size);
2304         }
2305         END OBJ(texeci, 0) unsigned int n;
2306         if (!arg || sscanf(arg, "%f %n", &obj->data.texeci.interval, &n) <= 0) {
2307                 char buf[256];
2308                 ERR("${texeci <interval> command}");
2309                 obj->type = OBJ_text;
2310                 snprintf(buf, 256, "${%s}", s);
2311                 obj->data.s = strdup(buf);
2312         } else {
2313                 obj->data.texeci.cmd = strdup(arg + n);
2314                 obj->data.texeci.buffer =
2315                         (char *) calloc(1, text_buffer_size);
2316         }
2317         obj->data.texeci.p_timed_thread = NULL;
2318         END OBJ(pre_exec, 0) obj->type = OBJ_text;
2319         if (arg) {
2320                 FILE *fp = popen(arg, "r");
2321                 unsigned int n;
2322                 char buf[2048];
2323
2324                 n = fread(buf, 1, 2048, fp);
2325                 buf[n] = '\0';
2326
2327                 if (n && buf[n - 1] == '\n')
2328                         buf[n - 1] = '\0';
2329
2330                 (void) pclose(fp);
2331
2332                 obj->data.s = strdup(buf);
2333         } else
2334                 obj->data.s = strdup("");
2335         END
2336 #endif
2337                 OBJ(fs_bar, INFO_FS) obj->data.fsbar.h = 4;
2338         arg = scan_bar(arg, &obj->data.fsbar.w, &obj->data.fsbar.h);
2339         if (arg) {
2340                 while (isspace(*arg))
2341                         arg++;
2342                 if (*arg == '\0')
2343                         arg = "/";
2344         } else
2345                 arg = "/";
2346         obj->data.fsbar.fs = prepare_fs_stat(arg);
2347         END OBJ(fs_bar_free, INFO_FS) obj->data.fsbar.h = 4;
2348         if (arg) {
2349                 unsigned int n;
2350                 if (sscanf(arg, "%d %n", &obj->data.fsbar.h, &n) >= 1)
2351                         arg += n;
2352         } else
2353                 arg = "/";
2354         obj->data.fsbar.fs = prepare_fs_stat(arg);
2355         END OBJ(fs_free, INFO_FS) if (!arg)
2356                 arg = "/";
2357         obj->data.fs = prepare_fs_stat(arg);
2358         END OBJ(fs_used_perc, INFO_FS) if (!arg)
2359                 arg = "/";
2360         obj->data.fs = prepare_fs_stat(arg);
2361         END OBJ(fs_free_perc, INFO_FS) if (!arg)
2362                 arg = "/";
2363         obj->data.fs = prepare_fs_stat(arg);
2364         END OBJ(fs_size, INFO_FS) if (!arg)
2365                 arg = "/";
2366         obj->data.fs = prepare_fs_stat(arg);
2367         END OBJ(fs_used, INFO_FS) if (!arg)
2368                 arg = "/";
2369         obj->data.fs = prepare_fs_stat(arg);
2370         END OBJ(hr, 0) obj->data.i = arg ? atoi(arg) : 1;
2371         END OBJ(offset, 0) obj->data.i = arg ? atoi(arg) : 1;
2372         END OBJ(voffset, 0) obj->data.i = arg ? atoi(arg) : 1;
2373         END OBJ(goto, 0)
2374
2375         if (!arg) {
2376                 ERR("goto needs arguments");
2377                 obj->type = OBJ_text;
2378                 obj->data.s = strdup("${goto}");
2379                 return NULL;
2380         }
2381         
2382         obj->data.i = atoi(arg);
2383         
2384         END OBJ(tab, 0)
2385         int a = 10, b = 0;
2386         if (arg) {
2387                 if (sscanf(arg, "%d %d", &a, &b) != 2)
2388                         sscanf(arg, "%d", &b);
2389         }
2390         if (a <= 0) 
2391                 a = 1;
2392         obj->data.pair.a = a;
2393         obj->data.pair.b = b;
2394
2395         END OBJ(i2c, INFO_I2C) char buf1[64], buf2[64];
2396         int n;
2397
2398         if (!arg) {
2399                 ERR("i2c needs arguments");
2400                 obj->type = OBJ_text;
2401                 //obj->data.s = strdup("${i2c}");
2402                 return NULL;
2403         }
2404
2405         if (sscanf(arg, "%63s %63s %d", buf1, buf2, &n) != 3) {
2406                 /* if scanf couldn't read three values, read type and num and use
2407                  * default device */
2408                 sscanf(arg, "%63s %d", buf2, &n);
2409                 obj->data.i2c.fd =
2410                         open_i2c_sensor(0, buf2, n, &obj->data.i2c.arg,
2411                                         obj->data.i2c.devtype);
2412                 strncpy(obj->data.i2c.type, buf2, 63);
2413         } else {
2414                 obj->data.i2c.fd =
2415                         open_i2c_sensor(buf1, buf2, n, &obj->data.i2c.arg,
2416                                         obj->data.i2c.devtype);
2417                 strncpy(obj->data.i2c.type, buf2, 63);
2418         }
2419
2420         END OBJ(top, INFO_TOP)
2421                 char buf[64];
2422         int n;
2423         if (!arg) {
2424                 ERR("top needs arguments");
2425                 obj->type = OBJ_text;
2426                 //obj->data.s = strdup("${top}");
2427                 return NULL;
2428         }
2429         if (sscanf(arg, "%63s %i", buf, &n) == 2) {
2430                 if (strcmp(buf, "name") == 0) {
2431                         obj->data.top.type = TOP_NAME;
2432                 } else if (strcmp(buf, "cpu") == 0) {
2433                         obj->data.top.type = TOP_CPU;
2434                 } else if (strcmp(buf, "pid") == 0) {
2435                         obj->data.top.type = TOP_PID;
2436                 } else if (strcmp(buf, "mem") == 0) {
2437                         obj->data.top.type = TOP_MEM;
2438                 } else {
2439                         ERR("invalid arg for top");
2440                         return NULL;
2441                 }
2442                 if (n < 1 || n > 10) {
2443                         CRIT_ERR("invalid arg for top");
2444                         return NULL;
2445                 } else {
2446                         obj->data.top.num = n - 1;
2447                         top_cpu = 1;
2448                 }
2449         } else {
2450                 ERR("invalid args given for top");
2451                 return NULL;
2452         }
2453         END OBJ(top_mem, INFO_TOP)
2454                 char buf[64];
2455         int n;
2456         if (!arg) {
2457                 ERR("top_mem needs arguments");
2458                 obj->type = OBJ_text;
2459                 obj->data.s = strdup("${top_mem}");
2460                 return NULL;
2461         }
2462         if (sscanf(arg, "%63s %i", buf, &n) == 2) {
2463                 if (strcmp(buf, "name") == 0) {
2464                         obj->data.top.type = TOP_NAME;
2465                 } else if (strcmp(buf, "cpu") == 0) {
2466                         obj->data.top.type = TOP_CPU;
2467                 } else if (strcmp(buf, "pid") == 0) {
2468                         obj->data.top.type = TOP_PID;
2469                 } else if (strcmp(buf, "mem") == 0) {
2470                         obj->data.top.type = TOP_MEM;
2471                 } else {
2472                         ERR("invalid arg for top");
2473                         return NULL;
2474                 }
2475                 if (n < 1 || n > 10) {
2476                         CRIT_ERR("invalid arg for top");
2477                         return NULL;
2478                 } else {
2479                         obj->data.top.num = n - 1;
2480                         top_mem = 1;
2481                 }
2482         } else {
2483                 ERR("invalid args given for top");
2484                 return NULL;
2485         }
2486         END OBJ(addr, INFO_NET)
2487                 if(arg) {
2488                         obj->data.net = get_net_stat(arg);
2489                 }
2490                 else {
2491                         CRIT_ERR("addr needs argument");
2492                 }
2493         END OBJ(linkstatus, INFO_WIFI) 
2494                 if(arg) {
2495                         obj->data.net = get_net_stat(arg);
2496                 }
2497                 else {
2498                         CRIT_ERR("linkstatus needs argument");
2499                 }
2500         END OBJ(tail, 0)
2501                 char buf[64];
2502         int n1, n2;
2503         if (!arg) {
2504                 ERR("tail needs arguments");
2505                 obj->type = OBJ_text;
2506                 obj->data.s = strdup("${tail}");
2507                 return NULL;
2508         }
2509         if (sscanf(arg, "%63s %i %i", buf, &n1, &n2) == 2) {
2510                 if (n1 < 1 || n1 > 30) {
2511                         CRIT_ERR("invalid arg for tail, number of lines must be between 1 and 30");
2512                         return NULL;
2513                 } else {
2514                         FILE *fp = NULL;
2515                         fp = fopen(buf, "r");
2516                         if (fp) {
2517                                 obj->data.tail.logfile =
2518                                         malloc(text_buffer_size);
2519                                 strcpy(obj->data.tail.logfile, buf);
2520                                 obj->data.tail.wantedlines = n1;
2521                                 obj->data.tail.interval =
2522                                         update_interval * 2;
2523                                 fclose(fp);
2524                         } else {
2525                                 //fclose (fp);
2526                                 CRIT_ERR("tail logfile does not exist, or you do not have correct permissions");
2527                         }
2528                 }
2529         } else if (sscanf(arg, "%63s %i %i", buf, &n1, &n2) == 3) {
2530                 if (n1 < 1 || n1 > 30) {
2531                         CRIT_ERR
2532                                 ("invalid arg for tail, number of lines must be between 1 and 30");
2533                         return NULL;
2534                 } else if (n2 < 1 || n2 < update_interval) {
2535                         CRIT_ERR
2536                                 ("invalid arg for tail, interval must be greater than 0 and Conky's interval");
2537                         return NULL;
2538                 } else {
2539                         FILE *fp;
2540                         fp = fopen(buf, "r");
2541                         if (fp != NULL) {
2542                                 obj->data.tail.logfile =
2543                                         malloc(text_buffer_size);
2544                                 strcpy(obj->data.tail.logfile, buf);
2545                                 obj->data.tail.wantedlines = n1;
2546                                 obj->data.tail.interval = n2;
2547                                 fclose(fp);
2548                         } else {
2549                                 //fclose (fp);
2550                                 CRIT_ERR("tail logfile does not exist, or you do not have correct permissions");
2551                         }
2552                 }
2553         }
2554
2555         else {
2556                 ERR("invalid args given for tail");
2557                 return NULL;
2558         }
2559         obj->data.tail.buffer = malloc(text_buffer_size * 20); /* asumming all else worked */
2560         END OBJ(head, 0)
2561                 char buf[64];
2562         int n1, n2;
2563         if (!arg) {
2564                 ERR("head needs arguments");
2565                 obj->type = OBJ_text;
2566                 obj->data.s = strdup("${head}");
2567                 return NULL;
2568         }
2569         if (sscanf(arg, "%63s %i %i", buf, &n1, &n2) == 2) {
2570                 if (n1 < 1 || n1 > 30) {
2571                         CRIT_ERR("invalid arg for head, number of lines must be between 1 and 30");
2572                         return NULL;
2573                 } else {
2574                         FILE *fp;
2575                         fp = fopen(buf, "r");
2576                         if (fp != NULL) {
2577                                 obj->data.tail.logfile =
2578                                         malloc(text_buffer_size);
2579                                 strcpy(obj->data.tail.logfile, buf);
2580                                 obj->data.tail.wantedlines = n1;
2581                                 obj->data.tail.interval =
2582                                         update_interval * 2;
2583                                 fclose(fp);
2584                         } else {
2585                                 //fclose (fp);
2586                                 CRIT_ERR("head logfile does not exist, or you do not have correct permissions");
2587                         }
2588                 }
2589         } else if (sscanf(arg, "%63s %i %i", buf, &n1, &n2) == 3) {
2590                 if (n1 < 1 || n1 > 30) {
2591                         CRIT_ERR
2592                                 ("invalid arg for head, number of lines must be between 1 and 30");
2593                         return NULL;
2594                 } else if (n2 < 1 || n2 < update_interval) {
2595                         CRIT_ERR
2596                                 ("invalid arg for head, interval must be greater than 0 and Conky's interval");
2597                         return NULL;
2598                 } else {
2599                         FILE *fp;
2600                         fp = fopen(buf, "r");
2601                         if (fp != NULL) {
2602                                 obj->data.tail.logfile =
2603                                         malloc(text_buffer_size);
2604                                 strcpy(obj->data.tail.logfile, buf);
2605                                 obj->data.tail.wantedlines = n1;
2606                                 obj->data.tail.interval = n2;
2607                                 fclose(fp);
2608                         } else {
2609                                 //fclose (fp);
2610                                 CRIT_ERR("head logfile does not exist, or you do not have correct permissions");
2611                         }
2612                 }
2613         }
2614
2615         else {
2616                 ERR("invalid args given for head");
2617                 return NULL;
2618         }
2619         obj->data.tail.buffer = malloc(text_buffer_size * 20); /* asumming all else worked */
2620         END OBJ(loadavg, INFO_LOADAVG) int a = 1, b = 2, c = 3, r = 3;
2621         if (arg) {
2622                 r = sscanf(arg, "%d %d %d", &a, &b, &c);
2623                 if (r >= 3 && (c < 1 || c > 3))
2624                         r--;
2625                 if (r >= 2 && (b < 1 || b > 3))
2626                         r--, b = c;
2627                 if (r >= 1 && (a < 1 || a > 3))
2628                         r--, a = b, b = c;
2629         }
2630         obj->data.loadavg[0] = (r >= 1) ? (unsigned char) a : 0;
2631         obj->data.loadavg[1] = (r >= 2) ? (unsigned char) b : 0;
2632         obj->data.loadavg[2] = (r >= 3) ? (unsigned char) c : 0;
2633         END OBJ(if_existing, 0)
2634                 if (blockdepth >= MAX_IF_BLOCK_DEPTH) {
2635                         CRIT_ERR("MAX_IF_BLOCK_DEPTH exceeded");
2636                 }
2637         if (!arg) {
2638                 ERR("if_existing needs an argument");
2639                 obj->data.ifblock.s = 0;
2640         } else
2641                 obj->data.ifblock.s = strdup(arg);
2642         blockstart[blockdepth] = object_count;
2643         obj->data.ifblock.pos = object_count + 2;
2644         blockdepth++;
2645         END OBJ(if_mounted, 0)
2646                 if (blockdepth >= MAX_IF_BLOCK_DEPTH) {
2647                         CRIT_ERR("MAX_IF_BLOCK_DEPTH exceeded");
2648                 }
2649         if (!arg) {
2650                 ERR("if_mounted needs an argument");
2651                 obj->data.ifblock.s = 0;
2652         } else
2653                 obj->data.ifblock.s = strdup(arg);
2654         blockstart[blockdepth] = object_count;
2655         obj->data.ifblock.pos = object_count + 2;
2656         blockdepth++;
2657         END OBJ(if_running, 0)
2658                 if (blockdepth >= MAX_IF_BLOCK_DEPTH) {
2659                         CRIT_ERR("MAX_IF_BLOCK_DEPTH exceeded");
2660                 }
2661         if (arg) {
2662                 char buf[256];
2663                 snprintf(buf, 256, "pidof %s >/dev/null", arg);
2664                 obj->data.ifblock.s = strdup(buf);
2665         } else {
2666                 ERR("if_running needs an argument");
2667                 obj->data.ifblock.s = 0;
2668         }
2669         blockstart[blockdepth] = object_count;
2670         obj->data.ifblock.pos = object_count + 2;
2671         blockdepth++;
2672         END OBJ(kernel, 0)
2673                 END OBJ(machine, 0)
2674                 END OBJ(mails, INFO_MAIL)
2675                 END OBJ(mboxscan, 0)
2676                 obj->data.mboxscan.args = (char*)malloc(TEXT_BUFFER_SIZE);
2677                 obj->data.mboxscan.output = (char*)malloc(text_buffer_size);
2678                 strncpy(obj->data.mboxscan.args, arg, TEXT_BUFFER_SIZE);
2679                 END OBJ(mem, INFO_MEM)
2680                 END OBJ(memmax, INFO_MEM)
2681                 END OBJ(memperc, INFO_MEM)
2682                 END OBJ(membar, INFO_MEM)
2683                 (void) scan_bar(arg, &obj->data.pair.a, &obj->data.pair.b);
2684         END OBJ(memgraph, INFO_MEM)
2685                 (void) scan_graph(arg, &obj->a, &obj->b, &obj->c, &obj->d, &obj->e);
2686         END OBJ(mixer, INFO_MIXER) obj->data.l = mixer_init(arg);
2687         END OBJ(mixerl, INFO_MIXER) obj->data.l = mixer_init(arg);
2688         END OBJ(mixerr, INFO_MIXER) obj->data.l = mixer_init(arg);
2689         END OBJ(mixerbar, INFO_MIXER)
2690                 scan_mixer_bar(arg, &obj->data.mixerbar.l,
2691                                 &obj->data.mixerbar.w, &obj->data.mixerbar.h);
2692         END OBJ(mixerlbar, INFO_MIXER)
2693                 scan_mixer_bar(arg, &obj->data.mixerbar.l,
2694                                 &obj->data.mixerbar.w, &obj->data.mixerbar.h);
2695         END OBJ(mixerrbar, INFO_MIXER)
2696                 scan_mixer_bar(arg, &obj->data.mixerbar.l,
2697                                 &obj->data.mixerbar.w, &obj->data.mixerbar.h);
2698         END
2699                 OBJ(new_mails, INFO_MAIL)
2700                 END OBJ(nodename, 0)
2701                 END OBJ(processes, INFO_PROCS)
2702                 END OBJ(running_processes, INFO_RUN_PROCS)
2703                 END OBJ(shadecolor, 0)
2704 #ifdef X11
2705                 obj->data.l = arg ? get_x11_color(arg) : default_bg_color;
2706 #endif /* X11 */
2707         END OBJ(outlinecolor, 0)
2708 #ifdef X11
2709                 obj->data.l = arg ? get_x11_color(arg) : default_out_color;
2710 #endif /* X11 */
2711         END OBJ(stippled_hr, 0)
2712 #ifdef X11
2713                 int a = stippled_borders, b = 1;
2714         if (arg) {
2715                 if (sscanf(arg, "%d %d", &a, &b) != 2)
2716                         sscanf(arg, "%d", &b);
2717         }
2718         if (a <= 0)
2719                 a = 1;
2720         obj->data.pair.a = a;
2721         obj->data.pair.b = b;
2722 #endif /* X11 */
2723         END OBJ(swap, INFO_MEM)
2724                 END OBJ(swapmax, INFO_MEM)
2725                 END OBJ(swapperc, INFO_MEM)
2726                 END OBJ(swapbar, INFO_MEM)
2727                 (void) scan_bar(arg, &obj->data.pair.a, &obj->data.pair.b);
2728         END OBJ(sysname, 0) END OBJ(temp1, INFO_I2C) obj->type = OBJ_i2c;
2729         obj->data.i2c.fd =
2730                 open_i2c_sensor(0, "temp", 1, &obj->data.i2c.arg,
2731                                 obj->data.i2c.devtype);
2732         END OBJ(temp2, INFO_I2C) obj->type = OBJ_i2c;
2733         obj->data.i2c.fd =
2734                 open_i2c_sensor(0, "temp", 2, &obj->data.i2c.arg,
2735                                 obj->data.i2c.devtype);
2736         END OBJ(time, 0) obj->data.s = strdup(arg ? arg : "%F %T");
2737         END OBJ(utime, 0) obj->data.s = strdup(arg ? arg : "%F %T");
2738         END OBJ(tztime, 0)
2739                 char buf1[256], buf2[256], *fmt, *tz;
2740                 fmt = tz = NULL;
2741                 if (arg) {
2742                         int nArgs = sscanf(arg, "%255s %255[^\n]", buf1, buf2);
2743                         switch (nArgs) {
2744                                 case 2:
2745                                         tz = buf1;
2746                                 case 1:
2747                                         fmt = buf2;
2748                         }
2749                 }
2750
2751                 obj->data.tztime.fmt = strdup(fmt ? fmt : "%F %T");
2752                 obj->data.tztime.tz = tz ? strdup(tz) : NULL;
2753 #ifdef HAVE_ICONV
2754         END OBJ(iconv_start, 0)
2755                 if (iconv_converting) {
2756                         CRIT_ERR("You must stop your last iconv conversion before starting another");
2757                 }
2758                 if (arg) {
2759                         char iconv_from[CODEPAGE_LENGTH];
2760                         char iconv_to[CODEPAGE_LENGTH];
2761                         if (sscanf(arg, "%s %s", iconv_from, iconv_to) != 2) {
2762                                 CRIT_ERR("Invalid arguments for iconv_start");
2763                         } else {
2764                                 iconv_t new_iconv;
2765                                 new_iconv = iconv_open(iconv_to, iconv_from);
2766                                 if (new_iconv == (iconv_t)(-1)) {
2767                                         ERR("Can't convert from %s to %s.", iconv_from, iconv_to);
2768                                 } else {
2769                                         obj->a = register_iconv(&new_iconv);
2770                                         iconv_converting = 1;
2771                                 }
2772                         }
2773                 } else {
2774                         CRIT_ERR("Iconv requires arguments");
2775                 }
2776         END OBJ(iconv_stop, 0)
2777                 iconv_converting = 0;
2778         
2779 #endif
2780         END OBJ(totaldown, INFO_NET)
2781                 if(arg) {
2782                         obj->data.net = get_net_stat(arg);
2783                 }
2784                 else {
2785                         CRIT_ERR("totaldown needs argument");
2786                 }
2787         END OBJ(totalup, INFO_NET) obj->data.net = get_net_stat(arg);
2788         if(arg) {
2789                 obj->data.net = get_net_stat(arg);
2790         }
2791         else {
2792                 CRIT_ERR("totalup needs argument");
2793         }
2794         END OBJ(updates, 0)
2795                 END OBJ(alignr, 0) obj->data.i = arg ? atoi(arg) : 0;
2796         END OBJ(alignc, 0) obj->data.i = arg ? atoi(arg) : 0;
2797         END OBJ(upspeed, INFO_NET)
2798                 if(arg) {
2799                         obj->data.net = get_net_stat(arg);
2800                 }
2801                 else {
2802                         CRIT_ERR("upspeed needs argument");
2803                 }
2804         END OBJ(upspeedf, INFO_NET) 
2805                 if(arg) {
2806                         obj->data.net = get_net_stat(arg);
2807                 }
2808                 else {
2809                         CRIT_ERR("upspeedf needs argument");
2810                 }
2811
2812         END OBJ(upspeedgraph, INFO_NET)
2813                 (void) scan_graph(arg, &obj->a, &obj->b, &obj->c, &obj->d, &obj->e);
2814         char buf[64];
2815         sscanf(arg, "%63s %*i,%*i %*i", buf);
2816         obj->data.net = get_net_stat(buf);
2817         if (sscanf(arg, "%*s %d,%d %*d", &obj->b, &obj->a) <= 1) {
2818                 if (sscanf(arg, "%*s %d,%d", &obj->a, &obj->a) <= 1) {
2819                         obj->a = 0;
2820                         obj->b = 25;
2821                 }
2822         }
2823         END OBJ(uptime_short, INFO_UPTIME) END OBJ(uptime, INFO_UPTIME) END
2824                 OBJ(adt746xcpu, 0) END OBJ(adt746xfan, 0) END
2825 #if defined(__FreeBSD__) && (defined(i386) || defined(__i386__))
2826                 OBJ(apm_adapter, 0) END
2827                 OBJ(apm_battery_life, 0) END
2828                 OBJ(apm_battery_time, 0) END
2829 #endif /* __FreeBSD__ */
2830                 OBJ(imap_unseen, 0)
2831                 if (arg) {
2832                         // proccss
2833                         obj->data.mail = parse_mail_args(IMAP, arg);
2834                         obj->global_mode = 0;
2835                 } else {
2836                         obj->global_mode = 1;
2837                 }
2838                 END
2839                 OBJ(imap_messages, 0)
2840                 if (arg) {
2841                         // proccss
2842                         obj->data.mail = parse_mail_args(IMAP, arg);
2843                         obj->global_mode = 0;
2844                 } else {
2845                         obj->global_mode = 1;
2846                 }
2847                 END
2848                 OBJ(pop3_unseen, 0)
2849                 if (arg) {
2850                         // proccss
2851                         obj->data.mail = parse_mail_args(POP3, arg);
2852                         obj->global_mode = 0;
2853                 } else {
2854                         obj->global_mode = 1;
2855                 }
2856                 END
2857                 OBJ(pop3_used, 0)
2858                 if (arg) {
2859                         // proccss
2860                         obj->data.mail = parse_mail_args(POP3, arg);
2861                         obj->global_mode = 0;
2862                 } else {
2863                         obj->global_mode = 1;
2864                 }
2865                 END
2866 #ifdef MPD
2867                 OBJ(mpd_artist, INFO_MPD)
2868                 END OBJ(mpd_title, INFO_MPD)
2869                 END OBJ(mpd_random, INFO_MPD)
2870                 END OBJ(mpd_repeat, INFO_MPD)
2871                 END OBJ(mpd_elapsed, INFO_MPD)
2872                 END OBJ(mpd_length, INFO_MPD)
2873                 END OBJ(mpd_track, INFO_MPD)
2874                 END OBJ(mpd_name, INFO_MPD)
2875                 END OBJ(mpd_file, INFO_MPD)
2876                 END OBJ(mpd_percent, INFO_MPD)
2877                 END OBJ(mpd_album, INFO_MPD)
2878                 END OBJ(mpd_vol, INFO_MPD)
2879                 END OBJ(mpd_bitrate, INFO_MPD)
2880                 END OBJ(mpd_status, INFO_MPD)
2881                 END OBJ(mpd_bar, INFO_MPD)
2882                 (void) scan_bar(arg, &obj->data.pair.a, &obj->data.pair.b);
2883                 END OBJ(mpd_smart, INFO_MPD) END
2884 #endif
2885 #ifdef XMMS2
2886                 OBJ(xmms2_artist, INFO_XMMS2)
2887                 END OBJ(xmms2_album, INFO_XMMS2)
2888                 END OBJ(xmms2_title, INFO_XMMS2)
2889                 END OBJ(xmms2_genre, INFO_XMMS2)
2890                 END OBJ(xmms2_comment, INFO_XMMS2)
2891                 END OBJ(xmms2_decoder, INFO_XMMS2)
2892                 END OBJ(xmms2_transport, INFO_XMMS2)
2893                 END OBJ(xmms2_url, INFO_XMMS2)
2894                 END OBJ(xmms2_tracknr, INFO_XMMS2)
2895                 END OBJ(xmms2_bitrate, INFO_XMMS2)
2896                 END OBJ(xmms2_date, INFO_XMMS2)
2897                 END OBJ(xmms2_id, INFO_XMMS2)
2898                 END OBJ(xmms2_duration, INFO_XMMS2)
2899                 END OBJ(xmms2_elapsed, INFO_XMMS2)
2900                 END OBJ(xmms2_size, INFO_XMMS2)
2901                 END OBJ(xmms2_status, INFO_XMMS2)
2902                 END OBJ(xmms2_percent, INFO_XMMS2)
2903                 END OBJ(xmms2_bar, INFO_XMMS2)
2904                 (void) scan_bar(arg, &obj->data.pair.a, &obj->data.pair.b);
2905                 END OBJ(xmms2_smart, INFO_XMMS2)
2906                 END
2907 #endif
2908 #ifdef AUDACIOUS
2909                 OBJ(audacious_status, INFO_AUDACIOUS) END
2910                 OBJ(audacious_title, INFO_AUDACIOUS) 
2911                 {
2912                         if (arg)
2913                         {
2914                             sscanf (arg, "%d", &info.audacious.max_title_len);
2915                             if (info.audacious.max_title_len > 0)
2916                                 info.audacious.max_title_len++;
2917                             else
2918                                 CRIT_ERR ("audacious_title: invalid length argument");
2919                         }
2920                 }
2921                 END
2922                 OBJ(audacious_length, INFO_AUDACIOUS) END
2923                 OBJ(audacious_length_seconds, INFO_AUDACIOUS) END
2924                 OBJ(audacious_position, INFO_AUDACIOUS) END
2925                 OBJ(audacious_position_seconds, INFO_AUDACIOUS) END
2926                 OBJ(audacious_bitrate, INFO_AUDACIOUS) END
2927                 OBJ(audacious_frequency, INFO_AUDACIOUS) END
2928                 OBJ(audacious_channels, INFO_AUDACIOUS) END
2929                 OBJ(audacious_filename, INFO_AUDACIOUS) END
2930                 OBJ(audacious_playlist_length, INFO_AUDACIOUS) END
2931                 OBJ(audacious_playlist_position, INFO_AUDACIOUS) END
2932                 OBJ(audacious_bar, INFO_AUDACIOUS)
2933                 (void) scan_bar(arg, &obj->a, &obj->b);
2934         END
2935 #endif
2936 #ifdef BMPX
2937                 OBJ(bmpx_title, INFO_BMPX)
2938                 memset(&(info.bmpx), 0, sizeof(struct bmpx_s));
2939         END
2940                 OBJ(bmpx_artist, INFO_BMPX)
2941                 memset(&(info.bmpx), 0, sizeof(struct bmpx_s));
2942         END
2943                 OBJ(bmpx_album, INFO_BMPX)
2944                 memset(&(info.bmpx), 0, sizeof(struct bmpx_s));
2945         END
2946                 OBJ(bmpx_track, INFO_BMPX)
2947                 memset(&(info.bmpx), 0, sizeof(struct bmpx_s));
2948         END
2949                 OBJ(bmpx_uri, INFO_BMPX)
2950                 memset(&(info.bmpx), 0, sizeof(struct bmpx_s));
2951         END
2952                 OBJ(bmpx_bitrate, INFO_BMPX)
2953                 memset(&(info.bmpx), 0, sizeof(struct bmpx_s));
2954         END
2955 #endif
2956 #ifdef HDDTEMP
2957         OBJ(hddtemp, 0)
2958                 if (!arg || scan_hddtemp(arg, &obj->data.hddtemp.dev, 
2959                         &obj->data.hddtemp.addr, &obj->data.hddtemp.port)) {
2960                         ERR("hddtemp needs arguments");
2961                         obj->type = OBJ_text;
2962                         obj->data.s = strdup("${hddtemp}");
2963                         return NULL;
2964                 }
2965         END
2966 #endif
2967 #ifdef TCP_PORT_MONITOR
2968                 OBJ(tcp_portmon, INFO_TCP_PORT_MONITOR) 
2969                 int argc, port_begin, port_end, item, connection_index;
2970         char itembuf[32];
2971         memset(itembuf,0,sizeof(itembuf));
2972         connection_index=0;
2973         /* massive argument checking */
2974         if (!arg) {
2975                 CRIT_ERR("tcp_portmon: needs arguments");
2976         }
2977         argc=sscanf(arg, "%d %d %31s %d", &port_begin, &port_end, itembuf, &connection_index);
2978         if ( (argc != 3) && (argc != 4) ) 
2979         {
2980                 CRIT_ERR("tcp_portmon: requires 3 or 4 arguments");
2981         }
2982         if ( (port_begin<1) || (port_begin>65535) || (port_end<1) || (port_end>65535) )
2983         {
2984                 CRIT_ERR("tcp_portmon: port values must be from 1 to 65535");
2985         }
2986         if ( port_begin > port_end )
2987         {
2988                 CRIT_ERR("tcp_portmon: starting port must be <= ending port");
2989         }
2990         if ( strncmp(itembuf,"count",31) == 0 )
2991                 item=COUNT;
2992         else if ( strncmp(itembuf,"rip",31) == 0 )
2993                 item=REMOTEIP;
2994         else if ( strncmp(itembuf,"rhost",31) == 0 )
2995                 item=REMOTEHOST;
2996         else if ( strncmp(itembuf,"rport",31) == 0 )
2997                 item=REMOTEPORT;
2998         else if ( strncmp(itembuf,"rservice",31) == 0 )
2999                 item=REMOTESERVICE;
3000         else if ( strncmp(itembuf,"lip",31) == 0 )
3001                 item=LOCALIP;
3002         else if ( strncmp(itembuf,"lhost",31) == 0 )
3003                 item=LOCALHOST;
3004         else if ( strncmp(itembuf,"lport",31) == 0 )
3005                 item=LOCALPORT;
3006         else if ( strncmp(itembuf,"lservice",31) == 0 )
3007                 item=LOCALSERVICE;
3008         else
3009         {
3010                 CRIT_ERR("tcp_portmon: invalid item specified"); 
3011         }
3012         if ( (argc==3) && (item!=COUNT) )
3013         {
3014                 CRIT_ERR("tcp_portmon: 3 argument form valid only for \"count\" item");
3015         }
3016         if ( (argc==4) && (connection_index<0) )
3017         {
3018                 CRIT_ERR("tcp_portmon: connection index must be non-negative");
3019         }
3020         /* ok, args looks good. save the text object data */
3021         obj->data.tcp_port_monitor.port_range_begin = (in_port_t)port_begin;
3022         obj->data.tcp_port_monitor.port_range_end = (in_port_t)port_end;
3023         obj->data.tcp_port_monitor.item = item;
3024         obj->data.tcp_port_monitor.connection_index = connection_index;
3025
3026         /* if the port monitor collection hasn't been created, we must create it */
3027         if ( !info.p_tcp_port_monitor_collection )
3028         {
3029                 info.p_tcp_port_monitor_collection = 
3030                         create_tcp_port_monitor_collection ();
3031                 if ( !info.p_tcp_port_monitor_collection )
3032                 {
3033                         CRIT_ERR("tcp_portmon: unable to create port monitor collection");
3034                 }
3035         }
3036
3037         /* if a port monitor for this port does not exist, create one and add it to the collection */
3038         if ( find_tcp_port_monitor( info.p_tcp_port_monitor_collection, port_begin, port_end ) == NULL )
3039         {
3040                 tcp_port_monitor_t * p_monitor = 
3041                         create_tcp_port_monitor( port_begin, port_end, &tcp_port_monitor_args );
3042                 if ( !p_monitor )
3043                 {
3044                         CRIT_ERR("tcp_portmon: unable to create port monitor");
3045                 }
3046                 /* add the newly created monitor to the collection */
3047                 if ( insert_tcp_port_monitor_into_collection( info.p_tcp_port_monitor_collection,
3048                                         p_monitor ) != 0 )
3049                 {
3050                         CRIT_ERR("tcp_portmon: unable to add port monitor to collection");
3051                 }
3052         }
3053         END
3054 #endif
3055         OBJ(entropy_avail, INFO_ENTROPY) END
3056         OBJ(entropy_poolsize, INFO_ENTROPY) END
3057         OBJ(entropy_bar, INFO_ENTROPY)
3058                 (void) scan_bar(arg, &obj->a, &obj->b);
3059         END
3060
3061         {
3062                 char buf[256];
3063                 ERR("unknown variable %s", s);
3064                 obj->type = OBJ_text;
3065                 snprintf(buf, 256, "${%s}", s);
3066                 obj->data.s = strdup(buf);
3067         }
3068 #undef OBJ
3069
3070         return obj;
3071 }
3072
3073 static struct text_object *create_plain_text(const char *s)
3074 {
3075         struct text_object *obj;
3076
3077         if (s == NULL || *s == '\0') {
3078                 return NULL;
3079         }
3080
3081         obj = new_text_object_internal();
3082
3083         obj->type = OBJ_text;
3084         obj->data.s = strdup(s);
3085         return obj;
3086 }
3087
3088 static struct text_object_list *extract_variable_text_internal(const char *p)
3089 {
3090         struct text_object_list *retval;
3091         struct text_object *obj;
3092         const char *s = p;
3093
3094         retval = malloc(sizeof(struct text_object_list));
3095         memset(retval, 0, sizeof(struct text_object_list));
3096         retval->text_object_count = 0;
3097
3098         long line = text_lines;
3099
3100         while (*p) {
3101                 if (*p == '\n') {
3102                         line++;
3103                 }
3104                 if (*p == '$') {
3105                         *(char *) p = '\0';
3106                         obj = create_plain_text(s);
3107                         if(obj != NULL) {
3108                                 // allocate memory for the object
3109                                 retval->text_objects = realloc(retval->text_objects, 
3110                                                 sizeof(struct text_object) * (retval->text_object_count+1));
3111                                 // assign the new object to the end of the list.
3112                                 memcpy(&retval->text_objects[retval->text_object_count++],
3113                                                 obj, sizeof(struct text_object));
3114                                 free(obj);
3115                         }
3116                         *(char *) p = '$';
3117                         p++;
3118                         s = p;
3119
3120                         if (*p != '$') {
3121                                 char buf[256];
3122                                 const char *var;
3123                                 unsigned int len;
3124
3125                                 /* variable is either $foo or ${foo} */
3126                                 if (*p == '{') {
3127                                         p++;
3128                                         s = p;
3129                                         while (*p && *p != '}')
3130                                                 p++;
3131                                 } else {
3132                                         s = p;
3133                                         if (*p == '#')
3134                                                 p++;
3135                                         while (*p && (isalnum((int) *p)
3136                                                                 || *p == '_'))
3137                                                 p++;
3138                                 }
3139
3140                                 /* copy variable to buffer */
3141                                 len = (p - s > 255) ? 255 : (p - s);
3142                                 strncpy(buf, s, len);
3143                                 buf[len] = '\0';
3144
3145                                 if (*p == '}')
3146                                         p++;
3147                                 s = p;
3148
3149                                 var = getenv(buf);
3150
3151                                 /* if variable wasn't found from environment, use some special */
3152                                 if (!var) {
3153                                         char *p;
3154                                         char *arg = 0;
3155
3156                                         /* split arg */
3157                                         if (strchr(buf, ' ')) {
3158                                                 arg = strchr(buf, ' ');
3159                                                 *arg = '\0';
3160                                                 arg++;
3161                                                 while (isspace((int) *arg))
3162                                                         arg++;
3163                                                 if (!*arg)
3164                                                         arg = 0;
3165                                         }
3166
3167                                         /* lowercase variable name */
3168                                         p = buf;
3169                                         while (*p) {
3170                                                 *p = tolower(*p);
3171                                                 p++;
3172                                         }
3173
3174                                         // create new object
3175                                         obj = construct_text_object(buf, arg, retval->text_object_count, retval->text_objects, line);
3176                                         if(obj != NULL) {
3177                                                 // allocate memory for the object
3178                                                 retval->text_objects = realloc(retval->text_objects, 
3179                                                                 sizeof(struct text_object) * (retval->text_object_count+1));
3180                                                 // assign the new object to the end of the list.
3181                                                 memcpy(&retval->text_objects[retval->text_object_count++],
3182                                                                 obj, sizeof(struct text_object));
3183                                                 free(obj);
3184                                         }
3185                                 }
3186                                 continue;
3187                         } else {
3188                                 obj = create_plain_text("$");
3189                                 if(obj != NULL) {
3190                                         // allocate memory for the object
3191                                         retval->text_objects = realloc(retval->text_objects, 
3192                                                         sizeof(struct text_object) * (retval->text_object_count+1));
3193                                         // assign the new object to the end of the list.
3194                                         memcpy(&retval->text_objects[retval->text_object_count++],
3195                                                         obj, sizeof(struct text_object));
3196                                         free(obj);
3197                                 }
3198                         }
3199                 }
3200                 p++;
3201         }
3202         obj = create_plain_text(s);
3203         if(obj != NULL) {
3204                 // allocate memory for the object
3205                 retval->text_objects = realloc(retval->text_objects,
3206                                 sizeof(struct text_object) * (retval->text_object_count+1));
3207                 // assign the new object to the end of the list.
3208                 memcpy(&retval->text_objects[retval->text_object_count++],
3209                                 obj, sizeof(struct text_object));
3210                 free(obj);
3211         }
3212
3213         if (blockdepth) {
3214                 ERR("one or more $endif's are missing");
3215         }
3216
3217         return retval;
3218 }
3219
3220 static void extract_variable_text(const char *p)
3221 {
3222         struct text_object_list *list;
3223
3224         free_text_objects(text_object_count, text_objects);
3225         text_object_count = 0;
3226         text_objects = NULL;
3227
3228
3229         list = extract_variable_text_internal(p);
3230         text_objects = list->text_objects;
3231         text_object_count = list->text_object_count;
3232
3233         free(list);
3234
3235         return;
3236 }
3237
3238 void parse_conky_vars(char * text, char * p, struct information *cur) { 
3239         struct text_object_list *object_list = extract_variable_text_internal(text);
3240         generate_text_internal(p, P_MAX_SIZE, object_list->text_objects, object_list->text_object_count, cur);
3241         free(object_list);
3242 }
3243
3244 static void generate_text_internal(char *p, int p_max_size, struct text_object *objs, unsigned int object_count, struct information *cur)
3245 {
3246         unsigned int i;
3247
3248 #ifdef HAVE_ICONV
3249         char buff_in[P_MAX_SIZE] = {0};
3250         iconv_converting = 0;
3251 #endif
3252
3253         for (i = 0; i < object_count; i++) {
3254                 struct text_object *obj = &objs[i];
3255
3256 #define OBJ(a) break; case OBJ_##a:
3257
3258                 switch (obj->type) {
3259                         default:
3260                                 {
3261                                         ERR("not implemented obj type %d",
3262                                                         obj->type);
3263                                 }
3264                                 OBJ(acpitemp) {
3265                                         /* does anyone have decimals in acpi temperature? */
3266                                         if (!use_spacer)
3267                                                 snprintf(p, p_max_size, "%d", (int)
3268                                                                 get_acpi_temperature(obj->
3269                                                                         data.
3270                                                                         i));
3271                                         else
3272                                                 snprintf(p, 5, "%d    ", (int)
3273                                                                 get_acpi_temperature(obj->
3274                                                                         data.
3275                                                                         i));
3276                                 }
3277                                 OBJ(acpitempf) {
3278                                         /* does anyone have decimals in acpi temperature? */
3279                                         if (!use_spacer)
3280                                                 snprintf(p, p_max_size, "%d", (int)
3281                                                                 ((get_acpi_temperature(obj->
3282                                                                                        data.
3283                                                                                        i)+ 40) * 9.0 / 5 - 40));
3284                                         else
3285                                                 snprintf(p, 5, "%d    ", (int)
3286                                                                 ((get_acpi_temperature(obj->
3287                                                                                        data.
3288                                                                                        i)+ 40) * 9.0 / 5 - 40));
3289                                 }
3290                                 OBJ(freq) {
3291                                         if (obj->a) {
3292                                                 obj->a = get_freq(p, p_max_size, "%.0f", 1, obj->data.cpu_index); 
3293                                         }
3294                                 }
3295                                 OBJ(freq_g) {
3296                                         if (obj->a) {
3297                                                 obj->a = get_freq(p, p_max_size, "%'.2f", 1000, obj->data.cpu_index); 
3298                                         }
3299                                 }
3300 #if defined(__linux__)
3301                                 OBJ(voltage_mv) {
3302                                         if (obj->a) {
3303                                                 obj->a = get_voltage(p, p_max_size, "%.0f", 1, obj->data.cpu_index);
3304                                         }
3305                                 }
3306                                 OBJ(voltage_v) {
3307                                         if (obj->a) {
3308                                                 obj->a = get_voltage(p, p_max_size, "%'.3f", 1000, obj->data.cpu_index);
3309                                         }
3310                                 }
3311 #endif /* __linux__ */
3312
3313                                 OBJ(freq_dyn) {
3314                                         if (use_spacer) {
3315                                                 get_freq_dynamic(p, 6, "%.0f     ", 1 ); 
3316                                         } else {
3317                                                 get_freq_dynamic(p, p_max_size, "%.0f", 1 ); 
3318                                         }
3319                                 }
3320                                 OBJ(freq_dyn_g) {
3321                                         if (use_spacer) {
3322                                                 get_freq_dynamic(p, 6, "%'.2f     ", 1000); 
3323                                         } else {
3324                                                 get_freq_dynamic(p, p_max_size, "%'.2f", 1000); 
3325                                         }
3326                                 }
3327                                 OBJ(adt746xcpu) {
3328                                         get_adt746x_cpu(p, p_max_size); 
3329                                 }
3330                                 OBJ(adt746xfan) {
3331                                         get_adt746x_fan(p, p_max_size); 
3332                                 }
3333                                 OBJ(acpifan) {
3334                                         get_acpi_fan(p, p_max_size);  
3335                                 }
3336                                 OBJ(acpiacadapter) {
3337                                         get_acpi_ac_adapter(p, p_max_size); 
3338                                 }
3339                                 OBJ(battery) {
3340                                         get_battery_stuff(p, p_max_size, obj->data.s, BATTERY_STATUS);
3341                                 }
3342                                 OBJ(battery_time) {
3343                                         get_battery_stuff(p, p_max_size, obj->data.s, BATTERY_TIME);
3344                                 }
3345                                 OBJ(buffers) {
3346                                         human_readable(cur->buffers * 1024, p, 255);
3347                                 }
3348                                 OBJ(cached) {
3349                                         human_readable(cur->cached * 1024, p, 255);
3350                                 }
3351                                 OBJ(cpu) {
3352                                         if (obj->data.cpu_index > info.cpu_count) {
3353                                                 printf("obj->data.cpu_index %i info.cpu_count %i", obj->data.cpu_index, info.cpu_count);
3354                                                 CRIT_ERR("attempting to use more CPUs then you have!");
3355                                         }
3356                                         if (!use_spacer)
3357                                                 snprintf(p, p_max_size, "%*d", pad_percents,
3358                                                                 (int) round_to_int(cur->cpu_usage[obj->data.cpu_index] *
3359                                                                                    100.0));
3360                                         else
3361                                                 snprintf(p, 4, "%*d    ",
3362                                                                 pad_percents,
3363                                                                 (int) round_to_int(cur->cpu_usage[obj->data.cpu_index] *
3364                                                                                    100.0));
3365                                 }
3366                                 OBJ(cpubar) {
3367                                         new_bar(p, obj->a,
3368                                                         obj->b,
3369                                                         (int) round_to_int(cur->cpu_usage[obj->data.cpu_index] * 255.0));
3370                                 }
3371                                 OBJ(cpugraph) {
3372                                         new_graph(p, obj->a,
3373                                                         obj->b, obj->c, obj->d,
3374                                                         (unsigned int) round_to_int(cur->cpu_usage[obj->data.cpu_index] *
3375                                                                                     100), 100, 1);
3376                                 }
3377                                 OBJ(color) {
3378                                         new_fg(p, obj->data.l);
3379                                 }
3380 #if defined(__linux__)
3381                                 OBJ(i8k_version) {
3382                                         snprintf(p, p_max_size, "%s", i8k.version);
3383                                 }
3384                                 OBJ(i8k_bios) {
3385                                         snprintf(p, p_max_size, "%s", i8k.bios);
3386                                 }
3387                                 OBJ(i8k_serial) { 
3388                                         snprintf(p, p_max_size, "%s", i8k.serial);
3389                                 }
3390                                 OBJ(i8k_cpu_temp) { 
3391                                         snprintf(p, p_max_size, "%s", i8k.cpu_temp);
3392                                 }
3393                                 OBJ(i8k_cpu_tempf) { 
3394                                         int cpu_temp;
3395                                         sscanf(i8k.cpu_temp, "%d", &cpu_temp);
3396                                         snprintf(p, p_max_size, "%.1f", cpu_temp*(9.0/5.0)+32.0);
3397                                 }
3398                                 OBJ(i8k_left_fan_status) { 
3399                                         int left_fan_status;
3400                                         sscanf(i8k.left_fan_status, "%d", &left_fan_status);
3401                                         if(left_fan_status == 0) {
3402                                                 snprintf(p, p_max_size,"off");
3403                                         } if(left_fan_status == 1) {
3404                                                 snprintf(p, p_max_size, "low");
3405                                         }       if(left_fan_status == 2) {
3406                                                 snprintf(p, p_max_size, "high");
3407                                         }
3408
3409                                 }
3410                                 OBJ(i8k_right_fan_status) { 
3411                                         int right_fan_status;
3412                                         sscanf(i8k.right_fan_status, "%d", &right_fan_status);
3413                                         if(right_fan_status == 0) {
3414                                                 snprintf(p, p_max_size,"off");
3415                                         } if(right_fan_status == 1) {
3416                                                 snprintf(p, p_max_size, "low");
3417                                         }       if(right_fan_status == 2) {
3418                                                 snprintf(p, p_max_size, "high");
3419                                         }
3420                                 }
3421                                 OBJ(i8k_left_fan_rpm) { 
3422                                         snprintf(p, p_max_size, "%s", i8k.left_fan_rpm);
3423                                 }
3424                                 OBJ(i8k_right_fan_rpm) { 
3425                                         snprintf(p, p_max_size, "%s", i8k.right_fan_rpm);
3426                                 }
3427                                 OBJ(i8k_ac_status) { 
3428                                         int ac_status;
3429                                         sscanf(i8k.ac_status, "%d", &ac_status);
3430                                         if(ac_status == -1) {
3431                                                 snprintf(p, p_max_size,"disabled (read i8k docs)");
3432                                         } if(ac_status == 0) {
3433                                                 snprintf(p, p_max_size, "off");
3434                                         }       if(ac_status == 1) {
3435                                                 snprintf(p, p_max_size, "on");
3436                                         }
3437                                 }
3438                                 OBJ(i8k_buttons_status) {
3439                                         snprintf(p, p_max_size, "%s", i8k.buttons_status); 
3440
3441                                 }
3442                                 OBJ(ibm_fan) {
3443                                     get_ibm_acpi_fan(p, p_max_size);
3444                                 }
3445                                 OBJ(ibm_temps) {
3446                                     get_ibm_acpi_temps();
3447                                     snprintf(p, p_max_size, "%d",
3448                                              ibm_acpi.temps[obj->data.sensor]);
3449                                 }
3450                                 OBJ(ibm_volume) {
3451                                     get_ibm_acpi_volume(p, p_max_size);
3452                                 }
3453                                 OBJ(ibm_brightness) {
3454                                     get_ibm_acpi_brightness(p, p_max_size);
3455                                 }
3456                                 OBJ(pb_battery) {
3457                                     get_powerbook_batt_info(p, p_max_size, obj->data.i);
3458                                 }
3459 #endif /* __linux__ */
3460
3461 #ifdef X11
3462                                 OBJ(font) {
3463                                         new_font(p, obj->data.s);
3464                                 }
3465 #endif /* X11 */
3466                                 void format_diskio(unsigned int diskio_value)
3467                                 {
3468                                         if (!use_spacer) {
3469                                                 if (diskio_value > 1024*1024) {
3470                                                         snprintf(p, p_max_size, "%.1fGiB",
3471                                                                         (double)diskio_value/1024/1024);
3472                                                 } else if (diskio_value > 1024) {
3473                                                         snprintf(p, p_max_size, "%.1fMiB",
3474                                                                         (double)diskio_value/1024);
3475                                                 } else if (diskio_value > 0) {
3476                                                         snprintf(p, p_max_size, "%dKiB", diskio_value);
3477                                                 } else {
3478                                                         snprintf(p, p_max_size, "%dB", diskio_value);
3479                                                 }
3480                                         } else {
3481                                                 if (diskio_value > 1024*1024) {
3482                                                         snprintf(p, 12, "%.1fGiB   ",
3483                                                                         (double)diskio_value/1024/1024);
3484                                                 } else if (diskio_value > 1024) {
3485                                                         snprintf(p, 12, "%.1fMiB   ",
3486                                                                         (double)diskio_value/1024);
3487                                                 } else if (diskio_value > 0) {
3488                                                         snprintf(p, 12, "%dKiB ", diskio_value);
3489                                                 } else {
3490                                                         snprintf(p, 12, "%dB     ", diskio_value);
3491                                                 }
3492                                         }
3493                                 }
3494                                 OBJ(diskio) {
3495                                         format_diskio(diskio_value);
3496                                 }
3497                                 OBJ(diskio_write) {
3498                                         format_diskio(diskio_write_value);
3499                                 }
3500                                 OBJ(diskio_read) {
3501                                         format_diskio(diskio_read_value);
3502                                 }
3503                                 OBJ(diskiograph) {
3504                                         new_graph(p, obj->a,
3505                                                         obj->b, obj->c, obj->d,
3506                                                         diskio_value, obj->e, 1);
3507                                 }
3508                                 OBJ(diskiograph_read) {
3509                                         new_graph(p, obj->a,
3510                                                         obj->b, obj->c, obj->d,
3511                                                         diskio_read_value, obj->e, 1);
3512                                 }
3513                                 OBJ(diskiograph_write) {
3514                                         new_graph(p, obj->a,
3515                                                         obj->b, obj->c, obj->d,
3516                                                         diskio_write_value, obj->e, 1);
3517                                 }
3518                                 OBJ(downspeed) {
3519                                         if (!use_spacer) {
3520                                                 snprintf(p, p_max_size, "%d",
3521                                                                 (int) (obj->data.net->
3522                                                                        recv_speed /
3523                                                                        1024));
3524                                         } else
3525                                                 snprintf(p, 6, "%d     ",
3526                                                                 (int) (obj->data.net->
3527                                                                        recv_speed /
3528                                                                        1024));
3529                                 }
3530                                 OBJ(downspeedf) {
3531                                         if (!use_spacer)
3532                                                 snprintf(p, p_max_size, "%.1f",
3533                                                                 obj->data.net->
3534                                                                 recv_speed / 1024.0);
3535                                         else
3536                                                 snprintf(p, 8, "%.1f       ",
3537                                                                 obj->data.net->
3538                                                                 recv_speed / 1024.0);
3539                                 }
3540                                 OBJ(downspeedgraph) {
3541           /*
3542                                         if (obj->data.net->recv_speed == 0)     
3543                                                 obj->data.net->recv_speed = 0.01;
3544             */
3545                                         new_graph(p, obj->a, obj->b, obj->c, obj->d,
3546                                                         (obj->data.net->recv_speed /
3547                                                          1024.0), obj->e, 1);
3548                                 }
3549                                 OBJ(else) {
3550                                         if (!if_jumped) {
3551                                                 i = obj->data.ifblock.pos - 1;
3552                                         } else {
3553                                                 if_jumped = 0;
3554                                         }
3555                                 }
3556                                 OBJ(endif) {
3557                                         if_jumped = 0;
3558                                 }
3559 #ifdef HAVE_POPEN
3560                                 OBJ(addr) {
3561                                         snprintf(p, p_max_size, "%u.%u.%u.%u",
3562                                                         obj->data.net->addr.
3563                                                         sa_data[2] & 255,
3564                                                         obj->data.net->addr.
3565                                                         sa_data[3] & 255,
3566                                                         obj->data.net->addr.
3567                                                         sa_data[4] & 255,
3568                                                         obj->data.net->addr.
3569                                                         sa_data[5] & 255);
3570
3571                                 }
3572                                 OBJ(linkstatus) {
3573                                         if (!use_spacer) {
3574                                                 snprintf(p, p_max_size, "%d",
3575                                                         obj->data.net->linkstatus);
3576                                         } else
3577                                         {
3578                                                 snprintf(p, 5, "%4d ",
3579                                                         obj->data.net->linkstatus);
3580                                         }
3581                                 }
3582 #if defined(IMLIB2) && defined(X11)
3583                                 OBJ(image) {
3584                                         if (obj->a < 1) {
3585                                                 obj->a++;
3586                                         } else {
3587                                                 Imlib_Image image, buffer;
3588                                                 image = imlib_load_image(obj->data.s);
3589                                                 imlib_context_set_image(image);
3590                                                 if (image) {
3591                                                         int w, h;
3592                                                         w = imlib_image_get_width();
3593                                                         h = imlib_image_get_height();
3594                                                         buffer = imlib_create_image(w, h);
3595                                                         imlib_context_set_display(display);
3596                                                         imlib_context_set_drawable(window.drawable);
3597                                                         imlib_context_set_colormap(DefaultColormap(display, screen));
3598                                                         imlib_context_set_visual(DefaultVisual(display, screen));
3599                                                         imlib_context_set_image(buffer);
3600                                                         imlib_blend_image_onto_image(image, 0, 0, 0, w, h, text_start_x, text_start_y, w, h);
3601                                                         imlib_render_image_on_drawable(text_start_x, text_start_y);
3602                                                         imlib_free_image();
3603                                                         imlib_context_set_image(image);
3604                                                         imlib_free_image();
3605                                                 }
3606                                         }
3607                                 }
3608 #endif /* IMLIB2 */
3609                                 OBJ(exec) {
3610                                         FILE *fp = popen(obj->data.s, "r");
3611                                         int length = fread(p, 1, p_max_size, fp);
3612                                         (void) pclose(fp);
3613
3614                                         /*output[length] = '\0';
3615                                           if (length > 0 && output[length - 1] == '\n') {
3616                                           output[length - 1] = '\0';
3617                                           }*/
3618                                         p[length] = '\0';
3619                                         if (length > 0 && p[length - 1] == '\n') {
3620                                                 p[length - 1] = '\0';
3621                                         }
3622
3623                                         //parse_conky_vars(output, p, cur);
3624                                 }
3625                                 OBJ(execbar) {
3626                                         char *p2 = p;
3627                                         FILE *fp = popen(obj->data.s, "r");
3628                                         int n2 = fread(p, 1, p_max_size, fp);
3629                                         (void) pclose(fp);
3630
3631                                         p[n2] = '\0';
3632                                         if (n2 && p[n2 - 1] == '\n')
3633                                                 p[n2 - 1] = '\0';
3634
3635                                         while (*p2) {
3636                                                 if (*p2 == '\001')
3637                                                         *p2 = ' ';
3638                                                 p2++;
3639                                         }
3640                                         double barnum;
3641                                         if (sscanf(p, "%lf", &barnum) == 0) {
3642                                                 ERR("reading execbar value failed (perhaps it's not the correct format?)");
3643                                         }
3644                                         if (barnum > 100 || barnum < 0) {
3645                                                 ERR("your execbar value is not between 0 and 100, therefore it will be ignored");
3646                                         } else {
3647                                                 barnum = barnum / 100.0;
3648                                                 new_bar(p, 0, 4, (int) (barnum * 255.0));
3649                                         }
3650
3651                                 }
3652                                 OBJ(execgraph) {
3653                                         char *p2 = p;
3654                                         FILE *fp = popen(obj->data.s, "r");
3655                                         int n2 = fread(p, 1, p_max_size, fp);
3656                                         (void) pclose(fp);
3657
3658                                         p[n2] = '\0';
3659                                         if (n2 && p[n2 - 1] == '\n')
3660                                                 p[n2 - 1] = '\0';
3661
3662                                         while (*p2) {
3663                                                 if (*p2 == '\001')
3664                                                         *p2 = ' ';
3665                                                 p2++;
3666                                         }
3667                                         double barnum;
3668                                         if (sscanf(p, "%lf", &barnum) == 0) {
3669                                                 ERR("reading execgraph value failed (perhaps it's not the correct format?)");
3670                                         }
3671                                         if (barnum > 100 || barnum < 0) {
3672                                                 ERR("your execgraph value is not between 0 and 100, therefore it will be ignored");
3673                                         } else {
3674                                                 new_graph(p, 0, 25, obj->c, obj->d, (int) (barnum), obj->e, 1);
3675                                         }
3676
3677                                 }
3678                                 OBJ(execibar) {
3679                                         if (current_update_time - obj->data.execi.last_update < obj->data.execi.interval) {
3680                                                 new_bar(p, 0, 4, (int) obj->f);
3681                                         } else {
3682                                                 char *p2 = p;
3683                                                 FILE *fp = popen(obj->data.execi.cmd, "r");
3684                                                 int n2 = fread(p, 1, p_max_size, fp);
3685                                                 (void) pclose(fp);
3686                                                 p[n2] = '\0';
3687                                                 if (n2 && p[n2 - 1] == '\n')
3688                                                         p[n2 - 1] = '\0';
3689
3690                                                 while (*p2) {
3691                                                         if (*p2 == '\001')
3692                                                                 *p2 = ' ';
3693                                                         p2++;
3694                                                 }
3695                                                 float barnum;
3696                                                 if (sscanf(p, "%f", &barnum) == 0) {
3697                                                         ERR("reading execibar value failed (perhaps it's not the correct format?)");
3698                                                 }
3699                                                 if (barnum > 100 || barnum < 0) {
3700                                                         ERR("your execibar value is not between 0 and 100, therefore it will be ignored");
3701                                                 } else {
3702                                                         obj->f = 255 * barnum / 100.0;
3703                                                         new_bar(p, 0, 4, (int) obj->f);
3704                                                 }
3705                                                 obj->data.execi.last_update =
3706                                                         current_update_time;
3707                                         }
3708                                 }
3709                                 OBJ(execigraph) {
3710                                         if (current_update_time - obj->data.execi.last_update < obj->data.execi.interval) {
3711                                                 new_graph(p, 0, 25, obj->c, obj->d, (int) (obj->f), 100, 0);
3712                                         } else {
3713                                                 char *p2 = p;
3714                                                 FILE *fp = popen(obj->data.execi.cmd, "r");
3715                                                 int n2 = fread(p, 1, p_max_size, fp);
3716                                                 (void) pclose(fp);
3717                                                 p[n2] = '\0';
3718                                                 if (n2 && p[n2 - 1] == '\n')
3719                                                         p[n2 - 1] = '\0';
3720
3721                                                 while (*p2) {
3722                                                         if (*p2 == '\001')
3723                                                                 *p2 = ' ';
3724                                                         p2++;
3725                                                 }
3726                                                 float barnum;
3727                                                 if (sscanf(p, "%f", &barnum) == 0) {
3728                                                         ERR("reading execigraph value failed (perhaps it's not the correct format?)");
3729                                                 }
3730                                                 if (barnum > 100 || barnum < 0) {
3731                                                         ERR("your execigraph value is not between 0 and 100, therefore it will be ignored");
3732                                                 } else {
3733                                                         obj->f = barnum;
3734                                                         new_graph(p, 0, 25, obj->c, obj->d, (int) (obj->f), 100, 1);
3735                                                 }
3736                                                 obj->data.execi.last_update = current_update_time;
3737
3738                                         }
3739
3740                                 }
3741                                 OBJ(execi) {
3742                                         if (current_update_time - obj->data.execi.last_update < obj->data.execi.interval || obj->data.execi.interval == 0) {
3743                                                 snprintf(p, p_max_size, "%s", obj->data.execi.buffer);
3744                                         } else {
3745                                                 char *output = obj->data.execi.buffer;
3746                                                 FILE *fp = popen(obj->data.execi.cmd, "r");
3747                                                 //int length = fread(output, 1, text_buffer_size, fp);
3748                                                 int length = fread(output, 1, text_buffer_size, fp);
3749                                                 (void) pclose(fp);
3750
3751                                                 output[length] = '\0';
3752                                                 if (length > 0 && output[length - 1] == '\n') {
3753                                                         output[length - 1] = '\0';
3754                                                 }
3755                                                 obj->data.execi.last_update = current_update_time;
3756                                                 snprintf(p, p_max_size, "%s", output);
3757                                         }
3758                                         //parse_conky_vars(output, p, cur);
3759                                 }
3760                                 OBJ(texeci) {
3761                                         if (!obj->data.texeci.p_timed_thread)
3762                                         {
3763                                             obj->data.texeci.p_timed_thread=
3764                                             timed_thread_create ((void*)threaded_exec, (void*) obj, 
3765                                                                  obj->data.texeci.interval * 1000000);
3766                                             if (!obj->data.texeci.p_timed_thread)
3767                                                 ERR("Error starting texeci thread");
3768                                             timed_thread_register (obj->data.texeci.p_timed_thread,
3769                                                                    &obj->data.texeci.p_timed_thread);
3770                                         }
3771                                         timed_thread_lock (obj->data.texeci.p_timed_thread);
3772                                         snprintf(p, p_max_size, "%s", obj->data.texeci.buffer);
3773                                         timed_thread_unlock (obj->data.texeci.p_timed_thread);
3774                                 }
3775 #endif /* HAVE_POPEN */
3776                                 OBJ(imap_unseen) {
3777                                         if (obj->global_mode && info.mail) { // this means we use info
3778                                                 if (!info.mail->p_timed_thread)
3779                                                 {
3780                                                     info.mail->p_timed_thread = 
3781                                                     timed_thread_create ((void*)imap_thread, 
3782                                                                          (void*)info.mail,
3783                                                                          info.mail->interval * 1000000);
3784                                                     if (!info.mail->p_timed_thread)
3785                                                          ERR("Error starting imap thread");
3786                                                     timed_thread_register (info.mail->p_timed_thread,
3787                                                                            &info.mail->p_timed_thread);
3788                                                 }
3789                                                 timed_thread_lock (info.mail->p_timed_thread);
3790                                                 snprintf(p, p_max_size, "%lu", info.mail->unseen);
3791                                                 timed_thread_unlock (info.mail->p_timed_thread);
3792                                         } else if (obj->data.mail) { // this means we use obj
3793                                                 if (!obj->data.mail->p_timed_thread)
3794                                                 {
3795                                                     obj->data.mail->p_timed_thread = 
3796                                                     timed_thread_create ((void*)imap_thread, 
3797                                                                          (void*)obj->data.mail,
3798                                                                          obj->data.mail->interval * 1000000);
3799                                                     if (!obj->data.mail->p_timed_thread)
3800                                                         ERR("Error starting imap thread");
3801                                                     timed_thread_register (obj->data.mail->p_timed_thread,
3802                                                                            &obj->data.mail->p_timed_thread);
3803                                                 }
3804                                                 timed_thread_lock (obj->data.mail->p_timed_thread);
3805                                                 snprintf(p, p_max_size, "%lu", obj->data.mail->unseen);
3806                                                 timed_thread_unlock (obj->data.mail->p_timed_thread);
3807                                         } else if (!obj->a) { // something is wrong, warn once then stop
3808                                                 ERR("Theres a problem with your imap_unseen settings.  Check that the global IMAP settings are defined properly (line %li).", obj->line);
3809                                                         obj->a++;
3810                                         }
3811                                 }
3812                                 OBJ(imap_messages) {
3813                                         if (obj->global_mode && info.mail) { // this means we use info
3814                                                 if (!info.mail->p_timed_thread)
3815                                                 {
3816                                                     info.mail->p_timed_thread =
3817                                                     timed_thread_create ((void*)imap_thread, 
3818                                                                          (void*)info.mail,
3819                                                                          info.mail->interval * 1000000);
3820                                                     if (!info.mail->p_timed_thread)
3821                                                          ERR("Error starting imap thread");
3822                                                     timed_thread_register (info.mail->p_timed_thread,
3823                                                                            &info.mail->p_timed_thread);
3824                                                 }
3825                                                 timed_thread_lock (info.mail->p_timed_thread);
3826                                                 snprintf(p, p_max_size, "%lu", info.mail->messages);
3827                                                 timed_thread_unlock (info.mail->p_timed_thread);
3828                                         } else if (obj->data.mail) { // this means we use obj
3829                                                 if (!obj->data.mail->p_timed_thread)
3830                                                 {
3831                                                     obj->data.mail->p_timed_thread =
3832                                                     timed_thread_create ((void*)imap_thread,
3833                                                                          (void*)obj->data.mail,
3834                                                                          obj->data.mail->interval * 1000000);
3835                                                     if (!obj->data.mail->p_timed_thread)
3836                                                         ERR("Error starting imap thread");
3837                                                     timed_thread_register (obj->data.mail->p_timed_thread,
3838                                                                            &obj->data.mail->p_timed_thread);
3839                                                 }
3840                                                 timed_thread_lock (obj->data.mail->p_timed_thread);
3841                                                 snprintf(p, p_max_size, "%lu", obj->data.mail->messages);
3842                                                 timed_thread_lock (obj->data.mail->p_timed_thread);
3843                                         } else if (!obj->a) { // something is wrong, warn once then stop
3844                                                 ERR("Theres a problem with your imap_messages settings.  Check that the global IMAP settings are defined properly (line %li).", obj->line);
3845                                                         obj->a++;
3846                                         }
3847                                 }
3848                                 OBJ(pop3_unseen) {
3849                                         if (obj->global_mode && info.mail) { // this means we use info
3850                                                 if (!info.mail->p_timed_thread)
3851                                                 {
3852                                                     info.mail->p_timed_thread = 
3853                                                     timed_thread_create ((void*)pop3_thread,
3854                                                                          (void*)info.mail,
3855                                                                          info.mail->interval * 1000000);
3856                                                     if (!info.mail->p_timed_thread)
3857                                                         ERR("Error starting pop3 thread");
3858                                                     timed_thread_register (info.mail->p_timed_thread,
3859                                                                            &info.mail->p_timed_thread);
3860                                                 }
3861                                                 timed_thread_lock (info.mail->p_timed_thread);
3862                                                 snprintf(p, p_max_size, "%lu", info.mail->unseen);
3863                                                 timed_thread_unlock (info.mail->p_timed_thread);
3864                                         } else if (obj->data.mail) { // this means we use obj
3865                                                 if (!obj->data.mail->p_timed_thread)
3866                                                 {
3867                                                     obj->data.mail->p_timed_thread = 
3868                                                     timed_thread_create ((void*)pop3_thread,
3869                                                                          (void*)info.mail,
3870                                                                          obj->data.mail->interval * 1000000);
3871                                                     if (!obj->data.mail->p_timed_thread)
3872                                                         ERR("Error starting pop3 thread");
3873                                                     timed_thread_register (obj->data.mail->p_timed_thread,
3874                                                                            &obj->data.mail->p_timed_thread);
3875                                                 }
3876                                                 timed_thread_lock (obj->data.mail->p_timed_thread);
3877                                                 snprintf(p, p_max_size, "%lu", obj->data.mail->unseen);
3878                                                 timed_thread_unlock (obj->data.mail->p_timed_thread);
3879                                         } else if (!obj->a) { // something is wrong, warn once then stop
3880                                                 ERR("Theres a problem with your pop3_unseen settings.  Check that the global POP3 settings are defined properly (line %li).", obj->line);
3881                                                         obj->a++;
3882                                         }
3883                                 }
3884                                 OBJ(pop3_used) {
3885                                         if (obj->global_mode && info.mail) { // this means we use info
3886                                                 if (!info.mail->p_timed_thread)
3887                                                 {
3888                                                     info.mail->p_timed_thread = 
3889                                                     timed_thread_create ((void*)pop3_thread,
3890                                                                          (void*)info.mail,
3891                                                                          info.mail->interval * 1000000);
3892                                                     if (!info.mail->p_timed_thread)
3893                                                         ERR("Error starting pop3 thread");
3894                                                     timed_thread_register (info.mail->p_timed_thread,
3895                                                                            &info.mail->p_timed_thread);
3896                                                 }
3897                                                 timed_thread_lock (info.mail->p_timed_thread);
3898                                                 snprintf(p, p_max_size, "%.1f", info.mail->used/1024.0/1024.0);
3899                                                 timed_thread_unlock (info.mail->p_timed_thread);
3900                                         } else if (obj->data.mail) { // this means we use obj
3901                                                 if (!obj->data.mail->p_timed_thread)
3902                                                 {
3903                                                     obj->data.mail->p_timed_thread =
3904                                                     timed_thread_create ((void*)pop3_thread,
3905                                                                          (void*)obj->data.mail,
3906                                                                          obj->data.mail->interval * 1000000);
3907                                                     if (!obj->data.mail->p_timed_thread)
3908                                                         ERR("Error starting pop3 thread");
3909                                                     timed_thread_register (obj->data.mail->p_timed_thread,
3910                                                                            &obj->data.mail->p_timed_thread);
3911                                                 }
3912                                                 timed_thread_lock (obj->data.mail->p_timed_thread);
3913                                                 snprintf(p, p_max_size, "%.1f", obj->data.mail->used/1024.0/1024.0);
3914                                                 timed_thread_unlock (obj->data.mail->p_timed_thread);
3915                                         } else if (!obj->a) { // something is wrong, warn once then stop
3916                                                 ERR("Theres a problem with your pop3_used settings.  Check that the global POP3 settings are defined properly (line %li).", obj->line);
3917                                                         obj->a++;
3918                                         }
3919                                 }
3920                         OBJ(fs_bar) {
3921                                 if (obj->data.fs != NULL) {
3922                                         if (obj->data.fs->size == 0)
3923                                                 new_bar(p,
3924                                                         obj->data.fsbar.w,
3925                                                         obj->data.fsbar.h,
3926                                                         255);
3927                                         else
3928                                                 new_bar(p,
3929                                                         obj->data.fsbar.w,
3930                                                         obj->data.fsbar.h,
3931                                                         (int) (255 -
3932                                                                obj->data.
3933                                                                fsbar.fs->
3934                                                                avail *
3935                                                                255 /
3936                                                                obj->data.
3937                                                                fs->size));
3938                                 }
3939                         }
3940                         OBJ(fs_free) {
3941                                 if (obj->data.fs != NULL)
3942                                         human_readable(obj->data.fs->avail,
3943                                                        p, 255);
3944                         }
3945                         OBJ(fs_free_perc) {
3946                                 if (obj->data.fs != NULL) {
3947                                         if (obj->data.fs->size)
3948                                                 snprintf(p, p_max_size, "%*d",
3949                                                          pad_percents,
3950                                                          (int) ((obj->data.
3951                                                                  fs->
3952                                                                  avail *
3953                                                                  100) /
3954                                                                 obj->data.
3955                                                                 fs->size));
3956                                         else
3957                                                 snprintf(p, p_max_size, "0");
3958                                 }
3959                         }
3960                         OBJ(fs_size) {
3961                                 if (obj->data.fs != NULL)
3962                                         human_readable(obj->data.fs->size,
3963                                                        p, 255);
3964                         }
3965                         OBJ(fs_used) {
3966                                 if (obj->data.fs != NULL)
3967                                         human_readable(obj->data.fs->size -
3968                                                        (obj->data.fs->free ? obj->data.fs->free :obj->data.fs->avail),
3969                                                        p, 255);
3970                         }
3971                         OBJ(fs_bar_free) {
3972                                 if (obj->data.fs != NULL) {
3973                                         if (obj->data.fs->size == 0)
3974                                                 new_bar(p,
3975                                                         obj->data.fsbar.w,
3976                                                         obj->data.fsbar.h,
3977                                                         255);
3978                                         else
3979                                                 new_bar(p,
3980                                                         obj->data.fsbar.w,
3981                                                         obj->data.fsbar.h,
3982                                                         (int) (obj->data.
3983                                                                fsbar.fs->
3984                                                                avail *
3985                                                                255 /
3986                                                                obj->data.
3987                                                                fs->size));
3988                                 }
3989                         }
3990                         OBJ(fs_used_perc) {
3991                                 if (obj->data.fs != NULL) {
3992                                         if (obj->data.fs->size)
3993                                                 snprintf(p, 4, "%d",
3994                                                          100 - ((int)
3995                                                                 ((obj->
3996                                                                   data.fs->
3997                                                                   avail *
3998                                                                   100) /
3999                                                                  obj->data.
4000                                                                  fs->
4001                                                                  size)));
4002                                         else
4003                                                 snprintf(p, p_max_size, "0");
4004                                 }
4005                         }
4006                         OBJ(loadavg) {
4007                                 float *v = info.loadavg;
4008
4009                                 if (obj->data.loadavg[2])
4010                                         snprintf(p, p_max_size, "%.2f %.2f %.2f",
4011                                                  v[obj->data.loadavg[0] -
4012                                                    1],
4013                                                  v[obj->data.loadavg[1] -
4014                                                    1],
4015                                                  v[obj->data.loadavg[2] -
4016                                                    1]);
4017                                 else if (obj->data.loadavg[1])
4018                                         snprintf(p, p_max_size, "%.2f %.2f",
4019                                                  v[obj->data.loadavg[0] -
4020                                                    1],
4021                                                  v[obj->data.loadavg[1] -
4022                                                    1]);
4023                                 else if (obj->data.loadavg[0])
4024                                         snprintf(p, p_max_size, "%.2f",
4025                                                  v[obj->data.loadavg[0] -
4026                                                    1]);
4027                         }
4028                         OBJ(goto) {
4029                                 new_goto(p, obj->data.i);
4030                         }
4031                         OBJ(tab) {
4032                                 new_tab(p, obj->data.pair.a, obj->data.pair.b);
4033                         }
4034                         OBJ(hr) {
4035                                 new_hr(p, obj->data.i);
4036                         }
4037 #ifdef HDDTEMP
4038                         OBJ(hddtemp) {
4039                                 char *temp;
4040                                 char unit;
4041                                 
4042                                 temp = get_hddtemp_info(obj->data.hddtemp.dev, 
4043                                                 obj->data.hddtemp.addr, obj->data.hddtemp.port, &unit);
4044                                 if (!temp) {
4045                                         snprintf(p, p_max_size, "N/A");
4046                                 } else if (unit == '*') {
4047                                         snprintf(p, p_max_size, "%s", temp);
4048                                 } else {
4049                                          snprintf(p, p_max_size, "%s°%c", temp, unit);
4050                                 }
4051                         }
4052 #endif
4053                         OBJ(offset) {
4054                                 new_offset(p, obj->data.i);
4055                         }
4056                         OBJ(voffset) {
4057                                 new_voffset(p, obj->data.i);
4058                         }
4059                         OBJ(i2c) {
4060                                 double r;
4061
4062                                 r = get_i2c_info(&obj->data.i2c.fd,
4063                                                  obj->data.i2c.arg,
4064                                                  obj->data.i2c.devtype,
4065                                                  obj->data.i2c.type);
4066
4067                                 if (r >= 100.0 || r == 0)
4068                                         snprintf(p, p_max_size, "%d", (int) r);
4069                                 else
4070                                         snprintf(p, p_max_size, "%.1f", r);
4071                         }
4072                         OBJ(alignr) {
4073                                 new_alignr(p, obj->data.i);
4074                         }
4075                         OBJ(alignc) {
4076                                 new_alignc(p, obj->data.i);
4077                         }
4078                         OBJ(if_existing) {
4079                                 struct stat tmp;
4080                                 if ((obj->data.ifblock.s)
4081                                     && (stat(obj->data.ifblock.s, &tmp) ==
4082                                         -1)) {
4083                                         i = obj->data.ifblock.pos;
4084                                         if_jumped = 1;
4085                                 } else {
4086                                         if_jumped = 0;
4087                                 }
4088                         }
4089                         OBJ(if_mounted) {
4090                                 if ((obj->data.ifblock.s)
4091                                     && (!check_mount(obj->data.ifblock.s))) {
4092                                         i = obj->data.ifblock.pos;
4093                                         if_jumped = 1;
4094                                 } else {
4095                                         if_jumped = 0;
4096                                 }
4097                         }
4098                         OBJ(if_running) {
4099                                 if ((obj->data.ifblock.s)
4100                                     && system(obj->data.ifblock.s)) {
4101                                         i = obj->data.ifblock.pos;
4102                                         if_jumped = 1;
4103                                 } else {
4104                                         if_jumped = 0;
4105                                 }
4106                         }
4107                         OBJ(kernel) {
4108                                 snprintf(p, p_max_size, "%s", cur->uname_s.release);
4109                         }
4110                         OBJ(machine) {
4111                                 snprintf(p, p_max_size, "%s", cur->uname_s.machine);
4112                         }
4113
4114                         /* memory stuff */
4115                         OBJ(mem) {
4116                                 human_readable(cur->mem * 1024, p, 255);
4117                         }
4118                         OBJ(memmax) {
4119                                 human_readable(cur->memmax * 1024, p, 255);
4120                         }
4121                         OBJ(memperc) {
4122                                 if (cur->memmax) {
4123                                         if (!use_spacer)
4124                                                 snprintf(p, p_max_size, "%*Lu",
4125                                                          pad_percents,
4126                                                          (cur->mem * 100) /
4127                                                          (cur->memmax));
4128                                         else
4129                                                 snprintf(p, 4, "%*Lu   ",
4130                                                          pad_percents,
4131                                                          (cur->mem * 100) /
4132                                                          (cur->memmax));
4133                                 }
4134                         }
4135                         OBJ(membar) {
4136                                 new_bar(p, obj->data.pair.a,
4137                                         obj->data.pair.b,
4138                                         cur->memmax ? (cur->mem * 255) /
4139                                         (cur->memmax) : 0);
4140                         }
4141
4142                         OBJ(memgraph) {
4143                                 new_graph(p, obj->a,
4144                                 obj->b, obj->c, obj->d,
4145                                 cur->memmax ? (cur->mem * 100.0) /
4146                                                 (cur->memmax) : 0.0, 100, 1);
4147                         }
4148                         /* mixer stuff */
4149                         OBJ(mixer) {
4150                                 snprintf(p, p_max_size, "%d",
4151                                          mixer_get_avg(obj->data.l));
4152                         }
4153                         OBJ(mixerl) {
4154                                 snprintf(p, p_max_size, "%d",
4155                                          mixer_get_left(obj->data.l));
4156                         }
4157                         OBJ(mixerr) {
4158                                 snprintf(p, p_max_size, "%d",
4159                                          mixer_get_right(obj->data.l));
4160                         }
4161                         OBJ(mixerbar) {
4162                                 new_bar(p, obj->data.mixerbar.w,
4163                                         obj->data.mixerbar.h,
4164                                         mixer_get_avg(obj->data.mixerbar.
4165                                                       l) * 255 / 100);
4166                         }
4167                         OBJ(mixerlbar) {
4168                                 new_bar(p, obj->data.mixerbar.w,
4169                                         obj->data.mixerbar.h,
4170                                         mixer_get_left(obj->data.mixerbar.
4171                                                        l) * 255 / 100);
4172                         }
4173                         OBJ(mixerrbar) {
4174                                 new_bar(p, obj->data.mixerbar.w,
4175                                         obj->data.mixerbar.h,
4176                                         mixer_get_right(obj->data.mixerbar.
4177                                                         l) * 255 / 100);
4178                         }
4179
4180                         /* mail stuff */
4181                         OBJ(mails) {
4182                                 snprintf(p, p_max_size, "%d", cur->mail_count);
4183                         }
4184                         OBJ(mboxscan) {
4185                                 mbox_scan(obj->data.mboxscan.args, obj->data.mboxscan.output, text_buffer_size);
4186                                 snprintf(p, p_max_size, "%s", obj->data.mboxscan.output);
4187                         }
4188                         OBJ(new_mails) {
4189                                 snprintf(p, p_max_size, "%d", cur->new_mail_count);
4190                         }
4191
4192                         OBJ(nodename) {
4193                                 snprintf(p, p_max_size, "%s",
4194                                          cur->uname_s.nodename);
4195                         }
4196                         OBJ(outlinecolor) {
4197                                 new_outline(p, obj->data.l);
4198                         }
4199                         OBJ(processes) {
4200                                 if (!use_spacer)
4201                                         snprintf(p, p_max_size, "%hu", cur->procs);
4202                                 else
4203                                         snprintf(p, 5, "%hu    ",
4204                                                  cur->procs);
4205                         }
4206                         OBJ(running_processes) {
4207                                 if (!use_spacer)
4208                                         snprintf(p, p_max_size, "%hu",
4209                                                  cur->run_procs);
4210                                 else
4211                                         snprintf(p, 3, "%hu     ",
4212                                                  cur->run_procs);
4213                         }
4214                         OBJ(text) {
4215                                 snprintf(p, p_max_size, "%s", obj->data.s);
4216                         }
4217                         OBJ(shadecolor) {
4218                                 new_bg(p, obj->data.l);
4219                         }
4220                         OBJ(stippled_hr) {
4221                                 new_stippled_hr(p, obj->data.pair.a,
4222                                                 obj->data.pair.b);
4223                         }
4224                         OBJ(swap) {
4225                                 human_readable(cur->swap * 1024, p, 255);
4226                         }
4227                         OBJ(swapmax) {
4228                                 human_readable(cur->swapmax * 1024, p,
4229                                                255);
4230                         }
4231                         OBJ(swapperc) {
4232                                 if (cur->swapmax == 0) {
4233                                         strncpy(p, "No swap", 255);
4234                                 } else {
4235                                         if (!use_spacer)
4236                                                 snprintf(p, 255, "%*Lu",
4237                                                          pad_percents,
4238                                                          (cur->swap *
4239                                                           100) /
4240                                                          cur->swapmax);
4241                                         else
4242                                                 snprintf(p, 4, "%*Lu   ",
4243                                                          pad_percents,
4244                                                          (cur->swap *
4245                                                           100) /
4246                                                          cur->swapmax);
4247                                 }
4248                         }
4249                         OBJ(swapbar) {
4250                                 new_bar(p, obj->data.pair.a,
4251                                         obj->data.pair.b,
4252                                         cur->swapmax ? (cur->swap * 255) /
4253                                         (cur->swapmax) : 0);
4254                         }
4255                         OBJ(sysname) {
4256                                 snprintf(p, p_max_size, "%s", cur->uname_s.sysname);
4257                         }
4258                         OBJ(time) {
4259                                 time_t t = time(NULL);
4260                                 struct tm *tm = localtime(&t);
4261                                 setlocale(LC_TIME, "");
4262                                 strftime(p, p_max_size, obj->data.s, tm);
4263                         }
4264                         OBJ(utime) {
4265                                 time_t t = time(NULL);
4266                                 struct tm *tm = gmtime(&t);
4267                                 strftime(p, p_max_size, obj->data.s, tm);
4268                         }
4269                         OBJ(tztime) {
4270                                 char* oldTZ = NULL;
4271                                 if (obj->data.tztime.tz) {
4272                                         oldTZ = getenv("TZ");
4273                                         setenv("TZ", obj->data.tztime.tz, 1);
4274                                         tzset();
4275                                 }
4276                                 time_t t = time(NULL);
4277                                 struct tm *tm = localtime(&t);
4278                                 setlocale(LC_TIME, "");
4279                                 strftime(p, p_max_size, obj->data.tztime.fmt, tm);
4280                                 if (oldTZ) {
4281                                         setenv("TZ", oldTZ, 1);
4282                                         tzset();
4283                                 } else {
4284                                         unsetenv("TZ");
4285                                 }
4286                                 // Needless to free oldTZ since getenv gives ptr to static data 
4287                         }
4288                         OBJ(totaldown) {
4289                                 human_readable(obj->data.net->recv, p,
4290                                                255);
4291                         }
4292                         OBJ(totalup) {
4293                                 human_readable(obj->data.net->trans, p,
4294                                                255);
4295                         }
4296                         OBJ(updates) {
4297                                 snprintf(p, p_max_size, "%d", total_updates);
4298                         }
4299                         OBJ(upspeed) {
4300                                 if (!use_spacer)
4301                                         snprintf(p, p_max_size, "%d",
4302                                                  (int) (obj->data.net->
4303                                                         trans_speed /
4304                                                         1024));
4305                                 else
4306                                         snprintf(p, 5, "%d     ",
4307                                                  (int) (obj->data.net->
4308                                                         trans_speed /
4309                                                         1024));
4310                         }
4311                         OBJ(upspeedf) {
4312                                 if (!use_spacer)
4313                                         snprintf(p, p_max_size, "%.1f",
4314                                                  obj->data.net->
4315                                                  trans_speed / 1024.0);
4316                                 else
4317                                         snprintf(p, 8, "%.1f       ",
4318                                                  obj->data.net->
4319                                                  trans_speed / 1024.0);
4320                         }
4321                         OBJ(upspeedgraph) {
4322         /*
4323                                 if (obj->data.net->trans_speed == 0)
4324                                         obj->data.net->trans_speed = 0.01;
4325           */
4326                                 new_graph(p, obj->a, obj->b, obj->c, obj->d,
4327                                           (obj->data.net->trans_speed /
4328                                 1024.0), obj->e, 1);
4329                         }
4330                         OBJ(uptime_short) {
4331                                 format_seconds_short(p, p_max_size,
4332                                                      (int) cur->uptime);
4333                         }
4334                         OBJ(uptime) {
4335                                 format_seconds(p, p_max_size, (int) cur->uptime);
4336                         }
4337
4338 #if defined(__FreeBSD__) && (defined(i386) || defined(__i386__))
4339                         OBJ(apm_adapter) {
4340                                 snprintf(p, p_max_size, "%s", get_apm_adapter());
4341                         }
4342                         OBJ(apm_battery_life) {
4343                                 char    *msg;
4344                                 msg = get_apm_battery_life();
4345                                 snprintf(p, p_max_size, "%s", msg);
4346                                 free(msg);
4347                         }
4348                         OBJ(apm_battery_time) {
4349                                 char    *msg;
4350                                 msg = get_apm_battery_time();
4351                                 snprintf(p, p_max_size, "%s", msg);
4352                                 free(msg);
4353                         }
4354 #endif /* __FreeBSD__ */
4355
4356 #ifdef MPD
4357                         OBJ(mpd_title) {
4358                                 snprintf(p, p_max_size, "%s", cur->mpd.title);
4359                         }
4360                         OBJ(mpd_artist) {
4361                                 snprintf(p, p_max_size, "%s", cur->mpd.artist);
4362                         }
4363                         OBJ(mpd_album) {
4364                                 snprintf(p, p_max_size, "%s", cur->mpd.album);
4365                         }
4366                         OBJ(mpd_random) {
4367                                 snprintf(p, p_max_size, "%s", cur->mpd.random);
4368                         }
4369                         OBJ(mpd_repeat) {
4370                                 snprintf(p, p_max_size, "%s", cur->mpd.repeat);
4371                         }
4372                         OBJ(mpd_track) {
4373                                 snprintf(p, p_max_size, "%s", cur->mpd.track);
4374                         }
4375                         OBJ(mpd_name) {
4376                                 snprintf(p, p_max_size, "%s", cur->mpd.name);
4377                         }
4378                         OBJ(mpd_file) {
4379                                 snprintf(p, p_max_size, "%s", cur->mpd.file);
4380                         }
4381                         OBJ(mpd_vol) {
4382                                 snprintf(p, p_max_size, "%i", cur->mpd.volume);
4383                         }
4384                         OBJ(mpd_bitrate) {
4385                                 snprintf(p, p_max_size, "%i", cur->mpd.bitrate);
4386                         }
4387                         OBJ(mpd_status) {
4388                                 snprintf(p, p_max_size, "%s", cur->mpd.status);
4389                         }
4390                         OBJ(mpd_elapsed) {
4391                                 int days = 0, hours = 0, minutes =
4392                                     0, seconds = 0;
4393                                 int tmp = cur->mpd.elapsed;
4394                                 while (tmp >= 86400) {
4395                                         tmp -= 86400;
4396                                         days++;
4397                                 }
4398                                 while (tmp >= 3600) {
4399                                         tmp -= 3600;
4400                                         hours++;
4401                                 }
4402                                 while (tmp >= 60) {
4403                                         tmp -= 60;
4404                                         minutes++;
4405                                 }
4406                                 seconds = tmp;
4407                                 if (days > 0)
4408                                         snprintf(p, p_max_size, "%i days %i:%02i:%02i",
4409                                                  days, hours, minutes,
4410                                                  seconds);
4411                                 else if (hours > 0)
4412                                         snprintf(p, p_max_size, "%i:%02i:%02i", hours,
4413                                                  minutes, seconds);
4414                                 else
4415                                         snprintf(p, p_max_size, "%i:%02i", minutes,
4416                                                  seconds);
4417                         }
4418                         OBJ(mpd_length) {
4419                                 int days = 0, hours = 0, minutes =
4420                                     0, seconds = 0;
4421                                 int tmp = cur->mpd.length;
4422                                 while (tmp >= 86400) {
4423                                         tmp -= 86400;
4424                                         days++;
4425                                 }
4426                                 while (tmp >= 3600) {
4427                                         tmp -= 3600;
4428                                         hours++;
4429                                 }
4430                                 while (tmp >= 60) {
4431                                         tmp -= 60;
4432                                         minutes++;
4433                                 }
4434                                 seconds = tmp;
4435                                 if (days > 0)
4436                                         snprintf(p, p_max_size,
4437                                                  "%i days %i:%02i:%02i",
4438                                                  days, hours, minutes,
4439                                                  seconds);
4440                                 else if (hours > 0)
4441                                         snprintf(p, p_max_size, "%i:%02i:%02i", hours,
4442                                                  minutes, seconds);
4443                                 else
4444                                         snprintf(p, p_max_size, "%i:%02i", minutes,
4445                                                  seconds);
4446                         }
4447                         OBJ(mpd_percent) {
4448                                 snprintf(p, p_max_size, "%2.0f",
4449                                          cur->mpd.progress * 100);
4450                         }
4451                         OBJ(mpd_bar) {
4452                                 new_bar(p, obj->data.pair.a,
4453                                         obj->data.pair.b,
4454                                         (int) (cur->mpd.progress *
4455                                                255.0f));
4456                         }
4457                         OBJ(mpd_smart) {
4458                                 if (strlen(cur->mpd.title) < 2 && strlen(cur->mpd.title) < 2) {
4459                                         snprintf(p, p_max_size, "%s", cur->mpd.file);
4460                                 } else {
4461                                         snprintf(p, p_max_size, "%s - %s", cur->mpd.artist, cur->mpd.title);
4462                                 }
4463                         }
4464 #endif
4465 #ifdef XMMS2
4466                         OBJ(xmms2_artist) {
4467                                 snprintf(p, p_max_size, "%s", cur->xmms2.artist);
4468                         }
4469                         OBJ(xmms2_album) {
4470                                 snprintf(p, p_max_size, "%s", cur->xmms2.album);
4471                         }
4472                         OBJ(xmms2_title) {
4473                                 snprintf(p, p_max_size, "%s", cur->xmms2.title);
4474                         }
4475                         OBJ(xmms2_genre) {
4476                                 snprintf(p, p_max_size, "%s", cur->xmms2.genre);
4477                         }
4478                         OBJ(xmms2_comment) {
4479                                 snprintf(p, p_max_size, "%s", cur->xmms2.comment);
4480                         }
4481                         OBJ(xmms2_decoder) {
4482                                 snprintf(p, p_max_size, "%s", cur->xmms2.decoder);
4483                         }
4484                         OBJ(xmms2_transport) {
4485                                 snprintf(p, p_max_size, "%s", cur->xmms2.transport);
4486                         }
4487                         OBJ(xmms2_url) {
4488                                 snprintf(p, p_max_size, "%s", cur->xmms2.url);
4489                         }
4490                         OBJ(xmms2_status) {
4491                                 snprintf(p, p_max_size, "%s", cur->xmms2.status);
4492                         }
4493             OBJ(xmms2_date) {
4494                     snprintf(p, p_max_size, "%s", cur->xmms2.date);
4495                         }
4496                         OBJ(xmms2_tracknr) {
4497                             if (cur->xmms2.tracknr != -1)
4498                     snprintf(p, p_max_size, "%i", cur->xmms2.tracknr);
4499                         }
4500                         OBJ(xmms2_bitrate) {
4501                                 snprintf(p, p_max_size, "%i", cur->xmms2.bitrate);
4502                         }
4503             OBJ(xmms2_id) {
4504                                 snprintf(p, p_max_size, "%u", cur->xmms2.id);
4505                         }
4506             OBJ(xmms2_size) {
4507                                 snprintf(p, p_max_size, "%2.1f", cur->xmms2.size);
4508                         }
4509                         OBJ(xmms2_elapsed) {
4510                                 int tmp = cur->xmms2.elapsed;
4511                                 snprintf(p, p_max_size, "%02d:%02d",
4512                                     tmp / 60000, (tmp / 1000) % 60);
4513                         }
4514                         OBJ(xmms2_duration) {
4515                                 int tmp = cur->xmms2.duration;
4516                                 snprintf(p, p_max_size, "%02d:%02d",
4517                                     tmp / 60000, (tmp / 1000) % 60);
4518                         }
4519                         OBJ(xmms2_percent) {
4520                                 snprintf(p, p_max_size, "%2.0f",
4521                                          cur->xmms2.progress * 100);
4522                         }
4523                         OBJ(xmms2_bar) {
4524                                 new_bar(p, obj->data.pair.a,
4525                                         obj->data.pair.b,
4526                                         (int) (cur->xmms2.progress *
4527                                                255.0f));
4528                         }
4529                         OBJ(xmms2_smart) {
4530                                 if (strlen(cur->xmms2.title) < 2 && strlen(cur->xmms2.title) < 2) {
4531                                         snprintf(p, p_max_size, "%s", cur->xmms2.url);
4532                                 } else {
4533                                         snprintf(p, p_max_size, "%s - %s", cur->xmms2.artist, cur->xmms2.title);
4534                                 }
4535                         }
4536 #endif
4537 #ifdef AUDACIOUS
4538                         OBJ(audacious_status) {
4539                             snprintf(p, p_max_size, "%s", cur->audacious.items[AUDACIOUS_STATUS]);
4540                         }
4541                         OBJ(audacious_title) {
4542                             snprintf(p, cur->audacious.max_title_len > 0 ?
4543                                         cur->audacious.max_title_len : p_max_size, "%s", 
4544                                      cur->audacious.items[AUDACIOUS_TITLE]);
4545                         }
4546                         OBJ(audacious_length) {
4547                             snprintf(p, p_max_size, "%s", cur->audacious.items[AUDACIOUS_LENGTH]);
4548                         }
4549                         OBJ(audacious_length_seconds) {
4550                             snprintf(p, p_max_size, "%s", cur->audacious.items[AUDACIOUS_LENGTH_SECONDS]);
4551                         }
4552                         OBJ(audacious_position) {
4553                             snprintf(p, p_max_size, "%s", cur->audacious.items[AUDACIOUS_POSITION]);
4554                         }
4555                         OBJ(audacious_position_seconds) {
4556                             snprintf(p, p_max_size, "%s", cur->audacious.items[AUDACIOUS_POSITION_SECONDS]);
4557                         }
4558                         OBJ(audacious_bitrate) {
4559                             snprintf(p, p_max_size, "%s", cur->audacious.items[AUDACIOUS_BITRATE]);
4560                         }
4561                         OBJ(audacious_frequency) {
4562                             snprintf(p, p_max_size, "%s", cur->audacious.items[AUDACIOUS_FREQUENCY]);
4563                         }
4564                         OBJ(audacious_channels) {
4565                             snprintf(p, p_max_size, "%s", cur->audacious.items[AUDACIOUS_CHANNELS]);
4566                         }
4567                         OBJ(audacious_filename) {
4568                             snprintf(p, p_max_size, "%s", cur->audacious.items[AUDACIOUS_FILENAME]);
4569                         }
4570                         OBJ(audacious_playlist_length) {
4571                             snprintf(p, p_max_size, "%s", cur->audacious.items[AUDACIOUS_PLAYLIST_LENGTH]);
4572                         }
4573                         OBJ(audacious_playlist_position) {
4574                             snprintf(p, p_max_size, "%s", cur->audacious.items[AUDACIOUS_PLAYLIST_POSITION]);
4575                         }
4576                         OBJ(audacious_bar) {
4577                             double progress;
4578                             progress= atof(cur->audacious.items[AUDACIOUS_POSITION_SECONDS]) /
4579                                       atof(cur->audacious.items[AUDACIOUS_LENGTH_SECONDS]);
4580                             new_bar(p,obj->a,obj->b,(int)(progress*255.0f));
4581                         }
4582 #endif
4583 #ifdef BMPX
4584                         OBJ(bmpx_title) {
4585                                 snprintf(p, p_max_size, "%s", cur->bmpx.title);
4586                         }
4587                         OBJ(bmpx_artist) {
4588                                 snprintf(p, p_max_size, "%s", cur->bmpx.artist);
4589                         }
4590                         OBJ(bmpx_album) {
4591                                 snprintf(p, p_max_size, "%s", cur->bmpx.album);
4592                         }
4593                         OBJ(bmpx_uri) {
4594                                 snprintf(p, p_max_size, "%s", cur->bmpx.uri);
4595                         }
4596                         OBJ(bmpx_track) {
4597                                  snprintf(p, p_max_size, "%i", cur->bmpx.track);
4598                         }
4599                         OBJ(bmpx_bitrate) {
4600                                 snprintf(p, p_max_size, "%i", cur->bmpx.bitrate);
4601                         }
4602 #endif
4603                         OBJ(top) {
4604                                 if (obj->data.top.type == TOP_NAME
4605                                     && obj->data.top.num >= 0
4606                                     && obj->data.top.num < 10) {
4607                                         // if we limit the buffer and add a bunch of space after, it stops the thing from
4608                                         // moving other shit around, which is really fucking annoying
4609                                         snprintf(p, 17, "%s                              ", cur->cpu[obj->data.top.num]->name);
4610                                 } else if (obj->data.top.type == TOP_CPU
4611                                            && obj->data.top.num >= 0
4612                                            && obj->data.top.num < 10) {
4613                                         snprintf(p, 7, "%3.2f      ",
4614                                                  cur->cpu[obj->data.top.
4615                                                           num]->amount);
4616                                 } else if (obj->data.top.type == TOP_PID
4617                                            && obj->data.top.num >= 0
4618                                            && obj->data.top.num < 10) {
4619                                         snprintf(p, 8, "%i           ",
4620                                                  cur->cpu[obj->data.top.
4621                                                           num]->pid);
4622                                 } else if (obj->data.top.type == TOP_MEM
4623                                            && obj->data.top.num >= 0
4624                                            && obj->data.top.num < 10) {
4625                                         snprintf(p, 7, "%3.2f       ",
4626                                                  cur->cpu[obj->data.top.
4627                                                           num]->totalmem);
4628                                 }
4629                         }
4630                         OBJ(top_mem) {
4631                                 if (obj->data.top.type == TOP_NAME
4632                                     && obj->data.top.num >= 0
4633                                     && obj->data.top.num < 10) {
4634                                         // if we limit the buffer and add a bunch of space after, it stops the thing from
4635                                         // moving other shit around, which is really fucking annoying
4636                                         snprintf(p, 17,
4637                                                  "%s                              ",
4638                                                  cur->memu[obj->data.top.
4639                                                            num]->name);
4640                                 } else if (obj->data.top.type == TOP_CPU
4641                                            && obj->data.top.num >= 0
4642                                            && obj->data.top.num < 10) {
4643                                         snprintf(p, 7, "%3.2f      ",
4644                                                  cur->memu[obj->data.top.
4645                                                            num]->amount);
4646                                 } else if (obj->data.top.type == TOP_PID
4647                                            && obj->data.top.num >= 0
4648                                            && obj->data.top.num < 10) {
4649                                         snprintf(p, 8, "%i           ",
4650                                                  cur->memu[obj->data.top.
4651                                                            num]->pid);
4652                                 } else if (obj->data.top.type == TOP_MEM
4653                                            && obj->data.top.num >= 0
4654                                            && obj->data.top.num < 10) {
4655                                         snprintf(p, 7, "%3.2f       ",
4656                                                  cur->memu[obj->data.top.
4657                                                            num]->totalmem);
4658                                 }
4659                         }
4660
4661
4662                         OBJ(tail) {
4663                                 if (current_update_time -obj->data.tail.last_update < obj->data.tail.interval) {
4664                                                         snprintf(p, p_max_size, "%s", obj->data.tail.buffer);
4665                                 } else {
4666                                         obj->data.tail.last_update = current_update_time;
4667                                         FILE *fp;
4668                                         long nl=0, bsize;
4669                                         int iter;
4670                                         fp = fopen(obj->data.tail.logfile, "rt");
4671                                         if (fp == NULL) {
4672                                                 /* Send one message, but do not consistently spam on
4673                                                  * missing logfiles. */
4674                                                 if(obj->data.tail.readlines != 0) {
4675                                                         ERR("tail logfile failed to open");
4676                                                         strcpy(obj->data.tail.buffer, "Logfile Missing");
4677                                                 }
4678                                                 obj->data.tail.readlines = 0;
4679                                                 snprintf(p, p_max_size, "Logfile Missing");
4680                                         }
4681                                         else {
4682                                                 obj->data.tail.readlines = 0;
4683                                                 /* -1 instead of 0 to avoid counting a trailing newline */
4684                                                 fseek(fp, -1, SEEK_END); 
4685                                                 bsize = ftell(fp) + 1;
4686                                                 for(iter = obj->data.tail.wantedlines; iter > 0; iter--) {
4687                                                         nl = rev_fcharfind(fp, '\n', iter);
4688                                                         if(nl >= 0)
4689                                                                 break;
4690                                                 }
4691                                                 obj->data.tail.readlines = iter;
4692                                                 if(obj->data.tail.readlines < obj->data.tail.wantedlines) {
4693                                                         fseek(fp, 0, SEEK_SET);
4694                                                 }
4695                                                 else {
4696                                                         fseek(fp, nl+1, SEEK_SET);
4697                                                         bsize -= ftell(fp);
4698                                                 }
4699                                                 /* Make sure bsize is at least 1 byte smaller than
4700                                                  * the buffer max size. */
4701                                                 if(bsize > text_buffer_size*20 - 1) {
4702                                                         fseek(fp, bsize - text_buffer_size*20 - 1, SEEK_CUR);
4703                                                         bsize = text_buffer_size*20 - 1;
4704                                                 }
4705                                                 bsize = fread(obj->data.tail.buffer, 1, bsize, fp);
4706                                                 fclose(fp);
4707                                                 if(bsize > 0) {
4708                                                         /* Clean up trailing newline, make sure the buffer
4709                                                          * is null terminated. */
4710                                                         if(obj->data.tail.buffer[bsize-1] == '\n')
4711                                                                 obj->data.tail.buffer[bsize-1] = '\0';
4712                                                         else
4713                                                                 obj->data.tail.buffer[bsize] = '\0';
4714                                                         snprintf(p, p_max_size, "%s", obj->data.tail.buffer);
4715                                                 }
4716                                                 else {
4717                                                         strcpy(obj->data.tail.buffer, "Logfile Empty");
4718                                                         snprintf(p, p_max_size, "Logfile Empty");
4719                                                 } /* bsize > 0 */
4720                                         } /*  fp == NULL  */
4721                                 } /* if cur_upd_time >= */
4722
4723                                 //parse_conky_vars(obj->data.tail.buffer, p, cur);
4724
4725                         }
4726                         OBJ(head) {
4727                                 if (current_update_time -obj->data.tail.last_update < obj->data.tail.interval) {
4728                                         snprintf(p, p_max_size, "%s", obj->data.tail.buffer);
4729                                 } else {
4730                                         obj->data.tail.last_update = current_update_time;
4731                                         FILE *fp;
4732                                         long nl=0;
4733                                         int iter;
4734                                         fp = fopen(obj->data.tail.logfile, "rt");
4735                                         if (fp == NULL) {
4736                                                 /* Send one message, but do not consistently spam on
4737                                                  * missing logfiles. */
4738                                                 if(obj->data.tail.readlines != 0) {
4739                                                         ERR("head logfile failed to open");
4740                                                         strcpy(obj->data.tail.buffer, "Logfile Missing");
4741                                                 }
4742                                                 obj->data.tail.readlines = 0;
4743                                                 snprintf(p, p_max_size, "Logfile Missing");
4744                                         } else {
4745                                                 obj->data.tail.readlines = 0;
4746                                                 for(iter = obj->data.tail.wantedlines; iter > 0; iter--) {
4747                                                         nl = fwd_fcharfind(fp, '\n', iter);
4748                                                         if(nl >= 0)
4749                                                                 break;
4750                                                 }
4751                                                 obj->data.tail.readlines = iter;
4752                                                 /* Make sure nl is at least 1 byte smaller than
4753                                                  * the buffer max size. */
4754                                                 if(nl > text_buffer_size*20 - 1) {
4755                                                         nl = text_buffer_size*20 - 1;
4756                                                 }
4757                                                 nl = fread(obj->data.tail.buffer, 1, nl, fp);
4758                                                 fclose(fp);
4759                                                 if(nl > 0) {
4760                                                         /* Clean up trailing newline, make sure the buffer
4761                                                          * is null terminated. */
4762                                                         if (obj->data.tail.buffer[nl-1] == '\n') {
4763                                                                 obj->data.tail.buffer[nl-1] = '\0';
4764                                                         }
4765                                                         else {
4766                                                                 obj->data.tail.buffer[nl] = '\0';
4767                                                         }
4768                                                         snprintf(p, p_max_size, "%s", obj->data.tail.buffer);
4769                                                 } 
4770                                                 else {
4771                                                         strcpy(obj->data.tail.buffer, "Logfile Empty");
4772                                                         snprintf(p, p_max_size, "Logfile Empty");
4773                                                 } /* nl > 0 */
4774                                         } /* if fp == null */
4775                                 } /* cur_upd_time >= */
4776
4777                                 //parse_conky_vars(obj->data.tail.buffer, p, cur);
4778
4779                         }
4780 #ifdef TCP_PORT_MONITOR
4781                         OBJ(tcp_portmon)
4782                         {
4783                                 /* grab a pointer to this port monitor */
4784                                 tcp_port_monitor_t * p_monitor = 
4785                                         find_tcp_port_monitor( info.p_tcp_port_monitor_collection,
4786                                                                 obj->data.tcp_port_monitor.port_range_begin,
4787                                                                 obj->data.tcp_port_monitor.port_range_end );
4788                                 if ( !p_monitor ) {
4789                                         snprintf(p, p_max_size, "monitor not found");
4790                                         break;
4791                                 }
4792
4793                                 /* now grab the text of interest */
4794                                 if ( peek_tcp_port_monitor( p_monitor, 
4795                                                             obj->data.tcp_port_monitor.item, 
4796                                                             obj->data.tcp_port_monitor.connection_index,
4797                                                             p, p_max_size ) != 0 )
4798                                 {
4799                                         snprintf(p, p_max_size, "monitor peek error");
4800                                         break;
4801                                 }
4802                         }
4803 #endif
4804
4805 #ifdef HAVE_ICONV
4806                         OBJ(iconv_start)
4807                         {
4808                                 iconv_converting = 1;
4809                                 iconv_selected = obj->a;
4810                                 
4811                         }
4812                         OBJ(iconv_stop)
4813                         {
4814                                 iconv_converting = 0;
4815                                 iconv_selected = 0;
4816                         }
4817 #endif
4818                         OBJ(entropy_avail) 
4819                         {
4820                                 snprintf(p, p_max_size, "%d", cur->entropy.entropy_avail);
4821                         }
4822                         OBJ(entropy_poolsize)
4823                         {
4824                                 snprintf(p, p_max_size, "%d", cur->entropy.poolsize);
4825                         }
4826                         OBJ(entropy_bar)
4827                         {
4828                                 double entropy_perc;
4829                                 entropy_perc = (double)cur->entropy.entropy_avail / 
4830                                                (double)cur->entropy.poolsize;
4831                                 new_bar(p,obj->a,obj->b,(int)(entropy_perc * 255.0f));
4832                         }
4833
4834
4835                         break;
4836                 }
4837
4838                 {
4839                         unsigned int a = strlen(p);
4840
4841 #ifdef HAVE_ICONV
4842                         if (a > 0 && iconv_converting && iconv_selected > 0 && (iconv_cd[iconv_selected - 1] != (iconv_t)(-1))) {
4843                                 int bytes;
4844                                 size_t dummy1, dummy2;
4845                                 char *ptr = buff_in;
4846                                 char *outptr = p;
4847
4848                                 dummy1 = dummy2 = a;
4849                                 
4850                                 strncpy(buff_in, p, P_MAX_SIZE);
4851
4852                                 iconv(*iconv_cd[iconv_selected - 1], NULL, NULL, NULL, NULL);
4853                                 while (dummy1 > 0) {
4854                                         bytes = iconv(*iconv_cd[iconv_selected - 1], &ptr, &dummy1, &outptr, &dummy2);
4855                                         if (bytes == -1) {
4856                                                 ERR("Iconv codeset conversion failed");
4857                                                 break;
4858                                         }
4859                                 }
4860
4861                                 /* It is nessecary when we are converting from multibyte to singlebyte codepage */
4862                                 a = outptr - p;
4863                         }
4864 #endif
4865                         p += a;
4866                         p_max_size -= a;
4867                 }
4868         }
4869 }
4870
4871
4872 double current_update_time, last_update_time;
4873
4874 static void generate_text()
4875 {
4876         struct information *cur = &info;
4877         char *p;
4878
4879
4880         special_count = 0;
4881
4882         /* update info */
4883
4884         current_update_time = get_time();
4885
4886         update_stuff(cur);
4887         /* fix diskio rates to b/s (use update_interval */
4888         diskio_read_value = diskio_read_value / update_interval;
4889         diskio_write_value = diskio_write_value / update_interval;
4890         diskio_value = diskio_value / update_interval;
4891         
4892
4893         /* add things to the buffer */
4894
4895         /* generate text */
4896
4897         p = text_buffer;
4898
4899         generate_text_internal(p, P_MAX_SIZE, text_objects, text_object_count, cur);
4900
4901         if (stuff_in_upper_case) {
4902                 char *p;
4903
4904                 p = text_buffer;
4905                 while (*p) {
4906                         *p = toupper(*p);
4907                         p++;
4908                 }
4909         }
4910
4911
4912         last_update_time = current_update_time;
4913         total_updates++;
4914         //free(p);
4915 }
4916
4917
4918 #ifdef X11
4919 static void set_font()
4920 {
4921 #ifdef XFT
4922         if (use_xft) {
4923                         if (window.xftdraw != NULL) {
4924                                 XftDrawDestroy(window.xftdraw);
4925                         }
4926                         window.xftdraw = XftDrawCreate(display, window.drawable,
4927                                         DefaultVisual(display,
4928                                                         screen),
4929                                         DefaultColormap(display,
4930                                                         screen));
4931                 } else
4932 #endif
4933 {
4934         XSetFont(display, window.gc, fonts[selected_font].font->fid);
4935 }
4936 }
4937
4938 #endif /* X11 */
4939
4940 static inline int get_string_width(const char *s)
4941 {
4942 #ifdef X11
4943         return *s ? calc_text_width(s, strlen(s)) : 0;
4944 #else
4945         return strlen(s);
4946 #endif /* X11 */
4947 }
4948
4949 static inline int get_string_width_special(char *s)
4950 {
4951         if (!s) {
4952                 return 0;
4953         }
4954 #ifdef X11
4955         char *p, *final;
4956         p = strdup(s);
4957         final = p;
4958         int index = 1;
4959         int width = 0;
4960         unsigned int i;
4961         while (*p) {
4962                 if (*p == SPECIAL_CHAR) {
4963                         /* shift everything over by 1 so that the special char doesn't mess up the size calculation */
4964                         for (i = 0; i < strlen(p); i++) {
4965                                 *(p + i) = *(p + i + 1);
4966                         }
4967                         if (specials[special_index+index].type == GRAPH || specials[special_index+index].type == BAR) {
4968                                 width += specials[special_index+index].width;
4969                         }
4970                         index++;
4971                 } else {
4972                         p++;
4973                 }
4974         }
4975         if (strlen(final) > 1) {
4976                 width += calc_text_width(final, strlen(final));
4977         }
4978         free(final);
4979         return width;
4980 #else
4981         return strlen(s);
4982 #endif /* X11 */
4983 }
4984
4985 #ifdef X11
4986 static void text_size_updater(char *s);
4987
4988 int last_font_height;
4989 static void update_text_area()
4990 {
4991         int x, y;
4992
4993         /* update text size if it isn't fixed */
4994 #ifdef OWN_WINDOW
4995         if (!fixed_size)
4996 #endif
4997         {
4998                 text_width = minimum_width;
4999                 text_height = 0;
5000                 special_index = 0;
5001                 last_font_height = font_height();
5002                 for_each_line(text_buffer, text_size_updater);
5003                 text_width += 1;
5004                 if (text_height < minimum_height)
5005                         text_height = minimum_height;
5006                 if (text_width > maximum_width && maximum_width > 0)
5007                         text_width = maximum_width;
5008         }
5009
5010         /* get text position on workarea */
5011         switch (text_alignment) {
5012         case TOP_LEFT:
5013                 x = gap_x;
5014                 y = gap_y;
5015                 break;
5016
5017         case TOP_RIGHT:
5018                 x = workarea[2] - text_width - gap_x;
5019                 y = gap_y;
5020                 break;
5021
5022         default:
5023         case BOTTOM_LEFT:
5024                 x = gap_x;
5025                 y = workarea[3] - text_height - gap_y;
5026                 break;
5027
5028         case BOTTOM_RIGHT:
5029                 x = workarea[2] - text_width - gap_x;
5030                 y = workarea[3] - text_height - gap_y;
5031                 break;
5032         
5033 #ifdef OWN_WINDOW
5034         case NONE: // Let the WM manage the window
5035                 x = window.x;
5036                 y = window.y;
5037
5038                 fixed_pos  = 1;
5039                 fixed_size = 1;
5040                 break;
5041 #endif
5042         }
5043 #ifdef OWN_WINDOW
5044
5045         if (own_window && !fixed_pos) {
5046                 x += workarea[0];
5047                 y += workarea[1];
5048                 text_start_x = border_margin + 1;
5049                 text_start_y = border_margin + 1;
5050                 window.x = x - border_margin - 1;
5051                 window.y = y - border_margin - 1;
5052         } else
5053 #endif
5054         {
5055                 /* If window size doesn't match to workarea's size, then window
5056                  * probably includes panels (gnome).
5057                  * Blah, doesn't work on KDE. */
5058                 if (workarea[2] != window.width
5059                     || workarea[3] != window.height) {
5060                         y += workarea[1];
5061                         x += workarea[0];
5062                 }
5063
5064                 text_start_x = x;
5065                 text_start_y = y;
5066         }
5067 }
5068
5069 /*
5070  * drawing stuff
5071  */
5072
5073 static int cur_x, cur_y;        /* current x and y for drawing */
5074 static int draw_mode;           /* FG, BG or OUTLINE */
5075 static long current_color;
5076
5077 #ifdef X11
5078 static void text_size_updater(char *s)
5079 {
5080         int w = 0;
5081         char *p;
5082         /* get string widths and skip specials */
5083         p = s;
5084         while (*p) {
5085                 if (*p == SPECIAL_CHAR) {
5086                         *p = '\0';
5087                         w += get_string_width(s);
5088                         *p = SPECIAL_CHAR;
5089
5090                         if (specials[special_index].type == BAR
5091                             || specials[special_index].type == GRAPH) {
5092                                 w += specials[special_index].width;
5093                                 if (specials[special_index].height > last_font_height) {
5094                                         last_font_height = specials[special_index].height;
5095                                         last_font_height += font_ascent();
5096                                 }
5097                         } else if (specials[special_index].type == OFFSET) {
5098                                 w += specials[special_index].arg + get_string_width("a"); /* filthy, but works */
5099                         } else if (specials[special_index].type == VOFFSET) {
5100                                 last_font_height += specials[special_index].arg;
5101                         } else if (specials[special_index].type == GOTO) {
5102                                 if (specials[special_index].arg >= 0)
5103                                         w += (int)specials[special_index].arg - cur_x;
5104                         } else if (specials[special_index].type == TAB) { 
5105                                 int start = specials[special_index].arg;
5106                                 int step = specials[special_index].width;
5107                                 if (!step || step < 0)
5108                                         step = 10;
5109                                 w += step - (cur_x - text_start_x - start) % step;
5110                         } else if (specials[special_index].type == FONT) {
5111                                 selected_font = specials[special_index].font_added;
5112                                 if (font_height() > last_font_height) {
5113                                         last_font_height = font_height();
5114                                 }
5115                         }
5116                         
5117                         special_index++;
5118                         s = p + 1;
5119                 }
5120                 p++;
5121         }
5122         w += get_string_width(s);
5123         if (w > text_width) {
5124                 text_width = w;
5125         }
5126         if (text_width > maximum_width && maximum_width) {
5127                 text_width = maximum_width;
5128         }
5129
5130         text_height += last_font_height;
5131         last_font_height = font_height();
5132 }
5133 #endif /* X11 */
5134
5135 static inline void set_foreground_color(long c)
5136 {
5137         current_color = c;
5138         XSetForeground(display, window.gc, c);
5139 }
5140 #endif /* X11 */
5141
5142 static void draw_string(const char *s)
5143 {
5144         if (s[0] == '\0')
5145                 return;
5146         int i, i2, pos, width_of_s;
5147         int max=0;
5148         int added;
5149         width_of_s = get_string_width(s);
5150         if (out_to_console) {
5151                 printf("%s\n", s);
5152                 fflush(stdout);   /* output immediately, don't buffer */
5153         }
5154         memset(tmpstring1,0,TEXT_BUFFER_SIZE);
5155         memset(tmpstring2,0,TEXT_BUFFER_SIZE);
5156         strncpy(tmpstring1, s, TEXT_BUFFER_SIZE-1);
5157         pos = 0;
5158         added = 0;
5159         char space[2];
5160         snprintf(space, 2, " ");
5161 #ifdef X11
5162         max = ((text_width - width_of_s) / get_string_width(space));
5163 #endif /* X11 */
5164         /*
5165          * This code looks for tabs in the text and coverts them to spaces.
5166          * The trick is getting the correct number of spaces,
5167          * and not going over the window's size without forcing
5168          * the window larger.
5169          */
5170         for (i = 0; i < TEXT_BUFFER_SIZE; i++) {
5171                 if (tmpstring1[i] == '\t')      // 9 is ascii tab
5172                 {
5173                         i2 = 0;
5174                         for (i2 = 0;
5175                              i2 < (8 - (1 + pos) % 8) && added <= max;
5176                              i2++) {
5177                                 /*
5178                                 if ( pos + i2 > TEXT_BUFFER_SIZE-1 )
5179                                         fprintf(stderr,"buffer overrun detected\n");
5180                                 */
5181                                 tmpstring2[ MIN(pos + i2, TEXT_BUFFER_SIZE-1) ] = ' '; /* guard against overrun */
5182                                 added++;
5183                         }
5184                         pos += i2;
5185                 } else {
5186                         if (tmpstring1[i] != 9) {
5187                                 /*
5188                                 if ( pos > TEXT_BUFFER_SIZE-1 )
5189                                          fprintf(stderr,"buffer overrun detected\n");
5190                                 */
5191                                 tmpstring2[ MIN(pos, TEXT_BUFFER_SIZE-1) ] = tmpstring1[i]; /* guard against overrun */
5192                                 pos++;
5193                         }
5194                 }
5195         }
5196 #ifdef X11
5197         if (text_width == maximum_width) {
5198                 /* this means the text is probably pushing the limit, so we'll chop it */
5199                 while (cur_x + get_string_width(tmpstring2) - text_start_x > maximum_width && strlen(tmpstring2) > 0) {
5200                         tmpstring2[strlen(tmpstring2)-1] = '\0';
5201                 }
5202         }
5203 #endif /* X11 */
5204         s = tmpstring2;
5205 #ifdef X11
5206 #ifdef XFT
5207         if (use_xft) {
5208                 XColor c;
5209                 XftColor c2;
5210                 c.pixel = current_color;
5211                 XQueryColor(display, DefaultColormap(display, screen), &c);
5212
5213                 c2.pixel = c.pixel;
5214                 c2.color.red = c.red;
5215                 c2.color.green = c.green;
5216                 c2.color.blue = c.blue;
5217                 c2.color.alpha = fonts[selected_font].font_alpha;
5218                 if (utf8_mode) {
5219                         XftDrawStringUtf8(window.xftdraw, &c2, fonts[selected_font].xftfont,
5220                                           cur_x, cur_y, (XftChar8 *) s,
5221                                           strlen(s));
5222                 } else {
5223                         XftDrawString8(window.xftdraw, &c2, fonts[selected_font].xftfont,
5224                                        cur_x, cur_y, (XftChar8 *) s,
5225                                        strlen(s));
5226                 }
5227         } else
5228 #endif
5229         {
5230                 XDrawString(display, window.drawable, window.gc,
5231                             cur_x, cur_y, s, strlen(s));
5232         }
5233         cur_x += width_of_s;
5234 #endif /* X11 */
5235         memcpy(tmpstring1, s, TEXT_BUFFER_SIZE);
5236 }
5237
5238 long redmask, greenmask, bluemask;
5239
5240 void set_up_gradient()
5241 {
5242 #ifdef X11
5243         colour_depth = DisplayPlanes(display, screen);
5244 #else
5245         colour_depth = 16;
5246 #endif /* X11 */
5247         if (colour_depth != 24 && colour_depth != 16) {
5248                 ERR("using non-standard colour depth, gradients may look like a lolly-pop");
5249         }
5250         int i;
5251         redmask = 0;
5252         greenmask = 0;
5253         bluemask = 0;
5254         for(i = (colour_depth / 3)-1; i>=0; i--) {
5255                 redmask |= 1 << i;
5256                 greenmask |= 1 << i;
5257                 bluemask |= 1 << i;
5258         }
5259         if (colour_depth%3 == 1) {
5260                 greenmask |= 1 << (colour_depth / 3);
5261         }
5262         redmask = redmask << (2*colour_depth / 3 + colour_depth%3);
5263         greenmask = greenmask << (colour_depth / 3);
5264 }
5265
5266 inline unsigned long do_gradient(unsigned long first_colour, unsigned long last_colour) { /* this function returns the next colour between two colours for a gradient */
5267         int tmp_color = 0;
5268         int red1, green1, blue1; // first colour
5269         int red2, green2, blue2; // second colour
5270         int red3 = 0, green3 = 0, blue3 = 0; // difference
5271         short redshift = (2*colour_depth / 3 + colour_depth%3);
5272         short greenshift = (colour_depth / 3);
5273         red1 = (first_colour & redmask) >> redshift;
5274         green1 = (first_colour & greenmask) >> greenshift;
5275         blue1 = first_colour & bluemask;
5276         red2 = (last_colour & redmask) >> redshift;
5277         green2 = (last_colour & greenmask) >> greenshift;
5278         blue2 = last_colour & bluemask;
5279         if (red1 > red2) {
5280                 red3 = -1;
5281         }
5282         if (red1 < red2) {
5283                 red3 = 1;
5284         }
5285         if (green1 > green2) {
5286                 green3 = -1;
5287         }
5288         if (green1 < green2) {
5289                 green3 = 1;
5290         }
5291         if (blue1 > blue2) {
5292                 blue3 = -1;
5293         }
5294         if (blue1 < blue2) {
5295                 blue3 = 1;
5296         }
5297         red1 += red3;
5298         green1 += green3;
5299         blue1 += blue3;
5300         if (red1 < 0) {
5301                 red1 = 0;
5302         }
5303         if (green1 < 0) {
5304                 green1 = 0;
5305         }
5306         if (blue1 < 0) {
5307                 blue1 = 0;
5308         }
5309         if (red1 > bluemask) {
5310                 red1 = bluemask;
5311         }
5312         if (green1 > bluemask) {
5313                 green1 = bluemask;
5314         }
5315         if (blue1 > bluemask) {
5316                 blue1 = bluemask;
5317         }
5318         tmp_color = (red1 << redshift) | (green1 << greenshift) | blue1;
5319         return tmp_color;
5320 }
5321
5322 inline unsigned long gradient_max(unsigned long first_colour, unsigned long last_colour) { /* this function returns the max diff for a gradient */
5323         if (colour_depth == 0) {
5324                 set_up_gradient();
5325         }
5326         int red1, green1, blue1; // first colour
5327         int red2, green2, blue2; // second colour
5328         long redshift = (2*colour_depth / 3 + colour_depth%3);
5329         long greenshift = (colour_depth / 3);
5330         int red3 = 0, green3 = 0, blue3 = 0; // difference
5331         red1 = (first_colour & redmask) >> redshift;
5332         green1 = (first_colour & greenmask) >> greenshift;
5333         blue1 = first_colour & bluemask;
5334         red2 = (last_colour & redmask) >> redshift;
5335         green2 = (last_colour & greenmask) >> greenshift;
5336         blue2 = last_colour & bluemask;
5337         red3 = abs(red1 - red2);
5338         green3 = abs(green1 - green2);
5339         blue3 = abs(blue1 - blue2);
5340         int max = red3;
5341         if (green3 > max)
5342                 max = green3;
5343         if (blue3 > max)
5344                 max = blue3;
5345         return max;
5346 }
5347
5348 static void draw_line(char *s)
5349 {
5350 #ifdef X11
5351         char *p;
5352         cur_x = text_start_x;
5353         cur_y += font_ascent();
5354         int cur_y_add = 0;
5355         short font_h = font_height();
5356
5357         /* find specials and draw stuff */
5358         p = s;
5359         while (*p) {
5360                 if (*p == SPECIAL_CHAR) {
5361                         int w = 0;
5362
5363                         /* draw string before special */
5364                         *p = '\0';
5365                         draw_string(s);
5366                         *p = SPECIAL_CHAR;
5367                         s = p + 1;
5368
5369                         /* draw special */
5370                         switch (specials[special_index].type) {
5371                         case HORIZONTAL_LINE:
5372                                 {
5373                                         int h =
5374                                             specials[special_index].height;
5375                                         int mid = font_ascent() / 2;
5376                                         w = text_start_x + text_width -
5377                                             cur_x;
5378
5379                                         XSetLineAttributes(display,
5380                                                            window.gc, h,
5381                                                            LineSolid,
5382                                                            CapButt,
5383                                                            JoinMiter);
5384                                         XDrawLine(display, window.drawable,
5385                                                   window.gc, cur_x,
5386                                                   cur_y - mid / 2,
5387                                                   cur_x + w,
5388                                                   cur_y - mid / 2);
5389                                 }
5390                                 break;
5391
5392                         case STIPPLED_HR:
5393                                 {
5394                                         int h =
5395                                             specials[special_index].height;
5396                                         int s =
5397                                             specials[special_index].arg;
5398                                         int mid = font_ascent() / 2;
5399                                         char ss[2] = { s, s };
5400                                         w = text_start_x + text_width -
5401                                             cur_x - 1;
5402
5403                                         XSetLineAttributes(display,
5404                                                            window.gc, h,
5405                                                            LineOnOffDash,
5406                                                            CapButt,
5407                                                            JoinMiter);
5408                                         XSetDashes(display, window.gc, 0,
5409                                                    ss, 2);
5410                                         XDrawLine(display, window.drawable,
5411                                                   window.gc, cur_x,
5412                                                   cur_y - mid / 2,
5413                                                   cur_x + w,
5414                                                   cur_y - mid / 2);
5415                                 }
5416                                 break;
5417
5418                         case BAR:
5419                                 {
5420                                         if (cur_x - text_start_x > maximum_width && maximum_width > 0) {
5421                                                 break;
5422                                         }
5423                                         int h =
5424                                             specials[special_index].height;
5425                                         int bar_usage =
5426                                             specials[special_index].arg;
5427                                         int by = cur_y - (font_ascent() / 2) - 1;
5428                                         if (h < font_height()) {
5429                                                 by -= h / 2 - 1;
5430                                         }
5431                                         w = specials[special_index].width;
5432                                         if (w == 0)
5433                                                 w = text_start_x +
5434                                                     text_width - cur_x - 1;
5435                                         if (w < 0)
5436                                                 w = 0;
5437
5438                                         XSetLineAttributes(display,
5439                                                            window.gc, 1,
5440                                                            LineSolid,
5441                                                            CapButt,
5442                                                            JoinMiter);
5443
5444                                         XDrawRectangle(display,
5445                                                        window.drawable,
5446                                                        window.gc, cur_x,
5447                                                        by, w, h);
5448                                         XFillRectangle(display,
5449                                                        window.drawable,
5450                                                        window.gc, cur_x,
5451                                                        by,
5452                                                        w * bar_usage / 255,
5453                                                        h);
5454                                         if (specials[special_index].
5455                                             height > cur_y_add
5456                                             && specials[special_index].
5457                                             height > font_h) {
5458                                                 cur_y_add =
5459                                                     specials
5460                                                     [special_index].height;
5461                                         }
5462                                 }
5463                                 break;
5464
5465                         case GRAPH:
5466                         {
5467                                         if (cur_x - text_start_x > maximum_width && maximum_width > 0) {
5468                                                 break;
5469                                         }
5470                                         int h =
5471                                             specials[special_index].height;
5472                                         unsigned long last_colour = current_color;
5473                                         int by = cur_y - (font_ascent()/2) - 1;
5474                                         if (h < font_height()) {
5475                                                 by -= h / 2 - 1;
5476                                         }
5477                                         w = specials[special_index].width;
5478                                         if (w == 0)
5479                                                 w = text_start_x + text_width - cur_x - 1;
5480                                         if (w < 0)
5481                                                 w = 0;
5482                                         if (draw_graph_borders) {
5483                                                 XSetLineAttributes(display, window.gc, 1, LineSolid, CapButt, JoinMiter);
5484                                                 XDrawRectangle(display,window.drawable, window.gc, cur_x, by, w, h);
5485                                         }
5486                                         XSetLineAttributes(display,
5487                                                            window.gc, 1,
5488                                                            LineSolid,
5489                                                            CapButt,
5490                                                            JoinMiter);
5491         int i;
5492         int j = 0;
5493         int gradient_size = 0;
5494         float gradient_factor = 0;
5495         float gradient_update = 0;
5496         unsigned long tmpcolour = current_color;
5497         if (specials[special_index].last_colour != 0 || specials[special_index].first_colour != 0) {
5498                 tmpcolour = specials[special_index].last_colour;
5499                 gradient_size = gradient_max(specials[special_index].last_colour, specials[special_index].first_colour);
5500                 gradient_factor = (float)gradient_size / (w - 2);
5501         }
5502         for (i = w - 2; i > -1; i--) {
5503                 if (specials[special_index].last_colour != 0 || specials[special_index].first_colour != 0) {
5504                         XSetForeground(display, window.gc, tmpcolour);
5505                         gradient_update += gradient_factor;
5506                         while (gradient_update > 0) {
5507                                 tmpcolour = do_gradient(tmpcolour, specials[special_index].first_colour);
5508                                 gradient_update--;
5509                         }
5510                 }
5511                 if ((w - i) / ((float) (w - 2) / (specials[special_index].graph_width)) > j && j < MAX_GRAPH_DEPTH - 3) {
5512                         j++;
5513                 }
5514                                                 XDrawLine(display,  window.drawable, window.gc, cur_x + i + 1, by + h, cur_x + i + 1, by + h - specials[special_index].graph[j] * (h - 1) / specials[special_index].graph_scale);       /* this is mugfugly, but it works */
5515                                         }
5516                                         if (specials[special_index].
5517                                             height > cur_y_add
5518                                             && specials[special_index].
5519                                             height > font_h) {
5520                                                 cur_y_add =
5521                                                     specials
5522                                                     [special_index].height;
5523                                         }
5524 /*                              if (draw_mode == BG) {
5525                                         set_foreground_color(default_bg_color);
5526                                 }
5527                                 else if (draw_mode == OUTLINE) {
5528                                         set_foreground_color(default_out_color);
5529                                 } else {
5530                                         set_foreground_color(default_fg_color);
5531                                 }*/
5532                                 set_foreground_color(last_colour);
5533                         }
5534                                 break;
5535                         
5536                                 case FONT:
5537                                 {
5538                                         int old = font_ascent();
5539                                         cur_y -= font_ascent();
5540                                         selected_font = specials[special_index].font_added;
5541                                         if (cur_y + font_ascent() < cur_y + old) {
5542                                                 cur_y += old;
5543                                         } else {
5544                                                 cur_y += font_ascent();
5545                                         }
5546                                         set_font();
5547                                 }
5548                                 break;
5549                         case FG:
5550                                 if (draw_mode == FG)
5551                                         set_foreground_color(specials
5552                                                              [special_index].
5553                                                              arg);
5554                                 break;
5555
5556                         case BG:
5557                                 if (draw_mode == BG)
5558                                         set_foreground_color(specials
5559                                                              [special_index].
5560                                                              arg);
5561                                 break;
5562
5563                         case OUTLINE:
5564                                 if (draw_mode == OUTLINE)
5565                                         set_foreground_color(specials
5566                                                              [special_index].
5567                                                              arg);
5568                                 break;
5569
5570                         case OFFSET:
5571                                 w += specials[special_index].arg;
5572                                 break;
5573                 
5574                         case VOFFSET:
5575                                 cur_y += specials[special_index].arg;
5576                                 break;
5577
5578                         case GOTO:
5579                                 if (specials[special_index].arg >= 0)
5580                                         cur_x = (int)specials[special_index].arg;
5581                                 break;
5582
5583                         case TAB:
5584                                 {
5585                                         int start = specials[special_index].arg;
5586                                         int step = specials[special_index].width;
5587                                         if (!step || step < 0)
5588                                                 step = 10;
5589                                         w = step - (cur_x - text_start_x - start) % step;
5590                                 }
5591                                 break;
5592
5593                         case ALIGNR:
5594                                 {
5595                                         int pos_x = text_start_x + text_width - get_string_width_special(s) /*+ border_margin*/;
5596                                         /*printf("pos_x %i text_start_x %i text_width %i cur_x %i get_string_width(p) %i gap_x %i specials[special_index].arg %i border_margin %i border_width %i\n", pos_x, text_start_x, text_width, cur_x, get_string_width_special(s), gap_x, specials[special_index].arg, border_margin, border_width);*/
5597                                         if (pos_x > specials[special_index].arg && pos_x > cur_x) {
5598                                                 cur_x = pos_x - specials[special_index].arg;
5599                                 }
5600                                 }
5601                                 break;
5602
5603                         case ALIGNC:
5604                                 {
5605                                         int pos_x = (text_width)/2 - get_string_width_special(s)/2 - (cur_x - text_start_x);
5606                                         /*int pos_x = text_start_x + text_width/2 - get_string_width_special(s)/2;*/
5607                                         /*printf("pos_x %i text_start_x %i text_width %i cur_x %i get_string_width(p) %i gap_x %i specials[special_index].arg %i\n", pos_x, text_start_x, text_width, cur_x, get_string_width(s), gap_x, specials[special_index].arg);*/
5608                                         if (pos_x >
5609                                             specials[special_index].arg)
5610                                                 w = pos_x -
5611                                                     specials
5612                                                     [special_index].arg;
5613                                 }
5614                                 break;
5615
5616                         }
5617
5618                         cur_x += w;
5619
5620                         special_index++;
5621                 }
5622
5623                 p++;
5624         }
5625 #else
5626         draw_string(s);
5627 #endif
5628 #ifdef X11
5629         if (cur_y_add > 0) {
5630                 cur_y += cur_y_add;
5631                 cur_y -= font_descent();
5632         }
5633
5634         draw_string(s);
5635
5636         cur_y += font_descent();
5637 #endif /* X11 */
5638 }
5639
5640 static void draw_text()
5641 {
5642 #ifdef X11
5643         cur_y = text_start_y;
5644
5645         /* draw borders */
5646         if (draw_borders && border_width > 0) {
5647                 unsigned int b = (border_width + 1) / 2;
5648
5649                 if (stippled_borders) {
5650                         char ss[2] =
5651                             { stippled_borders, stippled_borders };
5652                         XSetLineAttributes(display, window.gc,
5653                                            border_width, LineOnOffDash,
5654                                            CapButt, JoinMiter);
5655                         XSetDashes(display, window.gc, 0, ss, 2);
5656                 } else {
5657                         XSetLineAttributes(display, window.gc,
5658                                            border_width, LineSolid,
5659                                            CapButt, JoinMiter);
5660                 }
5661
5662                 XDrawRectangle(display, window.drawable, window.gc,
5663                                text_start_x - border_margin + b,
5664                                text_start_y - border_margin + b,
5665                                text_width + border_margin * 2 - 1 - b * 2,
5666                                text_height + border_margin * 2 - 1 -
5667                                b * 2);
5668         }
5669
5670         /* draw text */
5671         special_index = 0;
5672 #endif /* X11 */
5673         for_each_line(text_buffer, draw_line);
5674 }
5675
5676 static void draw_stuff()
5677 {
5678 #ifdef X11
5679         selected_font = 0;
5680         if (draw_shades && !draw_outline) {
5681                 text_start_x++;
5682                 text_start_y++;
5683                 set_foreground_color(default_bg_color);
5684                 draw_mode = BG;
5685                 draw_text();
5686                 text_start_x--;
5687                 text_start_y--;
5688         }
5689
5690         if (draw_outline) {
5691                 selected_font = 0;
5692                 int i, j;
5693                 for (i = -1; i < 2; i++)
5694                         for (j = -1; j < 2; j++) {
5695                                 if (i == 0 && j == 0)
5696                                         continue;
5697                                 text_start_x += i;
5698                                 text_start_y += j;
5699                                 set_foreground_color(default_out_color);
5700                                 draw_mode = OUTLINE;
5701                                 draw_text();
5702                                 text_start_x -= i;
5703                                 text_start_y -= j;
5704                         }
5705         }
5706
5707         set_foreground_color(default_fg_color);
5708         draw_mode = FG;
5709 #endif /* X11 */
5710         draw_text();
5711 #ifdef X11
5712 #ifdef HAVE_XDBE
5713         if (use_xdbe) {
5714                 XdbeSwapInfo swap;
5715                 swap.swap_window = window.window;
5716                 swap.swap_action = XdbeBackground;
5717                 XdbeSwapBuffers(display, &swap, 1);
5718         }
5719 #endif
5720 #endif /* X11 */
5721 }
5722 #ifdef X11
5723 static void clear_text(int exposures)
5724 {
5725 #ifdef HAVE_XDBE
5726         if (use_xdbe) {
5727                 return;         /* The swap action is XdbeBackground, which clears */
5728         } else
5729 #endif
5730         {
5731         /* there is some extra space for borders and outlines */
5732         XClearArea(display, window.window,
5733                    text_start_x - border_margin - 1,
5734                    text_start_y - border_margin - 1,
5735                    text_width + border_margin * 2 + 2,
5736                    text_height + border_margin * 2 + 2,
5737                    exposures ? True : 0);
5738         }
5739 }
5740 #endif /* X11 */
5741
5742 static int need_to_update;
5743
5744 /* update_text() generates new text and clears old text area */
5745 static void update_text()
5746 {
5747         generate_text();
5748 #ifdef X11
5749         clear_text(1);
5750 #endif /* X11 */
5751         need_to_update = 1;
5752 }
5753
5754 static void main_loop()
5755 {
5756 #ifdef SIGNAL_BLOCKING
5757         sigset_t  newmask, oldmask;
5758
5759         sigemptyset(&newmask);
5760         sigaddset(&newmask,SIGINT);
5761         sigaddset(&newmask,SIGTERM);
5762         sigaddset(&newmask,SIGUSR1);
5763 #endif
5764
5765 #ifdef X11
5766         Region region = XCreateRegion();
5767 #ifdef HAVE_XDAMAGE
5768         int event_base, error_base;
5769         if (!XDamageQueryExtension (display, &event_base, &error_base)) {
5770                 ERR("Xdamage extension unavailable");
5771         }
5772         Damage damage = XDamageCreate(display, window.window, XDamageReportNonEmpty);
5773         XserverRegion region2 = XFixesCreateRegionFromWindow(display, window.window, 0);
5774         XserverRegion part = XFixesCreateRegionFromWindow(display, window.window, 0);
5775 #endif /* HAVE_XDAMAGE */
5776 #endif /* X11 */
5777
5778         info.looped = 0;
5779         while (total_run_times == 0 || info.looped < total_run_times) {
5780                 info.looped++;
5781
5782 #ifdef SIGNAL_BLOCKING
5783                 /* block signals.  we will inspect for pending signals later */
5784                 if (sigprocmask(SIG_BLOCK, &newmask, &oldmask) < 0)
5785                         CRIT_ERR("unable to sigprocmask()");
5786 #endif
5787
5788 #ifdef X11
5789                 XFlush(display);
5790
5791                 /* wait for X event or timeout */
5792
5793                 if (!XPending(display)) {
5794                         fd_set fdsr;
5795                         struct timeval tv;
5796                         int s;
5797                         double t =
5798                             update_interval - (get_time() -
5799                                                last_update_time);
5800
5801                         if (t < 0)
5802                                 t = 0;
5803
5804                         tv.tv_sec = (long) t;
5805                         tv.tv_usec = (long) (t * 1000000) % 1000000;
5806                         FD_ZERO(&fdsr);
5807                         FD_SET(ConnectionNumber(display), &fdsr);
5808
5809
5810                         s = select(ConnectionNumber(display) + 1, &fdsr, 0,
5811                                    0, &tv);
5812 #else
5813                         usleep(update_interval*1000000); /* FIXME just sleep for the interval time if no X11 */
5814 #endif /* X11 */
5815 #ifdef X11
5816                         if (s == -1) {
5817                                 if (errno != EINTR)
5818                                         ERR("can't select(): %s",
5819                                             strerror(errno));
5820                         } else {
5821                                 /* timeout */
5822                                 if (s == 0)
5823 #endif /* X11 */
5824                                         update_text();
5825 #ifdef X11
5826                         }
5827                 }
5828                 
5829                 if (need_to_update) {
5830 #ifdef OWN_WINDOW
5831                         int wx = window.x, wy = window.y;
5832 #endif
5833
5834                         need_to_update = 0;
5835                         selected_font = 0;
5836                         update_text_area();
5837 #ifdef OWN_WINDOW
5838                         if (own_window) {
5839                                 /* resize window if it isn't right size */
5840                                 if (!fixed_size &&
5841                                     (text_width + border_margin * 2 + 1 !=
5842                                      window.width
5843                                      || text_height + border_margin * 2 + 1 !=
5844                                      window.height)) {
5845                                         window.width =
5846                                             text_width +
5847                                             border_margin * 2 + 1;
5848                                         window.height =
5849                                             text_height +
5850                                             border_margin * 2 + 1;
5851                                         XResizeWindow(display,
5852                                                       window.window,
5853                                                       window.width,
5854                                                       window.height);
5855                         if (own_window) {
5856                                 set_transparent_background(window.window);
5857                         }
5858                                      }
5859
5860                                 /* move window if it isn't in right position */
5861                                 if (!fixed_pos
5862                                     && (window.x != wx
5863                                         || window.y != wy)) {
5864                                         XMoveWindow(display, window.window,
5865                                                     window.x, window.y);
5866                                 }
5867                         }
5868 #endif
5869
5870                         clear_text(1);
5871
5872 #ifdef HAVE_XDBE
5873                         if (use_xdbe) {
5874                                 XRectangle r;
5875                                 r.x = text_start_x - border_margin;
5876                                 r.y = text_start_y - border_margin;
5877                                 r.width = text_width + border_margin * 2;
5878                                 r.height = text_height + border_margin * 2;
5879                                 XUnionRectWithRegion(&r, region, region);
5880                         }
5881 #endif
5882                 }
5883
5884                 /* handle X events */
5885
5886                 while (XPending(display)) {
5887                         XEvent ev;
5888                         XNextEvent(display, &ev);
5889                         switch (ev.type) {
5890                         case Expose:
5891                                 {
5892                                         XRectangle r;
5893                                         r.x = ev.xexpose.x;
5894                                         r.y = ev.xexpose.y;
5895                                         r.width = ev.xexpose.width;
5896                                         r.height = ev.xexpose.height;
5897                                         XUnionRectWithRegion(&r, region,
5898                                                              region);
5899                                 }
5900                                 break;
5901
5902 #ifdef OWN_WINDOW
5903                         case ReparentNotify:
5904                                 /* set background to ParentRelative for all parents */
5905                                 if (own_window) {
5906                                         set_transparent_background(window.
5907                                         window);
5908                                 }
5909                                 break;
5910
5911                         case ConfigureNotify:
5912                                 if (own_window) {
5913                                         /* if window size isn't what expected, set fixed size */
5914                                         if (ev.xconfigure.width !=
5915                                             window.width
5916                                             || ev.xconfigure.height !=
5917                                             window.height) {
5918                                                 if (window.width != 0
5919                                                     && window.height != 0)
5920                                                         fixed_size = 1;
5921
5922                                                 /* clear old stuff before screwing up size and pos */
5923                                                 clear_text(1);
5924
5925                                                 {
5926                                                         XWindowAttributes
5927                                                             attrs;
5928                                                         if (XGetWindowAttributes(display, window.window, &attrs)) {
5929                                                                 window.
5930                                                                     width =
5931                                                                     attrs.
5932                                                                     width;
5933                                                                 window.
5934                                                                     height
5935                                                                     =
5936                                                                     attrs.
5937                                                                     height;
5938                                                         }
5939                                                 }
5940
5941                                                 text_width =
5942                                                     window.width -
5943                                                     border_margin * 2 - 1;
5944                                                 text_height =
5945                                                     window.height -
5946                                                     border_margin * 2 - 1;
5947                                                 if (text_width > maximum_width && maximum_width > 0)
5948                                                         text_width = maximum_width;
5949                                         }
5950
5951                                         /* if position isn't what expected, set fixed pos, total_updates
5952                                          * avoids setting fixed_pos when window is set to weird locations
5953                                          * when started */
5954                                         /*if (total_updates >= 2 this is broken
5955                                             && !fixed_pos
5956                                             && (window.x != ev.xconfigure.x
5957                                                 || window.y !=
5958                                                 ev.xconfigure.y)
5959                                             && (ev.xconfigure.x != 0
5960                                                 || ev.xconfigure.y != 0)) {
5961                                                 fixed_pos = 1;
5962                                 }*/
5963                                         set_font();
5964                                 }
5965                                 break;
5966
5967                         case ButtonPress:
5968                                 if (own_window)
5969         {
5970           /* if an ordinary window with decorations */
5971           if ((window.type==TYPE_NORMAL) && (!TEST_HINT(window.hints,HINT_UNDECORATED)))
5972           {
5973             /* allow conky to hold input focus.*/
5974             break;
5975           }
5976           else
5977                                   {
5978                                     /* forward the click to the desktop window */
5979                                     XUngrabPointer(display, ev.xbutton.time);
5980                                     ev.xbutton.window = window.desktop;
5981                                     XSendEvent(display, ev.xbutton.window, False, ButtonPressMask, &ev);
5982             XSetInputFocus(display, ev.xbutton.window,RevertToParent,ev.xbutton.time);
5983                                   }
5984         }
5985                                 break;
5986
5987                         case ButtonRelease:
5988         if (own_window)
5989         {
5990           /* if an ordinary window with decorations */
5991           if ((window.type==TYPE_NORMAL) && (!TEST_HINT(window.hints,HINT_UNDECORATED)))
5992           {
5993             /* allow conky to hold input focus.*/
5994             break;
5995           }
5996           else
5997           {
5998             /* forward the release to the desktop window */
5999             ev.xbutton.window = window.desktop;
6000             XSendEvent(display, ev.xbutton.window, False, ButtonReleaseMask, &ev);
6001           }
6002         }
6003         break;
6004
6005 #endif
6006
6007                         default:
6008 #ifdef HAVE_XDAMAGE
6009                                 if (ev.type == event_base + XDamageNotify) {
6010                                         XDamageNotifyEvent  *dev = (XDamageNotifyEvent *) &ev;
6011                                         XFixesSetRegion(display, part, &dev->area, 1);
6012                                         XFixesUnionRegion(display, region2, region2, part);
6013                                 }
6014 #endif /* HAVE_XDAMAGE */
6015                                 break;
6016                         }
6017         }
6018 #ifdef HAVE_XDAMAGE
6019                 XDamageSubtract(display, damage, region2, None);
6020                 XFixesSetRegion(display, region2, 0, 0);
6021 #endif /* HAVE_XDAMAGE */
6022
6023                 /* XDBE doesn't seem to provide a way to clear the back buffer without
6024                  * interfering with the front buffer, other than passing XdbeBackground
6025                  * to XdbeSwapBuffers. That means that if we're using XDBE, we need to
6026                  * redraw the text even if it wasn't part of the exposed area. OTOH,
6027                  * if we're not going to call draw_stuff at all, then no swap happens
6028                  * and we can safely do nothing.
6029                  */
6030
6031                 if (!XEmptyRegion(region)) {
6032 #ifdef HAVE_XDBE
6033                         if (use_xdbe) {
6034                                 XRectangle r;
6035                                 r.x = text_start_x - border_margin;
6036                                 r.y = text_start_y - border_margin;
6037                                 r.width = text_width + border_margin * 2;
6038                                 r.height = text_height + border_margin * 2;
6039                                 XUnionRectWithRegion(&r, region, region);
6040                 }
6041 #endif
6042                         XSetRegion(display, window.gc, region);
6043 #ifdef XFT
6044                         if (use_xft) {
6045                                 XftDrawSetClip(window.xftdraw, region);
6046                         }
6047 #endif
6048 #endif /* X11 */
6049                         draw_stuff();
6050 #ifdef X11
6051                         XDestroyRegion(region);
6052                         region = XCreateRegion();
6053                 }
6054 #endif /* X11 */
6055
6056 #ifdef SIGNAL_BLOCKING
6057                 /* unblock signals of interest and let handler fly */
6058                 if (sigprocmask(SIG_SETMASK, &oldmask, NULL) < 0)
6059                         CRIT_ERR("unable to sigprocmask()");
6060 #endif
6061
6062                 switch(g_signal_pending) {
6063                 case SIGUSR1:
6064                         {
6065                         ERR("received SIGUSR1. reloading the config file.");
6066                         reload_config();
6067                         break;
6068                         }
6069                 case SIGINT:
6070                 case SIGTERM:
6071                         {
6072                         ERR("received SIGINT or SIGTERM to terminate. bye!");
6073                         clean_up();
6074 #ifdef X11
6075                         XDestroyRegion(region);
6076                         region = NULL;
6077 #endif /* X11 */
6078                         return;  /* return from main_loop */
6079                         /*break;*/
6080                         }
6081                 default:
6082                         {
6083                         /* Reaching here means someone set a signal( SIGXXXX, signal_handler )
6084                          * but didn't write any code to deal with it.   if you don't want to
6085                          * handle a signal, don't set a handler on it in the first place. */
6086                         if (g_signal_pending)
6087                                 ERR("ignoring signal (%d)", g_signal_pending);
6088                         break;
6089                         }
6090                 }
6091                 g_signal_pending=0;
6092         
6093         }
6094 #if defined(X11) && defined(HAVE_XDAMAGE)
6095         XDamageDestroy(display, damage);
6096         XFixesDestroyRegion(display, region2);
6097         XFixesDestroyRegion(display, part);
6098         XDestroyRegion(region);
6099         region = NULL;
6100 #endif /* X11 && HAVE_XDAMAGE */
6101 }
6102
6103 static void load_config_file(const char *);
6104
6105 /* reload the config file */
6106 void reload_config(void)
6107 {
6108         timed_thread_destroy_registered_threads ();
6109
6110         if (info.cpu_usage) {
6111                 free(info.cpu_usage);
6112                 info.cpu_usage = NULL;
6113         }
6114
6115 #ifdef TCP_PORT_MONITOR
6116         destroy_tcp_port_monitor_collection( info.p_tcp_port_monitor_collection );
6117 #endif
6118
6119         if (current_config) {
6120                 clear_fs_stats();
6121                 load_config_file(current_config);
6122
6123                 /* re-init specials array */
6124                 if ((specials = realloc ((void *)specials, sizeof(struct special_t)*max_specials)) == 0)
6125                     ERR("failed to realloc specials array");
6126
6127 #ifdef X11
6128                 load_fonts();
6129                 set_font();
6130                 XClearWindow(display, RootWindow(display, screen)); // clear the window first
6131
6132 #endif /* X11 */
6133 #ifdef TCP_PORT_MONITOR
6134                 info.p_tcp_port_monitor_collection = NULL; 
6135 #endif
6136 #ifdef AUDACIOUS
6137                 if (create_audacious_thread() !=0)
6138                     CRIT_ERR("unable to create audacious thread!");
6139                 timed_thread_register (info.audacious.p_timed_thread, &info.audacious.p_timed_thread);
6140 #endif
6141                 extract_variable_text(text);
6142                 free(text);
6143                 text = NULL;
6144                 update_text();
6145         }
6146 }
6147
6148 void clean_up(void)
6149 {
6150         timed_thread_destroy_registered_threads ();
6151
6152         if (info.cpu_usage) {
6153                 free(info.cpu_usage);
6154                 info.cpu_usage = NULL;
6155         }
6156 #ifdef X11
6157 #ifdef HAVE_XDBE
6158         if (use_xdbe) {
6159                 XdbeDeallocateBackBufferName(display, window.back_buffer);
6160         }
6161 #endif
6162 #ifdef OWN_WINDOW
6163         if (own_window) 
6164         {
6165                 XDestroyWindow(display, window.window);
6166                 XClearWindow(display, RootWindow(display, screen));
6167                 XFlush(display);
6168         }
6169         else
6170 #endif
6171         {
6172                 XClearWindow(display, RootWindow(display, screen));
6173                 clear_text(1);
6174                 XFlush(display);
6175         }
6176
6177         XFreeGC(display, window.gc);
6178 #endif /* X11 */
6179
6180         free_text_objects(text_object_count, text_objects);
6181         text_object_count = 0;
6182         text_objects = NULL;
6183
6184         if (text != original_text)
6185                 free(text);
6186
6187         free(current_config);
6188         free(current_mail_spool);
6189
6190 #ifdef TCP_PORT_MONITOR
6191         destroy_tcp_port_monitor_collection( info.p_tcp_port_monitor_collection );
6192         info.p_tcp_port_monitor_collection = NULL;
6193 #endif
6194
6195         if (specials) {
6196             free (specials);
6197             specials=NULL;
6198         }
6199
6200 #ifdef HAVE_LIBDEXTER
6201   dexter_library_exit ();
6202   if (dexter_config)
6203     free (dexter_config);
6204 #endif
6205 }
6206
6207 static int string_to_bool(const char *s)
6208 {
6209         if (!s)
6210                 return 1;
6211         if (strcasecmp(s, "yes") == 0)
6212                 return 1;
6213         if (strcasecmp(s, "true") == 0)
6214                 return 1;
6215         if (strcasecmp(s, "1") == 0)
6216                 return 1;
6217         return 0;
6218 }
6219 #ifdef X11
6220 static enum alignment string_to_alignment(const char *s)
6221 {
6222         if (strcasecmp(s, "top_left") == 0)
6223                 return TOP_LEFT;
6224         else if (strcasecmp(s, "top_right") == 0)
6225                 return TOP_RIGHT;
6226         else if (strcasecmp(s, "bottom_left") == 0)
6227                 return BOTTOM_LEFT;
6228         else if (strcasecmp(s, "bottom_right") == 0)
6229                 return BOTTOM_RIGHT;
6230         else if (strcasecmp(s, "tl") == 0)
6231                 return TOP_LEFT;
6232         else if (strcasecmp(s, "tr") == 0)
6233                 return TOP_RIGHT;
6234         else if (strcasecmp(s, "bl") == 0)
6235                 return BOTTOM_LEFT;
6236         else if (strcasecmp(s, "br") == 0)
6237                 return BOTTOM_RIGHT;
6238         else if (strcasecmp(s, "none") == 0)
6239                 return NONE;
6240         return TOP_LEFT;
6241 }
6242 #endif /* X11 */
6243
6244
6245 static void set_default_configurations(void)
6246 {
6247         fork_to_background = 0;
6248         total_run_times = 0;
6249         info.cpu_avg_samples = 2;
6250         info.net_avg_samples = 2;
6251         info.memmax = 0;
6252         top_cpu = 0;
6253         top_mem = 0;
6254 #ifdef MPD
6255         strcpy(info.mpd.host, "localhost");
6256         info.mpd.port = 6600;
6257         info.mpd.status = NULL;
6258         info.mpd.artist = NULL;
6259         info.mpd.album = NULL;
6260         info.mpd.title = NULL;
6261         info.mpd.random = NULL;
6262         info.mpd.track = NULL;
6263         info.mpd.name = NULL;
6264         info.mpd.file = NULL;
6265 #endif
6266 #ifdef XMMS2
6267     info.xmms2.artist = NULL;
6268     info.xmms2.album = NULL;
6269     info.xmms2.title = NULL;
6270     info.xmms2.genre = NULL;
6271     info.xmms2.comment = NULL;
6272     info.xmms2.decoder = NULL;
6273     info.xmms2.transport = NULL;
6274     info.xmms2.url = NULL;
6275     info.xmms2.status = NULL;
6276 #endif
6277         use_spacer = 0;
6278 #ifdef X11
6279         out_to_console = 0;
6280 #else
6281         out_to_console = 1;
6282 #endif
6283 #ifdef X11
6284         default_fg_color = WhitePixel(display, screen);
6285         default_bg_color = BlackPixel(display, screen);
6286         default_out_color = BlackPixel(display, screen);
6287         draw_shades = 1;
6288         draw_borders = 0;
6289         draw_graph_borders = 1;
6290         draw_outline = 0;
6291         set_first_font("6x10");
6292         gap_x = 5;
6293         gap_y = 5;
6294         minimum_width = 5;
6295         minimum_height = 5;
6296         maximum_width = 0;
6297 #ifdef OWN_WINDOW
6298         own_window = 0;
6299         window.type=TYPE_NORMAL;
6300         window.hints=0;
6301   strcpy(window.class_name, "Conky");   
6302   update_uname();
6303   sprintf(window.title,"%s - conky",info.uname_s.nodename);
6304 #endif
6305         stippled_borders = 0;
6306         border_margin = 3;
6307         border_width = 1;
6308         text_alignment = BOTTOM_LEFT;
6309 #endif /* X11 */
6310
6311         free(current_mail_spool);
6312         {
6313                 char buf[256];
6314                 variable_substitute(MAIL_FILE, buf, 256);
6315                 if (buf[0] != '\0')
6316                         current_mail_spool = strdup(buf);
6317         }
6318
6319         no_buffers = 1;
6320         update_interval = 10.0;
6321         stuff_in_upper_case = 0;
6322
6323 #ifdef TCP_PORT_MONITOR
6324         tcp_port_monitor_args.max_port_monitor_connections = MAX_PORT_MONITOR_CONNECTIONS_DEFAULT;
6325 #endif
6326 }
6327
6328 static void load_config_file(const char *f)
6329 {
6330 #define CONF_ERR ERR("%s: %d: config file error", f, line)
6331         int line = 0;
6332         FILE *fp;
6333
6334         set_default_configurations();
6335         fp = fopen(f, "r");
6336         if (!fp)
6337                 return;
6338
6339         while (!feof(fp)) {
6340                 char buf[256], *p, *p2, *name, *value;
6341                 line++;
6342                 if (fgets(buf, 256, fp) == NULL)
6343                         break;
6344
6345                 p = buf;
6346
6347                 /* break at comment */
6348                 p2 = strchr(p, '#');
6349                 if (p2)
6350                         *p2 = '\0';
6351
6352                 /* skip spaces */
6353                 while (*p && isspace((int) *p))
6354                         p++;
6355                 if (*p == '\0')
6356                         continue;       /* empty line */
6357
6358                 name = p;
6359
6360                 /* skip name */
6361                 p2 = p;
6362                 while (*p2 && !isspace((int) *p2))
6363                         p2++;
6364                 if (*p2 != '\0') {
6365                         *p2 = '\0';     /* break at name's end */
6366                         p2++;
6367                 }
6368
6369                 /* get value */
6370                 if (*p2) {
6371                         p = p2;
6372                         while (*p && isspace((int) *p))
6373                                 p++;
6374
6375                         value = p;
6376
6377                         p2 = value + strlen(value);
6378                         while (isspace((int) *(p2 - 1)))
6379                                 *--p2 = '\0';
6380                 } else {
6381                         value = 0;
6382                 }
6383
6384 #define CONF2(a) if (strcasecmp(name, a) == 0)
6385 #define CONF(a) else CONF2(a)
6386 #define CONF3(a,b) \
6387 else if (strcasecmp(name, a) == 0 || strcasecmp(name, b) == 0)
6388
6389
6390 #ifdef X11
6391                 CONF2("alignment") {
6392                 if (value) {
6393                         int a = string_to_alignment(value);
6394                         if (a <= 0)
6395                                 CONF_ERR;
6396                         else
6397                                 text_alignment = a;
6398                 } else
6399                         CONF_ERR;
6400                 }
6401                 CONF("background") {
6402                         fork_to_background = string_to_bool(value);
6403                 }
6404
6405 #else
6406                 CONF2("background") {
6407                         fork_to_background = string_to_bool(value);
6408                 }
6409 #endif /* X11 */
6410 #ifdef X11
6411                 CONF("border_margin") {
6412                         if (value)
6413                                 border_margin = strtol(value, 0, 0);
6414                         else
6415                                 CONF_ERR;
6416                 }
6417                 CONF("border_width") {
6418                         if (value)
6419                                 border_width = strtol(value, 0, 0);
6420                         else
6421                                 CONF_ERR;
6422                 }
6423                 CONF("default_color") {
6424                         if (value)
6425                                 default_fg_color = get_x11_color(value);
6426                         else
6427                                 CONF_ERR;
6428                 }
6429                 CONF3("default_shade_color", "default_shadecolor") {
6430                         if (value)
6431                                 default_bg_color = get_x11_color(value);
6432                         else
6433                                 CONF_ERR;
6434                 }
6435                 CONF3("default_outline_color", "default_outlinecolor") {
6436                         if (value)
6437                                 default_out_color = get_x11_color(value);
6438                         else
6439                                 CONF_ERR;
6440                 }
6441 #endif /* X11 */
6442                 CONF("imap") {
6443                         if (value) {
6444                                 info.mail = parse_mail_args(IMAP, value);
6445                         } else {
6446                                 CONF_ERR;
6447                         }
6448                 }
6449                 CONF("pop3") {
6450                         if (value) {
6451                                 info.mail = parse_mail_args(POP3, value);
6452                         } else {
6453                                 CONF_ERR;
6454                         }
6455                 }
6456 #ifdef MPD
6457                 CONF("mpd_host") {
6458                         if (value)
6459                                 strncpy(info.mpd.host, value, 127);
6460                         else
6461                                 CONF_ERR;
6462                 }
6463                 CONF("mpd_port") {
6464                         if (value) {
6465                                 info.mpd.port = strtol(value, 0, 0);
6466                                 if (info.mpd.port < 1
6467                                     || info.mpd.port > 0xffff)
6468                                         CONF_ERR;
6469                         }
6470                 }
6471                 CONF("mpd_password") {
6472                         if (value)
6473                                 strncpy(info.mpd.password, value, 127);
6474                         else
6475                                 CONF_ERR;
6476                 }
6477 #endif
6478                 CONF("cpu_avg_samples") {
6479                         if (value) {
6480                                 cpu_avg_samples = strtol(value, 0, 0);
6481                                 if (cpu_avg_samples < 1
6482                                     || cpu_avg_samples > 14)
6483                                         CONF_ERR;
6484                                 else
6485                                         info.
6486                                             cpu_avg_samples
6487                                             = cpu_avg_samples;
6488                         } else
6489                                 CONF_ERR;
6490                 }
6491                 CONF("net_avg_samples") {
6492                         if (value) {
6493                                 net_avg_samples = strtol(value, 0, 0);
6494                                 if (net_avg_samples < 1
6495                                     || net_avg_samples > 14)
6496                                         CONF_ERR;
6497                                 else
6498                                         info.
6499                                             net_avg_samples
6500                                             = net_avg_samples;
6501                         } else
6502                                 CONF_ERR;
6503                 }
6504
6505
6506
6507
6508
6509
6510 #ifdef HAVE_XDBE
6511                 CONF("double_buffer") {
6512                 use_xdbe = string_to_bool(value);
6513                 }
6514 #endif
6515 #ifdef X11
6516                 CONF("override_utf8_locale") {
6517         utf8_mode = string_to_bool(value);
6518                 }
6519
6520                 CONF("draw_borders") {
6521                         draw_borders = string_to_bool(value);
6522                 }
6523                 CONF("draw_graph_borders") {
6524                         draw_graph_borders = string_to_bool(value);
6525                 }
6526                 CONF("draw_shades") {
6527                         draw_shades = string_to_bool(value);
6528                 }
6529                 CONF("draw_outline") {
6530                         draw_outline = string_to_bool(value);
6531                 }
6532 #endif /* X11 */
6533                 CONF("out_to_console") {
6534                         out_to_console = string_to_bool(value);
6535                 }
6536                 CONF("use_spacer") {
6537                         use_spacer = string_to_bool(value);
6538                 }
6539 #ifdef X11
6540 #ifdef XFT
6541                 CONF("use_xft") {
6542                         use_xft = string_to_bool(value);
6543                 }
6544                 CONF("font") {
6545                         if (value) {
6546                                 set_first_font(value);
6547                         } else
6548                                 CONF_ERR;
6549                 }
6550                 CONF("xftalpha") {
6551                         if (value && font_count >= 0)
6552                                 fonts[0].font_alpha = atof(value)
6553                                     * 65535.0;
6554                         else
6555                                 CONF_ERR;
6556                 }
6557                 CONF("xftfont") {
6558                         if (use_xft) {
6559 #else
6560                 CONF("use_xft") {
6561                         if (string_to_bool(value))
6562                                 ERR("Xft not enabled");
6563                 }
6564                 CONF("xftfont") {
6565                         /* xftfont silently ignored when no Xft */
6566                 }
6567                 CONF("xftalpha") {
6568                         /* xftalpha is silently ignored when no Xft */
6569                 }
6570                 CONF("font") {
6571 #endif
6572                                 if (value) {
6573                                         set_first_font(value);
6574                                 } else
6575                                         CONF_ERR;
6576 #ifdef XFT
6577                         }
6578 #endif
6579                 }
6580                 CONF("gap_x") {
6581                         if (value)
6582                                 gap_x = atoi(value);
6583                         else
6584                                 CONF_ERR;
6585                 }
6586                 CONF("gap_y") {
6587                         if (value)
6588                                 gap_y = atoi(value);
6589                         else
6590                                 CONF_ERR;
6591                 }
6592 #endif /* X11 */
6593                 CONF("mail_spool") {
6594                         if (value) {
6595                                 char buf[256];
6596                                 variable_substitute(value, buf, 256);
6597
6598                                 if (buf[0]
6599                                     != '\0') {
6600                                         if (current_mail_spool)
6601                                                 free(current_mail_spool);
6602                                         current_mail_spool = strdup(buf);
6603                                 }
6604                         } else
6605                                 CONF_ERR;
6606                 }
6607 #ifdef X11
6608                 CONF("minimum_size") {
6609         if (value) {
6610                 if (sscanf
6611                                   (value, "%d %d", &minimum_width,
6612                                    &minimum_height) != 2)
6613                         if (sscanf
6614                                                  (value, "%d",
6615                                                    &minimum_width) != 1)
6616                                 CONF_ERR;
6617         } else
6618                 CONF_ERR;
6619                 }
6620                 CONF("maximum_width") {
6621                         if (value) {
6622                                 if (sscanf(value, "%d", &maximum_width) != 1)
6623                                         CONF_ERR;
6624                         } else
6625                                 CONF_ERR;
6626                 }
6627 #endif /* X11 */
6628                 CONF("no_buffers") {
6629                         no_buffers = string_to_bool(value);
6630                 }
6631                 CONF("pad_percents") {
6632         pad_percents = atoi(value);
6633                 }
6634 #ifdef X11
6635 #ifdef OWN_WINDOW
6636                 CONF("own_window") {
6637       if (value)
6638                           own_window = string_to_bool(value);
6639       else
6640         CONF_ERR;
6641                 }
6642                 CONF("own_window_class") {
6643       if (value)
6644       {
6645                           memset(window.class_name,0,sizeof(window.class_name));
6646                           strncpy(window.class_name, value, sizeof(window.class_name)-1);
6647       }
6648       else 
6649         CONF_ERR;
6650                 }
6651     CONF("own_window_title") {
6652       if (value)
6653       {
6654         memset(window.title,0,sizeof(window.title));
6655         strncpy(window.title, value, sizeof(window.title)-1);
6656       }
6657       else
6658         CONF_ERR;
6659     }
6660                 CONF("own_window_transparent") {
6661       if (value)
6662                           set_transparent = string_to_bool(value);
6663       else
6664         CONF_ERR;
6665                 }
6666                 CONF("own_window_colour") {
6667                         if (value) {
6668                                 background_colour = get_x11_color(value);
6669                         } else {
6670                                 ERR("Invalid colour for own_winder_colour (try omitting the '#' for hex colours");
6671                         }
6672                 }
6673                 CONF("own_window_hints") {
6674                         if (value) {
6675                                 char *p_hint, *p_save;
6676                                 char delim[] = ", ";
6677
6678                                 /* tokenize the value into individual hints */
6679                                 if ((p_hint=strtok_r(value, delim, &p_save)) != NULL)
6680                                 do {
6681                                          /*fprintf(stderr, "hint [%s] parsed\n", p_hint);*/
6682                                          if (strncmp(p_hint,"undecorate",10) == 0)
6683                                              SET_HINT(window.hints,HINT_UNDECORATED);
6684                                          else if (strncmp(p_hint,"below",5) == 0)
6685                                              SET_HINT(window.hints,HINT_BELOW);
6686                                          else if (strncmp(p_hint,"above",5) == 0)
6687                                              SET_HINT(window.hints,HINT_ABOVE);
6688                                          else if (strncmp(p_hint,"sticky",6) == 0)
6689                                              SET_HINT(window.hints,HINT_STICKY);
6690                                          else if (strncmp(p_hint,"skip_taskbar",12) == 0)
6691                                              SET_HINT(window.hints,HINT_SKIP_TASKBAR);
6692                                          else if (strncmp(p_hint,"skip_pager",10) == 0)
6693                                              SET_HINT(window.hints,HINT_SKIP_PAGER);
6694                                          else
6695                                              CONF_ERR;
6696
6697                                          p_hint=strtok_r(NULL, delim, &p_save);
6698                                 }
6699                                 while (p_hint!=NULL);
6700                         }
6701       else
6702         CONF_ERR;
6703                 }
6704                 CONF("own_window_type") {
6705                         if (value) {
6706                                 if (strncmp(value,"normal",6)==0)
6707                                         window.type = TYPE_NORMAL;
6708                                 else if  (strncmp(value,"desktop",7)==0)
6709                                         window.type = TYPE_DESKTOP;
6710                                 else if (strncmp(value,"override",8)==0)
6711                                         window.type = TYPE_OVERRIDE;
6712                                 else
6713                                   CONF_ERR;
6714                         }
6715       else
6716         CONF_ERR;
6717                 }
6718 #endif
6719                 CONF("stippled_borders") {
6720                         if (value)
6721                                 stippled_borders = strtol(value, 0, 0);
6722                         else
6723                                 stippled_borders = 4;
6724                 }
6725 #endif /* X11 */
6726                 CONF("temp1") {
6727                         ERR("temp1 configuration is obsolete, use ${i2c <i2c device here> temp 1}");
6728                 }
6729                 CONF("temp1") {
6730                         ERR("temp2 configuration is obsolete, use ${i2c <i2c device here> temp 2}");
6731                 }
6732                 CONF("update_interval") {
6733                         if (value)
6734                                 update_interval = strtod(value, 0);
6735                         else
6736                                 CONF_ERR;
6737                 }
6738                 CONF("total_run_times") {
6739                         if (value)
6740                                 total_run_times = strtod(value, 0);
6741                         else
6742                                 CONF_ERR;
6743                 }
6744                 CONF("uppercase") {
6745                         stuff_in_upper_case = string_to_bool(value);
6746                 }
6747                 CONF("max_specials") {
6748                         if (value)
6749                                 max_specials = atoi(value);
6750                         else
6751                                 CONF_ERR;
6752                 }
6753                 CONF("max_user_text") {
6754                         if (value)
6755                                 max_user_text = atoi(value);
6756                         else
6757                                 CONF_ERR;
6758                 }
6759                 CONF("text_buffer_size") {
6760                         if (value)
6761                                 text_buffer_size = atoi(value);
6762                         else
6763                                 CONF_ERR;
6764                 }
6765                 CONF("text") {
6766                         if (text != original_text)
6767                                 free(text);
6768
6769                         text = (char *)
6770                             malloc(1);
6771                         text[0]
6772                             = '\0';
6773
6774                         while (!feof(fp)) {
6775                                 unsigned
6776                                 int l = strlen(text);
6777                                 if (fgets(buf, 256, fp) == NULL)
6778                                         break;
6779                                 text = (char *)
6780                                     realloc(text, l + strlen(buf)
6781                                             + 1);
6782                                 strcat(text, buf);
6783
6784                                 if (strlen(text) > max_user_text)
6785                                         break;
6786                         }
6787                         fclose(fp);
6788                         text_lines = line + 1;
6789                         return;
6790                 }
6791 #ifdef TCP_PORT_MONITOR
6792                 CONF("max_port_monitor_connections") 
6793                 {
6794                         if ( !value || 
6795                              (sscanf(value, "%d", &tcp_port_monitor_args.max_port_monitor_connections) != 1) 
6796                              || tcp_port_monitor_args.max_port_monitor_connections < 0 )
6797                         {
6798                                 /* an error. use default, warn and continue. */
6799                                 tcp_port_monitor_args.max_port_monitor_connections = 
6800                                         MAX_PORT_MONITOR_CONNECTIONS_DEFAULT;
6801                                 CONF_ERR;
6802                         }
6803                         else if ( tcp_port_monitor_args.max_port_monitor_connections == 0 )
6804                         {
6805                                 /* no error, just use default */
6806                                 tcp_port_monitor_args.max_port_monitor_connections = 
6807                                         MAX_PORT_MONITOR_CONNECTIONS_DEFAULT;
6808                         }
6809                         /* else tcp_port_monitor_args.max_port_monitor_connections > 0 as per config */
6810                 }
6811 #endif
6812 #ifdef HAVE_LIBDEXTER
6813     CONF("dexter_client")
6814     {
6815       if (value)
6816         dexter_client = string_to_bool (value);
6817       else
6818         CONF_ERR;
6819     }
6820     CONF("dexter_server")
6821     {
6822       if (value)
6823         dexter_server = string_to_bool (value);
6824       else 
6825         CONF_ERR;
6826     }
6827     CONF("dexter_config")
6828     {
6829       if (value)
6830         dexter_config = strdup (value);
6831       else
6832         CONF_ERR;
6833     }
6834 #endif
6835
6836                 else
6837                 ERR("%s: %d: no such configuration: '%s'", f, line, name);
6838
6839 #undef CONF
6840 #undef CONF2
6841         }
6842
6843         fclose(fp);
6844 #undef CONF_ERR
6845
6846
6847 }
6848
6849                                                                                                                                                                                         /* : means that character before that takes an argument */
6850 static const char *getopt_string = "vVdt:f:u:i:hc:w:x:y:a:"
6851 #ifdef X11
6852                 "x:y:w:a:f:"
6853 #ifdef OWN_WINDOW
6854     "o"
6855 #endif
6856 #ifdef HAVE_XDBE
6857     "b"
6858 #endif
6859 #endif /* X11 */
6860     ;
6861
6862
6863 int main(int argc, char **argv)
6864 {
6865         struct sigaction act, oact;
6866
6867         g_signal_pending=0;
6868         memset(&info, 0, sizeof(info) );
6869
6870 #ifdef TCP_PORT_MONITOR
6871         tcp_port_monitor_args.max_port_monitor_connections = MAX_PORT_MONITOR_CONNECTIONS_DEFAULT;
6872 #endif
6873
6874         /* handle command line parameters that don't change configs */
6875 #ifdef X11
6876         char *s, *temp;
6877         unsigned int x;
6878
6879         if (((s = getenv("LC_ALL")) && *s) || ((s = getenv("LC_CTYPE")) && 
6880                      *s) || ((s = getenv("LANG")) && *s)) {
6881                 temp = (char *)malloc((strlen(s) + 1) * sizeof(char));
6882                 if (temp == NULL) {
6883                         ERR("malloc failed");
6884                 }
6885                 for (x = 0; x < strlen(s); x++) {
6886                         temp[x] = tolower(s[x]);
6887                 }
6888                 if (strstr(temp, "utf-8") || strstr(temp, "utf8")) {
6889                         utf8_mode = 1;
6890                 }
6891                 
6892                 free(temp);
6893         }
6894         if (!setlocale(LC_CTYPE, "")) {
6895                 ERR("Can't set the specified locale!\nCheck LANG, LC_CTYPE, LC_ALL.");
6896         }
6897 #endif /* X11 */
6898         while (1) {
6899                 int c = getopt(argc,
6900                                argv,
6901                                getopt_string);
6902                 if (c == -1)
6903                         break;
6904
6905                 switch (c) {
6906                 case 'v':
6907                 case 'V':
6908                         print_version();
6909                 case 'c':
6910                         /* if current_config is set to a strdup of CONFIG_FILE, free it (even
6911                          * though free() does the NULL check itself;), then load optarg value */
6912                         if (current_config)
6913                                 free(current_config);
6914                         current_config = strdup(optarg);
6915                         break;
6916
6917                 case 'h':
6918                         printf
6919                                         ("Usage: %s [OPTION]...\n"
6920                                         "Conky is a system monitor that renders text on desktop or to own transparent\n"
6921                                         "window. Command line options will override configurations defined in config\n"
6922                                         "file.\n"
6923                                         "   -V            version\n"
6924                                         "   -c FILE       config file to load instead of "
6925                                         CONFIG_FILE
6926                                         "\n"
6927                                         "   -d            daemonize, fork to background\n"
6928                                         "   -h            help\n"
6929 #ifdef X11
6930                                         "   -a ALIGNMENT  text alignment on screen, {top,bottom}_{left,right}\n"
6931                                         "   -f FONT       font to use\n"
6932 #ifdef OWN_WINDOW
6933                                         "   -o            create own window to draw\n"
6934 #endif
6935 #ifdef HAVE_XDBE
6936                                         "   -b            double buffer (prevents flickering)\n"
6937 #endif
6938                                         "   -w WIN_ID     window id to draw\n"
6939                                         "   -x X          x position\n"
6940                                         "   -y Y          y position\n"
6941 #endif /* X11 */
6942                                         "   -t TEXT       text to render, remember single quotes, like -t '$uptime'\n"
6943                                         "   -u SECS       update interval\n"
6944                                         "   -i NUM        number of times to update Conky\n", argv[0]);
6945                         return 0;
6946 #ifdef X11
6947                 case 'w':
6948                         window.window = strtol(optarg, 0, 0);
6949                         break;
6950 #endif /* X11 */
6951
6952                 case '?':
6953                         exit(EXIT_FAILURE);
6954                 }
6955         }
6956 #ifdef X11
6957         /* initalize X BEFORE we load config. (we need to so that 'screen' is set) */
6958         init_X11();
6959 #endif /* X11 */
6960
6961         /* load current_config or CONFIG_FILE */
6962
6963 #ifdef CONFIG_FILE
6964         if (current_config == NULL) {
6965                 /* load default config file */
6966                 char buf[256];
6967
6968                 variable_substitute(CONFIG_FILE, buf, 256);
6969
6970                 if (buf[0] != '\0')
6971                         current_config = strdup(buf);
6972         }
6973 #endif
6974
6975         if (current_config != NULL && fopen((const char *)current_config, (const char *)"r"))
6976                 load_config_file(current_config);
6977         else { 
6978                 set_default_configurations();
6979         }
6980
6981         /* init specials array */
6982         if ((specials = calloc (sizeof(struct special_t), max_specials)) == 0)
6983             ERR("failed to create specials array");
6984
6985 #ifdef MAIL_FILE
6986         if (current_mail_spool == NULL) {
6987                 char buf[256];
6988                 variable_substitute(MAIL_FILE, buf, 256);
6989
6990                 if (buf[0] != '\0')
6991                         current_mail_spool = strdup(buf);
6992         }
6993 #endif
6994
6995         /* handle other command line arguments */
6996
6997 #if defined(__FreeBSD__) || defined (__OpenBSD__) || defined(__NetBSD__)
6998         optind = optreset = 1;
6999 #else
7000         optind = 0;
7001 #endif
7002
7003 #if defined(__FreeBSD__)
7004         if ((kd = kvm_open("/dev/null", "/dev/null", "/dev/null",
7005                         O_RDONLY, "kvm_open")) == NULL)
7006                 CRIT_ERR( "cannot read kvm");
7007 #endif
7008         
7009         while (1) {
7010                 int c = getopt(argc,
7011                                argv,
7012                                getopt_string);
7013                 if (c == -1)
7014                         break;
7015
7016                 switch (c) {
7017                 case 'd':
7018                         fork_to_background = 1;
7019                         break;
7020
7021 #ifdef X11
7022                         case 'f':
7023                         set_first_font(optarg);
7024                         break;
7025                         case 'a':
7026                                 text_alignment = string_to_alignment(optarg);
7027                                 break;
7028
7029 #ifdef OWN_WINDOW
7030                 case 'o':
7031                         own_window = 1;
7032                         break;
7033 #endif
7034 #ifdef HAVE_XDBE
7035                 case 'b':
7036                                 use_xdbe = 1;
7037                         break;
7038 #endif
7039 #endif /* X11 */
7040                 case 't':
7041                         if (text != original_text)
7042                                 free(text);
7043                         text = strdup(optarg);
7044                         convert_escapes(text);
7045                         break;
7046
7047                 case 'u':
7048                         update_interval = strtod(optarg, 0);
7049                         break;
7050
7051                 case 'i':
7052                         total_run_times = strtod(optarg, 0);
7053                         break;
7054 #ifdef X11
7055                 case 'x':
7056                         gap_x = atoi(optarg);
7057                         break;
7058
7059                 case 'y':
7060                         gap_y = atoi(optarg);
7061                         break;
7062 #endif /* X11 */
7063
7064                 case '?':
7065                         exit(EXIT_FAILURE);
7066                 }
7067         }
7068
7069 #ifdef X11
7070         /* load font */
7071         load_fonts();
7072 #endif /* X11 */
7073
7074         /* generate text and get initial size */
7075         extract_variable_text(text);
7076         if (text != original_text) {
7077                 free(text);
7078         }
7079         text = NULL;
7080         /* fork */
7081         if (fork_to_background) {
7082                 int pid = fork();
7083                 switch (pid) {
7084                 case -1:
7085                         ERR("Conky: couldn't fork() to background: %s", strerror(errno));
7086                         break;
7087
7088                 case 0:
7089                         /* child process */
7090                         usleep(25000);
7091                         fprintf(stderr,"\n"); fflush(stderr);
7092                         break;
7093
7094                 default:
7095                         /* parent process */
7096                         fprintf(stderr,"Conky: forked to background, pid is %d\n", pid); fflush(stderr);
7097                         return 0;
7098                 }
7099         }
7100
7101 #ifdef HAVE_LIBDEXTER
7102   memset (&packet_arrival_time, 0, sizeof (struct timespec));
7103   dexter_library_init ();
7104   if (dexter_client)
7105   {
7106     /* wait until some data packets arrive, else conky complains
7107      * bittery that /proc filesystems cannot be opened and, worse,
7108      * will likely segfault when it references unchecked pointers
7109      * in get_text_internal() -- those should be cleaned up.
7110      */
7111     int try;
7112     const int max_tries=30;
7113     gboolean got_packet;
7114     GTimeVal timeval;
7115     fprintf (stderr, "Conky: waiting for data packets to arrive ...\n");
7116     for (try=0;try<max_tries;try++)
7117     {
7118       /* pause main thread for 1 sec */
7119       g_get_current_time (&timeval);
7120       g_time_val_add (&timeval, G_USEC_PER_SEC); 
7121       g_mutex_lock (packet_mutex);
7122       /* mutex released before sleeping; re-acquired after time elapses */
7123       g_cond_timed_wait (packet_cond, packet_mutex, &timeval);
7124       got_packet = packet_arrival_time.tv_sec>0;
7125       g_mutex_unlock (packet_mutex);
7126
7127       if (got_packet)
7128         break;
7129     }
7130     if (got_packet)
7131     {
7132       fprintf(stderr, "Conky: packets arriving ...\n");
7133     }
7134     else
7135     {
7136       fprintf(stderr, "Conky: no data packets ...\n");
7137       dexter_library_exit ();
7138       exit(1);
7139     }
7140   }
7141 #endif
7142
7143 #ifdef X11
7144         selected_font = 0;
7145         update_text_area();     /* to get initial size of the window */
7146
7147         init_window
7148                 (own_window,
7149                  text_width + border_margin * 2 + 1,
7150                  text_height + border_margin * 2 + 1,
7151                  set_transparent, background_colour, argv, argc);
7152         
7153         selected_font = 0;
7154         update_text_area();     /* to position text/window on screen */
7155 #endif /* X11 */
7156
7157 #ifdef X11
7158 #ifdef OWN_WINDOW
7159         if (own_window && !fixed_pos) {
7160                 XMoveWindow(display, window.window, window.x, window.y);
7161         }
7162         if (own_window) {
7163                 set_transparent_background(window.window);
7164         }
7165 #endif
7166
7167         create_gc();
7168
7169         set_font();
7170         draw_stuff();
7171 #endif /* X11 */
7172
7173
7174         /* Set signal handlers */
7175         act.sa_handler = signal_handler;
7176         sigemptyset(&act.sa_mask);
7177         act.sa_flags = 0;
7178 #ifdef SA_RESTART
7179         act.sa_flags |= SA_RESTART;
7180 #endif
7181
7182         if ( sigaction(SIGINT,&act,&oact) < 0 ||
7183              sigaction(SIGUSR1,&act,&oact) < 0 ||
7184              sigaction(SIGTERM,&act,&oact) < 0 )
7185         {
7186                 ERR("error setting signal handler: %s", strerror(errno) );
7187         }
7188
7189 #ifdef AUDACIOUS
7190         if (create_audacious_thread() !=0) 
7191             CRIT_ERR("unable to create audacious thread!");
7192         timed_thread_register (info.audacious.p_timed_thread, &info.audacious.p_timed_thread);
7193 #endif
7194
7195   /*
7196    * ***************
7197    * MAIN CONKY LOOP
7198    * ***************
7199    *
7200    */
7201   main_loop();
7202
7203 #if defined(__FreeBSD__)
7204         kvm_close(kd);
7205 #endif
7206         
7207         return 0;
7208 }
7209
7210 void signal_handler(int sig)
7211 {
7212         /* signal handler is light as a feather, as it should be. 
7213          * we will poll g_signal_pending with each loop of conky
7214          * and do any signal processing there, NOT here. */
7215         g_signal_pending=sig;
7216 }
7217
7218 #ifdef HAVE_LIBDEXTER
7219 void dexter_library_init (void)
7220 {
7221   /* start libdexter */
7222   if (dexter_client || dexter_server)
7223   {
7224     GError *error = NULL;
7225     dexter_init (dexter_config, &error);
7226     if (error)
7227       CRIT_ERR ("%s", error->message);
7228
7229     if (dexter_client)
7230     {
7231       if (!(info.dexter.channel = dexter_channel_new (NULL, NULL, NULL, dexter_channel_events)))
7232         CRIT_ERR("unable to create channel to server");
7233       dexter_channel_open (info.dexter.channel, &error);
7234       if (error)
7235         CRIT_ERR ("%s", error->message);
7236       dexter_channel_greet (info.dexter.channel, &error);
7237       if (error)
7238         CRIT_ERR ("%s", error->message);
7239       if (dexter_client_init () < 0)
7240         CRIT_ERR ("error initializing dexter client");
7241
7242       packet_mutex = g_mutex_new ();
7243       packet_cond = g_cond_new ();
7244     }
7245
7246     if (dexter_server)
7247     {
7248       if (!(info.dexter.server = dexter_server_new (NULL, NULL, NULL)))
7249         CRIT_ERR("unable to create server");
7250       dexter_server_start (info.dexter.server, &error);
7251       if (error)
7252         CRIT_ERR ("%s", error->message);
7253     }
7254
7255   }
7256 }
7257
7258 void dexter_library_exit (void)
7259 {
7260   /* shutdown libdexter */
7261   if (dexter_client || dexter_server)
7262   {
7263     GError *error = NULL;
7264
7265     if (dexter_client)
7266     {
7267       if (dexter_client_exit () < 0)
7268         ERR ("error de-initializing dexter client");
7269       if (info.dexter.channel)
7270       {
7271         dexter_channel_part (info.dexter.channel, &error);
7272         if (error)
7273         {
7274           ERR("%s", error->message);
7275           g_clear_error (&error);
7276         }
7277         dexter_channel_close (info.dexter.channel, &error);
7278         if (error)
7279         {
7280           ERR("%s", error->message);
7281           g_clear_error (&error);
7282         }
7283         dexter_channel_free (info.dexter.channel);
7284         info.dexter.channel=NULL;
7285       }
7286
7287       if (packet_mutex)
7288       {
7289         g_mutex_free (packet_mutex);
7290         packet_mutex=NULL;
7291       }
7292       if (packet_cond)
7293       {
7294         g_cond_free (packet_cond);
7295         packet_cond=NULL;
7296       }
7297     }
7298
7299     if (dexter_server)
7300     {
7301       if (info.dexter.server)
7302       {
7303         dexter_server_stop (info.dexter.server, &error);
7304         if (error)
7305         {
7306           ERR("%s", error->message);
7307           g_clear_error (&error);
7308         }
7309         dexter_server_free (info.dexter.server);
7310         info.dexter.server=NULL;
7311       }
7312     }
7313
7314     dexter_exit ();
7315   }
7316 }
7317
7318 void dexter_channel_events (DexterChannel *channel, gint event)
7319 {
7320   if (!channel)
7321     return;
7322
7323   /* if server disconnects we get this event.  we also get it normally
7324    * following dexter_channel_part(). */
7325   if (event == DEXTER_CHANNEL_EVENT_NOCONN)
7326   {
7327     fprintf (stderr, "Conky: channel to server closed\n");
7328     if (dexter_client && (dexter_client_exit () < 0))
7329       ERR ("error de-initializing dexter client");
7330   }
7331 }
7332 #endif