From 285f7ad7d0aed48cd5cb13a2437e80d26fffc254 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 3 Mar 2004 01:25:46 +0000 Subject: commit initial release git-svn-id: file:///home/lennart/svn/public/pgets/trunk@3 768266df-afd4-0310-94a7-d396c829e022 --- src/Makefile.am | 47 +++++++++ src/db.h | 29 ++++++ src/lock.c | 168 ++++++++++++++++++++++++++++++++ src/lock.h | 26 +++++ src/modem.c | 76 +++++++++++++++ src/modem.h | 26 +++++ src/pgets.c | 294 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/pgets.h | 35 +++++++ src/postgres.c | 93 ++++++++++++++++++ src/sqlite.c | 98 +++++++++++++++++++ src/util.c | 102 ++++++++++++++++++++ src/util.h | 35 +++++++ 12 files changed, 1029 insertions(+) create mode 100644 src/Makefile.am create mode 100644 src/db.h create mode 100644 src/lock.c create mode 100644 src/lock.h create mode 100644 src/modem.c create mode 100644 src/modem.h create mode 100644 src/pgets.c create mode 100644 src/pgets.h create mode 100644 src/postgres.c create mode 100644 src/sqlite.c create mode 100644 src/util.c create mode 100644 src/util.h (limited to 'src') diff --git a/src/Makefile.am b/src/Makefile.am new file mode 100644 index 0000000..ea26863 --- /dev/null +++ b/src/Makefile.am @@ -0,0 +1,47 @@ +# $Id$ + +# This file is part of pgets. +# +# pgets 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. +# +# pgets 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 pgets; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + +sbin_PROGRAMS = + +if SQLITE +sbin_PROGRAMS += pgets-sqlite +endif + +if POSTGRES +sbin_PROGRAMS += pgets-postgres +endif + + +SOURCES = pgets.c pgets.h \ + modem.c modem.h \ + lock.c lock.h \ + util.c util.h \ + db.h + +pgets_sqlite_SOURCES = $(SOURCES) sqlite.c +pgets_sqlite_LDADD = $(LDADD) $(SQLITE_LIBS) +pgets_sqlite_CLFAGS = $(AM_CFLAGS) $(SQLITE_CFLAGS) + +pgets_postgres_SOURCES = $(SOURCES) postgres.c +pgets_postgres_LDADD = $(LDADD) $(POSTGRES_LIBS) +pgets_postgres_CLFAGS = $(AM_CFLAGS) $(POSTGRES_CFLAGS) + +svnkeywords: + svn propset svn:keywords Id *.c *.h Makefile.am + +.PHONY: svnkeywords diff --git a/src/db.h b/src/db.h new file mode 100644 index 0000000..e8033cb --- /dev/null +++ b/src/db.h @@ -0,0 +1,29 @@ +#ifndef foodbhfoo +#define foodbhfoo + +/* $Id$ + * + * This file is part of pgets. + * + * pgets 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. + * + * pgets 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 pgets; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include "pgets.h" + +void* db_connect(const char*a); +void db_disconnect(void *t); +int db_write_entry(void *t, const struct entry *entry); + +#endif diff --git a/src/lock.c b/src/lock.c new file mode 100644 index 0000000..91878d4 --- /dev/null +++ b/src/lock.c @@ -0,0 +1,168 @@ +/* $Id$ + * + * This file is part of pgets. + * + * pgets 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. + * + * pgets 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 pgets; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#define _GNU_SOURCE + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "lock.h" +#include "util.h" + +#ifndef LOCKDIR +#define LOCKDIR "/var/lock" +#endif + +static const char *lockfile(const char *dev) { + static char lockfile[PATH_MAX]; + snprintf(lockfile, sizeof(lockfile), LOCKDIR"/LCK..%s", basename((char*) dev)); + return lockfile; +} + +static const char *tempfile(const char *path) { + static char t[PATH_MAX]; + snprintf(t, sizeof(t), "%s.tmp.%lu", path, (unsigned long) getpid()); + return t; +} + +int device_lock(const char *dev, const char *appname) { + struct stat st; + int fd; + const char *path, *temp; + char buf[100]; + char uidbuf[32]; + uid_t uid; + + if (stat(LOCKDIR, &st) != 0 || !S_ISDIR(st.st_mode)) { + fprintf(stderr, "Failed to lock device, directory "LOCKDIR" not existent.\n"); + return -1; + } + + path = lockfile(dev); + temp = tempfile(path); + + for (;;) { + mode_t u; + struct passwd* pw; + char *username; + + if ((fd = open(path, O_RDONLY)) < 0) { + if (errno != ENOENT) { + fprintf(stderr, "Failed to open lock file: %s\n", strerror(errno)); + return -1; + } + } + + if (fd >= 0) { + ssize_t n; + + n = loop_read(fd, buf, sizeof(buf) - 1); + close(fd); + + if (n < 0) { + close(fd); + fprintf(stderr, "Failed to read from lock file: %s\n", strerror(errno)); + return -1; + } + + if (n > 0) { + pid_t pid; + + if (n == 4) + pid = (pid_t) *((uint32_t*) buf); + else { + unsigned long v; + buf[n] = 0; + sscanf(buf, "%lu", &v); + pid = (pid_t) v; + } + + if (pid > 0) { + if (kill(pid, 0) < 0 && errno == ESRCH) { + fprintf(stderr, "Lockfile is stale. Overriding it.\n"); + /* Yes, here is a race condition */ + unlink(path); + } else + return 1; + } + } + } + + u = umask(0033); + fd = open(temp, O_WRONLY | O_CREAT | O_EXCL, 0666); + umask(u); + + if (fd < 0) { + fprintf(stderr, "Failed to create temporary lock file: %s\n", strerror(errno)); + return -1; + } + + uid = getuid(); + + if ((pw = getpwuid(uid))) + username = pw->pw_name; + else + snprintf(username = uidbuf, sizeof(uidbuf), "%lu", (unsigned long) uid); + + snprintf(buf, sizeof(buf), "%10lu %s %.20s\n", (unsigned long) getpid(), appname, username); + if (loop_write(fd, buf, strlen(buf)) < 0) { + fprintf(stderr, "Failed to write to temporary lock file: %s\n", strerror(errno)); + close(fd); + return -1; + } + + close(fd); + + if (link(temp, path) < 0) { + if (errno == EEXIST) + continue; + + fprintf(stderr, "Failed to link temporary lock file: %s\n", strerror(errno)); + } + + unlink(temp); + + return 0; + } +} + +int device_unlock(const char *dev) { + + if (unlink(lockfile(dev)) < 0) { + fprintf(stderr, "Failed to remove lock file: %s\n", strerror(errno)); + return -1; + } + + return 0; +} diff --git a/src/lock.h b/src/lock.h new file mode 100644 index 0000000..ec1ccd8 --- /dev/null +++ b/src/lock.h @@ -0,0 +1,26 @@ +#ifndef foolockhfoo +#define foolockhfoo + +/* $Id$ + * + * This file is part of pgets. + * + * pgets 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. + * + * pgets 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 pgets; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +int device_lock(const char *dev, const char *appname); +int device_unlock(const char *dev); + +#endif diff --git a/src/modem.c b/src/modem.c new file mode 100644 index 0000000..677d4cf --- /dev/null +++ b/src/modem.c @@ -0,0 +1,76 @@ +/* $Id$ + * + * This file is part of pgets. + * + * pgets 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. + * + * pgets 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 pgets; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include +#include +#include +#include +#include + +#include "modem.h" + +static struct termios _saved_termios; + +/* Opens the modem and sets the baud rate */ +int modem_open(const char *dev) { + struct termios pts; + int fd, n; + + if ((fd = open(dev, O_RDWR|O_NDELAY)) < 0) { + perror("Serial port open failure"); + return -1; + } + + n = fcntl(fd, F_GETFL, 0); + fcntl(fd, F_SETFL, n & ~O_NDELAY); + + if (tcgetattr(fd, &_saved_termios) != 0) { + perror("Serial port TERMIOS get failure"); + close(fd); + return -1; + } + + memset(&pts, 0, sizeof pts); + pts.c_cflag = CS8 | CLOCAL | CREAD; + pts.c_iflag = IGNPAR | IGNBRK | IGNCR | IXON | IXOFF; + pts.c_oflag = 0; + pts.c_lflag = 0; + + pts.c_cc[VMIN] = 1; + pts.c_cc[VTIME] = 0; + + cfsetospeed(&pts, B9600); + cfsetispeed(&pts, B9600); + + tcflush(fd, TCIFLUSH); + if (tcsetattr(fd, TCSANOW, &pts) != 0) { + perror("Serial port TERMIOS set failure"); + close(fd); + return -1; + } + + return fd; +} + +/* Closes the modem device and resets the baudrate */ +void modem_close(int fd) { + tcflush(fd, TCIFLUSH); + tcsetattr(fd, TCSANOW, &_saved_termios); + close(fd); +} diff --git a/src/modem.h b/src/modem.h new file mode 100644 index 0000000..0cc8c73 --- /dev/null +++ b/src/modem.h @@ -0,0 +1,26 @@ +#ifndef foomodemhfoo +#define foomodemhfoo + +/* $Id$ + * + * This file is part of pgets. + * + * pgets 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. + * + * pgets 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 pgets; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +int modem_open(const char *dev); +void modem_close(int fd); + +#endif diff --git a/src/pgets.c b/src/pgets.c new file mode 100644 index 0000000..993111e --- /dev/null +++ b/src/pgets.c @@ -0,0 +1,294 @@ +/* $Id$ + * + * This file is part of pgets. + * + * pgets 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. + * + * pgets 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 pgets; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#define _GNU_SOURCE + +#include +#include +#include +#include +#include +#include + +#include "lock.h" +#include "modem.h" +#include "util.h" +#include "db.h" + +#define ETS_RESET ('$') +#define ETS_NEXT ('%') + +int verbose = 1; +volatile int quit = 0; + +void sigint(int s) { + const char *e = "\r*** Got SIGINT, exiting *** \n"; + loop_write(2, e, strlen(e)); + quit = 1; +} + +int ets_reset(int fd) { + char c = ETS_RESET; + return (write(fd, &c, sizeof(c)) != sizeof(c)) ? -1 : 0; +} + +int ets_next(int fd) { + char c = ETS_NEXT; + return (write(fd, &c, sizeof(c)) != sizeof(c)) ? -1 : 0; +} + +int atoi_l(char *s, int l) { + char *p = strndup(s, l); + int r = atoi(p); + free(p); + return r; +} + +int ets_parse(struct entry *entry, char *ln) { + int i, t; + memset(entry, 0, sizeof(struct entry)); + + if (ln[0] != '*') + for (i = 0; i <= 20; i++) { + if (ln[i] >= '0' && ln[i] <= '9') + entry->remote_msn[i] = ln[i]; + else + break; + } + + if (ln[25] >= '0' && ln[25] <= '9' && ln[26] >= '0' && ln[26] <= '9') { + entry->local_mm = atoi_l(ln+25, 2); + + if (entry->local_mm <= 0) { + fprintf(stderr, "Corrupt local MM column.\n"); + return -1; + } + } + + if (ln[32] >= '0' && ln[32] <= '9' && ln[33] >= '0' && ln[33] <= '9') { + entry->participant = atoi_l(ln+32, 2); + + if (!((entry->participant >= 31 && entry->participant <= 38) || + (entry->participant >= 41 && entry->participant <= 48))) { + fprintf(stderr, "Corrupt participant column.\n"); + return -1; + } + } + + entry->incoming = ln[35] == 'K' ? 1 : 0; + + if (!(ln[39] >= '0' && ln[39] <= '9' && ln[40] >= '0' && ln[40] <= '9')) { + fprintf(stderr, "Corrupt day column.\n"); + return -1; + } + + if (!(ln[42] >= '0' && ln[42] <= '9' && ln[43] >= '0' && ln[43] <= '9')) { + fprintf(stderr, "Corrupt month column.\n"); + return -1; + } + + if (!(ln[45] >= '0' && ln[45] <= '9' && ln[46] >= '0' && ln[46] <= '9')) { + fprintf(stderr, "Corrupt hour column.\n"); + return -1; + } + + if (!(ln[48] >= '0' && ln[48] <= '9' && ln[49] >= '0' && ln[49] <= '9')) { + fprintf(stderr, "Corrupt minute column.\n"); + return -1; + } + + entry->day = atoi_l(ln+39, 2); + entry->month = atoi_l(ln+42, 2); + entry->hour = atoi_l(ln+45, 2); + entry->minute = atoi_l(ln+48, 2); + + if (entry->day < 1 || entry->day > 31 || entry->month < 1 || entry->month > 12 || entry->hour < 0 || entry->hour > 24 || entry->minute < 0 || entry->minute >= 60) { + fprintf(stderr, "Corrupt timespec column.\n"); + return -1; + } + + if (!((ln[51] == ' ' || (ln[51] >= '0' && ln[51] <= '9')) && (ln[52] == ' ' || (ln[52] >= '0' && ln[52] <= '9')) && ln[53] >= '0' && ln[53] <= '9')) { + fprintf(stderr, "Corrupt minute (duration) column.\n"); + return -1; + } + + if (!(ln[55] >= '0' && ln[55] <= '9' && ln[56] >= '0' && ln[56] <= '9')) { + fprintf(stderr, "Corrupt second (duration) column.\n"); + return -1; + } + + t = atoi_l(ln+55, 2); + + if (t < 0 || t >= 60) { + fprintf(stderr, "Corrupt second (duration) column. (#2)\n"); + return -1; + } + + entry->duration = atoi_l(ln+51,3)*60 + t; + + if (entry->duration < 0) { + fprintf(stderr, "Corrupt duration column.\n"); + return -1; + } + + return 0; +} + +int ets_read_entry(int fd, struct entry *entry) { + char ln[80]; + int r; + + if ((r = read_line(fd, ln, sizeof(ln))) != 74) { + if (r == 1 && ln[0] == '\n') + return -2; + + fprintf(stderr, "Error while reading line (%i|%i).\n", r, (int) ln[0]); + return -1; + } + + if (ln[73] != '\n') { + fprintf(stderr, "Corrupt line.\n"); + return -1; + } + + ln[73] = 0; + + if (ln[37] == 'V') + return 0; + + if (ets_parse(entry, ln) == 0) + return 1; + + fprintf(stderr, "Failure in line [%s]\n", ln); + return -1; +} + + +void work(int fd, void *db) { + int n = 0, v = 0, a = 0; + if (ets_reset(fd) != 0) { + fprintf(stderr, "Could not reset PBX.\n"); + return; + } + + // Accelerate a bit + if (ets_next(fd) != 0) + return; + + while (!quit) { + struct entry entry; + int r; + + if ((r = ets_read_entry(fd, &entry)) < 0) + break; + + if (r > 0) { + v++; + + if ((r = db_write_entry(db, &entry)) < 0) + break; + else if (r == 0) + a++; + } + + if (verbose) { + fprintf(stderr, "%3.1f%% done; %i of %i valid entries added.\r", (float)(++n)/10, a, v); + fflush(stdout); + } + + if (ets_next(fd) != 0) + break; + } + + if (verbose) + fprintf(stderr, "Finished; %i entries in PBX; %i of %i valid entries added.\n", n, a, v); +} + +void help(const char *p) { + fprintf(stderr, + "%s [-h] [-q] [-d DEVICE] [-b DATABASE]\n" + " -h Shows this help\n" + " -q Disables verbose mode\n" + " -d DEVICE specifies the serial device to use\n" + " -b DATABASE specifies the database to use\n", + p); + exit(1); +} + +int main(int argc, char *argv[]) { + int fd = -1, r = 1, locked = 0; + const char *dev = "/dev/ttyS1"; + void *db = NULL; + char* dbspec = NULL; + int c; + + while ((c = getopt (argc, argv, "hqd:b:")) != -1) + switch (c) { + case 'q': + verbose = 0; + break; + + case 'b': + dbspec = optarg; + break; + + case 'd': + dev = optarg; + break; + + default: + help(basename(argv[0])); + break; + } + + if (device_lock(dev, basename(argv[0])) != 0) + goto finish; + + locked = 1; + + if ((fd = modem_open(dev)) < 0) + goto finish; + + //"dbname=pgets user=pgets_fill password=mahatma" + if (!(db = db_connect(dbspec))) + goto finish; + + while (*dbspec) + *(dbspec++) = 'X'; + + signal(SIGINT, sigint); + siginterrupt(SIGINT, 0); + + flush_data(fd); + work(fd, db); + + r = 0; + +finish: + if (fd >= 0) + modem_close(fd); + + if (db) + db_disconnect(db); + + if (locked) + device_unlock(dev); + + return r; +} diff --git a/src/pgets.h b/src/pgets.h new file mode 100644 index 0000000..f1d34fa --- /dev/null +++ b/src/pgets.h @@ -0,0 +1,35 @@ +#ifndef foopgetshfoo +#define foopgetshfoo + +/* $Id$ + * + * This file is part of pgets. + * + * pgets 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. + * + * pgets 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 pgets; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +struct entry { + char remote_msn[22]; + int local_mm; + int participant; + int incoming; + int day; + int month; + int hour; + int minute; + int duration; +}; + +#endif diff --git a/src/postgres.c b/src/postgres.c new file mode 100644 index 0000000..090afaf --- /dev/null +++ b/src/postgres.c @@ -0,0 +1,93 @@ +/* $Id$ + * + * This file is part of pgets. + * + * pgets 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. + * + * pgets 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 pgets; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include +#include +#include + +#include + +#include "db.h" + +void* db_connect(const char*t) { + PGconn *pg; + + if (!t) { + fprintf(stderr, "Database specification required.\n"); + return NULL; + } + + if (!(pg = PQconnectdb(t))) + return NULL; + + if (PQstatus(pg) != CONNECTION_OK) { + fprintf(stderr, "Could not connect to database: %s\n", PQerrorMessage(pg)); + PQfinish(pg); + return NULL; + } + + return pg; +} + +void db_disconnect(void *db) { + assert(db); + PQfinish((PGconn*) db); +} + +int db_write_entry(void *db, const struct entry *entry) { + static time_t t = 0; + char query[512]; + struct tm tm; + PGresult* r; + PGconn *pg = db; + int year; + + assert(pg); + + if (t == 0) { + t = time(NULL); + localtime_r(&t, &tm); + } + + if (entry->month < tm.tm_mon+1 || (entry->month == tm.tm_mon+1 && entry->day <= tm.tm_mday)) + year = 1900+tm.tm_year; + else + year = 1900+tm.tm_year-1; + + snprintf(query, sizeof(query), "INSERT INTO pgets_accounting (remote_msn, local_mm, participant, incoming, _timestamp, duration) VALUES ('%s', %i, %i, '%c', TIMESTAMP '%04i-%02i-%02i %02i:%02i:00', %i)", + entry->remote_msn, entry->local_mm, entry->participant, entry->incoming ? 't' : 'f', year, entry->month, entry->day, entry->hour, entry->minute, entry->duration); + + if (!(r = PQexec(pg, query)) || PQstatus(pg) != CONNECTION_OK || PQresultStatus(r) != PGRES_COMMAND_OK) { + if (r) { + if (PQresultStatus(r) == PGRES_FATAL_ERROR) { + PQclear(r); + return 1; + } + + fprintf(stderr, "Query [%s] failed (#1), reason given: %s\n", query, PQresultErrorMessage(r)); + PQclear(r); + } else + fprintf(stderr, "Query [%s] failed (#2), reason given: %s\n", query, PQerrorMessage(pg)); + + return -1; + } + + PQclear(r); + return 0; +} diff --git a/src/sqlite.c b/src/sqlite.c new file mode 100644 index 0000000..ec9aef5 --- /dev/null +++ b/src/sqlite.c @@ -0,0 +1,98 @@ +/* $Id$ + * + * This file is part of pgets. + * + * pgets 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. + * + * pgets 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 pgets; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include +#include +#include +#include +#include + +#include + +#include "db.h" + + +static int busy(void *v, const char *name, int try) { + fprintf(stderr, "Table '%s' locked (try #%i), sleeping 2s ... \r", name, try); + sleep(2); + return 0; +} + +void* db_connect(const char*t) { + sqlite *db; + char *e; + + if (!t) { + fprintf(stderr, "Database specification required.\n"); + return NULL; + } + + if (!(db = sqlite_open(t, 0, &e))) { + fprintf(stderr, "Failed to open database: %s\n", e); + free(e); + } + + sqlite_busy_handler(db, busy, NULL); + + return db; +} + +void db_disconnect(void *db) { + assert(db); + sqlite_close((sqlite*) db); +} + +int db_write_entry(void *vdb, const struct entry *entry) { + static time_t t = 0; + char query[512]; + struct tm tm; + sqlite *db = vdb; + int year; + char *e = NULL; + int ret; + + assert(db); + + if (t == 0) { + t = time(NULL); + localtime_r(&t, &tm); + } + + if (entry->month < tm.tm_mon+1 || (entry->month == tm.tm_mon+1 && entry->day <= tm.tm_mday)) + year = 1900+tm.tm_year; + else + year = 1900+tm.tm_year-1; + + snprintf(query, sizeof(query), "INSERT INTO pgets_accounting (remote_msn, local_mm, participant, incoming, _timestamp, duration) VALUES ('%s', %i, %i, '%c', '%04i-%02i-%02i %02i:%02i:00', %i)", + entry->remote_msn, entry->local_mm, entry->participant, entry->incoming ? 't' : 'f', year, entry->month, entry->day, entry->hour, entry->minute, entry->duration); + + if ((ret = sqlite_exec(db, query, NULL, NULL, &e)) != SQLITE_OK) { + + if (ret == SQLITE_CONSTRAINT) { + free(e); + return 1; + } + + fprintf(stderr, "sqlite_exec(): %s\n", e); + free(e); + return -1; + } + + return 0; +} diff --git a/src/util.c b/src/util.c new file mode 100644 index 0000000..d6a5ad5 --- /dev/null +++ b/src/util.c @@ -0,0 +1,102 @@ +/* $Id$ + * + * This file is part of pgets. + * + * pgets 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. + * + * pgets 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 pgets; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include +#include +#include + +#include "util.h" + +ssize_t loop_read (int FILEDES, void *BUFFER, size_t SIZE) { + ssize_t c = 0; + + while (SIZE > 0) { + ssize_t r = read(FILEDES, BUFFER, SIZE); + + if (r <= 0) { + if (c == 0) + return r; + else + return c; + } + + SIZE -= r; + c += r; + BUFFER += r; + } + + return c; +} + +ssize_t loop_write(int FILEDES, const void *BUFFER, size_t SIZE) { + ssize_t c = 0; + + while (SIZE > 0) { + ssize_t r = write(FILEDES, BUFFER, SIZE); + + if (r <= 0) { + if (c == 0) + return r; + else + return c; + } + + SIZE -= r; + c += r; + BUFFER += r; + } + + return c; +} + +// The name says it all. +void flush_data(int fd) { + tcflush(fd, TCIFLUSH); + tcflush(fd, TCIFLUSH); +} + +ssize_t read_line(int FILEDES, char *ln, size_t SIZE) { + ssize_t c = 0; + + while (SIZE > 0) { + ssize_t r; + + if ((r = read(FILEDES, ln, 1)) != 1) { + if (r < 0 && !c) + return -1; + + break; + } + + SIZE--; + c++; + + if (*ln == '\r' || *ln == '\n') { + ln++; + break; + } + + ln++; + } + + if (SIZE) + *ln = 0; + + return c; +} diff --git a/src/util.h b/src/util.h new file mode 100644 index 0000000..2ac3eb7 --- /dev/null +++ b/src/util.h @@ -0,0 +1,35 @@ +#ifndef fooutilhfoo +#define fooutilhfoo + +/* $Id$ + * + * This file is part of pgets. + * + * pgets 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. + * + * pgets 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 pgets; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +/* A loop of write()s */ +ssize_t loop_write(int FILEDES, const void *BUFFER, size_t SIZE); + +/* A loop of read()s */ +ssize_t loop_read(int FILEDES, void *BUFFER, size_t SIZE); + +/* Read a line */ +ssize_t read_line(int FIELDES, char *ln, size_t SIZE); + +/* Flush all waiting data */ +void flush_data(int fd); + +#endif -- cgit