/* vim: set noet ts=4:
 *
 * Copyright (c) 1999 Michael G. Henderson <mghenderson@lanl.gov>.
 * Copyright (c) 2002-2026 Martin A. Godisch <martin@godisch.de>.
 *
 * This program is free software; you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free Software
 * Foundation; either version 2 of the License, or (at your option) any later
 * version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along with
 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
 * Place, Suite 330, Boston, MA 02111-1307 USA.
 */

#include <assert.h>
#include <config.h>
#include <ctype.h>
#include <errno.h>
#include <getopt.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <unistd.h>
#include <X11/xpm.h>
#include <curl/curl.h>

#include "wmgeneral.h"
#include "wmweather-master.xpm"
#include "wmweather-compat.xpm"
#include "wmweather-lcd.xpm"

#define MAX_STRING 256

struct memory {
	char *memory;
	size_t size;
};

#ifdef XMESSAGE
static void display_report(void);
#endif
#ifndef SYSCONFPATH
#define SYSCONFPATH "/etc/wmweather.conf"
#endif
static void handler(int);
static void do_conf(const char*);
static void do_opts(int, char**);
static void grab_weather(void);
static void update(int);
static size_t curl_callback(void*, size_t, size_t, void*);

CURL
	*curl       = NULL;
static struct memory
	header = {NULL, 0};
char
	url[]       = "https://tgftp.nws.noaa.gov/data/observations/metar/decoded/\0\0\0\0.TXT",
	xtitle[]    = "weather report for \0\0\0\0\0",
	*station    = NULL,
	*report     = NULL,
	*proxy      = NULL,
	*proxy_user = NULL,
	*xdisplay   = NULL,
	*geometry   = NULL,
	curl_errmsg[CURL_ERROR_SIZE];
int
	compat      = 0,
	lcd         = 0,
	delay       = DEFAULT_DELAY * 60,
	pth         = 0,
	metric      = 0,
	hPa         = 0,
	kPa         = 0,
	mmHg        = 0,
	beaufort    = 0,
	knots       = 0,
	mps         = 0,
	tzone       = -50000,
	showheat    = 0,
	showchill   = 0;
pid_t
	xmsg_child  = 0;
time_t
	last_update = 0;
volatile sig_atomic_t
	need_grab   = 0;
XpmColorSymbol colors[6] = {
	{"BackGroundColor",  "#181818", 0}, /* --bc  */
	{"LabelColor",       "#79bdbf", 0}, /* --lc  */
	{"DataColor",        "#ffbf50", 0}, /* --dc  */
	{"GustyWindColor",   "#ff0000", 0}, /* --wgc */
	{"StationTimeColor", "#c5a6ff", 0}, /* --tc  */
	{NULL, NULL, 0}};


int main(int argc, char *argv[])
{
	char
		wmweather_mask_bits[64*64];
	XEvent
		Event;
	static int signals[] =
		{SIGALRM, SIGCHLD, SIGHUP, SIGINT, SIGPIPE, SIGTERM, SIGUSR1, SIGUSR2, 0};
	int i;

	assert(sizeof(char) == 1);

	const char *home = getenv("HOME");
	if (home == NULL) {
		fprintf(stderr, "%s: environment variable HOME is not set\n", PACKAGE_NAME);
		exit(1);
	}
	report = malloc(strlen(home) + strlen("/.wmweather/config") + 1);
	assert(report);
	sprintf(report, "%s/.wmweather", home);
	if (chdir(report)) {
		if (errno == ENOENT) {
			if (mkdir(report, 0755)) {
				fprintf(stderr, "%s: cannot create %s: %m\n", PACKAGE_NAME, report);
				exit(errno);
			}
		} else {
			fprintf(stderr, "%s: cannot chdir into %s: %m\n", PACKAGE_NAME, report);
			exit(errno);
		}
	}

	do_conf(SYSCONFPATH);
	strcat(report, "/config");
	do_conf(report);
	do_opts(argc, argv);

	if (station == NULL) {
		fprintf(stderr, "%s: no ICAO location indicator specified\n", PACKAGE_NAME);
		exit(1);
	}
	if (strlen(station) != 4) {
		fprintf(stderr, "%s: ICAO location indicator must be exactly four characters\n", PACKAGE_NAME);
		exit(1);
	}
	{
		int k;
		for (k = 0; k < 4; k++)
			if (!isalnum((unsigned char)station[k])) {
				fprintf(stderr, "%s: ICAO location indicator must be alphanumeric\n", PACKAGE_NAME);
				exit(1);
			}
	}
	memcpy(url + strlen(url), station, 4);
	memcpy(xtitle + strlen(xtitle), station, 4);
	sprintf(rindex(report, '/'), "/%s", station);

	for (i = 0; signals[i]; i++)
		if (signal(signals[i], handler) == SIG_ERR)
			fprintf(stderr, "%s: cannot set handler for signal %d: %m\n", PACKAGE_NAME, signals[i]);

	memset(curl_errmsg, 0, CURL_ERROR_SIZE);
	curl_global_init(CURL_GLOBAL_NOTHING);
	curl = curl_easy_init();
	assert(curl);
	if (curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, curl_errmsg) != CURLE_OK ||
		curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 1) != CURLE_OK ||
		curl_easy_setopt(curl, CURLOPT_TIMEOUT, 120) != CURLE_OK ||
		curl_easy_setopt(curl, CURLOPT_USERAGENT, PACKAGE_STRING) != CURLE_OK ||
		curl_easy_setopt(curl, CURLOPT_URL, url) != CURLE_OK ||
		curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, curl_callback) != CURLE_OK ||
		curl_easy_setopt(curl, CURLOPT_WRITEHEADER, (void*)&header) != CURLE_OK ||
		(proxy && curl_easy_setopt(curl, CURLOPT_PROXY, proxy) != CURLE_OK) ||
		(proxy && proxy_user && curl_easy_setopt(curl, CURLOPT_PROXYUSERPWD, proxy_user) != CURLE_OK) ||
		curl_easy_setopt(curl, CURLOPT_PROTOCOLS_STR, "https") != CURLE_OK ||
		curl_easy_setopt(curl, CURLOPT_REDIR_PROTOCOLS_STR, "https") != CURLE_OK ||
		curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1) != CURLE_OK ||
		curl_easy_setopt(curl, CURLOPT_MAXREDIRS, 10) != CURLE_OK) {
		fprintf(stderr, "%s: %s\n", PACKAGE_NAME, curl_errmsg);
		exit(1);
	}

	initXwindow(xdisplay);
	if (compat) {
		createXBMfromXPM(wmweather_mask_bits, wmweather_compat_xpm, 64, 64);
		openXwindow(argc, argv, wmweather_compat_xpm, wmweather_mask_bits, 64, 64, geometry, colors);
	} else if (lcd) {
		createXBMfromXPM(wmweather_mask_bits, wmweather_lcd_xpm, 64, 64);
		openXwindow(argc, argv, wmweather_lcd_xpm, wmweather_mask_bits, 64, 64, geometry, NULL);
	} else {
		createXBMfromXPM(wmweather_mask_bits, wmweather_master_xpm, 64, 64);
		openXwindow(argc, argv, wmweather_master_xpm, wmweather_mask_bits, 64, 64, geometry, NULL);
	}

	update(1);
	kill(getpid(), SIGALRM);

	while (1) {
		if (need_grab) {
			time_t now;
			need_grab = 0;
			grab_weather();
			time(&now);
			alarm(pth ? now / 3600 * 3600 + delay - now + (now % 3600 < delay ? 0 : 3600) : delay);
		}
		if (time(NULL) != last_update)
			update(0);
		while (XPending(display)) {
			XNextEvent(display, &Event);
			switch (Event.type) {
			case Expose:
				RedrawWindow();
				break;
			case DestroyNotify:
				XCloseDisplay(display);
				exit(0);
			case ButtonPress:
				switch (Event.xbutton.button) {
#ifdef XMESSAGE
				case Button1:
					display_report();
					break;
#endif
				case Button2:
					metric = !metric;
					update(1);
					break;
				case Button3:
					grab_weather();
					break;
				}
				break;
			case ButtonRelease:
				break;
			}
		}
		usleep(50000L);
	}
}

#ifdef XMESSAGE
static void display_report(void)
{
	if (xmsg_child)
		return;
	if ((xmsg_child = fork()) < 0) {
		fprintf(stderr, "%s: cannot fork: %m\n", PACKAGE_NAME);
		xmsg_child = 0;
		return;
	}
	if (xmsg_child)
		return;
	if (execl(XMESSAGE, "xmessage", "-center", "-file", report, "-title", xtitle, NULL) < 0) {
		fprintf(stderr, "%s (pid %d): error executing xmessage: %m\n", PACKAGE_NAME, getpid());
		exit(1);
	}
}
#endif

static void do_conf(const char *rcfile)
{
	FILE
		*F = NULL;
	char
		buffer[512],
		*p      = NULL,
		*optarg = NULL;
	int
		line, i;

	if ((F = fopen(rcfile, "r")) == NULL) {
		if (errno != ENOENT)
			fprintf(stderr, "%s: cannot open %s: %m\n", PACKAGE_NAME, rcfile);
		return;
	}
	for (line = 1;; line++) {
		p = fgets(buffer, sizeof(buffer), F);
		if (feof(F))
			break;
		if ((p = index(buffer, '\n')) != NULL)
			*p = '\0';
		while ((p = index(buffer, ' ')) || (p = index(buffer, '\t')))
			do {
				*p = *(p+1);
			} while (*p++);
		if (*buffer == '\0' || *buffer == '#')
			continue;
		if ((optarg = index(buffer, '=')) != NULL)
			*(optarg++) = '\0';
		if (strcmp(buffer, "station") == 0 && optarg) {
			if (strlen(optarg) != 4) {
				fprintf(stderr, "%s: invalid ICAO location indicator in %s line %d\n", PACKAGE_NAME, rcfile, line);
				exit(1);
			}
			for (i = 0; i < 4; i++)
				optarg[i] = toupper(optarg[i]);
			if (station != NULL)
				free(station);
			station = strdup(optarg);
			assert(station);
		} else if (strcmp(buffer, "delay") == 0 && optarg) {
			if (optarg[0] == '@') {
				pth = 1;
				optarg[0] = '0';
			} else
				pth = 0;
			delay = strtol(optarg, &p, 10);
			if (*p != '\0') {
				fprintf(stderr, "%s: invalid delay -- %s minutes in %s line %d\n", PACKAGE_NAME, optarg, rcfile, line);
				exit(1);
			}
			delay *= 60;
		} else if (strcmp(buffer, "metric")   == 0) {
			metric = 1;
		} else if (strcmp(buffer, "imperial")   == 0) {
			metric = 0;
		} else if (strcmp(buffer, "hPa")      == 0) {
			hPa  = 1;
			mmHg = 0;
		} else if (strcmp(buffer, "kPa")      == 0) {
			kPa  = 1;
			mmHg = 0;
		} else if (strcmp(buffer, "mmHg")     == 0) {
			mmHg = 1;
		} else if (strcmp(buffer, "beaufort") == 0) {
			beaufort = 1;
		} else if (strcmp(buffer, "knots")    == 0) {
			knots = 1;
		} else if (strcmp(buffer, "mps")      == 0) {
			mps = 1;
		} else if (strcmp(buffer, "chill")    == 0) {
			showchill = 1;
 		} else if (strcmp(buffer, "heat")     == 0) {
 			showheat = 1;
		} else if (strcmp(buffer, "utc")      == 0) {
			tzone = 0;
		} else if (strcmp(buffer, "time") == 0 && optarg) {
			tzone = strtol(optarg, &p, 10);
			if (*p != '\0' || tzone < -1200 || tzone > +1200) {
				fprintf(stderr, "%s: invalid RFC 822 timezone -- %s in %s line %d\n", PACKAGE_NAME, optarg, rcfile, line);
				exit(1);
			}
			tzone = tzone / 100 * 3600 + tzone % 100 * 60;
		} else if (strcmp(buffer, "proxy") == 0 && optarg) {
			proxy = strdup(optarg);
			assert(proxy);
		} else if (strcmp(buffer, "proxy-user") == 0 && optarg) {
			proxy_user = strdup(optarg);
			assert(proxy_user);
			memset(optarg, '*', strlen(optarg));
		} else if (strcmp(buffer, "compat") == 0) {
			compat = 1;
			if (!hPa && !kPa)
				mmHg = 1;
		} else if (strcmp(buffer, "bc")  == 0 && optarg) {
			colors[0].value = strdup(optarg);
			assert(colors[0].value);
		} else if (strcmp(buffer, "lc")  == 0 && optarg) {
			colors[1].value = strdup(optarg);
			assert(colors[1].value);
		} else if (strcmp(buffer, "dc")  == 0 && optarg) {
			colors[2].value = strdup(optarg);
			assert(colors[2].value);
		} else if (strcmp(buffer, "wgc") == 0 && optarg) {
			colors[3].value = strdup(optarg);
			assert(colors[3].value);
		} else if (strcmp(buffer, "tc")  == 0 && optarg) {
			colors[4].value = strdup(optarg);
			assert(colors[4].value);
		} else if (strcmp(buffer, "lcd") == 0) {
			lcd = 1;
		} else if (strcmp(buffer, "display")  == 0 && optarg) {
			xdisplay = strdup(optarg);
			assert(xdisplay);
		} else if (strcmp(buffer, "geometry") == 0 && optarg) {
			geometry = strdup(optarg);
			assert(geometry);
		} else {
			fprintf(stderr, "%s: invalid or incomplete keyword `%s' in %s line %d\n", PACKAGE_NAME, buffer, rcfile, line);
			exit(1);
		}
	}
	fclose(F);
}

static void do_opts(int argc, char *argv[])
{
	static struct option long_opts[] = {
		{"station",    1, NULL, 's'},
		{"delay",      1, NULL, 'd'},
		{"metric",     0, NULL, 'm'},
		{"imperial",   0, NULL, 'i'},
		{"hPa",        0, NULL, 'a'},
		{"kPa",        0, NULL, 'k'},
		{"mmHg",       0, NULL, 'g'},
		{"beaufort",   0, NULL, 'b'},
		{"knots",      0, NULL, 'n'},
		{"mps",        0, NULL, 'p'},
		{"chill",      0, NULL, 'w'},
		{"heat",       0, NULL, 'e'},
		{"utc",        0, NULL, 'u'},
		{"time",       1, NULL, 't'},
		{"proxy",      1, NULL, 'x'},
		{"proxy-user", 1, NULL, 'U'},
		{"compat",     0, NULL, 'c'},
		{"help",       0, NULL, 'h'},
		{"version",    0, NULL, 'v'},
		{"bc",         1, NULL,  0 },
		{"lc",         1, NULL,  1 },
		{"dc",         1, NULL,  2 },
		{"wgc",        1, NULL,  3 },
		{"tc",         1, NULL,  4 },
		{"display",    1, NULL,  5 },
		{"geometry",   1, NULL,  6 },
		{"lcd",        0, NULL,  7 },
		{NULL,         0, NULL,  0}};
	char *p;
	int  i;

	if ((p = strstr(argv[0], "wmWeather")))
		if (*(p + 9) == '\0') {
			compat = 1;
			mmHg   = 1;
		}
	while (1) {
		if ((i = getopt_long(argc, argv, "s:d:miakgbnpwWeut:x:U:chv", long_opts, NULL)) == -1)
			break;
		switch (i) {
		case 's':
			assert(optarg);
			if (strlen(optarg) != 4) {
				fprintf(stderr, "%s: invalid ICAO location indicator\n", PACKAGE_NAME);
				exit(1);
			}
			for (i = 0; i < 4; i++)
				optarg[i] = toupper(optarg[i]);
			if (station != NULL)
				free(station);
			station = optarg;
			break;
		case 'd':
			assert(optarg);
			if (optarg[0] == '@') {
				pth = 1;
				optarg[0] = '0';
			} else
				pth = 0;
			delay = strtol(optarg, &p, 10);
			if (*p != '\0') {
				fprintf(stderr, "%s: invalid delay -- %s minutes\n", PACKAGE_NAME, optarg);
				exit(1);
			}
			delay *= 60;
			break;
		case 'm':
			metric = 1;
			break;
		case 'i':
			metric = 0;
			break;
		case 'a':
			hPa  = 1;
			mmHg = 0;
			break;
		case 'k':
			kPa  = 1;
			mmHg = 0;
			break;
		case 'g':
			mmHg = 1;
			break;
		case 'b':
			beaufort = 1;
			break;
		case 'n':
			knots = 1;
			break;
		case 'p':
			mps = 1;
			break;
		case 'w':
		case 'W':
			showchill = 1;
			break;
		case 'e':
			showheat = 1;
			break;
		case 'u':
			tzone = 0;
			break;
		case 't':
			assert(optarg);
			tzone = strtol(optarg, &p, 10);
			if (*p != '\0' || tzone < -1200 || tzone > +1200) {
				fprintf(stderr, "%s: invalid RFC 822 timezone -- %s\n", PACKAGE_NAME, optarg);
				exit(1);
			}
			tzone = tzone / 100 * 3600 + tzone % 100 * 60;
			break;
		case 'x':
			assert(optarg);
			proxy = optarg;
			break;
		case 'U':
			assert(optarg);
			proxy_user = strdup(optarg);
			assert(proxy_user);
			memset(optarg, '*', strlen(optarg));
			/*
			if (index(proxy_user, ':') == NULL || *(index(proxy_user, ':') + 1) == '\0') {
				fprintf(stderr, "%s: option --proxy-user requires proxy authentication password\n", PACKAGE_NAME);
				exit(1);
			}
			*/
			break;
		case 'c':
			compat = 1;
			if (!hPa && !kPa)
				mmHg = 1;
			break;
		case 'h':
			printf("Usage: wmweather -s <id> [options], wmWeather -s <id> [options]\n");
			printf("  -s, --station=<id>    four-letter ICAO location indicator (required),\n");
			printf("  -c, --compat          use version 1 monitor style, default in wmWeather,\n");
			printf("  -d, --delay=[@]<min>  update delay, use @ for minutes past the hour,\n");
			printf("  -m, --metric          display metric values: °C, hPa, km/h,\n");
			printf("  -i, --imperial        display metric values: °F, mmHg, mi/h,\n");
			printf("  -w, --chill           display wind chill instead of dew point,\n");
			printf("  -e, --heat            display heat index instead of dew point,\n");
			printf("  -b, --beaufort        display windspeed in Beaufort,\n");
			printf("  -n, --knots           display windspeed in knots (seamiles per hour),\n");
			printf("  -u, --utc             display UTC instead of localtime,\n");
			printf("  -t, --time=<offset>   convert UTC using time offset instead to localtime,\n");
			printf("  -x, --proxy=<host>[:<port>]            proxy specification,\n");
			printf("  -U, --proxy-user=<user>[:<password>]   proxy authentication,\n");
			printf("  --lcd                 use LCD style display,\n");
			printf("  --display=<id>        specify the display to use, e.g. `:0.0',\n");
			printf("  --geometry=<pos>      specify the position of the dock app, e.g. `+10+10',\n");
			printf("  -h, --help            display this command line summary,\n");
			printf("  -v, --version         display the version number.\n");
			printf("Available, if --metric has been specified:\n");
			printf("  -a, --hPa             display pressure in hPa, i.e. milliBars,\n");
			printf("  -k, --kPa             display pressure in kPa,\n");
			printf("  -g, --mmHg            display pressure in millimeters of Mercury,\n");
			printf("  -p, --mps             display windspeed in meters/second.\n");
			printf("Available, if --compat has been specified or `wmWeather' is called:\n");
			printf("  --bc=<color>          background color, e.g. `#7e9e69',\n");
			printf("  --lc=<color>          label color,\n");
			printf("  --dc=<color>          data color,\n");
			printf("  --wgc=<color>         gusty-wind (variable direction) color,\n");
			printf("  --tc=<color>          station ID and time color.\n");
			printf("System-wide configuration file is %s.\n", SYSCONFPATH);
			printf("For ICAO location indicators visit https://en.wikipedia.org/wiki/ICAO_airport_code.\n");
			exit(0);
		case 'v':
			printf("%s\n", PACKAGE_STRING);
			printf("copyright (c) 1999 Michael G. Henderson <mghenderson@lanl.gov>\n");
			printf("copyright (c) 2002-2019 Martin A. Godisch <martin@godisch.de>\n");
			exit(0);
		case 0:
		case 1:
		case 2:
		case 3:
		case 4:
			assert(optarg);
			colors[i].value = optarg;
			break;
		case 5:
			assert(optarg);
			xdisplay = optarg;
			break;
		case 6:
			assert(optarg);
			geometry = optarg;
			break;
		case 7:
			lcd = 1;
			break;
		case '?':
			exit(1);
		}
	}
	if (optind < argc) {
		fprintf(stderr, "%s: invalid argument -- %s\n", PACKAGE_NAME, argv[optind]);
		exit(1);
	}
}

static void grab_weather(void)
{
	static FILE
		*F    = NULL;
	static char
		*temp = NULL;
	long
		response;
	unsigned int
		http;

	if (F != NULL)
		return;
	if (temp == NULL) {
		temp = malloc(strlen(report) + 5);
		assert(temp);
		sprintf(temp, "%s.new", report);
	}
	if ((F = fopen(temp, "w")) == NULL) {
		fprintf(stderr, "%s: cannot open %s for writing: %m\n", PACKAGE_NAME, temp);
		goto GRAB_ERR;
	}
	if (curl_easy_setopt(curl, CURLOPT_FILE, F)) {
		fprintf(stderr, "%s: %s\n", PACKAGE_NAME, curl_errmsg);
		goto GRAB_ERR;
	}
	switch (curl_easy_perform(curl)) {
	case CURLE_OK:
		if (curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response) != CURLE_OK) {
			fprintf(stderr, "%s: %s\n", PACKAGE_NAME, curl_errmsg);
			goto GRAB_ERR;
		}
		http = (unsigned int)response;
		if (http < 200) {        /* 1xx - Informational */
			/* FIXME: what to do here? */
		} else if (http < 300) { /* 2xx - Success       */
			if (rename(temp, report) < 0) {
				fprintf(stderr, "%s: Cannot rename %s to %s: %m\n", PACKAGE_NAME, temp, report);
				goto GRAB_ERR;
			}
		} else if (http < 400) { /* 3xx - Redirection   */
			fprintf(stderr, "%s: Received error %u while fetching %s from NOAA, aborting\n", PACKAGE_NAME, http, station);
			fprintf(stderr, "%s: Please send a bug report to <%s>\n", PACKAGE_NAME, PACKAGE_BUGREPORT);
			goto GRAB_ERR;
		} else if (http < 500 && http != 403) { /* 4xx - Client Error  */
			if (http == 404)
				fprintf(stderr, "%s: ICAO location indicator %s not found at NOAA, aborting\n", PACKAGE_NAME, station);
			else
				fprintf(stderr, "%s: Received error %u while fetching %s from NOAA, aborting\n", PACKAGE_NAME, http, station);
			goto GRAB_ERR;
		} else {                 /* 5xx - Server Error  */
			fprintf(stderr, "%s: Received error %u while fetching %s from NOAA\n", PACKAGE_NAME, http, station);
		}
		break;
	default:
		fprintf(stderr, "%s: %s\n", PACKAGE_NAME, curl_errmsg);
	}
	free(header.memory);
	header.memory = NULL;
	header.size   = 0;
	fclose(F);
	F = NULL;
	unlink(temp);
	return;
GRAB_ERR:
	if (F != NULL) {
		fclose(F);
		unlink(temp);
	}
	curl_easy_cleanup(curl);
	curl_global_cleanup();
	exit(1);
}

static void handler(int signo)
{
	pid_t  pid;
	int status;

	switch (signo) {
	case SIGALRM:
		need_grab = 1;
		break;
	case SIGCHLD:
		if ((pid = waitpid(-1, &status, WNOHANG)) < 0)
			return;
		if (pid == xmsg_child)
			xmsg_child = 0;
		break;
	default:
		curl_easy_cleanup(curl);
		curl_global_cleanup();
		exit(0);
	}
}

static void update(int force_read)
{
	static char
		id[4],
		winddir[3];
	static int
		last24h          = 0,
		temperature      = 0,
		temperatureavail = 0,
		dewpoint         = 0,
		dewpointavail    = 0,
		windchill        = 0,
		windchillavail   = 0,
		heatindexavail   = 0,
		humidity         = 0,
		humidityavail    = 0,
		pressureavail    = 0,
		winddiravail     = 0,
		windspeedavail   = 0,
		gusting          = 0,
		showgusting      = 0,
		showwinddir      = 0,
		showerror        = 1;
	static double
		windspeed        = 0,
		heatindex        = 0,
		pressure         = 0;
	static time_t
		last_report      = 0,
		timestamp        = 0;
	struct stat rst;
	struct tm   *tm;
	time_t utc_diff;
	FILE   *F;
	char   buffer[MAX_STRING], *i;
	int    line, n, q, sgn;
	long   l = 0;
	time_t t;

	time(&t);
	tm = gmtime(&t);
	utc_diff = tm->tm_hour;
	tm = localtime(&t);
	utc_diff = (tm->tm_hour - utc_diff + 24) % 24 * 3600;

	if (stat(report, &rst) < 0 && errno != ENOENT) {
		if (showerror) {
			fprintf(stderr, "%s: cannot stat weather report %s: %m\n", PACKAGE_NAME, report);
			showerror = 0;
		}
		return;
	}

	if (rst.st_mtime > last_report || force_read) {
		F = fopen(report, "r");
		if (!F) {
			if (showerror && errno != ENOENT) {
				fprintf(stderr, "%s: cannot open weather report %s: %m\n", PACKAGE_NAME, report);
				showerror = 0;
			}
			return;
		}
		last_report = rst.st_mtime;
		memcpy(id, "\0\0\0\0", 4);
		memcpy(winddir, "\0\0\0", 3);
		timestamp        = 0;
		last24h          = 0;
		temperature      = 0;
		temperatureavail = 0;
		dewpoint         = 0;
		dewpointavail    = 0;
		windchill        = 0;
		windchillavail   = 0;
		heatindex        = 0;
		heatindexavail   = 0;
		humidity         = 0;
		humidityavail    = 0;
		pressureavail    = 0;
		winddiravail     = 0;
		windspeedavail   = 0;
		gusting          = 0;
		showgusting      = 0;
		showwinddir      = 0;
		showerror        = 1;
		windspeed        = 0;
		pressure         = 0;
		for (line = 1;; line++) {
			i = fgets(buffer, MAX_STRING, F);
			if (feof(F))
				break;

			if (!strncmp(buffer, "ob: ", 4)) {
				if ((i = strchr(buffer, ' ')) == NULL)
					continue;
				i++;
				for (n = 0; n < 4 && *i; n++, i++)
					id[n] = *i;
				continue;
			}

			if (line == 2) {
				if ((i = strrchr(buffer, ' ')) == NULL || i - buffer < 15) {
					fclose(F);
					return;
				}
				i -= 15;
				assert(tm);
				tm->tm_year = strtol(i, &i, 10) - 1900;
				if (*i != '.')
					continue;
				i++;
				tm->tm_mon  = strtol(i, &i, 10) - 1;
				if (*i != '.')
					continue;
				i++;
				tm->tm_mday = strtol(i, &i, 10);
				if (*i != ' ')
					continue;
				i++;
				l = strtol(i, &i, 10);
				if (*i != ' ' || l < 0 || l >= 2400)
					continue;
				tm->tm_hour  = l / 100;
				tm->tm_min   = l % 100;
				tm->tm_sec   =  0;
				tm->tm_isdst = -1;
				timestamp = mktime(tm) + utc_diff;
				continue;
			}

			if (!strncmp(buffer, "Wind: ", 6)) {
				if (strstr(buffer, " Calm")) {
					windspeed      = 0;
					windspeedavail = 1;
					winddiravail   = 0;
					continue;
				}
				if (strstr(buffer, " Variable "))
					memcpy(winddir, "VRB", 3);
				else
					for (n = 0; n < 3; n++)
						if (buffer[n+15] == ' ')
							break;
						else
							winddir[n] = buffer[n+15];
				winddiravail = 1;
				if ((i = strstr(buffer, " MPH")) == NULL) {
					if (showerror)
						fprintf(stderr, "%s: invalid windspeed: %s line %d\n", PACKAGE_NAME, report, line);
					continue;
				}
				i--;
				while (i > buffer && *i != ' ')
					i--;
				if (*i == ' ')
					i++;
				windspeed = strtol(i, &i, 10);
				if (*i != ' ') {
					if (showerror)
						fprintf(stderr, "%s: invalid windspeed: %s line %d\n", PACKAGE_NAME, report, line);
					continue;
				}
				if ((i = strstr(buffer, " gusting "))) {
					l = strtol(i + 12, &i, 10);
					if (*i != ' ') {
						if (showerror)
							fprintf(stderr, "%s: invalid gusting windspeed: %s line %d\n", PACKAGE_NAME, report, line);
						continue;
					}
					windspeed = (windspeed + l) / 2.0 + 0.5;
					gusting = 1;
				}
				windspeedavail = 1;
				if (knots)
					windspeed *= 0.8688; /* kt = sm/h */
				else if ((metric && mps) || beaufort)
					windspeed *= 0.4469; /* m/s  */
				else if (metric)
					windspeed *= 1.6090; /* km/h */
				/* else miles/h */
				if (beaufort) {
					if (windspeed <= 0.2)
						windspeed = 0;
					else if (windspeed >  0.2 && windspeed <=  1.5)
						windspeed = 1;
					else if (windspeed >  1.5 && windspeed <=  3.3)
						windspeed = 2;
					else if (windspeed >  3.3 && windspeed <=  5.4)
						windspeed = 3;
					else if (windspeed >  5.4 && windspeed <=  7.9)
						windspeed = 4;
					else if (windspeed >  7.9 && windspeed <= 10.7)
						windspeed = 5;
					else if (windspeed > 10.7 && windspeed <= 13.8)
						windspeed = 6;
					else if (windspeed > 13.8 && windspeed <= 17.1)
						windspeed = 7;
					else if (windspeed > 17.1 && windspeed <= 20.7)
						windspeed = 8;
					else if (windspeed > 20.7 && windspeed <= 24.4)
						windspeed = 9;
					else if (windspeed > 24.4 && windspeed <= 28.4)
						windspeed = 10;
					else if (windspeed > 28.4 && windspeed <= 32.6)
						windspeed = 11;
					else if (windspeed > 32.6 && windspeed <= 36.9)
						windspeed = 12;
					else {
						windspeed = 13;
					}
				}
				windspeed = (long)(windspeed + 0.5);
				continue;
			}

			if (!strncmp(buffer, "Windchill: ", 11)) {
				i = buffer + 11;
				windchill = strtol(i, &i, 10);
				if (*i != ' ') {
					if (showerror)
						fprintf(stderr, "%s: invalid wind chill temperature: %s line %d\n", PACKAGE_NAME, report, line);
					continue;
				}
				windchillavail = 1;
				if (metric)
					windchill = (windchill - 32.0) * 5.0 / 9.0 + 0.5;
				continue;
			}

			if (!strncmp(buffer, "Heat index: ", 12)) {
				i = buffer + 12;
				heatindex = strtod(i, &i);
				if (*i != ' ') {
					if (showerror)
						fprintf(stderr, "%s: invalid heat index temperature: %s line %d\n", PACKAGE_NAME, report, line);
					continue;
				}
				heatindexavail = 1;
				if (metric)
					heatindex = (heatindex - 32.0) * 5.0 / 9.0 + 0.5;
				continue;
			}

			if (!strncmp(buffer, "Temperature: ", 13)) {
				double t;
				i = buffer + 13;
				t = strtod(i, &i);
				if (*i != ' ') {
					if (showerror)
						fprintf(stderr, "%s: invalid temperature: %s line %d\n", PACKAGE_NAME, report, line);
					continue;
				}
				temperatureavail = 1;
				if (metric)
					t = (t - 32.0) * 5.0 / 9.0;
				temperature = (t < 0) ? t - 0.5 : t + 0.5;
				continue;
			}

			if (!strncmp(buffer, "Dew Point: ", 11)) {
				double d;
				i = buffer + 11;
				d = strtod(i, &i);
				if (*i != ' ') {
					if (showerror)
						fprintf(stderr, "%s: invalid dew point: %s line %d\n", PACKAGE_NAME, report, line);
					continue;
				}
				dewpointavail = 1;
				if (metric)
					d = (d - 32.0) * 5.0 / 9.0;
				dewpoint = (d < 0) ? d - 0.5 : d + 0.5;
				continue;
			}

			if (!strncmp(buffer, "Relative Humidity: ", 19)) {
				i = buffer + 19;
				humidity = strtol(i, &i, 10);
				if (*i != '%') {
					if (showerror)
						fprintf(stderr, "%s: invalid humidity: %s line %d\n", PACKAGE_NAME, report, line);
					continue;
				}
				humidityavail = 1;
				continue;
			}

			if (!strncmp(buffer, "Pressure (altimeter): ", 22)) {
				i = buffer + 22;
				pressure = strtod(i, &i);
				if (*i != ' ') {
					if (showerror)
						fprintf(stderr, "%s: invalid pressure: %s line %d\n", PACKAGE_NAME, report, line);
					continue;
				}
				pressureavail = 1;
				if (metric) {
					if (mmHg)
						pressure = pressure * 25.4;
					else if (kPa)
						pressure = pressure * 3.38639;
					else /* hPa */
						pressure = pressure * 33.8639;
				} /* else inHg */
				continue;
			}
		}
		fclose(F);
	}

	if (!id[0])
		return;
	last24h = time(NULL) - timestamp < 86400;

	if (compat) {

		copyXPMArea(5, 69, 54, 54, 5, 5);

		for (n = 0; n < 4; n++)
			if (id[n] >= 'A' && id[n] <= 'Z')
				copyXPMArea((int)(id[n] - 'A') * 5 + 2, 128, 5, 6, n * 5 + 7, 6);
			else if (id[n] >= '0' && id[n] <= '9')
				copyXPMArea((int)(id[n] - '0') * 5 + 2, 135, 5, 6, n * 5 + 7, 6);

		{
			time_t lt = timestamp + (tzone < -43200 ? utc_diff : tzone);
			copyXPMArea(lt / 3600 % 24 / 10 * 5 + (last24h ? 2 : 66), last24h ? 135 : 64, 5, 6, 36, 6);
			copyXPMArea(lt / 3600 % 24 % 10 * 5 + (last24h ? 2 : 66), last24h ? 135 : 64, 5, 6, 41, 6);
			copyXPMArea(last24h ? 53 : 55, 135, 1, 6, 46, 6);
			copyXPMArea(lt /   60 % 60 / 10 * 5 + (last24h ? 2 : 66), last24h ? 135 : 64, 5, 6, 48, 6);
			copyXPMArea(lt /   60 % 60 % 10 * 5 + (last24h ? 2 : 66), last24h ? 135 : 64, 5, 6, 53, 6);
		}

		if (temperatureavail) {
			q   = 0;
			l   = temperature;
			sgn = (l < 0) ? -1 : 1;
			if (sgn < 0) {
				copyXPMArea(125, 57, 5, 6, 25, 15);
				q +=  5;
				l *= -1;
			}
			if (l >= 100) {
				copyXPMArea(l %  1000 /  100 * 5 + 66, 57, 5, 6, 25 + q, 15);
				q += 5;
			}
			if (l >=  10) {
				copyXPMArea(l %   100 /   10 * 5 + 66, 57, 5, 6, 25 + q, 15);
				q += 5;
			}
			copyXPMArea(l % 10 * 5 + 66, 57, 5, 6, 25 + q, 15);
			if (metric) {
				copyXPMArea(72, 34, 3, 3, 30+q, 14);
				copyXPMArea(81, 35, 4, 6, 34+q, 15);
			} else {
				copyXPMArea(72, 34, 8, 7, 30+q, 14);
			}
		}

		if (windchillavail && (showchill || !dewpointavail)) {
			l = windchill;
			copyXPMArea(66, 87, 17, 8, 5, 23);
		} else if (dewpointavail) {
			l = dewpoint;
			copyXPMArea(5, 87, 17, 8, 5, 23);
		}
		if (windchillavail || dewpointavail) {
			q   = 0;
			sgn = (l < 0) ? -1 : 1;
			if (sgn < 0) {
				copyXPMArea(125, 57, 5, 6, 25, 24);
				q +=  5;
				l *= -1;
			}
			if (l >= 100) {
				copyXPMArea(l % 1000 / 100 * 5 + 66, 57, 5, 6, 25 + q, 24);
				q += 5;
			}
			if (l >=  10) {
				copyXPMArea(l %  100 /  10 * 5 + 66, 57, 5, 6, 25 + q, 24);
				q += 5;
			}
			copyXPMArea(l % 10 * 5 + 66, 57, 5, 6, 25 + q, 24);
			if (metric) {
				copyXPMArea(72, 34, 3, 3, 30 + q, 23);
				copyXPMArea(81, 35, 4, 6, 34 + q, 24);
			} else {
				copyXPMArea(72, 34, 8, 7, 30 + q, 23);
			}
		}

		if (pressureavail) {
			q = 0;
			if (pressure < 100)
				l = (long)(pressure * 100 + 0.5);
			else
				l = (long)(pressure * 100 + 50);
			if (l >= 100000) {
				copyXPMArea(l % 1000000 / 100000 * 5 + 66, 57, 5, 6, 25 + q, 33);
				q += 5;
			}
			if (l >=  10000) {
				copyXPMArea(l %  100000 /  10000 * 5 + 66, 57, 5, 6, 25 + q, 33);
				q += 5;
			}
			if (l >=   1000) {
				copyXPMArea(l %   10000 /   1000 * 5 + 66, 57, 5, 6, 25 + q, 33);
				q += 5;
			}
			copyXPMArea(l % 1000 / 100 * 5 + 66, 57, 5, 6, 25 + q, 33);
			q += 5;
			if (l < 10000) {
				copyXPMArea(117, 57, 4, 6, 25 + q, 33);
				q += 4;
				copyXPMArea(l % 100 / 10 * 5 + 66, 57, 5, 6, 25 + q, 33);
				q += 5;
				copyXPMArea(l %  10      * 5 + 66, 57, 5, 6, 25 + q, 33);
			}
		}

		if (humidityavail) {
			q = 0;
			l = humidity;
			if (l >= 100) {
				copyXPMArea(l % 1000 / 100 * 5 + 66, 57, 5, 6, 25 + q, 42);
				q += 5;
			}
			if (l >=  10) {
				copyXPMArea(l %  100 /  10 * 5 + 66, 57, 5, 6, 25 + q, 42);
				q += 5;
			}
			copyXPMArea(l % 10 * 5 + 66, 57, 5, 6, 25 + q, 42);
			copyXPMArea(121, 57, 5, 6, 30 + q, 42);
		}

		q = 0;
		if (winddiravail) {
			for (n = 0; n < 3; n++) {
				switch(winddir[n]) {
				case 'N':
					copyXPMArea(66, 0 ? 50 : 43, 5, 6, 25 + q, 51);
					break;
				case 'W':
					copyXPMArea(71, 0 ? 50 : 43, 5, 6, 25 + q, 51);
					break;
				case 'S':
					copyXPMArea(76, 0 ? 50 : 43, 5, 6, 25 + q, 51);
					break;
				case 'E':
					copyXPMArea(81, 0 ? 50 : 43, 5, 6, 25 + q, 51);
					break;
				case 'V':
					copyXPMArea(86, 1 ? 50 : 43, 5, 6, 25 + q, 51);
					break;
				case 'R':
					copyXPMArea(91, 1 ? 50 : 43, 5, 6, 25 + q, 51);
					break;
				case 'B':
					copyXPMArea(96, 1 ? 50 : 43, 4, 6, 25 + q, 51);
					break;
				}
				if (winddir[n])
					q += 5;
			}
		    q += 2;
		}
		if (windspeedavail)  {
			l = (long)(windspeed + 0.5);
			if (!l)
				copyXPMArea(66, 4, 23, 7, 25, 51);
			else {
				if (l >= 100) {
					copyXPMArea(l % 1000 / 100 * 5 + 66, gusting ? 64 : 57, 5, 6, 25 + q, 51);
					q += 5;
				}
				if (l >=  10) {
					copyXPMArea(l %  100 /  10 * 5 + 66, gusting ? 64 : 57, 5, 6, 25 + q, 51);
					q += 5;
				}
				copyXPMArea(l % 10 * 5 + 66, gusting ? 64 : 57, 5, 6, 25 + q, 51);
			}
		}

	} else {

		time(&t);
		tm = localtime(&t);
		if (gusting) {
			showwinddir = tm->tm_sec % 30 < 10;
			showgusting = tm->tm_sec % 30 >= 10 && tm->tm_sec % 30 < 20;
		} else {
			showwinddir = tm->tm_sec % 20 < 10;
			showgusting = 0;
		}

/*		copyXPMArea(64, 0, 56, 56, 4, 4); */
		copyXPMArea(65, 1, 54, 54, 5, 5);

		for (n = 0; n < 4; n++)
			if (id[n] >= 'A' && id[n] <= 'Z')
				copyXPMArea((int)(id[n] - 'A') * 5, 78, 5, 7, n * 6 + 6, 6);
			else if (id[n] >= '0' && id[n] <= '9')
				copyXPMArea((int)(id[n] - '0') * 5, 64, 5, 7, n * 6 + 6, 6);

		if (last24h) {
			time_t lt = timestamp + (tzone < -43200 ? utc_diff : tzone);
			copyXPMArea(lt / 3600 % 24 / 10 * 5 + 50, 64, 5, 7, 37, 6);
			copyXPMArea(lt / 3600 % 24 % 10 * 5 + 50, 64, 5, 7, 43, 6);
			copyXPMArea(lt /   60 % 60 / 10 * 4 + 90, 57, 4, 5, 49, 6);
			copyXPMArea(lt /   60 % 60 % 10 * 4 + 90, 57, 4, 5, 54, 6);
		} else {
			copyXPMArea( 81, 57, 5, 7, 37, 6);
			copyXPMArea( 10, 64, 5, 7, 43, 6);
			copyXPMArea( 20, 64, 5, 7, 49, 6);
			copyXPMArea(121, 51, 3, 5, 55, 6);
		}

		if (temperatureavail) {
			l = temperature;
			if (l < 0) {
				copyXPMArea(40, 67, 5, 1, (l <= -10) ? 31 : 37, 18);
				l *= -1;
			}
			if (l >= 100)
				copyXPMArea(l % 1000 / 100 * 5, 64, 5, 7, 31, 15);
			if (l >=  10)
				copyXPMArea(l %  100 /  10 * 5, 64, 5, 7, 37, 15);
			copyXPMArea(l % 10 * 5, 64, 5, 7, 43, 15);
			if (metric)
				copyXPMArea(121, 7, 9, 7, 49, 15);
			else
				copyXPMArea(121, 0, 9, 7, 49, 15);
		}

		if (windchillavail && (showchill || !dewpointavail)) {
			copyXPMArea(64, 57, 17, 7, 6, 24);
			l = windchill;
		} else
			l = dewpoint;
		if (windchillavail || dewpointavail) {
			if (l < 0) {
				copyXPMArea(40, 67, 5, 1, (l <= -10) ? 31 : 37, 27);
				l *= -1;
			}
			if (l >= 100)
				copyXPMArea(l % 1000 / 100 * 5, 64, 5, 7, 31, 24);
			if (l >=  10)
				copyXPMArea(l %  100 /  10 * 5, 64, 5, 7, 37, 24);
			copyXPMArea(l % 10 * 5, 64, 5, 7, 43, 24);
			if (metric)
				copyXPMArea(121, 7, 9, 7, 49, 24);
			else
				copyXPMArea(121, 0, 9, 7, 49, 24);
		}

		if (heatindexavail && (showheat || (!showchill && !dewpointavail))) {
			copyXPMArea(35, 71, 5, 7,  6, 24);
			copyXPMArea(95, 71, 5, 7, 12, 24);
			copyXPMArea(40, 71, 5, 7, 18, 24);
			l = (long)heatindex;
		} else
			l = dewpoint;
		if (heatindexavail || dewpointavail) {
			if (l < 0) {
				copyXPMArea(40, 67, 5, 1, (l <= -10) ? 31 : 37, 27);
				l *= -1;
			}
			if (l >= 100)
				copyXPMArea(l % 1000 / 100 * 5, 64, 5, 7, 31, 24);
			if (l >=  10)
				copyXPMArea(l %  100 /  10 * 5, 64, 5, 7, 37, 24);
			copyXPMArea(l % 10 * 5, 64, 5, 7, 43, 24);
			if (metric)
				copyXPMArea(121, 7, 9, 7, 49, 24);
			else
				copyXPMArea(121, 0, 9, 7, 49, 24);
		}

		if (pressureavail) {
			l = (long)(pressure + 0.5);
			if (l >= 1000)
				copyXPMArea(9, 64, 1, 7, 29, 33);
			if (l >=  100)
				copyXPMArea(l % 1000 / 100 * 5, 64, 5, 7, 31, 33);
			if (l >=   10)
				copyXPMArea(l %  100 /  10 * 5, 64, 5, 7, 37, 33);
			copyXPMArea(l % 10 * 5, 64, 5, 7, 43, 33);
			if (metric) {
				if (mmHg)
					copyXPMArea(121, 22, 9, 4, 49, 33);
				else if (kPa)
					copyXPMArea(121, 18, 9, 4, 49, 33);
				else /* hPa */
					copyXPMArea(121, 14, 9, 4, 49, 33);
			} else { /* inHg */
				copyXPMArea(121, 26, 9, 4, 49, 33);
			}
		}

		if (humidityavail) {
			l = humidity;
			if (l >= 100)
				copyXPMArea(9, 64, 1, 7, 35, 42);
			if (l >=  10)
				copyXPMArea(l %  100 /  10 * 5, 64, 5, 7, 37, 42);
			copyXPMArea(l % 10 * 5, 64, 5, 7, 43, 42);
			copyXPMArea(125, 30, 5, 7, 53, 42);
		}

		if (winddiravail) {
			if (showwinddir || !windspeedavail) {
				for (n = 0; n < 3; n++)
					if (winddir[n])
						copyXPMArea((int)(winddir[n] - 'A') * 5, 71, 5, 7, n * 6 + 31, 51);
			}
			copyXPMArea(123, 37, 7, 7, 51, 51);
			if      (!memcmp(winddir, "N\0\0", 3))
				copyXPMArea(129, 44, 1, 4, 54, 51);
			else if (!memcmp(winddir, "NNE",   3))
				copyXPMArea(122, 44, 2, 4, 54, 51);
			else if (!memcmp(winddir, "NE\0",  3))
				copyXPMArea(126, 44, 3, 3, 54, 52);
			else if (!memcmp(winddir, "ENE",   3))
				copyXPMArea(126, 47, 4, 2, 54, 53);
			else if (!memcmp(winddir, "E\0\0", 3))
				copyXPMArea(121, 50, 4, 1, 54, 54);
			else if (!memcmp(winddir, "ESE",   3))
				copyXPMArea(126, 48, 4, 2, 54, 54);
			else if (!memcmp(winddir, "SE\0",  3))
				copyXPMArea(124, 44, 3, 3, 54, 54);
			else if (!memcmp(winddir, "SSE",   3))
				copyXPMArea(122, 46, 2, 4, 54, 54);
			else if (!memcmp(winddir, "S\0\0", 3))
				copyXPMArea(129, 44, 1, 4, 54, 54);
			else if (!memcmp(winddir, "SSW",   3))
				copyXPMArea(121, 46, 2, 4, 53, 54);
			else if (!memcmp(winddir, "SW\0",  3))
				copyXPMArea(126, 44, 3, 3, 52, 54);
			else if (!memcmp(winddir, "WSW",   3))
				copyXPMArea(124, 48, 4, 2, 51, 54);
			else if (!memcmp(winddir, "W\0\0", 3))
				copyXPMArea(121, 50, 4, 1, 51, 54);
			else if (!memcmp(winddir, "WNW",   3))
				copyXPMArea(124, 47, 4, 2, 51, 53);
			else if (!memcmp(winddir, "NW\0",  3))
				copyXPMArea(124, 44, 3, 3, 52, 52);
			else if (!memcmp(winddir, "NNW",   3))
				copyXPMArea(121, 44, 2, 4, 53, 51);
		}
		if (windspeedavail && (!showwinddir || !winddiravail) && !showgusting) {
			l = (long)(windspeed + 0.5);
			if (l >= 100)
				copyXPMArea(9, 64, 1, 7, 35, 51);
			if (l >=  10)
				copyXPMArea(l %  100 /  10 * 5, 64, 5, 7, 37, 51);
			copyXPMArea(l % 10 * 5, 64, 5, 7, 43, 51);
		}
		if (showgusting) {
			copyXPMArea(30, 71, 5, 7, 31, 51);
			copyXPMArea(90, 71, 5, 7, 37, 51);
			copyXPMArea(95, 71, 5, 7, 43, 51);
		}
	}

	RedrawWindow();
	time(&last_update);
	showerror = 0;
}

static size_t curl_callback(void *ptr, size_t size, size_t n, void *data)
{
	struct memory
		*mem = (struct memory*)data;
	register unsigned long
		real;
	char
		*tmp;

	real = size * n;
	tmp = (char*)realloc(mem->memory, mem->size + real + 1);
	assert(tmp);
	mem->memory = tmp;
	memcpy(&(mem->memory[mem->size]), ptr, real);
	mem->size += real; 
	mem->memory[mem->size] = 0; 
	return real;
}
