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