summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am47
-rw-r--r--src/db.h29
-rw-r--r--src/lock.c168
-rw-r--r--src/lock.h26
-rw-r--r--src/modem.c76
-rw-r--r--src/modem.h26
-rw-r--r--src/pgets.c294
-rw-r--r--src/pgets.h35
-rw-r--r--src/postgres.c93
-rw-r--r--src/sqlite.c98
-rw-r--r--src/util.c102
-rw-r--r--src/util.h35
12 files changed, 1029 insertions, 0 deletions
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 <config.h>
+#endif
+
+#include <unistd.h>
+#include <sys/stat.h>
+#include <stdio.h>
+#include <limits.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <string.h>
+#include <inttypes.h>
+#include <pwd.h>
+
+#include <libdaemon/dlog.h>
+
+#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 <termios.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+
+#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 <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <signal.h>
+
+#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 <time.h>
+#include <assert.h>
+#include <stdio.h>
+
+#include <postgresql/libpq-fe.h>
+
+#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 <time.h>
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <sqlite.h>
+
+#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 <unistd.h>
+#include <termios.h>
+#include <string.h>
+
+#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