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