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