diff options
| -rw-r--r-- | Makefile.am | 1 | ||||
| -rw-r--r-- | Makefile.in | 2 | ||||
| -rw-r--r-- | config.h.in | 3 | ||||
| -rwxr-xr-x | configure | 12 | ||||
| -rw-r--r-- | drv_LEDMatrix.c | 52 | ||||
| -rw-r--r-- | font_6x8_bold.h | 21 | ||||
| -rw-r--r-- | lcd4linux.conf.sample | 30 | ||||
| -rw-r--r-- | plugin.c | 13 | ||||
| -rw-r--r-- | plugin_kvv.c | 714 | ||||
| -rw-r--r-- | plugins.m4 | 8 | ||||
| -rw-r--r-- | property.c | 24 | ||||
| -rw-r--r-- | widget_text.c | 9 | ||||
| -rw-r--r-- | widget_text.h | 9 | 
13 files changed, 866 insertions, 32 deletions
| diff --git a/Makefile.am b/Makefile.am index 96be71f..c4d286a 100644 --- a/Makefile.am +++ b/Makefile.am @@ -104,6 +104,7 @@ plugin_file.c                 \  plugin_i2c_sensors.c          \  plugin_imon.c                 \  plugin_isdn.c                 \ +plugin_kvv.c                  \  plugin_loadavg.c              \  plugin_meminfo.c              \  plugin_mpd.c		      \ diff --git a/Makefile.in b/Makefile.in index 0339fc1..89c7472 100644 --- a/Makefile.in +++ b/Makefile.in @@ -279,6 +279,7 @@ plugin_file.c                 \  plugin_i2c_sensors.c          \  plugin_imon.c                 \  plugin_isdn.c                 \ +plugin_kvv.c                  \  plugin_loadavg.c              \  plugin_meminfo.c              \  plugin_mpd.c		      \ @@ -458,6 +459,7 @@ distclean-compile:  @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/plugin_i2c_sensors.Po@am__quote@  @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/plugin_imon.Po@am__quote@  @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/plugin_isdn.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/plugin_kvv.Po@am__quote@  @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/plugin_loadavg.Po@am__quote@  @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/plugin_math.Po@am__quote@  @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/plugin_meminfo.Po@am__quote@ diff --git a/config.h.in b/config.h.in index c0df0ef..625293b 100644 --- a/config.h.in +++ b/config.h.in @@ -281,6 +281,9 @@  /* ISDN plugin */  #undef PLUGIN_ISDN +/* kvv plugin */ +#undef PLUGIN_KVV +  /* loadavg plugin */  #undef PLUGIN_LOADAVG @@ -8245,6 +8245,7 @@ echo "$as_me: error: run ./configure --with-plugins=..." >&2;}           PLUGIN_I2C_SENSORS="yes"           PLUGIN_IMON="yes"           PLUGIN_ISDN="yes" +         PLUGIN_KVV="yes"           PLUGIN_LOADAVG="yes"           PLUGIN_MEMINFO="yes"           PLUGIN_MPD="yes" @@ -8289,6 +8290,9 @@ echo "$as_me: error: run ./configure --with-plugins=..." >&2;}        isdn)           PLUGIN_ISDN=$val           ;; +      kvv) +         PLUGIN_KVV=$val +         ;;        loadavg)           PLUGIN_LOADAVG=$val           ;; @@ -8771,6 +8775,14 @@ cat >>confdefs.h <<\_ACEOF  _ACEOF  fi +if test "$PLUGIN_KVV" = "yes"; then +   PLUGINS="$PLUGINS plugin_kvv.o" + +cat >>confdefs.h <<\_ACEOF +#define PLUGIN_KVV 1 +_ACEOF + +fi  if test "$PLUGIN_LOADAVG" = "yes"; then     PLUGINS="$PLUGINS plugin_loadavg.o" diff --git a/drv_LEDMatrix.c b/drv_LEDMatrix.c index 38e10ca..f6fdee3 100644 --- a/drv_LEDMatrix.c +++ b/drv_LEDMatrix.c @@ -1,4 +1,4 @@ -/* $Id: drv_LEDMatrix.c,v 1.5 2006/08/13 09:53:10 reinelt Exp $ +/* $Id: drv_LEDMatrix.c,v 1.6 2006/08/13 18:14:03 harbaum Exp $   *   * LED matrix driver for LCD4Linux    * (see http://www.harbaum.org/till/ledmatrix for hardware) @@ -23,6 +23,9 @@   *   *   * $Log: drv_LEDMatrix.c,v $ + * Revision 1.6  2006/08/13 18:14:03  harbaum + * Added KVV plugin + *   * Revision 1.5  2006/08/13 09:53:10  reinelt   * dynamic properties added (used by 'style' of text widget)   * @@ -106,7 +109,13 @@ static int port = DSP_DEFAULT_PORT;  static void drv_LEDMatrix_blit(const int row, const int col, const int height, const int width)  { -    int r, c; +    int r, c, i; +    fd_set rfds; +    struct timeval tv; +    unsigned char reply[256]; +    struct sockaddr_in cli_addr; +    int fromlen, ack = 0; +    int timeout = 10;      for (r = row; r < row + height; r++) {  	for (c = col; c < col + width; c++) { @@ -127,8 +136,42 @@ static void drv_LEDMatrix_blit(const int row, const int col, const int height, c      // scan entire display      tx_buffer[0] = DSP_CMD_IMAGE; -    if ((sendto(sock, tx_buffer, DSP_MEM + 1, 0, (struct sockaddr *) &dsp_addr, sizeof(dsp_addr))) != DSP_MEM + 1) -	error("%s: sendto error on socket", Name); + +    do { + +	if ((sendto(sock, tx_buffer, DSP_MEM + 1, 0, (struct sockaddr *) &dsp_addr, sizeof(dsp_addr))) != DSP_MEM + 1) +	    error("%s: sendto error on socket", Name); + +	/* now wait for reply */ + +	FD_ZERO(&rfds); +	FD_SET(sock, &rfds); +	tv.tv_sec = 0; +	tv.tv_usec = 100000; + +	// wait 1 sec for ack +	if ((i = select(FD_SETSIZE, &rfds, NULL, NULL, &tv)) < 0) { +	    perror("select"); +	} + +	if (FD_ISSET(sock, &rfds)) { +	    // wait for ack +	    fromlen = sizeof(dsp_addr); +	    i = recvfrom(sock, reply, sizeof(reply), 0, (struct sockaddr *) &cli_addr, &fromlen); +	    if (i < 0) { +		perror("recvfrom"); +	    } else { +		if ((i == 2) && (reply[0] == DSP_CMD_ACK) && (reply[1] == DSP_CMD_IMAGE)) { +		    ack = 1; +//      } else if((i > 1) && (reply[0] == DSP_CMD_IR)) { +//        ir_receive(reply+1, i-1); +		} else { +		    fprintf(stderr, "Unexpected reply message\n"); +		} +	    } +	} +	timeout--; +    } while ((!ack) && (timeout > 0));  }  static int drv_LEDMatrix_start(const char *section) @@ -137,7 +180,6 @@ static int drv_LEDMatrix_start(const char *section)      struct sockaddr_in cli_addr;      struct hostent *hp;      int val; -    char *attr;      IPAddress = cfg_get(section, "IPAddress", NULL);      if (IPAddress == NULL || *IPAddress == '\0') { diff --git a/font_6x8_bold.h b/font_6x8_bold.h index 0fb37fc..d8dbb15 100644 --- a/font_6x8_bold.h +++ b/font_6x8_bold.h @@ -1,4 +1,4 @@ -/* $Id: font_6x8_bold.h,v 1.1 2006/08/09 17:25:34 harbaum Exp $ +/* $Id: font_6x8_bold.h,v 1.2 2006/08/13 18:14:03 harbaum Exp $   *   * 6x8 bold font   * @@ -23,6 +23,9 @@   *   *   * $Log: font_6x8_bold.h,v $ + * Revision 1.2  2006/08/13 18:14:03  harbaum + * Added KVV plugin + *   * Revision 1.1  2006/08/09 17:25:34  harbaum   * Better bar color support and new bold font   * @@ -175,11 +178,11 @@ unsigned char Font_6x8_bold[256][8] = {  	    _OO___,  	    ______},      [0x2a] {______, -	    __OO__, -	    O_OO_O, -	    _OOOO_, -	    O_OO_O, -	    __OO__, +	    ___O__, +	    _O_O_O, +	    __OOO_, +	    _O_O_O, +	    ___O__,  	    ______,  	    ______},      [0x2b] {______, @@ -230,12 +233,12 @@ unsigned char Font_6x8_bold[256][8] = {  	    _OO_OO,  	    __OOO_,  	    ______}, -    [0x31] {____O_, -	    ___OO_, +    [0x31] {___OO_,  	    __OOO_,  	    ___OO_,  	    ___OO_,  	    ___OO_, +	    ___OO_,  	    __OOOO,  	    ______},      [0x32] {__OOO_, @@ -767,8 +770,8 @@ unsigned char Font_6x8_bold[256][8] = {  	    _OOOO_,  	    ______},      [0x74] {__OO__, -	    _OOOO_,  	    __OO__, +	    _OOOO_,  	    __OO__,  	    __OO__,  	    __OO__, diff --git a/lcd4linux.conf.sample b/lcd4linux.conf.sample index 6b15dc1..c55f33b 100644 --- a/lcd4linux.conf.sample +++ b/lcd4linux.conf.sample @@ -420,6 +420,14 @@ Display Image {      Basecolor  '80d000'  } +Plugin KVV { +    StationID '12_701' +    Refresh 30 + +    Proxy 'igate' +    Port 8080; +} +  Plugin Seti {      Directory '/root/setiathome-3.08.i686-pc-linux-gnu'  } @@ -877,6 +885,28 @@ Widget ImageTest {      inverted 0  } +Widget KVV { +    class 'Text' +    expression kvv::line(0).' '.kvv::station(0) +    width 11 + +    align 'L' +    update tick +    Foreground 'ffff00' +    style 'bold' +} + +Widget KVV_TIME { +    class 'Text' +    expression kvv::time_str(0) +    width 2 + +    align 'R' +    update tick +    foreground kvv::time(0) < 2 ? 'FF0000' : ( kvv::time(0) < 5 ? 'FFFF00' : '00FF00' ) +    style 'bold' +} +  Layout Default {      Row1 {  	Col1  'OS' @@ -1,4 +1,4 @@ -/* $Id: plugin.c,v 1.44 2006/07/31 03:48:09 reinelt Exp $ +/* $Id: plugin.c,v 1.45 2006/08/13 18:14:03 harbaum Exp $   *   * plugin handler for the Evaluator   * @@ -23,6 +23,9 @@   *   *   * $Log: plugin.c,v $ + * Revision 1.45  2006/08/13 18:14:03  harbaum + * Added KVV plugin + *   * Revision 1.44  2006/07/31 03:48:09  reinelt   * preparations for scrolling   * @@ -250,6 +253,8 @@ int plugin_init_imon(void);  void plugin_exit_imon(void);  int plugin_init_isdn(void);  void plugin_exit_isdn(void); +int plugin_init_kvv(void); +void plugin_exit_kvv(void);  int plugin_init_loadavg(void);  void plugin_exit_loadavg(void);  int plugin_init_meminfo(void); @@ -319,6 +324,9 @@ int plugin_init(void)  #ifdef PLUGIN_ISDN      plugin_init_isdn();  #endif +#ifdef PLUGIN_KVV +    plugin_init_kvv(); +#endif  #ifdef PLUGIN_LOADAVG      plugin_init_loadavg();  #endif @@ -402,6 +410,9 @@ void plugin_exit(void)  #ifdef PLUGIN_ISDN      plugin_exit_isdn();  #endif +#ifdef PLUGIN_KVV +    plugin_exit_kvv(); +#endif  #ifdef PLUGIN_LOADAVG      plugin_exit_loadavg();  #endif diff --git a/plugin_kvv.c b/plugin_kvv.c new file mode 100644 index 0000000..9db6674 --- /dev/null +++ b/plugin_kvv.c @@ -0,0 +1,714 @@ +/* $Id: plugin_kvv.c,v 1.1 2006/08/13 18:14:03 harbaum Exp $ + * + * plugin kvv (karlsruher verkehrsverbund) + * + * Copyright (C) 2006 Till Harbaum <till@harbaum.org> + * Copyright (C) 2006 The LCD4Linux Team <lcd4linux-devel@users.sourceforge.net> + * + * This file is part of LCD4Linux. + * + * LCD4Linux 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, or (at your option) + * any later version. + * + * LCD4Linux 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * + * $Log: plugin_kvv.c,v $ + * Revision 1.1  2006/08/13 18:14:03  harbaum + * Added KVV plugin + * + * + */ + +/*  + * exported functions: + * + * int plugin_init_kvv (void) + *  adds various functions + * void plugin_exit_kvv (void) + * + */ + +/* define the include files you need */ +#include "config.h" + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <ctype.h> +#include <errno.h> +#include <signal.h> + +/* network specific includes */ +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <netdb.h> +#include <arpa/inet.h> + +/* these should always be included */ +#include "debug.h" +#include "plugin.h" +#include "cfg.h" +#include "thread.h" + +/* these can't be configured as it doesn't make sense to change them */ +#define HTTP_SERVER "www.init-ka.de" +#define HTTP_REQUEST "/webfgi/StopInfoInplace.aspx?ID=%s" + +#define DEFAULT_STATION_ID    "89"	// Hauptbahnhof + +/* example ids:  + * 89     = Hauptbahnhof + * 12_701 = Berufsakademie + */ + +/* total max values to calculate shm size */ +#define MAX_LINES           4 +#define MAX_LINE_LENGTH     8 +#define MAX_STATION_LENGTH 32 + +typedef struct { +    char line[MAX_LINE_LENGTH + 1]; +    char station[MAX_STATION_LENGTH + 1]; +    int time; +} kvv_entry_t; + +typedef struct { +    int entries; +    kvv_entry_t entry[MAX_LINES]; +} kvv_shm_t; + +static char *station_id = NULL; +static char *proxy_name = NULL; +static int port = 80; +static pid_t pid = -1; +static int refresh = 60; +static int stringlen = 16; + +static int mutex = 0; +static int shmid; +static kvv_shm_t *shm; + +#define SECTION   "Plugin:KVV" + +#define TIMEOUT_SHORT 1		/* wait this long for additional data */ +#define TIMEOUT_LONG  10	/* wait this long for initial data */ + +/* search an element in the result string */ +static int get_element(char *input, char *name, char **data) +{ +    int skip = 0; +    int len = 0; +    int state = 0;		// nothing found yet + +    // search entire string +    while (*input) { +	if (skip == 0) { +	    switch (state) { +	    case 0: +		if (*input == '<') +		    state = 1; +		else +		    state = 0; +		break; + +	    case 1: +		// ignore white spaces +		if (*input != ' ') { +		    if (strncasecmp(input, name, strlen(name)) == 0) { +			state = 2; +			skip = strlen(name) - 1; +		    } else +			state = 0; +		} +		break; + +	    case 2: +		if (*input == ' ') { +		    *data = ++input; +		    while (*input++ != '>') +			len++; + +		    return len; +		} else +		    state = 0; +		break; +	    } +	} else if (skip) +	    skip--; + +	input++; +    } +    return -1; +} + +/* serach an attribute within an element */ +static int get_attrib(char *input, char *name, char **data) +{ +    int skip = 0; +    int len = 0; +    int state = 0;		// nothing found + +    // search in this element +    while (*input != '>') { +	// ignore white spaces +	if (((*input != ' ') && (*input != '\t')) && (skip == 0)) { +	    switch (state) { +	    case 0: +		if (strncasecmp(input, name, strlen(name)) == 0) { +		    state = 1; +		    skip = strlen(name) - 1; +		} +		break; + +	    case 1: +		if (*input == '=') +		    state = 2; +		else +		    state = 0; +		break; + +	    case 2: +		if (*input == '\"') { +		    *data = ++input; +		    while (*input++ != '\"') +			len++; + +		    return len; +		} else +		    state = 0; + +		break; +	    } +	} else if (skip) +	    skip--; + +	input++; +    } +    return -1; +} + +static int http_open(char *name) +{ +    struct sockaddr_in server; +    struct hostent *host_info; +    unsigned long addr; +    int sock; + +    /* create socket */ +    sock = socket(PF_INET, SOCK_STREAM, 0); +    if (sock < 0) { +	perror("failed to create socket"); +	return -1; +    } + +    /* Erzeuge die Socketadresse des Servers  +     * Sie besteht aus Typ, IP-Adresse und Portnummer */ +    memset(&server, 0, sizeof(server)); +    if ((addr = inet_addr(name)) != INADDR_NONE) { +	memcpy((char *) &server.sin_addr, &addr, sizeof(addr)); +    } else { +	/* Wandle den Servernamen in eine IP-Adresse um */ +	host_info = gethostbyname(name); +	if (NULL == host_info) { +	    error("[KVV] Unknown server: %s", name); +	    return -1; +	} +	memcpy((char *) &server.sin_addr, host_info->h_addr, host_info->h_length); +    } + +    server.sin_family = AF_INET; +    server.sin_port = htons(port); + +    /* Baue die Verbindung zum Server auf */ +    if (connect(sock, (struct sockaddr *) &server, sizeof(server)) < 0) { +	perror("can't connect to server"); +	return -1; +    } + +    return sock; +} + +static void get_text(char *input, char *end, char *dest, int dlen) +{ +    int state = 0;		// nothing yet, outside any element +    int cnt = 0; + +    while (*input) { +	switch (state) { +	case 0: +	    if (*input == '<') +		state = 1; +	    else { +		if (cnt < (dlen - 1)) +		    dest[cnt++] = *input; +	    } +	    break; + +	case 1: +	    if (*input == '/') +		state = 2; +	    else if (*input == '>') +		state = 0; +	    break; + +	case 2: +	    if (strncasecmp(input, end, strlen(end)) == 0) { +		dest[cnt++] = 0; +		return; +	    } +	    break; +	} + +	input++; +    } + +} + +static void process_station_string(char *str) +{ +    char *p, *q; +    int last, i; +    char *repl[] = { +	"Hauptbahnhof", "Hbf.", +	"Bahnhof", "Bhf.", +	"Karlsruhe", "KA", +	"Schienenersatzverkehr", "Ersatzv.", +	"Marktplatz", "Marktpl.", +    }; + +    /* erase multiple spaces */ +    p = q = str; +    last = 1;			// no leading spaces +    while (*p) { +	if ((!last) || (*p != ' ')) +	    *q++ = *p; + +	last = (*p == ' '); +	p++; +    } +    *q++ = 0; + +    /* decode utf8 */ +    p = q = str; +    last = 0; +    while (*p) { +	if (last) { +	    *q++ = (last << 6) | (*p & 0x3f); +	    last = 0; +	} else if ((*p & 0xe0) == 0xc0) { +	    last = *p & 3; +	} else +	    *q++ = *p; + +	p++; +    } +    *q++ = 0; + +    /* replace certain (long) words with e.g. abbreviations */ +    for (i = 0; i < (int) (sizeof(repl) / (2 * sizeof(char *))); i++) { +	if ((p = strstr(str, repl[2 * i])) != NULL) { + +	    /* move new string */ +	    memcpy(p, repl[2 * i + 1], strlen(repl[2 * i + 1])); +	    /* move rest of string down */ +	    memmove(p + strlen(repl[2 * i + 1]), +		    p + strlen(repl[2 * i]), strlen(str) - (p - str) - strlen(repl[2 * i]) + 1); +	} +    } +} + +static void kvv_client(void) +{ +    char ibuffer[8192]; +    char obuffer[8192]; +    int count, i, sock; + +    char server_name[] = HTTP_SERVER; +    char *connect_to; + +    /* connect to proxy if given, to server otherwise */ +    if ((proxy_name != NULL) && (strlen(proxy_name) != 0)) +	connect_to = proxy_name; +    else +	connect_to = server_name; + +    info("[KVV] Connecting to %s", connect_to); + +    while (1) { + +	sock = http_open(connect_to); +	if (sock < 0) { +	    error("[KVV] Error accessing server/proxy: %s", strerror(errno)); +	    return; +	} +	// create and set get request +	sprintf(obuffer, "GET http://%s" HTTP_REQUEST " HTTP/1.1\n" "Host: %s\n\n", server_name, station_id, +		server_name); + +	info("[KVV] Sending first (GET) request ..."); +	send(sock, obuffer, strlen(obuffer), 0); + +	count = 0; +	do { +	    fd_set rfds; +	    struct timeval tv; + +	    FD_ZERO(&rfds); +	    FD_SET(sock, &rfds); + +	    tv.tv_sec = count ? TIMEOUT_SHORT : TIMEOUT_LONG; +	    tv.tv_usec = 0; + +	    i = select(FD_SETSIZE, &rfds, NULL, NULL, &tv); +	    if (i < 0) { +		perror("select"); +		exit(1); +	    } + +	    if (i != 0) { +		i = recv(sock, ibuffer + count, sizeof(ibuffer) - count, 0); +		count += i; +	    } +	} +	while (i > 0); + +	ibuffer[count] = 0;	// terminate string +	close(sock); + +	if (count > 0) { +	    char *input, *cookie, *name, *value; +	    int input_len, cookie_len, name_len, value_len; + +	    // buffer to html encode value +	    char value_enc[512]; +	    int value_enc_len; + +	    // find cookie +	    cookie_len = 0; +	    cookie = strstr(ibuffer, "Set-Cookie:"); +	    if (cookie) { +		cookie += strlen("Set-Cookie:"); + +		while (*cookie == ' ') +		    cookie++; + +		while (cookie[cookie_len] != ';') +		    cookie_len++; +	    } +	    // find input element +	    input_len = get_element(ibuffer, "input", &input); + + +	    if (input_len > 0) { +		char *input_end = input; +		while (*input_end != '>') +		    input_end++; +		while (*input_end != '\"') +		    input_end--; +		*(input_end + 1) = 0; + +		name_len = get_attrib(input, "name", &name); +		value_len = get_attrib(input, "value", &value); + +		for (value_enc_len = 0, i = 0; i < value_len; i++) { +		    if (isalnum(value[i])) +			value_enc[value_enc_len++] = value[i]; +		    else { +			sprintf(value_enc + value_enc_len, "%%%02X", 0xff & value[i]); +			value_enc_len += 3; +		    } +		} + +		if (cookie_len >= 0) +		    cookie[cookie_len] = 0; +		if (name_len >= 0) +		    name[name_len] = 0; +		if (value_len >= 0) +		    value[value_len] = 0; +		if (value_enc_len >= 0) +		    value_enc[value_enc_len] = 0; + +		sock = http_open(connect_to); + +		// send POST +		sprintf(obuffer, +			"POST http://%s" HTTP_REQUEST " HTTP/1.1\n" +			"Host: %s\n" +			"Cookie: %s\n" +			"Content-Type: application/x-www-form-urlencoded\n" +			"Content-Length: %d\n" +			"\n%s=%s", +			server_name, station_id, server_name, cookie, name_len + value_enc_len + 1, name, value_enc); + +		info("[KVV] Sending second (POST) request ..."); +		send(sock, obuffer, strlen(obuffer), 0); + +		count = 0; +		do { +		    fd_set rfds; +		    struct timeval tv; + +		    FD_ZERO(&rfds); +		    FD_SET(sock, &rfds); + +		    tv.tv_sec = count ? TIMEOUT_SHORT : TIMEOUT_LONG; +		    tv.tv_usec = 0; + +		    i = select(FD_SETSIZE, &rfds, NULL, NULL, &tv); +		    if (i > 0) { +			i = recv(sock, ibuffer + count, sizeof(ibuffer) - count, 0); +			count += i; +		    } +		} +		while (i > 0);	/* leave on select or read error */ + +		ibuffer[count] = 0; + +		/* close connection */ +		close(sock); + +		if (count > 0) { +		    int last_was_stop = 0; +		    char *td = ibuffer; +		    char str[32]; +		    int td_len, i, overflow = 0; + +		    /* lock shared memory */ +		    mutex_lock(mutex); + +		    /* free allocated memory */ +		    shm->entries = 0; + +		    /* scan through all <td> entries and search the line nums */ +		    do { +			if ((td_len = get_element(td, "td", &td)) > 0) { +			    char *attr, *p; +			    int attr_len; + +			    /* time does not have a class but comes immediately after stop :-( */ +			    if (last_was_stop) { +				td += td_len + 1; +				get_text(td, "td", str, sizeof(str)); + +				/* time needs special treatment */ +				if (strncasecmp(str, "sofort", strlen("sofort")) == 0) +				    i = 0; +				else { +				    /* skip everything that is not a number */ +				    p = str; +				    while (!isdigit(*p)) +					p++; + +				    /* and convert remaining to number */ +				    i = atoi(p); +				} + +				/* save time */ +				if (!overflow) +				    shm->entry[shm->entries - 1].time = i; + +				last_was_stop = 0; +			    } + +			    /* linenum and stopname fields have proper classes */ +			    if ((attr_len = get_attrib(td, "class", &attr)) > 0) { + +				if (strncasecmp(attr, "lineNum", strlen("lineNum")) == 0) { +				    td += td_len + 1; +				    get_text(td, "td", str, sizeof(str)); + +				    if (shm->entries < MAX_LINES) { +					// allocate a new slot +					shm->entries++; +					shm->entry[shm->entries - 1].time = -1; +					memset(shm->entry[shm->entries - 1].line, 0, MAX_LINE_LENGTH + 1); +					memset(shm->entry[shm->entries - 1].station, 0, MAX_STATION_LENGTH + 1); + +					// add new lines entry +					strncpy(shm->entry[shm->entries - 1].line, str, MAX_LINE_LENGTH); +				    } else +					overflow = 1;	/* don't add further entries */ +				} + +				if (strncasecmp(attr, "stopname", strlen("stopname")) == 0) { +				    td += td_len + 1; +				    get_text(td, "td", str, sizeof(str)); + +				    /* stopname may need further tuning */ +				    process_station_string(str); + +				    if (!overflow) +					strncpy(shm->entry[shm->entries - 1].station, str, MAX_STATION_LENGTH); + +				    last_was_stop = 1; +				} +			    } +			} +		    } while (td_len >= 0); + +		    mutex_unlock(mutex); +		} +	    } +	} + +	sleep(refresh); +    } +} + +static void kvv_line(RESULT * result, RESULT * arg1) +{ +    int index = (int) R2N(arg1); + +    mutex_lock(mutex); + +    if (index < shm->entries) { +	SetResult(&result, R_STRING, shm->entry[index].line); +    } else +	SetResult(&result, R_STRING, "---"); + +    mutex_unlock(mutex); +} + +static void kvv_station(RESULT * result, RESULT * arg1) +{ +    int index = (int) R2N(arg1); + +    mutex_lock(mutex); + +    if (index < shm->entries) +	SetResult(&result, R_STRING, shm->entry[index].station); +    else +	SetResult(&result, R_STRING, "---"); + +    mutex_unlock(mutex); +} + +static void kvv_time(RESULT * result, RESULT * arg1) +{ +    int index = (int) R2N(arg1); +    double value = -1.0; + +    mutex_lock(mutex); + +    if (index < shm->entries) +	value = shm->entry[index].time; + +    SetResult(&result, R_NUMBER, &value); + +    mutex_unlock(mutex); +} + +static void kvv_time_str(RESULT * result, RESULT * arg1) +{ +    int index = (int) R2N(arg1); + +    mutex_lock(mutex); + +    if (index < shm->entries) { +	char str[8]; +	sprintf(str, "%d", shm->entry[index].time); +	SetResult(&result, R_STRING, str); +    } else +	SetResult(&result, R_STRING, "---"); + +    mutex_unlock(mutex); +} + +/* plugin initialization */ +int plugin_init_kvv(void) +{ +    int val; +    char *p; + +    /* register all our cool functions */ +    AddFunction("kvv::line", 1, kvv_line); +    AddFunction("kvv::station", 1, kvv_station); +    AddFunction("kvv::time", 1, kvv_time); +    AddFunction("kvv::time_str", 1, kvv_time_str); + +    /* parse parameter */ +    if ((p = cfg_get(SECTION, "StationID", DEFAULT_STATION_ID)) != NULL) { +	station_id = malloc(strlen(p) + 1); +	strcpy(station_id, p); +    } +    info("[KVV] Using station %s", station_id); + +    if ((p = cfg_get(SECTION, "Proxy", NULL)) != NULL) { +	proxy_name = malloc(strlen(p) + 1); +	strcpy(proxy_name, p); +	info("[KVV] Using proxy \"%s\"", proxy_name); +    } + +    if (cfg_number(SECTION, "Port", 0, 0, 65535, &val) > 0) { +	port = val; +	info("[KVV] Using port %d", port); +    } else { +	info("[KVV] Using default port %d", port); +    } + +    if (cfg_number(SECTION, "Refresh", 0, 0, 65535, &val) > 0) { +	refresh = val; +	info("[KVV] Using %d seconds refresh interval", refresh); +    } else { +	info("[KVV] Using default refresh interval of %d seconds", refresh); +    } + +    if (cfg_number(SECTION, "Stringlen", 0, 0, 65535, &val) > 0) { +	stringlen = val; +	info("[KVV] Using %d character string length", stringlen); +    } else { +	info("[KVV] Using %d characters default string length", stringlen); +    } + +    /* create communication buffer */ +    shmid = shm_create((void **) &shm, sizeof(kvv_shm_t)); + +    /* catch error */ +    if (shmid < 0) { +	error("[KVV] Shared memory allocation failed!"); +	return -1; +    } + +    /* attach client thread */ +    mutex = mutex_create(); +    pid = fork(); +    if (pid < 0) { +	error("[KVV] Unable to fork client: %s", strerror(errno)); +	return -1; +    } + +    if (pid == 0) +	kvv_client(); +    else +	info("[KVV] forked client with pid %d", pid); + +    return 0; +} + +void plugin_exit_kvv(void) +{ +    if (pid != -1) +	kill(pid, SIGTERM); + +    if (station_id) +	free(station_id); +    if (proxy_name) +	free(proxy_name); + +    mutex_destroy(mutex); + +    if (shm) +	shm_destroy(shmid, shm); +} @@ -58,6 +58,7 @@ for plugin in $plugins; do           PLUGIN_I2C_SENSORS="yes"           PLUGIN_IMON="yes"           PLUGIN_ISDN="yes" +         PLUGIN_KVV="yes"           PLUGIN_LOADAVG="yes"           PLUGIN_MEMINFO="yes"           PLUGIN_MPD="yes" @@ -102,6 +103,9 @@ for plugin in $plugins; do        isdn)           PLUGIN_ISDN=$val           ;; +      kvv) +         PLUGIN_KVV=$val +         ;;        loadavg)           PLUGIN_LOADAVG=$val           ;; @@ -203,6 +207,10 @@ if test "$PLUGIN_ISDN" = "yes"; then     PLUGINS="$PLUGINS plugin_isdn.o"     AC_DEFINE(PLUGIN_ISDN,1,[ISDN plugin])  fi +if test "$PLUGIN_KVV" = "yes"; then +   PLUGINS="$PLUGINS plugin_kvv.o" +   AC_DEFINE(PLUGIN_KVV,1,[kvv plugin]) +fi  if test "$PLUGIN_LOADAVG" = "yes"; then     PLUGINS="$PLUGINS plugin_loadavg.o"     AC_DEFINE(PLUGIN_LOADAVG,1,[loadavg plugin]) @@ -1,4 +1,4 @@ -/* $Id: property.c,v 1.2 2006/08/13 11:38:20 reinelt Exp $ +/* $Id: property.c,v 1.3 2006/08/13 18:14:03 harbaum Exp $   *   * dynamic properties   * @@ -23,6 +23,9 @@   *   *   * $Log: property.c,v $ + * Revision 1.3  2006/08/13 18:14:03  harbaum + * Added KVV plugin + *   * Revision 1.2  2006/08/13 11:38:20  reinelt   * text widget uses dynamic properties   * @@ -93,32 +96,31 @@ int property_eval(PROPERTY * prop)  {      RESULT old;      int update = 1; -     +      /* this is a bit ugly: we need to remember the old value */ -     +      old.type = prop->result.type;      old.size = prop->result.size;      old.number = prop->result.number; -    old.string = prop->result.string != NULL ? strdup(prop->result.string) : NULL;  -     +    old.string = prop->result.string != NULL ? strdup(prop->result.string) : NULL; +      DelResult(&prop->result);      Eval(prop->compiled, &prop->result); -     +      if (prop->result.type & R_NUMBER && old.type & R_NUMBER && prop->result.number == old.number) {  	update = 0;      } -     +      if (prop->result.type & R_STRING && old.type & R_STRING && prop->result.size == old.size) {  	if (prop->result.string == NULL && old.string == NULL) {  	    update = 0; -	} -	else if (prop->result.string != NULL && old.string != NULL && strcmp(prop->result.string, old.string) == 0) { +	} else if (prop->result.string != NULL && old.string != NULL && strcmp(prop->result.string, old.string) == 0) {  	    update = 0;  	}      } -     +      if (old.string) -	free (old.string); +	free(old.string);      return update;  } diff --git a/widget_text.c b/widget_text.c index 033d6f8..d543534 100644 --- a/widget_text.c +++ b/widget_text.c @@ -1,4 +1,4 @@ -/* $Id: widget_text.c,v 1.26 2006/08/13 11:38:20 reinelt Exp $ +/* $Id: widget_text.c,v 1.27 2006/08/13 18:14:03 harbaum Exp $   *   * simple text widget handling   * @@ -21,6 +21,9 @@   *   *   * $Log: widget_text.c,v $ + * Revision 1.27  2006/08/13 18:14:03  harbaum + * Added KVV plugin + *   * Revision 1.26  2006/08/13 11:38:20  reinelt   * text widget uses dynamic properties   * @@ -172,7 +175,7 @@ void widget_text_scroll(void *Self)      char *postfix = P2S(&T->postfix);      char *string = T->string; -     +      int num, len, width, pad;      char *src, *dst; @@ -325,7 +328,7 @@ void widget_text_update(void *Self)      /* text style */      update += property_eval(&T->style); -     +      /* something has changed and should be updated */      if (update) {  	/* reset marquee counter if content has changed */ diff --git a/widget_text.h b/widget_text.h index 61e5b35..bd9a18d 100644 --- a/widget_text.h +++ b/widget_text.h @@ -1,4 +1,4 @@ -/* $Id: widget_text.h,v 1.9 2006/08/13 11:38:20 reinelt Exp $ +/* $Id: widget_text.h,v 1.10 2006/08/13 18:14:03 harbaum Exp $   *   * simple text widget handling   * @@ -23,6 +23,9 @@   *   *   * $Log: widget_text.h,v $ + * Revision 1.10  2006/08/13 18:14:03  harbaum + * Added KVV plugin + *   * Revision 1.9  2006/08/13 11:38:20  reinelt   * text widget uses dynamic properties   * @@ -77,9 +80,9 @@ typedef enum { ALIGN_LEFT, ALIGN_CENTER, ALIGN_RIGHT, ALIGN_MARQUEE } TEXT_ALIGN  typedef struct WIDGET_TEXT {      PROPERTY prefix;		/* label on the left side */      PROPERTY postfix;		/* label on the right side */ -    PROPERTY value;             /* value of text widget */ +    PROPERTY value;		/* value of text widget */      PROPERTY style;		/* text style (plain/bold/slant) */ -    char *string;               /* formatted value */ +    char *string;		/* formatted value */      char *buffer;		/* string with 'width+1' bytes allocated  */      int width;			/* field width */      int precision;		/* number of digits after the decimal point */ | 
