mirror of
https://github.com/netfun2000/lcd4linux.git
synced 2026-02-27 09:44:34 +08:00
git-svn-id: https://ssl.bulix.org/svn/lcd4linux/trunk@797 3ae390bd-cb1e-0410-b409-cd5a39f66f1f
797 lines
18 KiB
C
797 lines
18 KiB
C
/* $Id$
|
|
* $URL$
|
|
*
|
|
* 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.
|
|
*
|
|
*/
|
|
|
|
/*
|
|
* 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 USER_AGENT "lcd4linux - KVV plugin (http://ssl.bulix.org/projects/lcd4linux/wiki/plugin_kvv)"
|
|
|
|
#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 40
|
|
|
|
typedef struct {
|
|
char line[MAX_LINE_LENGTH + 1];
|
|
char station[MAX_STATION_LENGTH + 1];
|
|
int time;
|
|
} kvv_entry_t;
|
|
|
|
typedef struct {
|
|
int entries, error;
|
|
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 abbreviate = 0;
|
|
|
|
static int initialized = 0;
|
|
static int mutex = 0;
|
|
static int shmid = -1;
|
|
static kvv_shm_t *shm = NULL;
|
|
|
|
#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 && (*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;
|
|
|
|
/* some strings to replace */
|
|
char *repl[] = {
|
|
"Hauptbahnhof", "Hbf.",
|
|
"Bahnhof", "Bhf.",
|
|
"Karlsruhe", "KA",
|
|
"Schienenersatzverkehr", "Ersatzv.",
|
|
"Marktplatz", "Marktpl.",
|
|
};
|
|
|
|
/* 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;
|
|
|
|
/* erase multiple spaces and replace umlauts */
|
|
p = q = str;
|
|
last = 1; /* no leading spaces */
|
|
while (*p) {
|
|
if ((!last) || (*p != ' ')) {
|
|
|
|
/* translate from latin1 to hd44780 */
|
|
if (*p == (char) 228) /* lower a umlaut */
|
|
*q++ = (char) 0xe1;
|
|
else if (*p == (char) 223) /* sz ligature */
|
|
*q++ = (char) 0xe2;
|
|
else if (*p == (char) 246) /* lower o umlaut */
|
|
*q++ = (char) 0xef;
|
|
else if (*p == (char) 252) /* lower u umlaut */
|
|
*q++ = (char) 0xf5;
|
|
else
|
|
*q++ = *p;
|
|
}
|
|
|
|
last = (*p == ' ');
|
|
p++;
|
|
}
|
|
*q++ = 0;
|
|
|
|
/* replace certain (long) words with e.g. abbreviations if enabled */
|
|
if (abbreviate) {
|
|
|
|
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( __attribute__ ((unused))
|
|
void *dummy)
|
|
{
|
|
char ibuffer[8192];
|
|
char obuffer[1024];
|
|
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 */
|
|
if (snprintf(obuffer, sizeof(obuffer),
|
|
"GET http://%s" HTTP_REQUEST " HTTP/1.1\n"
|
|
"Host: %s\n" "User-Agent: " USER_AGENT "\n\n", server_name, station_id,
|
|
server_name) >= (int) sizeof(obuffer)) {
|
|
|
|
info("[KVV] Warning, request has been truncated!");
|
|
}
|
|
|
|
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 - 1, 0);
|
|
count += i;
|
|
}
|
|
}
|
|
while (i > 0);
|
|
|
|
ibuffer[count] = 0; /* terminate string */
|
|
close(sock);
|
|
|
|
if (!count)
|
|
info("[KVV] empty/no reply");
|
|
|
|
if (count > 0) {
|
|
char *input, *cookie, *name = NULL, *value = NULL;
|
|
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 */
|
|
if (snprintf(obuffer, sizeof(obuffer),
|
|
"POST http://%s" HTTP_REQUEST " HTTP/1.1\n"
|
|
"Host: %s\n"
|
|
"User-Agent: " USER_AGENT "\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) >= (int) sizeof(obuffer)) {
|
|
|
|
info("[KVV] Warning, request has been truncated!");
|
|
}
|
|
|
|
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 - 1, 0);
|
|
count += i;
|
|
}
|
|
}
|
|
while (i > 0); /* leave on select or read error */
|
|
|
|
ibuffer[count] = 0;
|
|
|
|
/* printf("Result (%d):\n%s\n", count, ibuffer); */
|
|
|
|
/* close connection */
|
|
close(sock);
|
|
|
|
if (!count)
|
|
info("[KVV] empty/no reply");
|
|
|
|
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;
|
|
|
|
if (strstr(ibuffer, "Die Daten konnten nicht abgefragt werden.") != NULL) {
|
|
info("[KVV] Server returned error!");
|
|
/* printf("%s\n", ibuffer); */
|
|
shm->error = 1;
|
|
} else
|
|
shm->error = 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 int kvv_fork(void)
|
|
{
|
|
if (initialized)
|
|
return 0;
|
|
|
|
info("[KVV] creating client thread");
|
|
|
|
/* set this here to prevent continous retries if init fails */
|
|
initialized = 1;
|
|
|
|
/* 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 = thread_create("plugin_kvv", kvv_client, NULL);
|
|
|
|
if (pid < 0) {
|
|
error("[KVV] Unable to fork client: %s", strerror(errno));
|
|
return -1;
|
|
}
|
|
|
|
info("[KVV] forked client with pid %d", pid);
|
|
return 0;
|
|
}
|
|
|
|
static void kvv_line(RESULT * result, RESULT * arg1)
|
|
{
|
|
int index = (int) R2N(arg1);
|
|
|
|
if (kvv_fork() != 0) {
|
|
SetResult(&result, R_STRING, "");
|
|
return;
|
|
}
|
|
|
|
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);
|
|
|
|
if (kvv_fork() != 0) {
|
|
SetResult(&result, R_STRING, "");
|
|
return;
|
|
}
|
|
|
|
mutex_lock(mutex);
|
|
|
|
if (shm->error && index == 0)
|
|
SetResult(&result, R_STRING, "Server Err");
|
|
else {
|
|
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;
|
|
|
|
if (kvv_fork() != 0) {
|
|
SetResult(&result, R_STRING, "");
|
|
return;
|
|
}
|
|
|
|
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);
|
|
|
|
if (kvv_fork() != 0) {
|
|
SetResult(&result, R_STRING, "");
|
|
return;
|
|
}
|
|
|
|
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, "Abbreviate", 0, 0, 65535, &val) > 0) {
|
|
abbreviate = val;
|
|
info("[KVV] Abbreviation enabled: %s", abbreviate ? "on" : "off");
|
|
} else {
|
|
info("[KVV] Default abbreviation setting: %s", abbreviate ? "on" : "off");
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
void plugin_exit_kvv(void)
|
|
{
|
|
/* kill client thread if it's running */
|
|
if (initialized) {
|
|
/* kill client */
|
|
if (pid != -1)
|
|
thread_destroy(pid);
|
|
|
|
/* free shared mem and its mutex */
|
|
if (shm) {
|
|
shm_destroy(shmid, shm);
|
|
mutex_destroy(mutex);
|
|
}
|
|
}
|
|
|
|
if (station_id)
|
|
free(station_id);
|
|
if (proxy_name)
|
|
free(proxy_name);
|
|
}
|