summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile.am40
-rwxr-xr-xbootstrap.sh45
-rw-r--r--configure.ac89
-rw-r--r--php/pgets-intro.html43
-rw-r--r--php/pgets.php119
-rw-r--r--php/style.css39
-rw-r--r--sql/pgets-access.sql38
-rw-r--r--sql/pgets.sql28
-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
20 files changed, 1470 insertions, 0 deletions
diff --git a/Makefile.am b/Makefile.am
new file mode 100644
index 0000000..386d51d
--- /dev/null
+++ b/Makefile.am
@@ -0,0 +1,40 @@
+# $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.
+
+EXTRA_DIST=bootstrap.sh README LICENSE
+SUBDIRS=src #conf doc man
+
+MAINTAINERCLEANFILES = README
+noinst_DATA = README
+
+README:
+ rm -f README
+# $(MAKE) -C doc README
+ cd $(srcdir) && ln -s doc/README README
+
+homepage: all dist
+ test -d $$HOME/homepage/lennart
+ mkdir -p $$HOME/homepage/lennart/projects/pgets
+ cp *.tar.gz $$HOME/homepage/lennart/projects/pgets
+# cp doc/style.css doc/README.html $$HOME/homepage/lennart/projects/pgets/
+ cp $$HOME/homepage/lennart/projects/pgets/README.html $$HOME/homepage/lennart/projects/pgets/index.html
+
+distcleancheck:
+ @:
+
+.PHONY: homepage distcleancheck
diff --git a/bootstrap.sh b/bootstrap.sh
new file mode 100755
index 0000000..9cc81f4
--- /dev/null
+++ b/bootstrap.sh
@@ -0,0 +1,45 @@
+#!/bin/bash
+# $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.
+
+run_versioned() {
+ local P
+ type -p "$1-$2" &> /dev/null && P="$1-$2" || local P="$1"
+
+ shift 2
+ "$P" "$@"
+}
+
+if [ "x$1" = "xam" ] ; then
+ set -ex
+ run_versioned automake 1.7 -a -c
+ ./config.status
+else
+ set -ex
+ rm -rf autom4te.cache
+ rm -f config.cache
+
+ run_versioned aclocal 1.7
+ autoheader
+ run_versioned automake 1.7 -a -c
+ autoconf -Wall
+
+ ./configure --sysconfdir=/etc "$@"
+
+ make clean
+fi
diff --git a/configure.ac b/configure.ac
new file mode 100644
index 0000000..8d6e9e3
--- /dev/null
+++ b/configure.ac
@@ -0,0 +1,89 @@
+# -*- Autoconf -*-
+# Process this file with autoconf to produce a configure script.
+
+# $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.
+
+AC_PREREQ(2.59)
+AC_INIT([pgets],[0.1],[mzctrgf (at) 0pointer (dot) de])
+AC_CONFIG_SRCDIR([src/pgets.c])
+AC_CONFIG_HEADERS([config.h])
+AM_INIT_AUTOMAKE([foreign -Wall])
+
+AC_SUBST(PACKAGE_URL, [http://0pointer.de/lennart/projects/pgets/])
+
+if type -p stow > /dev/null && test -d /usr/local/stow ; then
+ AC_MSG_NOTICE([*** Found /usr/local/stow: default install prefix set to /usr/local/stow/${PACKAGE_NAME}-${PACKAGE_VERSION} ***])
+ ac_default_prefix="/usr/local/stow/${PACKAGE_NAME}-${PACKAGE_VERSION}"
+fi
+
+# Checks for programs.
+AC_PROG_CC
+AC_PROG_LN_S
+AC_PROG_MAKE_SET
+
+# If using GCC specifiy some additional parameters
+if test "x$GCC" = "xyes" ; then
+ CFLAGS="$CFLAGS -pipe -Wall"
+fi
+
+AC_CHECK_LIB([pq], [PQconnectdb])
+AC_CHECK_LIB([sqlite], [sqlite_open])
+
+AM_CONDITIONAL([POSTGRES], [true])
+AM_CONDITIONAL([SQLITE], [true])
+
+# Checks for header files.
+AC_HEADER_STDC
+AC_CHECK_HEADERS([fcntl.h inttypes.h limits.h stdlib.h string.h termios.h unistd.h])
+
+# Checks for typedefs, structures, and compiler characteristics.
+AC_C_CONST
+AC_TYPE_MODE_T
+AC_TYPE_PID_T
+AC_TYPE_SIZE_T
+AC_STRUCT_TM
+AC_TYPE_UID_T
+AC_C_VOLATILE
+
+# Checks for library functions.
+AC_TYPE_SIGNAL
+AC_FUNC_STAT
+AC_CHECK_FUNCS([localtime_r memset strerror strndup])
+
+# LYNX documentation generation
+AC_ARG_ENABLE(lynx,
+ AS_HELP_STRING(--disable-lynx,Turn off lynx usage for documentation generation),
+[case "${enableval}" in
+ yes) lynx=yes ;;
+ no) lynx=no ;;
+ *) AC_MSG_ERROR(bad value ${enableval} for --disable-lynx) ;;
+esac],[lynx=yes])
+
+if test x$lynx = xyes ; then
+ AC_CHECK_PROG(have_lynx, lynx, yes, no)
+
+ if test x$have_lynx = xno ; then
+ AC_MSG_ERROR([*** Sorry, you have to install lynx or use --disable-lynx ***])
+ fi
+fi
+
+AM_CONDITIONAL([USE_LYNX], [test "x$lynx" = xyes])
+
+AC_CONFIG_FILES([src/Makefile Makefile]) # conf/Makefile doc/Makefile doc/README.html])
+AC_OUTPUT
diff --git a/php/pgets-intro.html b/php/pgets-intro.html
new file mode 100644
index 0000000..98a66c2
--- /dev/null
+++ b/php/pgets-intro.html
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="iso-8895-15"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+
+<head>
+<title>pgETS</title>
+<link rel="stylesheet" type="text/css" href="style.css" />
+</head>
+
+<body>
+<h1>ETS Call Accounting - Make Your Selection</h1>
+
+<form action="pgets.php" method="get">
+
+<h3>Direction</h3>
+<div class="radiobox">
+<div><input type="radio" checked name="direction" value="0"/>Outgoing + Incoming</div>
+<div><input type="radio" name="direction" value="1"/>Outgoing</div>
+<div><input type="radio" name="direction" value="2"/>Incoming</div>
+</div>
+
+<h3>Sort Order</h3>
+<div class="radiobox">
+<div><input type="radio" checked name=order value="0"/>Ascending</div>
+<div><input type="radio" name="order" value="1"/>Descending</div>
+</div>
+
+<h3>Time Range</h3>
+<p>Format is YYYY-MM-DD, leave empty for complete list.</p>
+<p>Between <input type=input name="sdate" value=""/> and <input type=input name="edate" value=""/></p>
+<div><input type="submit" value="Submit Query"/></div>
+
+</form>
+
+<hr/>
+<p>
+<b>Shortcuts:</b> <a href="pgets.php">Complete List</a> | <a href="pgets.php?special=1&amp;direction=1">Outgoing This Month</a>
+</p>
+
+<hr/>
+<div class="grey"><!-- hhmts start -->Last modified: Mon Mar 1 00:03:59 CET 2004 <!-- hhmts end --></div>
+</body>
+</html>
diff --git a/php/pgets.php b/php/pgets.php
new file mode 100644
index 0000000..d1e8036
--- /dev/null
+++ b/php/pgets.php
@@ -0,0 +1,119 @@
+<?php echo '<?xml version="1.0" encoding="iso-8895-15"?>' ?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+
+<head>
+<title>pgETS</title>
+<link rel="stylesheet" type="text/css" href="style.css" />
+</head>
+
+<body>
+<h1>ETS Call Accounting - Query Results</h1>
+<?php
+
+$local_prefix = "040";
+$dbspec = "dbname=pgets user=pgets_web password=gandhi";
+
+$n_order = (int) $HTTP_GET_VARS['order'];
+$n_direction = (int) $HTTP_GET_VARS['direction'];
+$order = $n_order ? "DESC" : "ASC";
+
+if (isset($HTTP_GET_VARS['sdate'])) {
+ $sdate = addslashes($HTTP_GET_VARS['sdate']);
+} else if (isset($HTTP_GET_VARS['sday'])) {
+ $sday = (int) $HTTP_GET_VARS['sday'];
+ $smon = (int) $HTTP_GET_VARS['smon'];
+ $syear = (int) $HTTP_GET_VARS['syear'];
+
+ $sdate = sprintf("%04s-%02s-%02s", $syear, $smon, $sday);
+} else {
+ $sdate = "";
+}
+
+if (isset($HTTP_GET_VARS['edate'])) {
+ $edate = addslashes($HTTP_GET_VARS['edate']);
+} else if (isset($HTTP_GET_VARS['eday'])) {
+ $eday = (int) $HTTP_GET_VARS['eday'];
+ $emon = (int) $HTTP_GET_VARS['emon'];
+ $eyear = (int) $HTTP_GET_VARS['eyear'];
+ $edate = sprintf("%04s-%02s-%02s", $eyear, $emon, $eday);
+} else {
+ $edate = "";
+}
+
+if (isset($HTTP_GET_VARS['special'])) {
+ if ($HTTP_GET_VARS['special'] == 1)
+ $sdate = date("Y-m-01");
+}
+
+
+if ($edate != "" || $sdate != "") {
+ echo "<p><i>";
+
+ if ($edate != "" && $sdate != "") {
+ echo "Showing entries between $sdate (incl) and $edate (excl).";
+ } else if ($edate != "") {
+ echo "Showing entries before $edate (excl).";
+ } else if ($sdate != "") {
+ echo "Showing entries after $sdate (incl).";
+ }
+
+ echo "</p></i>";
+}
+
+$db = pg_pconnect($dbspec);
+
+$where = "WHERE 1=1";
+if ($n_direction == 1) $where = $where." AND incoming='f'";
+if ($n_direction == 2) $where = $where." AND incoming='t'";
+if ($sdate != "") $where = $where." AND _timestamp >= '$sdate'";
+if ($edate != "") $where = $where." AND _timestamp < '$edate'";
+
+$q = pg_query($db, "SELECT CASE WHEN SUBSTRING(remote_msn FROM 1 FOR 3)='".$local_prefix."' THEN SUBSTRING(TRIM(remote_msn) FROM 4) ELSE TRIM(remote_msn) END, CASE WHEN incoming='t' THEN 'Incoming' ELSE 'Outgoing' END, participant, TO_CHAR(_timestamp, 'DD.MM.YYYY HH24:MI'), CASE WHEN duration > 60 THEN duration/60||'m '||duration%60||'s' ELSE duration||'s' END FROM pgets_accounting ".$where." ORDER BY _timestamp ".$order);
+
+$num = pg_numrows($q);
+
+if ($num == 0) {
+ echo "<p><b>No entries found.</b></p>\n";
+} else {
+ echo "<table summary=\"Phone calls\" cellspacing=\"0\" cellpadding=\"2\">\n<tr class=\"theader\"><th>Remote MSN</th><th><a href=\"pgets.php?sdate=$sdate&amp;edate=$edate&amp;order=$n_order&amp;direction=".(($n_direction+1)%3)."\">Direction</a></th><th>P.</th><th><a href=\"pgets.php?sdate=$sdate&amp;edate=$edate&amp;order=".(1-$n_order)."&amp;direction=$n_direction\">Start time</a></th><th>Duration</th></tr>\n";
+
+ $c = 0;
+
+ for ($i = 0; $i < $num; $i++) {
+ $r = pg_fetch_row($q, $i);
+
+
+ $c = 1-$c;
+
+ echo "<tr class=\"line$c\">";
+
+ for ($j=0; $j < count($r); $j++) {
+ echo "<td>&nbsp;$r[$j]&nbsp;</td>";
+ }
+
+ echo "</tr>\n";
+ }
+
+ echo "</table>\n";
+
+ $q = pg_query($db, "SELECT COUNT(*),SUM(duration) FROM pgets_accounting $where");
+ $r = pg_fetch_row($q, 0);
+
+ if ($r[1] > 3600) {
+ $sum = (int) ($r[1]/3600)."h ".(int)($r[1] % 3600 / 60)."m ".(int)($r[1] % 60)."s";
+ } else if ($r[1] > 60) {
+ $sum = (int)($r[1]/60)."m ".(int)($r[1] % 60)."s";
+ } else {
+ $sum = $r[1]."s";
+ }
+
+ echo "<p><b>$r[0] items, $sum total duration.</b></p>";
+}
+
+?>
+
+<hr/>
+<div class="grey">Generated: <?php echo date("r") ?></div>
+</body>
+</html> \ No newline at end of file
diff --git a/php/style.css b/php/style.css
new file mode 100644
index 0000000..ae6132c
--- /dev/null
+++ b/php/style.css
@@ -0,0 +1,39 @@
+/* $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.
+ ***/
+
+body { color: black; background-color: white; margin: 0.5cm; }
+a:link, a:visited { color: #900000; }
+p { margin-left: 0.5cm; margin-right: 0.5cm; }
+div.news-date { margin-left: 0.5cm; font-size: 80%; color: #4f0000; }
+p.news-text { margin-left: 1cm; }
+h1 { color: #00009F; }
+h2 { color: #00009F; }
+h3 { color: #00004F; margin-left: 0.5cm; }
+ul { margin-left: .5cm; }
+ol { margin-left: .5cm; }
+pre { margin-left: .5cm; background-color: #f0f0f0; padding: 0.4cm;}
+.grey { color: #afafaf; }
+
+.radiobox { margin-left: .5cm; background-color:#f0f0f0; padding: 0.4cm; }
+.line0 { background-color:#f0f0f0; }
+.line1 { background-color:#ffffff; }
+.theader { background-color:#d0d0d0; }
+
+table { border:1px solid black; }
diff --git a/sql/pgets-access.sql b/sql/pgets-access.sql
new file mode 100644
index 0000000..e4507f5
--- /dev/null
+++ b/sql/pgets-access.sql
@@ -0,0 +1,38 @@
+-- $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.
+
+-- Create database
+
+DROP DATABASE pgets;
+CREATE DATABASE pgets;
+
+\c pgets
+
+-- Create tables
+
+\i pgets.sql
+
+-- Manage access rights
+
+DROP USER pgets_fill;
+CREATE USER pgets_fill PASSWORD 'mahatma';
+DROP USER pgets_web;
+CREATE USER pgets_web PASSWORD 'gandhi';
+
+GRANT INSERT ON pgets_accounting TO pgets_fill;
+GRANT SELECT ON pgets_accounting TO pgets_web;
diff --git a/sql/pgets.sql b/sql/pgets.sql
new file mode 100644
index 0000000..0ba22aa
--- /dev/null
+++ b/sql/pgets.sql
@@ -0,0 +1,28 @@
+-- $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.
+
+CREATE TABLE pgets_accounting (
+ remote_msn CHAR(22) NOT NULL,
+ local_mm SMALLINT NOT NULL,
+ participant SMALLINT NOT NULL,
+ incoming BOOL NOT NULL,
+ _timestamp TIMESTAMP NOT NULL,
+ duration INT NOT NULL);
+
+CREATE INDEX pgets_accounting_timestamp ON pgets_accounting(_timestamp);
+CREATE UNIQUE INDEX pgets_accounting_unique ON pgets_accounting(remote_msn, local_mm, participant, incoming, _timestamp, duration);
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