[hamradio-commits] [aprx] 01/02: Import Upstream version 2.08.svn593+dfsg

Dave Hibberd hibby-guest at moszumanska.debian.org
Sat Jan 21 23:59:21 UTC 2017


This is an automated email from the git hooks/post-receive script.

hibby-guest pushed a commit to branch master
in repository aprx.

commit 71f02d51f95f71dc1e3e9f2348633dcfa1ef2a11
Author: Hibby <d at vehibberd.com>
Date:   Sat Jan 21 23:58:46 2017 +0000

    Import Upstream version 2.08.svn593+dfsg
---
 ChangeLog                                          | 2539 ++++++++
 INSTALL                                            |   60 +
 LICENSE                                            |   27 +
 Makefile                                           |  226 +
 Makefile.in                                        |  226 +
 PROTOCOLS                                          |  258 +
 README                                             |   86 +
 ROADMAP                                            |   26 +
 SVNVERSION                                         |    1 +
 TIMESTAMP-AT-APRSIS                                |  264 +
 TODO                                               |  109 +
 VER                                                |    1 +
 VERSION                                            |    1 +
 ViscousDigipeater.README                           |   60 +
 ViscousDigipeaterTxEffect.png                      |  Bin 0 -> 30001 bytes
 agwpesocket.c                                      |  731 +++
 apparmor.aprx                                      |   17 +
 aprsis.c                                           | 1279 ++++
 aprx-complex.conf.in                               |  528 ++
 aprx-config.xsd                                    |  263 +
 aprx-rxigate.conf.in                               |  118 +
 aprx-stat.8.in                                     |  217 +
 aprx-stat.c                                        |  258 +
 aprx.8.in                                          | 1428 +++++
 aprx.c                                             |  635 ++
 aprx.conf.in                                       |  390 ++
 aprx.h                                             |  784 +++
 aprx.spec                                          |  118 +
 aprxpolls.c                                        |   51 +
 ax25.c                                             |  295 +
 beacon.c                                           | 1235 ++++
 build-stamp                                        |    0
 cellmalloc.c                                       |  357 ++
 cellmalloc.h                                       |   31 +
 config.c                                           |  814 +++
 config.h.in                                        |  182 +
 configure                                          | 6245 ++++++++++++++++++++
 configure-stamp                                    |    0
 configure.in                                       |  318 +
 coverity-build-submit.sh                           |   27 +
 crc.c                                              |  286 +
 debian/aprx.default                                |   10 +
 debian/aprx.init                                   |  155 +
 debian/aprx.postinst.debhelper                     |   15 +
 debian/aprx.postrm.debhelper                       |    5 +
 debian/aprx.prerm.debhelper                        |    9 +
 debian/aprx.substvars                              |    1 +
 debian/aprx/DEBIAN/conffiles                       |    5 +
 debian/aprx/DEBIAN/control                         |   19 +
 debian/aprx/DEBIAN/md5sums                         |   13 +
 debian/aprx/DEBIAN/postinst                        |   17 +
 debian/aprx/DEBIAN/postrm                          |    7 +
 debian/aprx/DEBIAN/prerm                           |   11 +
 debian/aprx/etc/apparmor.d/sbin.aprx               |   17 +
 debian/aprx/etc/default/aprx                       |   10 +
 debian/aprx/etc/init.d/aprx                        |  155 +
 debian/aprx/etc/logrotate.d/aprx                   |    8 +
 debian/aprx/usr/sbin/aprx                          |  Bin 0 -> 454267 bytes
 debian/aprx/usr/sbin/aprx-stat                     |  Bin 0 -> 29954 bytes
 debian/aprx/usr/share/doc/aprx/LICENSE             |   27 +
 debian/aprx/usr/share/doc/aprx/PROTOCOLS.gz        |  Bin 0 -> 3521 bytes
 debian/aprx/usr/share/doc/aprx/README              |   86 +
 debian/aprx/usr/share/doc/aprx/ROADMAP             |   26 +
 debian/aprx/usr/share/doc/aprx/TODO.gz             |  Bin 0 -> 2186 bytes
 .../aprx/usr/share/doc/aprx/aprx-complex.conf.gz   |  Bin 0 -> 7003 bytes
 debian/aprx/usr/share/doc/aprx/aprx-manual.pdf.gz  |  Bin 0 -> 465580 bytes
 debian/aprx/usr/share/doc/aprx/aprx.conf.gz        |  Bin 0 -> 5375 bytes
 debian/aprx/usr/share/doc/aprx/copyright           |    1 +
 debian/aprx/usr/share/man/man8/aprx-stat.8.gz      |  Bin 0 -> 2507 bytes
 debian/aprx/usr/share/man/man8/aprx.8.gz           |  Bin 0 -> 15564 bytes
 debian/changelog                                   |   12 +
 debian/compat                                      |    1 +
 debian/control                                     |   22 +
 debian/copyright                                   |    1 +
 debian/dirs                                        |    6 +
 debian/docs                                        |    8 +
 debian/files                                       |    1 +
 debian/postinst.off                                |   49 +
 debian/rules                                       |   96 +
 digipeater.c                                       | 1867 ++++++
 doc/aprx-manual-pics.odp                           |  Bin 0 -> 12644 bytes
 doc/aprx-manual.odt                                |  Bin 0 -> 197896 bytes
 doc/aprx-manual.pdf                                |  Bin 0 -> 438348 bytes
 doc/aprx-requirement-specification.odt             |  Bin 0 -> 34162 bytes
 doc/aprx-requirement-specification.pdf             |  Bin 0 -> 175248 bytes
 dprsgw.c                                           | 1094 ++++
 dupecheck.c                                        |  484 ++
 erlang.c                                           |  703 +++
 filter.c                                           | 2331 ++++++++
 filter.c.2.06-to-head.diff                         |  585 ++
 historydb.c                                        |  631 ++
 historydb.h                                        |  101 +
 hlog.c                                             |  561 ++
 hlog.h                                             |   57 +
 igate.c                                            |  650 ++
 install-sh                                         |  507 ++
 interface.c                                        | 1895 ++++++
 keyhash.c                                          |   91 +
 keyhash.h                                          |   17 +
 kiss.c                                             |  710 +++
 logrotate.aprx.in                                  |    8 +
 man-to-html.sh                                     |  118 +
 netax25.c                                          |  810 +++
 netresolver.c                                      |  151 +
 parse_aprs.c                                       | 1416 +++++
 pbuf.c                                             |  237 +
 pbuf.h                                             |  125 +
 rpm/aprx.default                                   |   10 +
 rpm/aprx.init                                      |   84 +
 rpm/aprx.service                                   |   11 +
 ssl.c                                              |  920 +++
 ssl.h                                              |  102 +
 svnversion                                         |    3 +
 svnversion-test.sh                                 |   36 +
 telemetry.c                                        |  572 ++
 test.c                                             |   21 +
 timercmp.c                                         |  157 +
 timestamp.c                                        |  184 +
 tt.5383                                            | 3101 ++++++++++
 ttyreader.c                                        | 1080 ++++
 valgrind.c                                         |  101 +
 121 files changed, 42815 insertions(+)

diff --git a/ChangeLog b/ChangeLog
new file mode 100644
index 0000000..1affd13
--- /dev/null
+++ b/ChangeLog
@@ -0,0 +1,2539 @@
+2014-03-24 Matti Aarnio - OH2MQK - KP20NG  <oh2mqk at sral.fi>
+
+	* interface.c:
+	    Igated 3rd-party frames are produced with different TNC2 format
+	    message from AX.25 frame message.  This is because TNC2 format
+	    is used at filter processing, and needs to have original source
+	    address arriving from APRS-IS.
+
+	* ttyreader.c:
+	    Set default read timeout to 60 minutes, it can be configured to
+	    any value from 1 second to 4 hours as channel busyness supports,
+	    and even disabled.
+
+	* ttyreader.c:
+	    Use aprxlog() to record tty state changes: close/open
+
+	* netresolver.c:
+	    Use same "die_now" flag as all other thread loops do.
+
+	* historydb.c:
+	    Fix key pickup of sourcename.
+	    Debug print key in history_db_insert_()
+
+	* agwpesocket.c:
+	    Code cleaning.
+
+	* cellmalloc.c:
+	    No need to include <pthread.h>
+
+	* configure.in:
+	    Make pthread autoconfig default with option to disable it.
+
+	* pbuf.c:
+	    Declare pbuf_alloc() static.
+
+2014-03-22 Matti Aarnio - OH2MQK - KP20NG  <oh2mqk at sral.fi>
+
+	* aprx.c:
+	    Fix aprxlog() function internal varargs usage.
+	    It must be reset for each vfprintf() call...
+
+	* aprx.c:
+	    Initial value of time_reset = 1; start in "reset state",
+	    which does time resetting in all prepoll codes in main
+	    loop. At second round and there after of the main loop
+	    the reset_time flag will be reset after execution of all
+	    prepoll functions.
+
+	* aprsis.c:
+	    Do initial connect at about current tick + 10 seconds.
+	    Reset phase will also put next connect attempt at that time.
+
+	* aprx.c:
+	    Change stdout and stderr buffering definition to have
+	    a buffer, and make line buffering in a way that works..
+
+	* aprsis.c:
+	    Correct calls to aprxlog().
+
+	* configure.in, Makefile.in:
+	    Revised the pthread support autoconfig to really find where
+	    the libraries are, and set correct definitions and compile/link
+	    time parameters.
+
+2014-03-21 Matti Aarnio - OH2MQK - KP20NG  <oh2mqk at sral.fi>
+
+	* aprx.h, interface.c, beacon.c, config.c, digipeater.c,
+	  telemetry.c:
+	    Change the "flags are bits in an int" to "packet bit fields"
+	    allowing direct setting of flags.
+
+	* aprx.c, beacon.c:
+	    Do not use stdout FILE* to print things out of signal handler.
+	    Use sprintf(3) to put things into local buffer, then use write(2)
+	    to send them to file handle 1.  Otherwise GLIBC has some
+	    interlock issue causing a deadlock in rare case. (Happened
+	    with debug printouts in development.)
+
+	* beacon.c:
+	    Correct close() of exec type beacon file descriptor.
+
+	* interface.c:
+	    Correct primary <interface> flags defaults, and setting of
+	    "telem-to-is <boolean>" and "telem-t-rf <boolean>" flags.
+
+	* telemetry.c:
+	    Debug-printout (debug>1) of telemetry about time until next
+	    output, plus packet that is being telemetered along with
+	    hex coding of interface flags. Also streamlined the telemetry
+	    label output code.
+
+2014-03-11 Matti Aarnio - OH2MQK - KP20NG  <oh2mqk at sral.fi>
+
+	* ttyreader.c:
+	    Do open /dev/ttySnnn up front in non-blocking mode so that
+	    if the serial port hardware needs to be wired specially to
+	    be considered active ( = flow control ) the serial port open
+	    will not stop -- hang -- at it missing.
+
+	* agwpesocket.c:
+	    Update time comparison codes to current model.
+
+	* aprx.c:
+	    time_reset gets cleared only after first round through
+	    the main loop.
+
+	* beacon.c:
+	    The 'file' and 'exec' directives need at most 256 bytes of read
+	    buffer to get beacon body content. No need for 2kB buffer alloc.
+
+2014-03-08 Matti Aarnio - OH2MQK - KP20NG  <oh2mqk at sral.fi>
+
+	* digipeater.c:
+	    Corrected the digipeating recognition algorithm.
+	    If the current leading VIA field value without
+	    H-bit set is not recognized as transmitter callsign,
+	    transmitter alias, or value of <trace> or <wide>
+	    directive at digipeater source or digipeater transmitter
+	    configuration, then the packet is _not_ eligible for
+	    digipeat.
+
+2014-03-08 Matti Aarnio - OH2MQK - KP20NG  <oh2mqk at sral.fi>
+
+	* aprx.h, beacon.c, digipeater.c, parse_aprs.c, telemetry.c,
+	  timercmp.c, ttyreader.c:
+	     Fix all things flagged at CFLAGS="-g -O2 -Wall".
+
+	* configure.in, config.h.in, aprx.c:
+	    Autoconf test for <sys/wait.h>, and include if available.
+
+	* aprx.h, beacon.c, config.c, digipeater.c, interface.c, netax25.c,
+	  telemetry.c, doc/aprx-manual.odt, aprx.8.in:
+	    Change single boolean flag 'txok' into multiple interface flags
+	    where the 'txok' is just one bit.  Added 'telem-to-is <boolean>'
+	    option to <interface>
+
+	* aprsis.c:
+	    Warn at startup if an <aprsis> block does not contain passcode.
+
+2014-03-04 Matti Aarnio - OH2MQK - KP20NG  <oh2mqk at sral.fi>
+
+	* aprx.c, aprx.h, beacon.c:
+	    Pickup child process exit SIGCHLD signals, and track
+	    which child did exit.
+
+	* beacon.c, aprx.c, aprx.h, aprx.conf.in, aprx.8.in:
+	    Kamil Palkowiski SQ8KFH's beacon exec idea rewritten to be
+	    non-blocking in execution.  The Aprx main loop does not
+	    tolerate blocking programs.
+
+	* aprsis.c, ttyreader.c:
+	    poll(2) results on file handles asking for POLLIN can include
+	    POLLHUP and POLLERR.
+
+2014-03-04 Matti Aarnio - OH2MQK - KP20NG  <oh2mqk at sral.fi>
+
+	* aprx.8.in, doc/aprx-manual.odt:
+	    Document <aprsis> passcode a bit more.
+
+	* aprsis.c, aprx.c, aprx.h, netax25.c:
+	    Move aprxlog() from aprsis.c to aprx.c.
+	    Use aprxlog() instead of open coded logger at netax25.c.
+	    Modify which type of APRSIS events get logged without
+	    the runtime -L option to the aprxlogfile.
+
+2014-02-26 Matti Aarnio - OH2MQK - KP20NG  <oh2mqk at sral.fi>
+
+	* Makefile.in,  agwpesocket.c, aprsis.c, aprx-stat.c, aprx.c, aprx.h,
+	  aprxpolls.c, beacon.c, config.h.in, configure.in, digipeater.c,
+	  dprsgw.c, dupecheck.c, erlang.c, filter.c, historydb.c, hlog.c,
+	  igate.c, interface.c, kiss.c, netax25.c, netresolver.c, pbuf.c,
+	  telemetry.c, timercmp.c, ttyreader.c:
+	    Change primary time management to use system monotonic clock
+	    instead of time-of-day clock that can jump back/forward.
+	    This clock is in -lrt as: clock_gettime(CLOCK_MONOTONIC, ...)
+	    and it is the kernel internal primary jiffy lock.
+	    This value is not synchronized with wall clock, although it
+	    does proceeds at about same rate.  It is also present at FreeBSD,
+	    and presumably several other platforms too. (It is a POSIX thing,
+	    after all.)
+
+	    The system also watches over if the delta in between subsequent
+	    value extracts exceeds about 30 seconds, or the time jumps
+	    backwards at all. If such happens, next call cycle on all prepoll
+	    routines are resetting all time management things in particular
+	    subsystem.
+
+	    Renamed the primary time tracking variable from "now" to "tick",
+	    as it has no correlation with current wall-clock time.
+
+	    There are no Y2038 issues in this code approach.
+
+
+2014-02-24 Matti Aarnio - OH2MQK - KP20NG  <oh2mqk at sral.fi>
+
+	* agwpesocket.c, aprsis.c, digipeater.c, dptsgw.c, dupecheck.c,
+	  filter.c, interface.c, netresolver.c:
+
+	    Y2038 comparison things of time values. Somewhat premature, but
+	    gets things in line with uses of 'struct timeval' -- tv_timercmp().
+
+2014-02-23 Matti Aarnio - OH2MQK - KP20NG  <oh2mqk at sral.fi>
+
+	* all files:
+	    Change copyright statement to read 2007-2014.
+
+	* timercmp.c, Makefile.in:
+	    New file bringing all struct timeval tools to one place.
+	    Added tv_timerbounds() that monitors time targets vs.
+	    current time value -- if machine has hibernated a lot
+	    without running timers and the 'now' jumps ahead a lot
+	    (or backwards for complete coverage), then the target
+	    time is reset.  This avoids running a burst of beacon
+	    events when 'now' jumps ahead a lot, as an example.
+
+	* netax25.c, digipeater.c, beacon.c, ttyreader.c, telemetry.c, dprsgw.c,
+	  agwpesocket.c, aprsis.c, aprx.h, historydb.c, dupecheck.c, erlang.c:
+	    Timer tracking against possibly jumping 'now' with conditional
+	    resetting.
+
+	* beacon.c, dupecheck.c, netax25.c, telemetry.c, timercmp.c:
+	    Few wrong initializations of timers fixed.
+
+2014-02-13 Forgot to record the author
+
+	* debian/control:
+	    Add build and run dependency of OpenSSL.
+	    (Actually not yet necessary, SSL support is not being
+	     compilable / compiled yet.)
+
+2014-02-13 Heikki Hannikainen <hes at aprs.fi>
+
+	* parse_aprs.c:
+	    Check that the timestamp ends with one of valid timestamp type ids.
+	    Those being: 'z', 'h', '/'
+
+2014-02-03 Matti Aarnio - OH2MQK - KP20NG  <oh2mqk at sral.fi>
+
+	* ttyreader.c:
+	    Read only when poll reports data availability.  (uh3ack)
+
+2014-02-01 Matti Aarnio - OH2MQK - KP20NG  <oh2mqk at sral.fi>
+
+	* rpm/aprx.spec.in:
+	    Forcing RPM building to produce i386 package.
+	    (There is no need to produce x86-64 binary package.
+	     Small footprint is the goal.)
+
+	* erlang.c:
+	    Do not call aprx_syslog_init() from this module.
+
+	* ssl.c, ssl.h, hlog.c, hlog.h:
+	    Copied SSL client code material from Aprsc. Not yet functional.
+
+	* agwpesocket.c, beacon.c, digipeater.c, dupecheck.c, erlang.c,
+	  telemetry.c, ttyreader.c:
+	    If the time reported by time(2) seems to jump ahead or backwards
+	    too much, various deadline schedulers keeping time goals in mind
+	    will reset themselves upon detection of the condition.
+
+2013-11-01 Matti Aarnio - OH2MQK - KP20NG  <oh2mqk at sral.fi>
+
+	* historydb.c:
+	    Initialize also tokenbucket value so that freshly arrived
+	    packet at the historydb will have at least 1.0 tokens
+	    at hand to permit one initial digipeat. Will not be enough
+	    for multi-transmitter case.
+
+	* digipeater.c:
+	    Display Ratelimit caused packet drops at all debug levels.
+	    ( Instead of >1 )
+
+	* filter.c:
+	    Correct parse of s// filter.  (Original author not recorded.)
+
+2013-10-08 Matti Aarnio - OH2MQK - KP20NG  <oh2mqk at sral.fi>
+
+	* config.c, digipeater.c:
+	    Add conditionals so that --disable-igate works.
+
+2013-10-07 Matti Aarnio - OH2MQK - KP20NG  <oh2mqk at sral.fi>
+
+	* Makefile.in, svnversion-test.sh:
+	    A bit more complicated way to pick up SVNVERSION information.
+
+	* aprx.c, VERSION, README, TODO, INSTALL, doc/aprx-manual.odt
+	    Version 2.08 under way.
+
+	* aprx.h, aprx.c, aprsis.c, aprx-stat.c, aprxpolls.c, beacon.c,
+	  digipeater.c, dupecheck.c, erlang.c, interface.c, telemetry.c,
+	  ttyreader.c:
+	    Changed time tracking from "time_t" to "struct timeval".
+	    This supports (sub)millisecond granularity e.g. in KISS
+	    polling, and overall smoothness of processing.
+	    No, it isn't really necessary besides of that KISS polling,
+	    but unified API is always better.
+
+2013-10-06 Matti Aarnio - OH2MQK - KP20NG  <oh2mqk at sral.fi>
+
+	* filter.c:
+	    Add 'g/call1/call2..' filter to match "group messaging" recently
+	    added on javAPRSSrvr.
+
+	* doc/aprx-manual.odt:
+	    Document internally supported APRS-IS style filter tokens.
+
+	* filter.c:
+	    Code cleaning around reference definitions.
+
+	* filter.c:
+	    * Add feature to recognize 3rd-party frames by type (t/3)
+	    * Enable support of D filter (they are meaningful at RF too)
+
+	* filter.c, aprx.c, aprx.h, config.c:
+	    * Fix M filter preparation to include cos(lat).
+
+	* aprx.h, interface.c, parse_aprs.c:
+	    Always look inside 3rd party APRS frames too to determine
+	    their content for filtering uses. RF->RF relaying didn't
+	    do that.
+
+2013-10-05 Matti Aarnio - OH2MQK - KP20NG  <oh2mqk at sral.fi>
+
+	* configure.in, Makefile.in, aprx.c, aprx.8.in:
+	    Support integrated binary version printout:
+	         aprx -V
+
+	* configure.in, Makefile.in:
+	     Preparing for new code features, picking up more
+	     library locations.
+
+	* aprsis.c:
+	     Improve the error diagnostics on upstream socket
+	     connection error situations.
+
+	* beacon.c:
+	     Debug report number of parsed beacons.
+
+2013-10-03 Geoffrey F4FXL <max at planetemax.com>
+
+	* digipeater.c:
+	    Fixed badly formatted AX.25 after insertion of MYCALL
+	    value on VIA path. The end-pointer was mis-managed.
+
+2013-08-10 Matti Aarnio - OH2MQK - KP20NG  <oh2mqk at sral.fi>
+
+	* configure.in:
+	    Look for OpenSSL library, SCTP network protocol.
+
+2013-08-03 Heikki Hannikainen  <oh7lzb at sral.fi>
+
+	* aprsis.c, aprs-complex.conf.in, aprx.8.in, aprx.conf.in,
+	  doc/aprx-manual.odt:
+	    Require manually configured APRS-IS passcode.
+
+2013-08-03 Matti Aarnio - OH2MQK - KP20NG  <oh2mqk at sral.fi>
+
+	* agwpesocket.c, aprsis.c, beacon.c, cellmalloc.c, dprsgw.c,
+	  dupecheck.c, filter.c, historydb.c, keyhash.c, pbuf.c,
+	  telemetry.c, ttyreader.c:
+	    Coding style change: Use cmalloc() instead of malloc() + memset().
+
+2013-08-03 Frank Knobbe <frank at knobbe.us>
+
+	* interface.c:
+	    Correct the way how messages are passed from APRS-IS to RF.
+	    There was a parse bug around pb->dstname field.
+
+2013-04-25 Matti Aarnio - OH2MQK - KP20NG  <oh2mqk at sral.fi>
+
+	* netax25.c:
+	    Receive from AX.25 interface only if it has associated
+	    an Aprx interface configuration object with it.
+	    Less noise on logs that way.
+
+2013-04-25 Matti Aarnio - OH2MQK - KP20NG  <oh2mqk at sral.fi>
+
+	* filter.c:
+	    Commented out code, but make it conform with API
+	    of historydb.
+
+	* parse_aprs.c:
+	    The call parameter 'historydb' can be NULL,
+	    don't SEGV on it.
+
+	* telemetry.c:
+	    Pointer writing to beyond end of buffer (one last time)
+
+	* ttyreader.c:
+	    hexdumpfp() text dump fix
+
+	* beacon.c:
+	    Restructured the beacon data preparation for transmit.
+	    Lots of mistakes had crept in recently (2.06?)
+
+	* interface.c, netax25.c:
+	    Debug printouts of processing errors, and transmissions.
+
+2013-04-23 Matti Aarnio - OH2MQK - KP20NG  <oh2mqk at sral.fi>
+
+	* config.c:
+	    Show 'myloc' lat/lon in degrees instead of radians.
+
+	* digipeater.c:
+	    debugging..
+
+	* filter.c:
+	    A fence-post error while parsing o/A8CDEF-12 -- accepted
+	    only A8CDEF-1.
+
+2013-04-22 Matti Aarnio - OH2MQK - KP20NG  <oh2mqk at sral.fi>
+
+	* aprx.8.in, aprx-complex.conf.in, aprx.conf.in,
+	  doc/aprx-manual.odt, doc/aprx-manual.pdf:
+	    Change documentation wording around <beacon>.
+
+	* config.c:
+	    Fix myloc config parameter parsing.
+
+	* beacon.c:
+	    Every <beacon> group is now independent from each other.
+	    If you define multiple <beacon> groups, they will be
+	    running in parallel with their own scheduling.
+	    Meaning that you can have different cycles, and defaults
+	    at each.
+
+	* all source files:
+	    Change Copyright claim years to  2007-2013.
+
+	* configure.in:
+	    Auto-test for <netinet/sctp.h> header file.
+
+2013-04-22 Geoffrey F4FXL <max at planetemax.com>
+
+	* digipeater.c:
+	    Recent rewrite of viafield tracking code forgot
+	    to initialize it in many cases -- and Covarity
+	    tool did not notice that :-(
+
+2013-04-20 Matti Aarnio - OH2MQK - KP20NG  <oh2mqk at sral.fi>
+
+	* aprsis.c:
+	    Preparing for new communication modes
+
+	* parse_aprs.c:
+	    Two condition expression goofups that were always
+	    "false"
+
+	* filter.c:
+	    Match filter parsing with aprsc (issue found with
+	    Covarity testing)
+
+	* aprsis.c, aprx.c, aprx.h, aprxpolls.c, cellmalloc.c,
+	  config.c, digipeater.c, dprsgw.c, filter.c, interface.c,
+	  kiss.c, netax25.c, telemetry.c, ttyreader.c:
+	    Covarity testing revealed unclear error cases, unnecessary
+	    comparisons against NULL, and other mostly harmless things.
+	    There is still a memory leak in interface.c configuration
+	    parsing in error path -- but that is not a big deal.
+
+	* digipeater.c:
+	    Modified "fixall" processing to put transmitter
+	    callsign into first VIA field in every case,
+	    possibly truncating the VIA list in order to make
+	    room for the callsign in the incoming request.
+	    Replacing numeric literals with #define constants
+	    to inline document of what is going on at places.
+
+2013-04-18 Matti Aarnio - OH2MQK - KP20NG  <oh2mqk at sral.fi>
+
+	* aprx.c, VERSION:
+	    Version 2.07 (APRX27)
+
+	* aprx.8.in:
+	    Document "myloc" and "$myloc", "filter m/100", etc.
+
+	* aprx.c, aprx.h:
+	    Variables for myloc_lat, myloc_lon, and string forms.
+
+	* config.c:
+	    Parse "myloc lat xx long yy" entry.
+	    Moved couple tool functions here from beacon.c.
+
+	* filter.c:
+	    Support "m/100", if top-level configuration has
+	    "myloc lat xx lon yy" entry.
+
+	* beacon.c:
+	    new "macro" definition of "$myloc", which takes
+	    lat+lon of top-level configuration "myloc.." entry.
+
+	* interface.c:
+	    Recognizing incoming messages targeted to this server
+	    (by $mycall, and transmit interface callsigns.)
+	    Processing them by rudimentary acknowledgement, and
+	    optional place to actually process them.
+	    Actual processing is still not written.
+
+2013-02-02 Matti Aarnio - OH2MQK - KP20NG  <oh2mqk at sral.fi>
+
+	* ttyreader.c:
+	    Improve the error report, when serial port opening failed.
+
+	* filter.c:
+	    Coverity reports over aprsc reflect directly to aprx too.
+	    We use same code in parts...
+
+2012-12-29 Matti Aarnio - OH2MQK - KP20NG  <oh2mqk at sral.fi>
+
+	* digipeater.c, aprx.h, historydb.h:
+	    Track digipeated messages by source callsign.
+
+	* aprsis.c:
+	    Use A->rdlin_len  instead of strlen(A->rdline)
+
+	* aprx-stat.c, aprx.c, aprx.h, erlang.c:
+	    Moved syslog init from erlang to aprx core.
+
+	* parse_aprs.c, aprx.h:
+	    Function parse_aprs_message() for planned future use.
+
+2012-12-09 Matt Maguire VK2RQ <matt.vk2rq at gmail.com>
+
+	* telemetry.c:
+	    Sometimes the Erlang registery contains interface
+	    entries that are no longer actually in the system.
+	    Avoid NULL referral at such situations.
+
+2012-11-09 Matti Aarnio - OH2MQK - KP20NG  <oh2mqk at sral.fi>
+
+	* dprsgw.c:
+	    Better accounting on DPRS side-channel data occupancy,
+	    assuming the DPRS gw does send bytes all the time.
+
+2012-11-09 FUJIURA Toyonori JG2RZF <toyokun at gmail.com>
+
+	* dprsgw.c:
+	    Add receiver Erlang estimators to received packets.
+
+2012-11-01  Matti Aarnio - OH2MQK - KP20NG  <oh2mqk at sral.fi>
+
+	* aprsis.c:
+	    Move CRLF appending later into APRSIS transmission.
+
+2012-10-31  Matti Aarnio - OH2MQK - KP20NG  <oh2mqk at sral.fi>
+
+	* aprx.c:
+	    Use thread-safe gmtime_r() instead of gmtime() for time printout.
+
+2012-10-29  Matti Aarnio - OH2MQK - KP20NG  <oh2mqk at sral.fi>
+
+	* Makefile.in:
+	    Improve distribution tar RPM building support.
+
+	* rpm/aprx.init, rpm/aprx.service, rpm/aprx.spec.in:
+	    RPM package packing files
+
+	* filter.c:
+	    Clean filter parser.
+
+	* aprx.c:
+	    Acquire a lock on pid-file, and keep the file open.
+
+2012-10-29 FUJIURA Toyonori JG2RZF <toyokun at gmail.com>
+
+	* dprsgw.c:
+	    D-STAR callsign formatting for suffixless ones:
+	      * "JG2RZF A" -> "JG2RZF-A"
+	      * "JG2RZF  " -> "JG2RZF-"  Oops!
+
+2012-10-12  Matti Aarnio - OH2MQK - KP20NG  <oh2mqk at sral.fi>
+
+	* rpm/aprx.spec.in, rpm/aprx.service:
+	    Andrew Elwell <Andrew.Elwell at gmail.com>  supplied better
+	    version of Fedora, and rhel.
+
+	* filter.c:
+	    Leave the "over-long parameters are rejected" logic, but don't
+	    support alternate group field splitter input.
+
+2012-10-03  Matti Aarnio - OH2MQK - KP20NG  <oh2mqk at sral.fi>
+
+	* TODO, INSTALL, aprx.c, aprx-manual.odt, aprx-manual.pdf,
+	  VERSION: 2.06
+
+2012-10-02  Matti Aarnio - OH2MQK - KP20NG  <oh2mqk at sral.fi>
+
+	* filter.c:
+	    Parse filters with callsign sets without overflowing buffer.
+	    Officially syntax is:   OP/callsign1/callsign2   but support
+	    also:  OP/callsign1,callsign2
+
+	* digipeater.c:
+	    Correct analysis of first "via" field, bail out of the loop
+	    only after it has been parsed.
+
+2012-10-01  Matti Aarnio - OH2MQK - KP20NG  <oh2mqk at sral.fi>
+
+	* debian/postinst, debian/aprx.init:
+	    Removed postinst from debian installations.  That script is
+	    bad and causes install/upgrade to stall.  Modernized the
+	    aprx init-script.
+
+2012-09-30  Matti Aarnio - OH2MQK - KP20NG  <oh2mqk at sral.fi>
+
+	* aprx.h, digipeater.c, interface.c, pbuf.h, pbuf.c, parse_aprs.c:
+	    Sync pbuf_new() implementation with aprsc's approach, and
+	    sync parse_aprs() with aprsc's code.  This should fix some
+	    strange MICe bugs, among others.
+
+2012-09-18  Matti Aarnio - OH2MQK - KP20NG  <oh2mqk at sral.fi>
+
+	* parse_aprs.c:
+	    Corrected MICe longitude degrees parser. Again.
+	    (Sorry, F4FXL's parser fix was wrong.)
+
+2012-09-05  Matti Aarnio - OH2MQK - KP20NG  <oh2mqk at sral.fi>
+
+	* apparmor.aprx, debian/rules, debian/dirs, debian/postint:
+	    Copied bits of Aprsc's debian packaging to Aprx.
+	    (Original packaging stuff was copied from Aprx to Aprsc.)
+
+2012-09-02  Matti Aarnio - OH2MQK - KP20NG  <oh2mqk at sral.fi>
+
+	* aprx.8.in, aprx.conf.in, aprx-complex.conf.in, aprx-rxigate.conf.in,
+	  configure.in:
+	    Exterminated all instances of yours truly's own address from
+	    the sample configurations, and replaced them with 0000.00N
+	    00000.00E coordinate, which aprs.fi treats as invalid.
+
+	* beacon.c:
+	    In addition to the long time used qTYPE_LOCALGEN, added on
+	    APRSIS beacons also  ",TCPIP*" at the tail of whatever is
+	    being sent.  Pete is not happy with q-code alone...
+
+2012-08-26  Matti Aarnio - OH2MQK - KP20NG  <oh2mqk at sral.fi>
+
+	* digipeater.c, interface.c, aprx.h, TODO, aprx-manual.*:
+	    Add to APRSIS tx-gated packets optionally different via-path
+	    (parameter: msg-path) for message packets, than for any other
+	    type packets. For example:  via-path WIDE1-1,  msg-path WIDE2-2
+	    (By request of OH3BK.)
+
+	* VERSION:  2.05
+
+	* beacon.c, interface.c:
+	    Support beaconin to APRSIS without having any radio interfaces.
+	    Make null-device interface and (in special conditions the internal
+	    APRSIS interface) beaconable.
+
+	* doc/aprx-manual.*:
+	    Fixes on <beacon> explanations.
+	    Diagrams on subsystem configuration examples describing message
+	    flows.
+
+2012-08-07  Matti Aarnio - OH2MQK - KP20NG  <oh2mqk at sral.fi>
+
+	* configure.in, aprsis.c, ROADMAP, doc/aprx-manual.odt:
+	    Fix the "pthreads" typo by using correct "pthread" spelling
+	    in the documents + "--with-pthreads" option alias in configure.
+
+2012-08-07  Matti Aarnio - OH2MQK - KP20NG  <oh2mqk at sral.fi>
+
+	* interface.c:
+	    Automatically create  igate-group N  values for radio interfaces
+	    start from 1, and go onwards. Manually defined values start from
+	    one, and it is up to the configuration writers to have a sane
+	    upper limit.
+
+	* aprx.c, aprx.h, ttyreader.c, erlang.c, kiss.c:
+	    Fixed a) poll of KISS subinterfaces, b) KISS polling time
+	    management issues.  The polling does not yet have serial-device
+	    specific timing management, rather a global cadence.
+
+	* aprx.c:
+	    Version 2.05
+
+	* ttyreader.c, aprxpolls.c, aprx.c, aprx.h:
+	    Do millisecond timings, send KISS POLL (0x0E) code requests every
+	    configured number of milliseconds per serial-device:
+	       serial-device ... KISS pollmillis 100
+
+	* agwpesocket.c, aprsis.c, aprx.c, aprx.h, aprxpolls.c, aprx-stat.c,
+	  beacon.c, configure.in, digipeater.c, dprsgw.c, dupecheck.c,
+	  erlang.c, filter.c, historydb.c, igate.c, interface.c, kiss.c,
+	  netax25.c, netresolver.c, pbuf.c, telemetry.c, ttyreader.c:
+	    Changed "now" from type "time_t" to "struct timeval" enabling
+	    the ttyreader to do millisecond level timing operations.
+
+2012-08-06  Matti Aarnio - OH2MQK - KP20NG  <oh2mqk at sral.fi>
+
+	* debian/aprx.init, rpm/aprx.init:
+	    Correct the package start dependency definitions.
+
+2012-08-04  Matti Aarnio - OH2MQK - KP20NG  <oh2mqk at sral.fi>
+
+	* interface.c, kiss.c:
+	    Debug printout claimed reversed logical meaning in history-db
+	    lookup. Typo fixes at kiss processing comments.
+
+	* interface.c:
+	    Config parser bug in defining multiple <kiss-subif ..>.
+	    Thanks to N2PYI for report.
+
+2012-07-31  Matti Aarnio - OH2MQK - KP20NG  <oh2mqk at sral.fi>
+
+	* configure.in, digipeater.c, aprx.h, valgrind.c:
+	    Supply implementation of memrchr() if the platform does not have
+	    it. (GNU Libc extension, not a standard POSIX thing.)
+
+	* Makefile.in:
+	    Fixing details around how to run "make make-deb".
+	    Fixing how SVNVERSION is determined.
+
+	* interface.c, igate.c, aprx.h:
+	    rflog() parameter set modification, show directly at calls if
+	    the logged item is 'R' or 'T'.
+
+	* dupecheck.c, aprsis.c, igate.c, aprx.h, digipeater.c:
+	    Prepare for the duplicate checker to be able to control the time
+	    window of the duplicate checks - minimum will be 30 seconds, maximum
+	    can be higher.
+
+	* digipeater.c:
+	    TNC2 format quirks in "VIA field" data caused missed identification
+	    of "ping pong relay" - where a packet contains this node's
+	    transmitter callsign, and this node has logged its address as
+	    "sent through me".  Also known as TRACE mode:
+	        SRC>DEST,MYTRANS,OTHERTX*,WIDE3-1
+
+2012-07-30  Matti Aarnio - OH2MQK - KP20NG  <oh2mqk at sral.fi>
+
+	* keyhash.c, keyhash.h, netax25.c, netresolver.c, interface.c,
+	  cellmalloc.c, config.c, dprsgw.c, ax25.c:
+	    A compiler test with -Wall complained a bit around missing ANSI-C
+	    prototypes.
+
+2012-07-29  Matti Aarnio - OH2MQK - KP20NG  <oh2mqk at sral.fi>
+
+	* keyhash.c, filter.c:
+	    Threw away the long unused CRC32 stuff, and added a hashkeyuc()
+	    function.  Fixed the way how  filter_entrycall_*() and
+	    filter_wx_*() functions processed the key. Now both of
+	    them store keys as converted to upper case, and lookup
+	    with mixed case.
+
+	* aprx-config.xsd:
+	    An attempt at writing a "formal" configuration file syntax
+	    description.  It is really not XML that config file, nor
+	    can XSD define it clearly, I think..
+
+2012-07-28  Matti Aarnio - OH2MQK - KP20NG  <oh2mqk at sral.fi>
+
+	* VERSION: 2.04
+
+	* filter.c:
+	    Wrong way to put len* fields into an union vs. a few other things.
+
+	* dupecheck.c, digipeater.c:
+	    Fix from iw3ijq + k3pdk about AX25 duplicate tracking dropping null
+	    pointers.  This has _not_ been validated for TNC mode frames yet,
+	    but now AX.25 works properly.
+
+2012-01-18  Matti Aarnio - OH2MQK - KP20NG  <oh2mqk at sral.fi>
+
+	* VERSION: 2.03test4
+
+	* interface.c:
+	    Record outbound "history heard" per interface.
+
+	* historydb.c:
+	    Simple refactoring to use same hash function all the time.
+
+	* digipeater.c:
+	    Feed all transmitted packets to dupe-filter of that transmitter.
+	    This will handle cross-band digipeat + tx-gates so that
+	    an APRS packet transmitted to a channel won't be digipeated
+	    again by this transmitter.
+
+	* igate.c:
+	    When constructing APRSIS originated 3rd-party tx-igate
+	    packets, use correct version of "TCPIP" in the header.
+
+2012-01-07  Matti Aarnio - OH2MQK - KP20NG  <oh2mqk at sral.fi>
+
+	* VERSION:  2.03test3
+
+	* pbuf.h, pbuf.c, aprx.h:
+	    New infrastructure function: pbuf_fill() that does
+	    former two (then 3) copies of same code in interface.c
+
+	* interface.c:
+	    Use new pbuf_fill().
+	    On 3rd-party receiver, parse original (sort of) TNC2 frame
+	    to temporary AX.25 frame for filter analysis.
+	    Rearranged filter running and reactioning.
+
+	* filter.c:
+	    Debug printouts
+
+	* All files...
+	    Copyright text update.
+
+2011-12-30  Matti Aarnio - OH2MQK - KP20NG  <oh2mqk at sral.fi>
+
+	* interface.c:
+	    3rd-party igate tx processing fixes, now it allows also
+	    other than messages
+
+2011-12-25  Matti Aarnio - OH2MQK - KP20NG  <oh2mqk at sral.fi>
+
+	* VERSION, aprx.c, TODO, INSTALL, doc/aprx-manual.*:
+	    Version 2.03
+
+	* interface.c:
+	    At top-level of the <interface> the "callsign" parameter
+	    did not override device defined callsign and its AX.25
+	    parse result.
+
+	* aprx.h, config.c, dprsgw.c, logrotate.aprx.in,
+	  aprx.conf.in, aprx-complex.conf.in:
+	    Configurability of logging parameter "dprslog".
+
+	* aprx.h, aprsis.c, beacon.c, igate.c, telemetry.c:
+	    Supply qcode on outgoing packets depending it being
+	    locally generated (qAS) or rx-i-gated (qAR)
+
+	* telemetry.c:
+	    Fix telemetry "tocall" to use software identifier,
+	    and to put "TCPIP*" on APRSIS beacon path.
+
+	* aprx.conf.in:
+	    Fix default server list
+
+	* crc.c, kiss.c:
+	    Document polynomes and fix comments
+
+2011-08-29  Matti Aarnio - OH2MQK - KP20NG  <oh2mqk at sral.fi>
+
+	* parse_aprs.c:
+	    F4FXL found bug in position parser cos() pre-calculator.
+	    Input needs to be in radians, it was in degrees.
+
+2011-07-26  Matti Aarnio - OH2MQK - KP20NG  <oh2mqk at sral.fi>
+
+	* interface.c:
+	    If preceding address processing detects an error, do not call
+	    packet transmitter.
+
+	* aprx.h, dprsgw.c, parse_aprs.c:
+	    Moved DPRS related APRS symbol translation from parse_aprs.c
+	    to dprsgw.c.
+
+	* parse_aprs.c:
+	    Introduced APRS symbol mapper/generator for GPS messages.
+
+	* parse_aprs.c:
+	    Rewrite of parse_aprs_mice() degrees parser inspired by F4FXL.
+
+2011-03-16  Matti Aarnio - OH2MQK - KP20NG  <oh2mqk at sral.fi>
+
+	* beacon.c, telemetry.c, aprx.h, interface.c:
+	    Transmit only radio data port related beacons,
+	    and telemetry. Don't touch on other pseudo-interfaces.
+
+2011-01-02  Matti Aarnio - OH2MQK - KP20NG  <oh2mqk at sral.fi>
+
+	* interface.c, agwpesocket.c, aprx.h:
+	    Configure <interface> agwpe-device.
+
+	* netresolv.c:
+	    Oops..  fixed functionality. Tuned debugging.
+
+	* aprsis.c, aprx.c:
+	    Tuned debugging.
+
+	* configure.in, aprsis.c:
+	    Autoconfig stdarg.h existence, use varargs on debug printout code.
+
+	* agwpesocket.c:
+	    Debug printout on received frame.
+
+	* interface.c, doc/aprx-manual.odt:
+	    Unlimit the number of "igate-group N" parameter's N value range.
+
+	* aprsis.c, aprx.c, beacon.c, config.c, digipeater.c, dprsgw.c,
+	  filter.c, historydb.c, igate.c, interface.c, keyhash.c, kiss.c,
+	  netresolver.c, ttyreader.c:
+	    Cleaning compiling on a very old FreeBSD -- essentially K&R C
+	    compiler (gcc 2.95.4) not permitting variable declarations
+	    anywhere but beginning of code block.
+
+2011-01-01  Matti Aarnio - OH2MQK - KP20NG  <oh2mqk at sral.fi>
+
+	* interface.c:
+	    Always init interface specific Erlang accounting
+
+	* filter.c:
+	    Negative ranges on filters means "outside the distance".
+	    This allows adding "substractive" filters that tell
+	    "don't pass messages to receipients outside given range".
+
+	* configure.in, interface.c, cellmalloc.c, timestamp.c,
+	  kiss.c, historydb.h, netax25.c, pbuf.h, aprx.c, aprx.h,
+	  filter.c:
+	    Clean autoconfig tests, make the code compilable on oldish
+	    FreeBSD.
+
+	* configure.in, aprx.h, aprx.c, agwpesocket.c, interface.c:
+	    Configuration option --enable-agwpe  to enable AGWPE socket
+	    interface code.
+
+	* configure.in, aprx.h, aprx.c, aprsis.c, ax25.c, beacon.c,
+	  digipeater.c, dpwsgw.c, erlang.c, filter.c, historydb.c,
+	  igate.c, interface.c, parse_aprs.c, telemetry.c, ttyreader.c:
+	    Configuration option  --disable-igate   for embedding
+	    code without igate network connection. Disables DPRS GW code,
+	    and all of historydb, igate.c, aprsis.c.
+
+	* aprx.c, VERSION, INSTALL, README, TODO
+	    Version: 2.02
+
+	* aprx.h, interface.c:
+	    A  null-device   for sinking infinite digipeat output.
+	    A debug tool.
+
+	* aprx.h, interface.c, historydb.c, historydb.h, pbuf.h:
+	    Properly track "heard from interface(group)" information
+	    for tx-igate processing.  Now a full APRSIS traffic feed
+	    won't transmit anything to RF, unless explicit manual
+	    filter definitions tells to transmit, or message recipient
+	    has been recently heard behind a radio channel X.
+	    See the new 'igate-group'  parameter on documents.
+
+	* aprsis.c, netresolver.c:
+	    Cleaned pthreads thread creation calls.
+
+	* agwpesocket.c:
+	    Erlang account on outbound socket.
+
+	* digipeater.c:
+	    Allow ratelimit parameter to be defined very high.
+	    This way a full APRSIS traffic feed can be sent to null-device.
+
+	* aprx.conf.in, aprx-complex.conf.in:
+	    Some new notes on digipeater and tx-igate controls.
+
+	* doc/aprx-manual.odt:
+	    Document update.
+
+2010-12-18  Matti Aarnio - OH2MQK - KP20NG  <oh2mqk at sral.fi>
+
+	* interface.c, aprx.h:
+	    Add a "null-device" for system.  Never receive anything from it,
+	    have infinite transmit capacity.
+
+	* netresolver.c, aprx.h, aprx.c:
+	    A pthread that resolves dynamic DNS names on background,
+	    and updates static copy of address data so that main loop
+	    can safely do asynchronous connections without needing
+	    to do synchronous DNS resolving processing.
+
+	* aprsis.c:
+	    Use pthread_cancel() in smart way to expedite shutdown.
+
+	* agwpesocket.c, aprx.h, aprx.c:
+	    Draft of a socket communication mechanism with AGWPE, and LDSPED.
+
+2010-12-17  Matti Aarnio - OH2MQK - KP20NG  <oh2mqk at sral.fi>
+
+	* VERSION, INSTALL, README, TODO
+	    Version: 2.01
+
+	* doc/aprx-manual.odt:
+	    Write a few pages about debugging
+
+	* aprx.c:
+	    Version tocall code: APRX21
+
+	* aprx.c, aprx.8.in:
+	    Add '-i' option to keep the program foreground without
+	    enabling any debug printouts.
+
+	* digipeater.c:
+	    Correct the recognition of "probably heard on first hop"
+
+	* historydb.c:
+	    Memory realloc() bug fixed.
+
+	* kiss.c:
+	    Recognize a write attempt on closed file handle, don't write.
+
+2010-08-08  Matti Aarnio - OH2MQK - KP20NG  <oh2mqk at sral.fi>
+
+	* VERSION:  2.00
+	* aprx.c:   Version tocall code: APRX20
+	* doc/aprx-manual.odt: version 2.00/1.00
+
+2010-08-02  Matti Aarnio - OH2MQK - KP20NG  <oh2mqk at sral.fi>
+
+	* aprx.c:
+	    Version tocall code: APRX1M
+
+	* ROADMAP:
+	    Planning update.
+
+	* beacon.c, aprx.8.in, aprx.conf.in, aprx-complex.conf.in:
+	    OH7MMT complained difficulty of defining beacons on Rx-iGate.
+	    The default aprx.conf shows the use of "interface ..", which
+	    requires tx-enabled target interfaces.  Something that rx-only
+	    will not have.
+
+	* doc/aprx-manual.odt:
+	    Cross references, additional notes on digipeat of non-APRS
+	    packets.
+
+2010-07-27  Matti Aarnio - OH2MQK - KP20NG  <oh2mqk at sral.fi>
+
+	* config.c:
+	    Accept valid APRSIS login callsigns for "mycall" parameter
+	    value.  Will complain latter if end usage did want valid AX.25
+	    callsigns instead.
+
+2010-06-25  Matti Aarnio - OH2MQK - KP20NG  <oh2mqk at sral.fi>
+
+	* interface.c:
+	    Account the number of created interfaces and subinterfaces,
+	    and if there is just one and no callsign has been defined,
+	    only then supply a default value ("callsign $mycall").
+
+	* interface.c:
+	    Check interface callsigns to be unique.
+
+	* aprsis.c, beacon.c, digipeater.c, interface.c, telemetry.c:
+	    Recognize "$mycall" in case insensitive matching.
+
+2010-06-22  Matti Aarnio - OH2MQK - KP20NG  <oh2mqk at sral.fi>
+
+	* aprx.c:
+	    Version tocall code: APRX1L
+
+	* digipeater.c:
+	    If there is a viscous-delay defined, add a random value of 0..2
+	    to the configured number of seconds delay.
+	    This way similarly configured adjacent Tx-iGates can at random
+	    find a first transmitter and others will drop the Tx-iGate.
+
+	* digipeater.c:
+	    Digipeater didn't detect interface callsigns and aliases properly,
+	    when determining if there is some work to be done.  It did detect
+	    them when to avoid doing duplicate work.
+
+2010-06-19  Matti Aarnio - OH2MQK - KP20NG  <oh2mqk at sral.fi>
+
+	* aprx.c, aprx.h, aprsis.c, beacon.c, config.c, digipeater.c,
+	  interface.c, telemetry.c, ttyreader.c:
+	    Improve config file parsing error reporting.
+	    Any ERROR observed on configuration parsing causes immediate
+	    abort with exit-code 1.
+
+	* aprx.conf.in, aprx-complex.conf.in, aprx.8.in:
+	    Clarify the documentation at man-page, and at config templates.
+
+	* firmware/*
+	    Copied one source of TNC2 firmwares
+
+	* windows/*
+	    Just a placeholder.
+
+	* Makefile.in:
+	    Improving "make dist" behaviour.
+
+2010-06-13  Matti Aarnio - OH2MQK - KP20NG  <oh2mqk at sral.fi>
+
+	* aprx.8.in, doc/aprx-manual.odt:
+	    Some notes on available baud-rates, fixes on
+	    documentation about CRC algorithms.
+
+	* ttyreader.c:
+	    Missed baud speed 57600.
+
+	* dupecheck.c:
+	    Shrink the arena allocation size to 4 kB.  This allows
+	    14 reference packets in the dupecheck dataset within that
+	    arena alone, and will possibly request second arena when
+	    this get really busy.
+
+	* historydb.c, dupecheck.c, pbuf.c, filter.c:
+	    Made cell object sizes readable with a debugger
+
+	* crc.c:
+	    Object visibility adjustments.
+
+	* Makefile.in, crc.c, aprx.h, kiss.c, ttyreader.c, interface.c:
+	    Separated KISS processing to kiss.c, and CRC processing
+	    to crc.c.  Disabled unused codes.
+
+	* pbuf.c, historydb.c, dupecheck.c:
+	    Shrink RAM usage, cellmalloc() does perfectly good job
+	    of using free-chains, no need to do it in applications.
+
+	* interface.c, pbuf.c:
+	    The pbuf_new() has a limit on maximum total size that
+	    a packet can be: 2150 bytes.  If ax25len + tnc2len are
+	    more than that, pbuf_new() returns NULL.
+
+	* historydb.c, historydb.h:
+	    Instead of historydb instance specific history entry pools,
+	    have one global pool.
+
+2010-06-12  Matti Aarnio - OH2MQK - KP20NG  <oh2mqk at sral.fi>
+
+	* cellmalloc.c:
+	    Remove pthread_mutex_t usage, not needed in this application!
+	    Conditionalize debugging code.
+
+	* pbuf.c, aprx.c, aprx.h:
+	    Using cellmalloc() on pbuf storage. Support up to 2150 byte
+	    received AX.25 frames. (Up to 7 pbufs of that size on 16 kB
+	    cell arena .. and there never should be larger than around
+	    512 byte AX.25 frames.)
+
+	* dupecheck.c:
+	    Shrink dupecheck to 16 kB per alloc arena (from 256 KB).
+	    That should be enough for a very busy 1200 bps channel,
+	    and probably even for a 9600 bps channel.
+
+	* filter.c:
+	    Shrink filter cell storage to 4 kB per alloc arena (from 512 kB!)
+
+	* historydb.c:
+	    Shrink historydb cell storage to 32 kB per alloc arena (from 128 kB)
+
+	* debian/aprx.init:
+	    Pleasing init-script behaviour during package re-install
+
+	* telemetry.c, doc/aprx-manual.odt:
+	    Stagger telemetry transmissions a bit.
+	    All RF reported telemetry sources are reported at the same time,
+	    but telemetry data is time-wise separated from labels, and labels
+	    are sent so that 3 different labels are sent every 2 hours, and
+	    total label carouselle time is 6 hours.
+
+	* aprx.c:
+	    Giving this version code: APRX1K
+
+	* telemetry.c:
+	    Correct AX.25 data frame for RF transmission
+
+	* telemetry.c, config.c, aprx.h, doc/aprx-manual.odt,
+	  aprx.conf.in, aprx-complex.conf.in:
+	    New <telemetry> config section, be able to tx
+	    telemetry to RF ports.
+
+	* beacon.c:
+	    Error reporting additions.
+
+	* erlang.c, aprx-stat.c, aprx.h, telemetry.c:
+	    Use pre-processor conditionals to select only small
+	    subset of storage and processing codes used for
+	    erlang data in embedded mode.
+
+	* parse_aprs.c:
+	    Compile warning silencing.
+
+2010-06-10  Matti Aarnio - OH2MQK - KP20NG  <oh2mqk at sral.fi>
+
+	* kiss.c, ttyreader.c, dprsgw.c, aprx.h:
+	    Tracked specification origins of each of the three
+	    different CRC-16 calculations that this code has.
+	    What was called "crc_ccitt" was in fact something
+	    totally different: the SMACK CRC16.
+
+2010-06-07  Matti Aarnio - OH2MQK - KP20NG  <oh2mqk at sral.fi>
+
+	* README, ROADMAP, TODO, INSTALL, PROTOCOLS:
+	    Updates on plans and rough guides.
+
+	* TIMESTAMP-AT-APRSIS, timestamp.c:
+	    A proposal to put about 1ms resolution timestamps
+	    on APRSIS with full backwards compatibility.
+
+	* aprx.c:
+	    Giving this version code: APRX1J
+
+	* dprsgw.c, digipeater.c, aprx.h, doc/aprx-manual.odt:
+	    Clean DPRS Rx gateway code.
+
+	* interface.c:
+	    Correct 3rd-party packet gating filter behaviour:
+	    If there are _no_ filters, pass all packets thru.
+
+	* interface.c, aprx.h, dprsgw.c, igate.c:
+	    Rate-limit source callsigns per source interface to
+	    once per 30 seconds.  RF iGate DPRS messages to APRS
+	    as 3rd-party messages.
+
+2010-06-06  Matti Aarnio - OH2MQK - KP20NG  <oh2mqk at sral.fi>
+
+	* parse_aprs.c, dprsgw.c:
+	    Rudimentary GPSxyz -> APRS symbol mapping for DPRS,
+	    with GPSxyz overlay character where possible.
+	    Also IDENT TEXT, if any.
+
+	* debian/aprx.init:
+	    The "restart" command fails to work quite often.
+	    The reason being "set -e"...
+
+	* aprx.h, igate.c, dprsgw.c, ttyreader.c, ax25.c:
+	    igate_to_aprsis(... , STRICTAX25)  -- new flag
+	    to control source specific information about
+	    TNC2 format address formats.
+
+	* parse_aprs.c:
+	    Remove unnecessary double precission floating point math.
+	    Use of 'float' is quite enough.
+
+	* debian/control:
+	    Change package name a bit
+
+	* dprsgw.c:
+	    Data collection code fixes
+
+	* telemetry.c:
+	    Send first telemetry at 20.0 minutes after start.
+	    This is related to defaulting to EMBEDDED operation mode.
+
+	* configure.in, aprx.h, erlang.c:
+	    Change defaults so that System is always "--with-embedded",
+	    and requires explicit "--with-erlangstorage" to compile with
+	    a filesystem based backing storage codes.
+
+2010-06-04  Matti Aarnio - OH2MQK - KP20NG  <oh2mqk at sral.fi>
+
+	* aprx.h, dprsgw.c:
+	    Couple steps onwards with DPRS Rx-IGate.
+
+2010-06-01  Matti Aarnio - OH2MQK - KP20NG  <oh2mqk at sral.fi>
+
+	* aprx.c:
+	    Set software tocall to 'APRX1H'.
+
+	* interface.c:
+	    Found a memory leak on AX.25 type packet receiver. Oops!
+	    Ax.25 packets that were rejected by <digipeater> <source>'s
+	    filters were just leaked, not disposed.
+
+	* historydb.c:
+	    Allocate cell arenas in 128 kB blocks.
+
+	* digipeater.c:
+	    Valgrind complained about uninitialized variables.
+	    Default zero is not good enough...
+
+2010-05-30  Matti Aarnio - OH2MQK - KP20NG  <oh2mqk at sral.fi>
+
+	* aprx.h, digipeater.c:
+	    Use 'float' for ratelimit variables.  Permitting as low
+	    rate definitions as 'once per 10 minutes.
+
+	* dprsgw.c:
+	    XOR checksums of "GPS" mode packets.  No Rx-iGate of them yet.
+
+2010-05-29  Matti Aarnio - OH2MQK - KP20NG  <oh2mqk at sral.fi>
+
+	* dprsgw.c, ttyreader.c, aprx.c, aprx.h:
+	    Experimental DPRS receiver. Studying packet identification
+	    from serial port datastream with Rx-IGate of GPS-A type DPRS
+	    packets.
+
+	* interface.c, doc/aprx-manual.odt:
+	    Effects of 'filter ...'  on different <digipeater>
+	    <source> sections are subtly different. See the manual!
+
+	* aprx.h, digipeater.c, doc/aprx-manual.odt, aprx.conf.in,
+	  aprx-complex.conf.in:
+	    Remodelled the ratelimiting to use 'token bucket filter':
+	       ratelimit average burst
+	    both values are packets per minute, and both default to 60.
+
+	* digipeater.c, interface.c:
+	    Return adjunk filters to RF->RF digipeating.
+	    They got lost a bit back with Tx-IGate needing
+	    them placed a bit differently.
+
+	* man-to-html.sh:
+	    groff has changed its -Tascii output a bit, and
+	    its own HTML output is horrible...
+
+2010-05-27  Matti Aarnio - OH2MQK - KP20NG  <oh2mqk at sral.fi>
+
+	* parse_aprs.c:
+	    Correct parse of message recipients.
+	    Fix from Patrick Domack K3PDK.
+
+2010-05-26  Matti Aarnio - OH2MQK - KP20NG  <oh2mqk at sral.fi>
+
+	* debian/rules, rpm/aprx.spec.in, aprsis.c:
+	    Fixes on pthread:ed aprsis implementation.
+	    Default packaging for Debian and RPM to use --with-pthread.
+	    Now it shows only one "process", and two threads.
+	    This makes the program portable to uCLinux, and possibly
+	    to Windows.
+
+	* dprsgw.c, aprx.h, ttyreader.c, Makefile.in, interface.c,
+	  aprx.8.in, aprx.conf.in, aprx-complex.conf.in:
+	    Add basic configuration and infra of DPRS-to-APRS gw.
+
+	* interface.c, igate.c:
+	    Comment editing, adding Tx-IGate Rule 4, second half.
+	    First half probably exists in igate..
+
+2010-05-25  Matti Aarnio - OH2MQK - KP20NG  <oh2mqk at sral.fi>
+
+	* aprx.c, README, TODO, VERSION:
+	    Mark version 1.99, APRX1G
+
+2010-05-25  Matti Aarnio - OH2MQK - KP20NG  <oh2mqk at sral.fi>
+
+	* interface.c, filter.c:
+	    Filtering logic change on 3rd-party digipeating.
+
+2010-05-24  Matti Aarnio - OH2MQK - KP20NG  <oh2mqk at sral.fi>
+
+	* interface.c, TODO:
+	    Notes about missing bits for full Tx-IGate.
+
+	* historydb.c, historydb.h:
+	    Keep knowledge of last coordinate on historydb.
+	    Mark also last coordinate update time.
+
+	* aprx.h, pbuf.h, parse_aprs.c, interface.c, digipeater.c:
+	    Tx-IGate processing details..
+
+2010-05-23  Matti Aarnio - OH2MQK - KP20NG  <oh2mqk at sral.fi>
+
+	* aprx.c, aprx.h, digipeater.c, filter.c, historydb.c, historydb.h,
+	  igate.c, interface.c, parse_aprs.c:
+	    Rearranged bits so that Tx-IGate's processing has transmitter
+	    specific history database.   Better (but yet a bit incomplete)
+	    Tx-IGate filtering is in interface.c.
+
+	* kiss.c, aprx.8.in, aprx.conf.in, aprx-complex.conf.in,
+	  netax25.c, aprx.h, ttyreader.c:
+	    Add FLEXNET support.  (Finnish HamDR speaks it by default!)
+
+	* interface.c:
+	    Corrections on <kiss-subif> definitions, in particular
+	    the aliases.
+	    Fixed Tx-IGate workhorse interface_receive_3rdparty()'s
+	    packet address header construction.
+
+	* digipeater.c, aprx.h:
+	    APRSIS specific via-path parameter parsing fixes, additional
+	    debugging outputs, config error detection outputs.
+
+	* netax25.c, ax25.c:
+	    Debugging outputs.
+
+	* ttyreader.c, aprx.h:
+	    Debugging outputs.
+	    Special KISS subtype "RFCRC" - received KISS frames have
+	    two RANDOM bytes at their end. Looks like CRC16, but is
+	    random junk.
+
+	* erlang.c:
+	    Debug printout.
+
+	* beacon.c:
+	    When an interface has no callsign, do not send beacon to it.
+	    (It could be tty master interface which has multiple KISS
+	     sub-interfaces.)
+
+	* igate.c:
+	    Parse packet to be tx-igated for acceptable address syntaxes.
+	    Debug printouts.
+
+2010-05-16  Matti Aarnio - OH2MQK - KP20NG  <oh2mqk at sral.fi>
+
+	* aprsis.c, aprx.conf.in, aprx.8.in, doc/aprx-manual.odt:
+	    Emphasize that <aprsis>'s login parameter is to be
+	    set ONLY when it needs to be different than mycall
+	    value.  (But tolerate also '$mycall' alias.)
+
+	* aprx.c:
+	    Update internal tocall default to 'APRX1F'.
+
+	* interface.c, digipeater.c:
+	    Tx-iGate fixes for case where outgoing packet has no
+	    VIA field(s).  System saw that "requested hops = 0,
+	    done hops = 0 -> no need to send out".
+
+	* parse_aprs.c:
+	    Make sure that all things creating debug output are
+	    followed by a "\n".
+
+	* igate.c:
+	    Relax station callsign format rules inside a received
+	    3rd-party frame.
+
+2010-05-13  Matti Aarnio - OH2MQK - KP20NG  <oh2mqk at sral.fi>
+
+	* interface.c:
+	    Under all situations, fill in pbuf_t->dstcall_end.
+
+	* debian/rules:
+	    Do not strip resulting objects. We want debug symbols!
+
+	* digipeater.c:
+	    Improve config error reporting.
+
+	* config.c:
+	    Tolerate config file ending without a newline.
+
+2009-12-27  Matti Aarnio - OH2MQK - KP20NG  <oh2mqk at sral.fi>
+
+	* aprx.c, VERSION: 1.98
+
+	* rpm/aprx.spec,  debian/docs, debian/control:
+	    More documents into the packages
+
+	* beacon.c, aprx.8.in, aprx.conf.in, aprx-complex.conf.in,
+	  doc/aprx-manual.odt, doc/aprx-manual.pdf:
+	    Changes on beacon definition keywords to make them clearer
+	    for a user.  Old forms continue as silently accepted aliases.
+
+2009-12-27  Matti Aarnio - OH2MQK - KP20NG  <oh2mqk at sral.fi>
+
+	* VERSION: 1.97
+
+	* beacon.c, aprx.8.in, aprx.conf.in, aprx-complex.conf.in:
+	    Never send to APRSIS interface.
+	    Define 'object' and 'item' type named entities.
+	    Uppercasify several of input fields.
+
+	* interface.c, digipeater.c, aprx.h:
+	    On tx-igate behaviour, add configured via-path on outgoing
+	    3rd-party frames
+
+2009-12-16  Matti Aarnio - OH2MQK - KP20NG  <oh2mqk at sral.fi>
+
+	* beacon.c:
+	    Reworked more..  beacons were sent only for "tx-ok true"
+	    interfaces, while netbeacons are to be sent for all interfaces.
+
+2009-12-03  Matti Aarnio - OH2MQK - KP20NG  <oh2mqk at sral.fi>
+
+	* beacon.c:
+	    Reworked things a bit, on how and with what content to
+	    send beacons.
+
+	* netax25.c:
+	    Valgrind pleasing
+
+	* telemetry.c, ttyreader.c, beacon.c, netax25.c, aprx.h:
+	    Debug printouts.
+
+2009-12-01  Matti Aarnio - OH2MQK - KP20NG  <oh2mqk at sral.fi>
+
+	* interface.c:
+	    Register tty KISS subinterface 0 only once.
+
+	* beacon.c:
+	    When a file-beacon is defined, the message content is
+	    no longer at  bm->msg, instead at local variable msg.
+
+	* netax25.c, aprsis.c:
+	    Pleasing valgrind.
+
+2009-11-26  Matti Aarnio - OH2MQK - KP20NG  <oh2mqk at sral.fi>
+
+	* parse_aprs.c:
+	    Sometimes ran memchr() with bad length. Caused rare crash.
+
+	* digipeater.c, aprxpolls.c, netax25.c, aprsis.c, aprx.c, aprx.h:
+	    Valgrind tested minor changes.
+
+2009-11-17  Matti Aarnio - OH2MQK - KP20NG  <oh2mqk at sral.fi>
+
+	* aprx.8.in:
+	    Big rewrite.
+
+	* aprx.h, interface.c, digipeater.c, netax25.c:
+	    Digipeater "relay-type directonly"  mode.
+	    Interface parsing error detection improvement.
+
+2009-11-08  Matti Aarnio - OH2MQK - KP20NG  <oh2mqk at sral.fi>
+
+	* VERSION 1.96
+
+	* beacon.c, aprx.8.in, aprx.conf.in, aprx-complex.conf.in:
+	    Rewrote beacon transmission interval codes, and documents
+	    of the beacon system.
+
+	* configure.in, Makefile.in:
+	    Added  --with-pthread   option,  rewrote the  --with-embedded
+	    option processing.
+
+	* aprsis.c, configure.in:
+	    Optionally support pthreads(3) where available, this can be
+	    important for uCLinux and perhaps Windows, where fork(2) is
+	    not available.
+
+2009-11-07  Matti Aarnio - OH2MQK - KP20NG  <oh2mqk at sral.fi>
+
+	* aprx.c:
+	    Software tocall identity: APRX1C
+
+	* cellmalloc.c:
+	    Drop semaphores.  Not used in this codebase.
+
+	* filter.c, aprx.h, parse_aprs.c, Makefile.in:
+	    Port Aprsc's filter code to Aprx.
+
+	* debian/aprx.init, rpm/aprx.init:
+	    Update Debian's version, sync the rpm's version
+
+	* telemetry.c:
+	    Report every 20 minutes, but scale values telling 10 minute
+	    traffic.  Start sending telemetry PARM blocks from system
+	    start.
+
+	* aprx.c:
+	    Init configurations before starting erlang accounting subsystem.
+
+2009-11-02  Matti Aarnio - OH2MQK - KP20NG  <oh2mqk at sral.fi>
+
+	* VERSION 1.95
+
+	* aprx.c:
+	    Software tocall identity: APRX1B
+
+	* telemetry.c:
+	    Erlang reporting confusion fixed.
+
+2009-10-30  Matti Aarnio - OH2MQK - KP20NG  <oh2mqk at sral.fi>
+
+	* interface.c:
+	    More logging of interface setups.
+
+	* beacon.c, aprx.8.in, aprx.conf.in, aprx-complex.conf.in
+	    New type of beacon:  file  /path/to/file,  the first line
+	    in given file is read every time this beacon entry is
+	    executed, and the text is sent out sans line end LF.
+	    There are no quote processing available.
+	.
+	    Validate latitude and longitude input, and complain if
+	    validate failed.
+	.
+	    Beacon timefixing on all message types that support it,
+	    and only upon special "timefix" option set on the beacon.
+	.
+	    Beacon construction from small parts supports 6 different
+	    fundamental packet types with coordinates.
+
+	* config.c:
+	    Make config parser debugging needs  -ddd  runtime options.
+
+	* telemetry.c:
+	    Report higher of 10 minute integrated packet/byte counts in
+	    the 20 minute account interval.  This makes graphs smoother.
+
+2009-10-27  Matti Aarnio - OH2MQK - KP20NG  <oh2mqk at sral.fi>
+
+	* aprx.h, aprx.c, aprsis.c, beacon.c, netax25.c, ttyreader.c,
+	  erlang.c, aprx-stat.c, igate.c:
+	    Modify the printtime() to print millisecond resolution times.
+
+2009-10-26  Matti Aarnio - OH2MQK - KP20NG  <oh2mqk at sral.fi>
+
+	* beacon.c, config.c, aprx.h, aprx.conf.in, aprx-complex.conf.in,
+	  aprx.8.in:
+	    Added a 'beaconmode { aprsis | both | radio }' config option,
+	    which says where the beacons are sent to.
+
+	* ROADMAP
+	    Development roadmap for first digit of version number
+
+2009-10-25  Matti Aarnio - OH2MQK - KP20NG  <oh2mqk at sral.fi>
+
+	* digipeater.c, beacon.c, interface.c, aprx.h:
+	    Put all beacons on digipeater's transmitter duplicate checker
+	    storage.  Now a beacon with WIDE2-2 path will not be repeated
+	    by message originator.  Re-organized beacon's code base.
+
+	* netax25.c, interface.c, aprx.h:
+	    Use Link-Level mechanism to send arbitrary AX.25 packets to
+	    desired devices.  Added also a about once minute run code
+	    that checks current AX.25 devices in the system, and maps
+	    necessary ifindex:es to netdevices wanting to do IO.
+	    And all parameters to 'netax25_sendto()' are const..
+
+	* aprx.h, aprx.c, aprx-stat.c, aprsis.c, erlang.c, igate.c:
+	    Commonly used strftime() got put into  printtime() function.
+
+	* VERSION 1.94
+
+	* interface.c:
+	    That final part of <interface> thing (below) can only
+	    be done, if this interface has non-null tty field.
+
+	* Makefile.in
+	    "make valgrind" - helps debugging some screwups..
+
+	* digipeater.c:
+	    Stop scanning the viscous queue, once time limit exceeds
+	    current time.
+
+	* aprxpolls.c:
+	    A screwup on allocations found with valgrind.  Oops!
+
+	* netax25.c, aprsis.c, dupecheck.c, ttyreader.c, erlang.c,
+	  aprx.c, aprx.h, ax25.c, beacon.c, igate.c, historydb.c,
+	  valgrind.c, Makefile.in:
+	    Code changes to clean valgrind outputs on nuisance messages.
+	    And at least one bugfix for valgrind environment...
+
+2009-10-24  Matti Aarnio - OH2MQK - KP20NG  <oh2mqk at sral.fi>
+
+	* telemetry.c:
+	    Changed telemetry channel 2:  Erlangs from bytes_tx accounting.
+	    Now there is separate channel load graph showing how much this
+	    transmitter is affecting the channel.
+	    Give also better label for channel 4: IGateDropRx
+
+	* rfbeacon.c -> beacon.c, aprx.h, aprx.c, config.c, Makefile.in:
+	    Rename  rfbeacon.c  to  beacon.c.
+
+	* interface.c:
+	    As a final part of <interface> definition, check if
+	    the default tnc-subid (0) has associated ttycallsign
+	    defined, and netax25 pty not enabled.  If so, create it.
+
+	* parse_aprs.c, interface.c, aprx.h:
+	    Depending upon usage, either do not look inside 3rd-party
+	    frame, or do look inside.   For Tx-iGate call paths we need
+	    the analysis!
+
+	* parse_aprs.c, interface.c, historydb.c, digipeater.c,
+	  rfbeacon.c, dupecheck.c, igate.c:
+	    Removed codes ignoring "trailing CRLF in APRS frame tail".
+	    They kept causing more trouble than good.  The parse_aprs.c
+	    is anyway diverged from its origins a bit more than I would
+	    like, so no need to maintain mess related on its original
+	    environment.
+
+	* dupecheck.c, aprx.h:
+	    Adjust dupecheck hash bucket size - 16 is quite sufficient
+	    enough even for a very busy igate/digi!
+
+	* igate.c, aprx.h, ax25.c, ttyreader.c
+	    Restructured 3rd-party frame rx-igate processing so that it
+	    does not need to alter TNC2 format buffer in any way.
+	    This caused some weird things to happen in digipeater on cases
+	    of 3rd-party frames.
+	    Also modified ax25-to-tnc2 UI-formatter so that there will
+	    always be zero termination of output text string.
+
+	* interface.c, digipeater.c:
+	    Small restructuring while debugging other things.
+
+	* parse_aprs.c:
+	    Parse APRS 3rd-party frame content, and recognize real
+	    3rd-party frame for sure.
+
+2009-10-24  Matti Aarnio - OH2MQK - KP20NG  <oh2mqk at sral.fi>
+
+	* VERSION: 1.93
+
+	* ttyreader.c, erlang.c:
+	    Feeding in generated random noise did raise a few errors
+	    in KISS frame processing, and erlang accounting.
+	    KISS tncid:s sometimes did not have a callsign associated
+	    with them, and then erlang accounting blew up...
+
+	* interface.c, rfbeacon.c, ax25.c, aprx.h:
+	    Beacons to radio interfaces, KISS works best, NET-AX.25 less
+	    well -- transmits OK UI frames, transmit of arbitrary other
+	    types of frames is necessary for generic digipeating.
+
+	* digipeater.c:
+	    Add alias to config parameter 'transmit' -> 'transmitter'.
+
+	* netax25.c, config.c:
+	    Removed unused parameter on  netax25_addrxport().
+	    Rebuilt netax25_sendto(), however it sends out only UI frames..
+	    Removed pre-created tx_socket, and associated codes.
+
+	* configure.in:
+	    Remove unused autoconf test for  cfmakeraw()..
+
+2009-10-23  Matti Aarnio - OH2MQK - KP20NG  <oh2mqk at sral.fi>
+
+	* rfbeacon.c:
+	    Fix the debug printout of beacon to be sent.
+
+	* aprx.h, config.c: readconfigline()
+	    Keep the cf->linenum showing first source line number on
+	    continued multiline.  This helps a bit on debugging, and
+	    similar things are already done when a (sub)group parser
+	    is reporting where that subgroup begins in case of missing
+	    parameters in a group.
+
+	* digipeater.c:
+	    Validating received requests better. Now marking also probable
+	    situations that can say "this came from originator to me directly"
+
+	* netbeacon.c, rfbeacon.c, config.c, aprx.h, aprx.c, aprsis.c,
+	  Makefile.in:
+	    Removing the old netbeacon code.
+
+2009-10-22  Matti Aarnio - OH2MQK - KP20NG  <oh2mqk at sral.fi>
+
+	* aprx.h, rfbeacon.c, interface.c:
+	    Implemented new infra for sending APRS beacons to radio
+	    interfaces.  Incoming request will at first construct
+	    the AX.25 header, then send that to physical interfaces.
+
+	* aprx.h, ax25.c, digipeater.c, interface.c, kiss.c, pbuf.h,
+	  pbuf.c, netax25.c, parse_aprs.c, rfbeacon.c, ttyreader.c:
+	    Changed all instances of 'unsigned char' to 'uint8_t'.
+
+2009-10-21  Matti Aarnio - OH2MQK - KP20NG  <oh2mqk at sral.fi>
+
+	* config.c:
+	    Clean away some superflous debugs.
+
+	* digipeater.c:
+	    Viscous mode debug printout crashes on SEGV.. Oops.
+	    (without debug the bug does not hit.)
+
+	* README.ViscousDigipeater, digipeater.c:
+	    Thinking about what are correct rules on Viscous Digipeat.
+
+	* digipeater.c:
+	    On configuration, make sure that no two <source> definitions
+	    within single <digipeater> definition have same <interface>:s.
+
+2009-10-20  Matti Aarnio - OH2MQK - KP20NG  <oh2mqk at sral.fi>
+
+	* aprx.h, digipeater.c:
+	    Viscous digipeater special corner cases..
+
+	* aprx.h, config.c, aprx.conf.in, aprx-complex.conf.in
+	    Interval parser for "timeout" and "interval" parameters
+	    used in several places.
+
+	* config.c, aprx.conf.in, aprx-complex.conf.in:
+	    Line continuation (the '\' character at the end of
+	    input line - with possible whitespaces following it)
+	    is now supported.
+	    An interval parser is added; timeouts and intervals
+	    can be defined in human readable way:  3m2s
+
+	* aprx.8.in:
+	    Larger rewrite to bring it up to current version.
+
+	* aprsis.c, aprx.conf.in, aprx-complex.conf.in:
+	    Reworked details of <aprsis> configuring, and internal
+	    operational semantics.  Most notable difference is on
+	    possibility to define used filters in small fragments,
+	    which the system will then catenate.
+
+	* aprx.h, digipeater.c, dupecheck.c:
+	    Returned the viscous delay processing back to version
+	    just before "simplified viscous delay and dupechecking".
+	    It really needs to check delayed vs. immediate counts.
+
+2009-10-19  Matti Aarnio - OH2MQK - KP20NG  <oh2mqk at sral.fi>
+
+	* VERSION: 1.92
+
+	* digipeater.c, interface.c:
+	    Clean variable naming on digipeater <source> subsystem.
+
+	* aprx.h, aprx.conf.in, aprx-complex.conf.in, igate.c:
+	    Update documentation
+
+	* igate.c:
+	    Reject packets with destcall=RXTLM-* from Tx-IGate.
+
+	* digipeater.c:
+	    Simplify control flow when feeding to viscous queue vs.
+	    when running the backend directly.
+
+	* aprx.h, digipeater.c, dupecheck.c, igate.c:
+	    - Fixed 3rd party dupechecking
+	    - Simplified viscous delay and dupechecking.
+	      The dupechecking happens at the start of digipeater_backend(),
+	      which is called after pbuf's have been subjected to a viscous
+	      delay, if ever necessary.  First arriving packet is digipeated,
+	      if it has steps to do. If not, rest are still considered dupes,
+	      and not digipeated.
+
+	* aprx.h, igate.c:
+	    Make rflog() public function to be used by multiple parties.
+	    Also mark on the log line the direction to which the packet
+	    was going (R/T), and not only its source interface.
+
+	* ax25.c:
+	    Moved igate_to_aprsis() call before interface_receive_ax25(),
+	    and thus also log received packet on rf.log before it is sent
+	    out anywhere.
+
+	* aprx.h, interface.c, digipeater.c, aprx.8.in, aprx.conf.in,
+	  aprx-complex.conf.in, dupecheck.c:
+	    Moved viscous-delay processor into digipeater's <source>
+	    control area.  Implemented Tx-IGate's packet re-formatting
+	    rules on interface.c.  Implemented viscous-delay processing
+	    in digipeater. Added refcounting on dupe_record_t objects.
+
+	* digipeater.c, igate.c, config.c, aprx.h, aprx-complex.conf.in:
+	    Moved regexp reject filters from old style setup at igate.c
+	    to new style at digipeater.c.  This will not be able to reject
+	    trivially configurable things from Rx-IGate datastreams, but
+	    it can be used to control digipeating.
+
+	* ax25.c:
+	    Remove unnecessary debug printout.
+
+2009-10-18  Matti Aarnio - OH2MQK - KP20NG  <oh2mqk at sral.fi>
+
+	* VERSION: 1.91
+
+	* aprx.h, dupecheck.c, digipeater.c, pbuf.c, pbuf.h, aprsis.c,
+	  igate.c, keyhash.c:
+	    Digipeater local instance of dupechecker.  The dupe-checker
+	    does recursive analysis of APRS packets for 3rd party
+	    frames, and dupecheck the innermost frame of them.
+	    Cleaned the keyhash.c to contain only FVN-1a hasher.
+
+	* digipeater.c, interface.c, telemetry.c, aprx.h, ttyreader.c,
+	  erlang.c, aprx-stat.c:
+	    Start transmitting digipeated frames to ttyreader's KISS
+	    output.  netax25's similar interface is not tested.
+	    Changed also the Erlang dataset format, and begun to
+	    produce Tx packet counts on telemetry.  Accounting
+	    saves also tx byte counts, but they are not reported.
+
+	* aprx.h, interface.c, digipeater.c, pbuf.h, pbuf.c, ax25.c:
+	    Pass the UI PID information all the way to interface,
+	    where it can be matched against a list of PIDs that will
+	    be treated alike APRS in digipeating.
+	    Have two modes in digipeating: one with interface (and
+	    aliases) as recognized work targets, and other with APRS
+	    wide/trace tags in addition to interface (and aliases).
+
+	* aprx.h, ax25.c, interface.c, digipeater.c, aprx.conf.in,
+	  aprx-complex.conf.in:
+	    - Prefill AX.25 address field formatted ax25callsign
+	      field on all <interface> datastructures.  That comes
+	      handy when doing TRACE processing.
+	    - Put exact "callsigns" of "WIDE", "TRACE", and "RELAY"
+	      into system as interface callsign aliases. When they
+	      are present in the request path, substitute interface
+	      callsign there with H-bit set.
+	    - Update aprx.conf samples to how the system can be
+	      configured.
+
+2009-10-17  Matti Aarnio - OH2MQK - KP20NG  <oh2mqk at sral.fi>
+
+	* aprx.h, digipeater.c, interface.c, pbuf.h, parse_aprs.c:
+	    Digipeater preparation, system counts done and requested
+	    distribution operations with source specific as well as
+	    transmitter specific keywords.
+
+	* aprx.h, ax25.c, interface.c, aprsis.c, pbuf.c, parse_aprs.c:
+	    Changed a few "parse failed" returns to "parse OK".
+	    Systematic feed of datapacket "with TNC2 line end CRLF pair".
+
+2009-10-16  Matti Aarnio - OH2MQK - KP20NG  <oh2mqk at sral.fi>
+
+	* erlang.c, aprx.h, ttyreader.c, netax25.c, igate.c:
+	    Clean Erlang accountig API.  Removed unused parameters.
+
+	* interface.c, aprsis.c, igate.c, aprx.h, aprx.c, digipeater.c:
+	    Minimal <digipeater> <source> definition parsers.
+	    Additionally internal "APRSIS" pseudo-interface.
+
+2009-10-15  Matti Aarnio - OH2MQK - KP20NG  <oh2mqk at sral.fi>
+
+	* aprx.h, aprx.c, rfbeacon.c:
+	    Add internal "tocall" constant with value "APRX19".
+	    That one will track software versions.
+	    The 'for' keyword on beacons defaults to $mycall.
+
+	* aprx.h, aprx.c, interface.c, config.c, rfbeacon.c, aprsis.c,
+	  ttyreader.c, netbeacon.c:
+	    Config machinery redone towards new style.  Rx-IGate
+	    works again.  (Old config should work too.)
+
+	* aprx.h, pbuf.c, pbuf.h, interface.c, digipeater.c, aprx.c:
+	    Skeletons for pbufs, digipeaters, and their uses in
+	    the interface layer.
+
+	* aprsdigi.c, ax25.c, Makefile.in:
+	    Remove obsolete placeholder.  Things will be done differently.
+
+	* config.c, rfbeacon.c:
+	    The rfbeacon code will be doing all variants of beacons..
+
+	* interface.c, netax25.c, ttyreader.c, aprx.h, ax25.c:
+	    interface_transmit_ax25() is able to transmit a fully formed
+	    AX.25 header+control+body frame to Linux internal AX.25 network
+	    devices as well as to any serial port attached KISS device.
+	    Transmission to TNC2 devices is not supported.
+	    Code is also very careful on checking the AX.25 frame header
+	    structure, and rejecting outright any with invalid header
+	    structure (bad continuation flags, bad chars in callsigns,
+	    not so careful with SSID byte contents - too many are careless
+	    with those :-( )
+
+2009-10-14  Matti Aarnio - OH2MQK - KP20NG  <oh2mqk at sral.fi>
+
+	* rfbeacon.c, interface.c, Makefile.in, config.c, aprx.c,
+	  aprx.h, aprx.conf.in, aprsis.c, netbeacon.c:
+	    Add a stub of rfbeacon.
+
+2009-10-13  Matti Aarnio - OH2MQK - KP20NG  <oh2mqk at sral.fi>
+
+	* interface.c, config.c, netax25.c, ttyreader.c, ax25.c,
+	  aprx.h, ChangeLog:
+	    Feed received AX.25 frames to interface layer for possible
+	    digipeat processing.  (Missing: APRSIS originated frames!)
+
+	* interface.c, ttyreader.c, aprx.h, aprx.conf.in, aprx.8.in:
+	    Remodelled serial-device definitions into interface layer.
+	    Documentation updates to match new system.
+
+2009-10-13  Matti Aarnio - OH2MQK - KP20NG  <oh2mqk at sral.fi>
+
+	* aprsis.c, aprx.h, config.c, netbeacon.c, aprx.conf.in,
+	  VERSION, README, INSTALL, TODO:
+	    <aprsis> interface config with new style entry.
+	    More of <interface> definitions.
+	    Experiments at aprx.conf.in writing.
+
+
+	* Makefile.in, aprx.8.in, aprx.conf.in, aprx.h, config.c,
+	  filter.c, interface.c, netax25.c, netbeacon.c, pbuf.c,
+	  pbuf.h, ttyreader.c:
+	    Incremental work on new style of configurations
+	    as outlined in the Requirement Specification document.
+	    Old style configurations do still work.
+	    Serial port initstring is now binary transparent.
+
+2009-10-05  Matti Aarnio - OH2MQK - KP20NG  <oh2mqk at sral.fi>
+
+	* VERSION: 1.06
+
+	* netbeacon.c:
+	    Complete beacon coordinate validator code, now it
+	    can detect invalid input values properly.
+
+	* netax25.c, aprsis.c, ttyreader.c, igate.c, aprx.h:
+	    Cleaning gcc -Wall warnings on various platforms,
+	    including OpenBSD.
+
+2009-10-01  Matti Aarnio - OH2MQK - KP20NG  <oh2mqk at sral.fi>
+
+	* VERSION: 1.05
+
+	* kiss.c, netax25.c, ttyreader.c, aprx.h, ax25.c:
+	    Write the SMACK frame with correctly escaped CRC.
+	    Fixed also serial-port initstring handling.
+
+2009-09-30  Matti Aarnio - OH2MQK - KP20NG  <oh2mqk at sral.fi>
+
+	* VERSION: 1.04
+
+	* netax25.c:
+	    When writing AX.25 KISS frame to kernel, try to do it
+	    up to 3 times.  Also add some debug statements on
+	    ax25-rxport processing.
+
+	* VERSION: 1.03
+
+	* ttyreader.c:
+	    Fix on serial port startup - always turn on flows on
+	    the port, and explicitely flush the driver level
+	    buffers discarding possibly accumulated data.
+
+2009-09-28  Matti Aarnio - OH2MQK - KP20NG  <oh2mqk at sral.fi>
+
+	* VERSION:  1.02
+
+	* erlang.c, aprx-stat.c, aprx.h:
+	    Remove subport from erlang codes, having "tncid N" on serial
+	    port definitions takes care of this kind of things.
+
+	* kiss.c, ttyreader.c, netax25.c, ax25.h:
+	    Moved KISS/SMACK encoder to separate module, the CRC16 calculator
+	    went there as well.  For each ttyreader sub-tncid there is
+	    separately opened KISS-pty channel on Linux systems with given
+	    callsign as interface's writer channel.  The  netax25 ax25-port
+	    reader does not accept packets with source callsign as any of
+	    our ttyreader callsigns.
+
+	* erlang.c:
+	    Fix the erlang_find() to really find the interface call.
+
+2009-09-07  Matti Aarnio - OH2MQK - KP20NG  <oh2mqk at sral.fi>
+
+	* cellmalloc.c, netax25.c, keyhash.c:
+	    Compiling at OS/X found a few odd problems, corrected.
+
+2009-08-30  Matti Aarnio - OH2MQK - KP20NG  <oh2mqk at sral.fi>
+
+	* aprx.8.in, aprx.conf.in, config.c, aprx.h, aprx.c, telemetry.c,
+	  netax25.c, netbeacon.c, aprsis.c, ttyreader.c, erlang.c, 
+	  aprx-stat.c:
+	    Rename the "mycall" configuration parameter to "aprsis-login",
+	    what it really is being used at.  There is no "mycall", anywhere!
+
+	* dupecheck.c, aprx.h, aprx.c, [dupecheck.h]:
+	    Removed dupecheck.h after incorporating it into aprx.h.
+	    Added the poll-interfaces to handle housekeeping operations.
+
+	* beacon.c -> netbeacon.c, Makefile.in, aprsis.c, aprx.c, aprx.h:
+	    Change file name, and all references therein.
+	    A preparation for separate RF beacons.
+
+	* netbeacon.c, aprx.8.in, aprx.conf.in:
+	    Add "netbeacon dest APRS via NOGATE ..."  options for configuration.
+
+	* netbeacon.c:
+	    Use float math to determine next event times for all beacons
+	    for smoother distribution.
+
+2009-08-29  Matti Aarnio - OH2MQK - KP20NG  <oh2mqk at sral.fi>
+
+	* Makefile.in, dupecheck.c, dupecheck.h, aprx.c, aprx.h, aprsis.c:
+	    Add infrastructure for future:  dupecheck()
+
+	* telemetry.c:
+	    Add "NOGATE" on telemetry messages transmitted to APRSIS.
+
+	* igate.c:
+	    Deeper look into Rx-IGate specs revealed couple missing details.
+	    More bits towards Tx-IGate.
+
+2009-08-23  Matti Aarnio - OH2MQK - KP20NG  <oh2mqk at sral.fi>
+
+	* VERSION, INSTALL:
+	    Mark version as: 1.00
+
+	* aprx.c:
+	    Document '-L' option.
+
+	* aprx.h, aprsis.c, beacon.c, igate.c:
+	    New internal API to pass data from  aprx proper, and APRS-IS
+	    communicator.  This is able to carry binary (including NUL
+	    bytes) data both on received AX.25 address, and frame content.
+
+	* telemetry.c:
+	    Change a bit on information texts, and transmit frequency.
+
+	* aprx.conf.in, aprx.8.in:
+	    Edit prototype configurations, and documentation
+
+	* aprx.c, aprx.h, igate.c, cellmalloc.h, historydb.h, historydb.c,
+	  keyhash.h, keyhash.c, pbuf.h, parse_aprs.c:
+	    Preparing infrastructure for TX capable i-gate, and digipeater.
+
+2009-02-10  Matti Aarnio - OH2MQK - KP20NG  <oh2mqk at sral.fi>
+
+	* Makefile.in, aprsdigi.c, igate.c, aprx.h, ax25.c, ttyreader.c,
+	  netax25.c, aprsis.c:
+	    Move rx-igate code to igate.c,and make initial moves to
+	    collect information about what to do for tx-igate.
+
+	* PROTOCOLS, TODO, README:
+	    Document updates.
+
+2008-12-07  Matti Aarnio - OH2MQK - KP20NG  <oh2mqk at sral.fi>
+
+	* aprx.c, aprsis.c, netax25.c, configure.in, ttyreader.c, Makefile.in:
+	    Compile testing to get this to work on Solaris 10.
+	    Also fixes on PIPE failure handling (correct SIGPIPE ignoring)
+	    on platforms other than Linux -- and possibly also for Linux.
+	    Now this should drop in to FreeBSD and OS/X as well.
+
+2008-10-28  Matti Aarnio - OH2MQK - KP20NG  <oh2mqk at sral.fi>
+
+	* netax25.c, aprx.8.in:
+	    Turned upside-down the meaning of  ax25-rxport  config
+	    parameter.  There is no longer a wild-card receiving
+	    mode in Linux internal AX.25 network receiving.
+	    All APRS receiving interface callsigns must be listed
+	    explicitely.
+
+	* netax25.c, ttyreader.c, aprx.h:
+	    SMACK probe transmits on link that is configured for it.
+	    Also offers some debug messages on SMACK activation.
+
+	* beacon.c, ax25.c:
+	    Cleaning debug printouts
+
+2008-07-18  Matti Aarnio - OH2MQK - KP20NG  <oh2mqk at sral.fi>
+
+	* config.c:
+	    Function for validate of callsign input syntax
+
+	* telemetry.c:
+	    Please the compiler a bit, increment the telemetry
+	    sequence number only after all telemetered interfaces
+	    have been reported.
+
+	* aprsis.c:
+	    If there is need to reconnect to APRSIS, pick all possible
+	    IP addresses for it, and use them all.  Also improved
+	    the use of new IP resolver API a bit.
+
+	* ttyreader.c:
+	    Explicitely set "KISSSTATE_SYNCHUNT = 0" in enumeration.
+	    Memory blocks are created with memset() call clearing them.
+
+	* aprx.h, beacon.c:
+	    Compiler pleasing
+
+	* erlang.c:
+	    One-off array size handling, resulted in SEGV...
+
+2008-04-11  Matti Aarnio - OH2MQK - KP20NG  <oh2mqk at sral.fi>
+
+	* VERSION:
+	    0.22:
+
+	* erlang.c:
+	    Auto-embed the erlang-dataset if backing-store open fails.
+
+	* ttyreader.c:
+	    Mark closed socket as closed.
+
+2008-03-29  Matti Aarnio - OH2MQK - KP20NG  <oh2mqk at sral.fi>
+
+	* VERSION:
+	    0.21
+
+	* telemetry.c:
+	    New "send Erlang data as telemetry packets to APRS-IS"
+	    subsystem.
+
+	* aprsis.c:
+	    Fix the APRS-IS network login protocol.  There are TWO
+	    parameter strings after the "vers" keyword.
+
+	* configure.in, Makefile.in, erlang.c:
+	    Support compilation as embedded target.  Then the erlang
+	    datasets are not off-loadable to the memory mapped files,
+	    rather they are very small in-memory tables.
+
+	* erlang.c, aprx.h, telemetry.c, ax25.c, aprx-stat.c:
+	    Support for telemetry sending out info on received packets.
+
+	* beacon.c:
+	    Improve input validation.
+
+2008-02-18  Matti Aarnio - OH2MQK - KP20NG  <oh2mqk at sral.fi>
+
+	* VERSION: aprx-0.18
+
+	* aprx.8.in, aprx.conf.in, beacon.c:
+	    New syntax to define netbeacons.  Also support older methods.
+
+	* config.c:
+	    Bug in  config_SKIPTEXT  quoted string termination scanning.
+
+	* netax25.c, aprsis.c, aprx.h:
+	    Removing dead code, hooks for future "TNC2 -> AX.25"
+
+	* ttyreader.c:
+	    Send received KISS frames to system internal AX.25 network,
+	    if host has such (such as Linux)
+
+2008-02-03  Matti Aarnio - OH2MQK - KP20NG  <oh2mqk at sral.fi>
+
+	* configure.in, netax25.c,
+	    autodetect header <pty.h>, and libutil function openpty().
+
+	* netax25.c, aprx.h, aprx.c:
+	    Rearranged  netax25 module initing - to happen _latter_.
+
+	* ttyreader.c, aprx.h, netax25.c:
+	    kissencoder() function
+
+	* ttyreader.c, aprx.h, netax25.c:
+	    On Linux, use openpty() to create an AX.25pseudo-device on
+	    which we then can push AX.25 format packets received from
+	    non-AX.25 interfaces.  This will itself also _ignore_ packets
+	    received from this created interface.
+
+	* beacon.c:
+	    "for" attribute for beacon messages, thus this system
+	    can claim to be sending the beacons on behalf of others.
+
+	* ax25.c, aprx.h:
+	    parse_ax25addr() function.
+
+	* config.c, aprx.8.in, aprx.conf.in:
+	    The mycall parameter must be all uppercase AX.25 valid
+	    callsign, and must not be same as any other callsign
+	    in system internal AX.25 network.  (This is meaningful
+	    only on Linux systems..)
+
+	* Makefile.in:
+	    Just some cleanup
+
+2008-01-30  Matti Aarnio - OH2MQK - KP20NG  <oh2mqk at sral.fi>
+
+	* aprsis.c:
+	    Spotted watchdog doing reconnects every 2 minutes
+	    (like it is supposed to be), and realized that
+	    it really should not care what the server says,
+	    just that server is saying something...
+
+	* erlang.c:
+	    A bug in backing-store map protection logic.
+
+	* aprx.c:
+	    See if pidfile exists.  If it does and the start
+	    is not for foreground, refuse to run if process
+	    given in the pidfile does exist.
+
+	* aprx.8.in, config.c, netax25.c, ttyreader.c, aprsis.c,
+	  aprx.h, ax25.c, aprx.conf.in, beacon.c:
+	    New "callsign" config parameter for "radio serial" ports.
+	    messages received from given port are sent out using that
+	    callsign.    Revamp the whole config parsing.
+
+	* aprsis.c:
+	    Smarter main-loop to aprs-is loop  message pass preparation
+	    and usage codes -- pass a struct block as message leader.
+
+	* ttyreader.c, netax25.c, aprsis, ax25.c, beacon.c, aprx.h:
+	    Pass explicite parameter towards the APRSIS telling, which
+	    callsign (radio receiver) the message came in from.
+
+	* aprx.h, config.c, ttyreader.c, beacon.c:
+	    Rework config parameter line parsing.  Just one param is
+	    processed by the main config reader loop, any further are
+	    tasks of the individual subroutines (ttyreader, beacon)
+
+
+2008-01-26  Matti Aarnio - OH2MQK - KP20NG  <oh2mqk at sral.fi>
+
+	* erlang.c:
+	    Properly handle r/o share mapping of the aprx.state erlang
+	    dataset.  This mode is used by the  aprx-stat  program.
+
+	* netax25.c, aprx.conf.in, aprx.8.in:
+	    For each AX.25 socket received packet, query reception
+	    interface address and reformat it to TNC2 format.
+	    Use that for reception reports, logs, filters etc.
+	    Reason: port names given in /etc/ax25/axports do not
+	    persist at all!  Even clean system boot may yield
+	    different port names than what the file lists.
+
+	* Version 0.17
+
+	* INSTALL, README:
+	    Minor edits
+
+	* configure.in, Makefile.in, debian/rules, rpm/aprx.spec.in,
+	  Makefile:
+	    A bit more coherency on make system regarding linking.
+	    Remove generated  Makefile.  (Keep generated  configure !)
+
+	* config.c, ttyreader.c, aprx.conf.in, aprx.8.in:
+	    Call the "serialport"  now with name "radio".
+	    (Also old one works, so old config does not break.)
+
+	* aprx.h, netax25.c, ax25.c, ttyreader.c:
+	    Pass port name down to tnc2_rxgate() function where
+	    it is used in rf.log outputs.  A distributed multi-
+	    receiver setup log is somewhat .. odd looking when
+	    most receivers get same packet.
+
+	* logrotate.arpx.in:
+	    Rotate weekly, and compress immediately.
+	    Monthly turned out to be too much for "embedded"
+	    OH1GSM-1 system.
+
+2008-01-12  Matti Aarnio - OH2MQK - KP20NG  <oh2mqk at sral.fi>
+
+	* configure.in, configure, debian/rules, rpm/aprx.spec.in,
+	  rpm/aprx.init, Makefile, config.h.in:
+	    More RPM / configure rework.
+
+	* configure.in, configure, Makefile.in, Makefile, config.h.in,
+	  install-sh, rpm/aprx.spec.in, debian/rules:
+	    Had to add minimalistic  configure  script into system for
+	    the RPM multi-target compilation to work. 
+
+	* Makefile, rpm/aprx.spec.in, rpm/aprx.default, rpm/aprx.init:
+	    RPM package build framework, including init and logrotate -scripts
+
+2008-01-10  Matti Aarnio - OH2MQK - KP20NG  <oh2mqk at sral.fi>
+
+	* version 0.16
+
+	* erlang.c:
+	    Make the logged data narrower - to usually fit in 80 char lines.
+
+	* aprx.c:
+	    Always close STDIN from reading, and replace it with
+	    a file handle opened on /dev/null.
+	    When daemoning, close also STDOUT and STDERR, and
+	    replace them with handles writing to /dev/null.
+	    .. and do it as late as possible.
+
+	* aprx.h, aprx.c, config.c, erlang.c, aprx.8.in, aprx.conf.in,
+	  aprx-stat.c:
+	    Add (and document) option for logging erlang data on separate
+	    file without any runtime options or need to divert stdout
+	    or syslog anywhere.
+
+2008-01-08  Matti Aarnio - OH2MQK - KP20NG  <oh2mqk at sral.fi>
+
+	* aprx.h, ttyreader.c, erlang.c, netax25.c, aprx-stat.c:
+	    When talking with multi-drop KISS, account each TNC
+	    separately.
+
+2008-01-07  Matti Aarnio - OH2MQK - KP20NG  <oh2mqk at sral.fi>
+
+	* version 0.15
+
+	* erlang.c:
+	    Do not double-open the state backingstore file
+
+	* aprsis.c:
+	    Remember to close the opened log files.
+
+	* ttyreader.c:
+	    Support case of _no_ serialports (reading only via AX.25 net)
+
+	* Makefile, logrotate.aprx.in:
+	    Put aprx logs on /var/log/aprx/,  and have monthly rotate.
+
+	* debian/*, Makefile:
+	    Debian package building infrastructure
+
+	* aprx.8.in, aprx.conf.in:
+	    A bit elaboration on how to add multiple entries of
+	    aprsis-server, and  serialport  definitions.
+
+	* aprsis.c, ttyreader.c, aprx.8.in, aprx.conf.in:
+	    Remove last vestiges of program having any hardwired limits
+	    on number of anything.  There are (of course) lots of
+	    parameters that are singletons, but all multiples are
+	    now unlimited (within memory limits..)
+
+	* Makefile:
+	    "make install"  does install the  CFGFILE (aprx.conf)
+	    if it does not have to overwrite the thing.
+	    "make dist" is even more interesting beast..
+
+2008-01-06  Matti Aarnio - OH2MQK - KP20NG  <oh2mqk at sral.fi>
+
+	* version 0.14
+
+	* ttyreader.c, aprx.conf.in, aprx.8.in:
+	    Support TNC2 monitor format on reception.
+
+	* ttyreader.c, aprx.conf.in, aprx.8.in:
+	    Overload the "serialport" configuration option with a mechanism
+	    to define a IP-literal addressable remote TCP port somewhere
+	    with e.g. KISS TNC on it.
+
+2008-01-05  Matti Aarnio - OH2MQK - KP20NG  <oh2mqk at sral.fi>
+
+	* Makefile:
+	    Radical revisioning, Best Current Practice
+
+	* aprx.c:
+	    Write aprx.pid  file in all cases, not only when starting
+	    as daemon.
+
+	* version 0.13
+
+	* aprx.h, aprx.c, erlang.c, aprx-stat.c:
+	    Modifications on shared memory segment head, stores
+	    MYCALL, correct running process PID.
+
+	* INSTALL:
+	    Some text fixes
+
+	* aprx-stat.c, aprx.h, erlang.c:
+	    Report also server process PID on the SNMP dataset,
+	    and time in seconds since it was started.
+
+	* ax25.c:
+	    Verify TNC2 format APRS message's FROM>DEST,VIA,VIA:
+	    callsigns to be of proper syntax.
+
+	* Makefile, aprx.8, aprx.8.in, aprx-stat.8, aprx-stat.8.in,
+	  aprx.conf, aprx.conf.in:
+	    Centralized a bit of configuring into Makefile, generating
+	    files from *.in versions.
+
+	* aprxpolls.c:
+	    Library function used everywhere, part of "eliminate fixed
+	    size preallocations" -task.
+
+	* aprsis.c:
+	    Debug logging improvements, parent death detection.
+	    Preserved MAXAPRSIS setting - of 10 servers.
+
+	* ttyreader.c:
+	    Unfix the number of TTYs, now can be as many as one wants.
+
+	* config.c, aprx.c, aprx.h, aprx.conf.in, aprx.8.in:
+	    pidfile configuration parameter, and its usage
+
+2008-01-04  Matti Aarnio - OH2MQK - KP20NG  <oh2mqk at sral.fi>
+
+	* VERSION, arpx.c, Makefile, aprx.8, aprx.8.in,
+	  aprx-stat.8, aprx-stat.8.in:
+	    Define system version in VERSION file, have it stamped
+	    on programs and packages.
+
+	* config.c:
+	    The "aprxlog" and "rflog" parameters were interchanged
+	    at some point.
+
+	* aprx.c, aprsis.c, beacon.c:
+	    Complain loudly with -d or -v options on, and if the
+	    configuration does not set global  mycall  parameter.
+	    Do not refuse to run, though!  This is perfectly valid
+	    for things like Erlang-monitoring.
+
+2007-12-29  Matti Aarnio - OH2MQK - KP20NG  <oh2mqk at sral.fi>
+
+	* version aprx-v0.12
+
+	* PROTOCOLS:
+	    Writeup of existing (and planned) protocols that this
+	    software uses.
+
+	* ax25.c:
+	    Correct processing of 3rd-party frames.
+	    Also separate TNC2 formatted frame Rx-igateing rules
+	    from AX.25-to-TNC2 format translation routine.
+
+	* ax25.c, beacon.c, aprsis.c:
+	    Centralize the APRSIS communication line ending CRLF char pair
+	    addition into common code, not distributed all over.
+
+2007-12-25  Matti Aarnio - OH2MQK - KP20NG  <oh2mqk at sral.fi>
+
+	* version aprx-v0.11
+
+	* TODO, README:
+	    Cleanup
+
+	* config.c, netax25.c, aprx.8, aprx.conf:
+	    Config option "ax25-rxport" - Limits acceptance of APRS
+	    packets only from listed Linux AX.25 ports.
+
+	* ttyreader.c, aprx.conf, aprx.8:
+	    Reworked a bit of the serialport config options.
+	    Now initstring, and various KISS modes are configurable
+
+	* erlang.c:
+	    Carefull approach on erlang-file opening, if file exists,
+	    and is non-zero size, open it only if magics match.
+
+	* config.c:
+	    config_SKIPTEXT() terminates all scanned strings with NUL byte,
+	    and moves to byte following it, if the termination byte was not
+	    a NUL byte originally.
+
+	* aprx-stat.c, aprx-stat.8:
+	    Option -t  to show timestamps differently.
+
+	* Makefile, man-to-html.sh:
+	    Produce decent format HTML versions of the man-pages.
+
+	* config.c, erlang.c, aprx.8, aprx.conf:
+	    Added "erlang-log1min" option to control 1 minute interval
+	    Erlang sampling logging behaviour.
+
+	* Makefile:
+	    Fix "make install" of man-pages
+
+	* version aprx-v0.10
+
+	* aprx-stat.c, aprx-stat.8, erlang.c, Makefile:
+	    Statistics reporter tool.
+
+	* aprsis.c, config.c, aprx.8, aprx.conf:
+	    Multiple aprsis-server  config definitions are now
+	    supported, and used in round-robin fashion.
+
+	* ax25.c, config.c, aprx.8, aprx.conf:
+	    Config option  ax25-filter
+
+	* ttyreader.c, erlang.c:
+	    Magic channel capacity constant expressions updated..
+
+2007-12-23  Matti Aarnio - OH2MQK - KP20NG  <oh2mqk at sral.fi>
+
+	* aprx.c, aprx.h, aprsis.c, aprx.8, aprx.conf, ax25.c, erlang.c:
+	    Multiple configuration file options, rf-log, and aprx-log -files,
+	    related documentation.
+
+	* config.c, aprx.8:
+	    Special quoted-string escape processing.
+
+	* version aprx-v0.08
+
+	* erlang.c, aprx.c, aprx.h:
+	    Erlang data has now a mmap():ed filesystem based backing-store.
+	    Erlang-data can be syslog()ed, and independently of that,
+	    it can be printed on STDOUT.  Default syslog facility is "NONE".
+
+	* Great Rename -- the thing is now called:  aprx
+
+2007-12-06  Matti Aarnio - OH2MQK - KP20NG  <oh2mqk at sral.fi>
+
+	* aprsg.8, erlang.c, aprsg.c, netax25.c, ttyreader.c:
+	    Erlang logging now uses syslog(3), unless explicitely told to use
+	    output to stdout.  Also the Erlang log format was altered a bit,
+	    now it reports also number of packets in the interval.
+
+	* erlang.c, Makefile:
+	    "make ERLANG1=1" compiles in also 1 minute erlang logging interval.
+
+	* aprsis.c:
+	    Code refactored to put the APRS-IS communication into its own
+	    fork()ed sub-process communicating via a socketpair() with the
+	    main loop.   Now reconnection time with the APRS-IS server does
+	    not affect functionality of the main loop.
+
+2007-12-05  Matti Aarnio - OH2MQK - KP20NG  <oh2mqk at sral.fi>
+
+	* ChangeLog
+	   Opened for the first time.  Version 0.06.
+
diff --git a/INSTALL b/INSTALL
new file mode 100644
index 0000000..baba939
--- /dev/null
+++ b/INSTALL
@@ -0,0 +1,60 @@
+
+          INSTALL of  APRX 2.08
+
+
+Pre-made binary package building system exists for Debian and
+Redhat/Fedora systems.  See details at the end of this file.
+
+
+A rough-cut version of the installation instructions
+
+  0) Prerequisites:
+      Does not need anything beside standard libc!
+      (In particular the Linux version does not need
+       libax25 / libax25-dev !)
+
+  1) Start with  ./configure  --parameters
+     For a small memory system without writable /tmp
+     you have to use  --with-embedded   option.
+
+  2) Cleanliness is good start:
+
+         $ make clean
+
+  3) Compile the thing:
+
+         $ make
+
+  4) There is automatic "install" as:
+
+         # make install
+
+      with several presumptions about directories fixed
+      into the Makefile (possibly some adjustments are
+      required, depending upon your environment.)
+
+  5) Edit the configuration file to match your system:
+
+        # emacs /etc/aprx.conf
+
+     See the  aprx(8) man-page for more info (man 8 aprx)
+
+  6) Program startup scripts ("init-scripts") exist for
+     couple system environments, others may need manual
+     adapting.
+
+
+
+For Debian users wanting to compile themselves instead of using
+precompiled binaries:
+
+     $ make make-deb
+
+     # dpkg -i aprx_2.07-....deb
+
+
+For RedHat/Fedora users:
+
+    $ make make-rpm
+
+    # rpm -Uvh aprx-2.07.svn###-1.i386.rpm
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..db21adc
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,27 @@
+Copyright (c) 2007-2014, Matti Aarnio
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of  Matti Aarnio  nor the names of its contributors
+      may be used to endorse or promote products derived from this software
+      without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..1d358ea
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,226 @@
+#
+#  APRX -- 2nd generation receive-only APRS-i-gate with
+#          minimal requirement of esoteric facilities or
+#          libraries of any kind beyond UNIX system libc.
+#
+# Note: This makefile uses features from GNU make
+
+# -------------------------------------------------------------------- #
+
+# target paths
+VARRUN=		/var/run	# directory for aprx.state and pid-file
+VARLOG=		/var/log/aprx	# directory for direct logfiles
+CFGFILE=	/etc/aprx.conf	# default configuration file
+SBINDIR=	/usr/sbin	# installation path for programs
+MANDIR=		/usr/share/man	# installation path for manual pages
+
+# -------------------------------------------------------------------- #
+
+srcdir = .
+
+
+
+PROF=		# used by 'make profile'
+
+# Compiler and flags
+CC=		gcc
+CFLAGS=		-Wall -g -O2 -pthread
+
+# Linker and flags
+LD=		gcc
+LDFLAGS=	-Wall -g -O2 -z noexecstack $(PROF)
+datarootdir=	${prefix}/share
+
+INSTALL=	$(srcdir)/install-sh
+INSTALL_PROGRAM=$(INSTALL)  -m 755
+INSTALL_DATA=	$(INSTALL)  -m 644
+
+# -------------------------------------------------------------------- #
+# no user serviceable parts below 
+# -------------------------------------------------------------------- #
+
+# strip extra whitespace from paths
+VARRUN:=$(strip $(VARRUN))
+VARLOG:=$(strip $(VARLOG))
+CFGFILE:=$(strip $(CFGFILE))
+SBINDIR:=$(strip $(SBINDIR))
+MANDIR:=$(strip $(MANDIR))
+
+# generate version strings
+
+VERSION    = 2.08
+SVNVERSION = $(shell cat SVNVERSION)
+versionupdate := $(shell if [ "$(PKG_REV)-$(PKG_RELEASE)" != "-" ]; then echo "$(PKG_REV)-$(PKG_RELEASE)" > SVNVERSION; fi)
+
+# VERSION:=$(shell cat VERSION)
+# SVNVERSION_CMD:=$(shell which svnversion)
+# SVNVERSION:=$(shell if ${SVNVERSION_CMD} > /dev/null 2>&1  \&\& test -x ${SVNVERSION_CMD} -a \( -d .svn -o -d ../.svn -o -d ../../.svn \)  ; then ${SVNVERSION_CMD} | tee SVNVERSION ; else cat SVNVERSION; fi)
+
+DATE:=$(shell date +"%Y %B %d")
+RFCDATE:=$(shell date +"%a, %d %b %Y %H:%M:%S %z")
+
+DEFS=	-DAPRXVERSION="\"2.08r$(SVNVERSION)\"" \
+	-DVARRUN="\"$(VARRUN)\"" -DVARLOG="\"$(VARLOG)\"" \
+	-DCFGFILE="\"$(CFGFILE)\""
+
+# program names
+PROGAPRX=	aprx
+PROGSTAT=	$(PROGAPRX)-stat
+
+LIBS=		-lrt  -lutil    -lm -pthread  -lrt
+OBJSAPRX=	aprx.o ttyreader.o ax25.o aprsis.o beacon.o config.o	\
+		netax25.o erlang.o aprxpolls.o telemetry.o igate.o	\
+		cellmalloc.o historydb.o keyhash.o parse_aprs.o		\
+		dupecheck.o  kiss.o interface.o pbuf.o digipeater.o	\
+		valgrind.o filter.o dprsgw.o  crc.o  agwpesocket.o	\
+		netresolver.o timercmp.o #ssl.o
+
+OBJSSTAT=	erlang.o aprx-stat.o aprxpolls.o valgrind.o timercmp.o
+
+# man page sources, will be installed as $(PROGAPRX).8 / $(PROGSTAT).8
+MANAPRX := 	aprx.8
+MANSTAT := 	aprx-stat.8
+
+OBJS=		$(OBJSAPRX) $(OBJSSTAT)
+MAN=		$(MANAPRX) $(MANSTAT)
+
+# -------------------------------------------------------------------- #
+
+.PHONY: 	all
+all:		$(PROGAPRX) $(PROGSTAT) man aprx.conf aprx-complex.conf
+
+valgrind:
+		@echo "Did you do 'make clean' before 'make valgrind' ?"
+		make all CFLAGS="${CFLAGS} -D_FOR_VALGRIND_"
+
+profile:
+		@echo "Did you do 'make clean' before 'make profile' ?"
+		make all PROF="-pg"
+
+
+$(PROGAPRX):	$(OBJSAPRX) VERSION Makefile
+		$(LD) $(LDFLAGS) -o $@ $(OBJSAPRX) $(LIBS)
+
+$(PROGSTAT):	$(OBJSSTAT) VERSION Makefile
+		$(LD) $(LDFLAGS) -o $@ $(OBJSSTAT) $(LIBS)
+
+.PHONY:		man
+man:		$(MAN)
+
+.PHONY:		doc html pdf
+doc:		html pdf
+pdf:		$(MAN:=.pdf)
+html:		$(MAN:=.html)
+
+# -------------------------------------------------------------------- #
+
+.PHONY:	install install-deb
+install: all
+	$(INSTALL_PROGRAM) $(PROGAPRX) $(DESTDIR)$(SBINDIR)/$(PROGAPRX)
+	$(INSTALL_PROGRAM) $(PROGSTAT) $(DESTDIR)$(SBINDIR)/$(PROGSTAT)
+	$(INSTALL_DATA) $(MANAPRX) $(DESTDIR)$(MANDIR)/man8/$(PROGAPRX).8
+	$(INSTALL_DATA) $(MANSTAT) $(DESTDIR)$(MANDIR)/man8/$(PROGSTAT).8
+	if [ ! -f  $(DESTDIR)$(CFGFILE) ] ; then \
+		$(INSTALL_DATA) aprx.conf $(DESTDIR)$(CFGFILE) ; \
+	else true ; fi
+
+.PHONY: clean
+clean:
+	rm -f $(PROGAPRX) $(PROGSTAT)
+	rm -f $(MAN) $(MAN:=.html) $(MAN:=.ps) $(MAN:=.pdf)	\
+	rm -f aprx.conf	 logrotate.aprx
+	rm -f *~ *.o *.d
+
+.PHONY: distclean
+distclean: clean
+	rm -f config.log config.status config.h
+	rm -rf autom4te.cache *.log* doc/.~*#
+
+# -------------------------------------------------------------------- #
+
+%.o: %.c VERSION Makefile
+	$(CC) $(CFLAGS)  $(PROF) $(DEFS) -c $<
+	@$(CC) -MM $(CFLAGS) $(PROF) $(DEFS) $< > $(@:.o=.d)
+
+$(MAN:=.html): %.html : %
+	sh man-to-html.sh $< > $@
+
+$(MAN:=.ps): %.ps : %
+	groff -man $< > $@
+
+$(MAN:=.pdf): %.pdf : %.ps
+	ps2pdf $<
+
+logrotate.aprx $(MAN) aprx-complex.conf aprx.conf: % : %.in VERSION Makefile
+	perl -ne "s{\@DATEVERSION\@}{$(VERSION) - $(DATE)}g;	\
+	          s{\@VARRUN\@}{$(VARRUN)}g;			\
+	          s{\@VARLOG\@}{$(VARLOG)}g;			\
+	          s{\@CFGFILE\@}{$(CFGFILE)}g;			\
+		  print;"					\
+	 < $< > $@
+
+# -------------------------------------------------------------------- #
+
+#
+# Following is for the original author only...
+#
+
+DISTVERSION:=aprx-$(VERSION).svn$(SVNVERSION)
+DISTTARGET:=../$(DISTVERSION)
+RPMVERSION:=$(shell echo "${DISTVERSION}" | sed -e 's/aprx-//')
+.PHONY: dist svnversion-test
+
+svnversion-test:
+	# Special for the source maintainer only..
+	@sh svnversion-test.sh $(SVNVERSION)
+
+dist:	svnversion-test
+	if [ ! -d $(DISTTARGET) ] ; then	\
+		mkdir $(DISTTARGET) ;		\
+	fi
+	tar cf - --exclude-backups --exclude-vcs --exclude=windows --exclude=*.log* --exclude=*.conf . | (cd $(DISTTARGET) ; tar xf -)
+	echo "$(DISTVERSION)" > $(DISTTARGET)/VERSION
+	perl -ne "\$$ver = '$(DISTVERSION)'; 	\
+		  \$$ver =~ tr/0-9.//cd;	\
+		  \$$ver .= '-1';		\
+		  s{\@VERSION\@}{\$$ver}g;	\
+		  s{\@RFCDATE\@}{$(RFCDATE)}g;	\
+		  print;"			\
+		  < $(DISTTARGET)/debian/changelog.release	\
+		  > $(DISTTARGET)/debian/changelog
+	rm -f $(DISTTARGET)/debian/changelog.release
+	rm -f $(DISTTARGET)/aprx.spec
+	perl -ne "s{\@VERSION\@}{$(RPMVERSION)}g;	\
+		  s{\@DATE0\@}{$(DATE0)}g;		\
+		  print;"				\
+		  < $(DISTTARGET)/rpm/aprx.spec.in	\
+		  > $(DISTTARGET)/aprx.spec
+	rm -f $(DISTTARGET)/rpm/aprx.spec.in
+	make -C $(DISTTARGET) distclean
+	cd .. && 	\
+	tar czvf $(DISTVERSION).tar.gz $(DISTVERSION)
+
+# -------------------------------------------------------------------- #
+
+.PHONY: make-deb make-rpm
+
+make-deb:
+	if [ -f debian/changelog.release ] ; then \
+	perl -ne "\$$ver = '$(DISTVERSION)'; 	\
+		  \$$ver =~ tr/0-9.//cd;	\
+		  \$$ver .= '-1';		\
+		  s{\@VERSION\@}{\$$ver}g;	\
+		  s{\@RFCDATE\@}{$(RFCDATE)}g;	\
+		  print;"			\
+		  < debian/changelog.release	\
+		  > debian/changelog ; \
+	fi
+	dpkg-buildpackage -b -us -uc -rfakeroot
+
+make-rpm: # actually just a reminder of how to do it..
+	rpmbuild --target i386 -ta ../$(DISTVERSION).tar.gz 
+
+# -------------------------------------------------------------------- #
+
+# include object depencies if available
+-include $(OBJS:.o=.d)
diff --git a/Makefile.in b/Makefile.in
new file mode 100644
index 0000000..aa33e84
--- /dev/null
+++ b/Makefile.in
@@ -0,0 +1,226 @@
+#
+#  APRX -- 2nd generation receive-only APRS-i-gate with
+#          minimal requirement of esoteric facilities or
+#          libraries of any kind beyond UNIX system libc.
+#
+# Note: This makefile uses features from GNU make
+
+# -------------------------------------------------------------------- #
+
+# target paths
+VARRUN=		/var/run	# directory for aprx.state and pid-file
+VARLOG=		/var/log/aprx	# directory for direct logfiles
+CFGFILE=	@sysconfdir@/aprx.conf	# default configuration file
+SBINDIR=	@sbindir@	# installation path for programs
+MANDIR=		@mandir@	# installation path for manual pages
+
+# -------------------------------------------------------------------- #
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+ at SET_MAKE@
+
+PROF=		# used by 'make profile'
+
+# Compiler and flags
+CC=		@CC@
+CFLAGS=		@CFLAGS@ @CCPTHREAD@
+
+# Linker and flags
+LD=		@CC@
+LDFLAGS=	@LDFLAGS@ $(PROF)
+datarootdir=	@datarootdir@
+
+INSTALL=	$(srcdir)/install-sh
+INSTALL_PROGRAM=$(INSTALL)  -m 755
+INSTALL_DATA=	$(INSTALL)  -m 644
+
+# -------------------------------------------------------------------- #
+# no user serviceable parts below 
+# -------------------------------------------------------------------- #
+
+# strip extra whitespace from paths
+VARRUN:=$(strip $(VARRUN))
+VARLOG:=$(strip $(VARLOG))
+CFGFILE:=$(strip $(CFGFILE))
+SBINDIR:=$(strip $(SBINDIR))
+MANDIR:=$(strip $(MANDIR))
+
+# generate version strings
+
+VERSION    = @VERSION_STRING@
+SVNVERSION = $(shell cat SVNVERSION)
+versionupdate := $(shell if [ "$(PKG_REV)-$(PKG_RELEASE)" != "-" ]; then echo "$(PKG_REV)-$(PKG_RELEASE)" > SVNVERSION; fi)
+
+# VERSION:=$(shell cat VERSION)
+# SVNVERSION_CMD:=$(shell which svnversion)
+# SVNVERSION:=$(shell if ${SVNVERSION_CMD} > /dev/null 2>&1  \&\& test -x ${SVNVERSION_CMD} -a \( -d .svn -o -d ../.svn -o -d ../../.svn \)  ; then ${SVNVERSION_CMD} | tee SVNVERSION ; else cat SVNVERSION; fi)
+
+DATE:=$(shell date +"%Y %B %d")
+RFCDATE:=$(shell date +"%a, %d %b %Y %H:%M:%S %z")
+
+DEFS=	-DAPRXVERSION="\"@VERSION_STRING at r$(SVNVERSION)\"" \
+	-DVARRUN="\"$(VARRUN)\"" -DVARLOG="\"$(VARLOG)\"" \
+	-DCFGFILE="\"$(CFGFILE)\""
+
+# program names
+PROGAPRX=	aprx
+PROGSTAT=	$(PROGAPRX)-stat
+
+LIBS=		@LIBS@ @LIBRESOLV@ @LIBSOCKET@  @LIBM@ @LIBPTHREAD@ @LIBGETADDRINFO@ @LIBRT@
+OBJSAPRX=	aprx.o ttyreader.o ax25.o aprsis.o beacon.o config.o	\
+		netax25.o erlang.o aprxpolls.o telemetry.o igate.o	\
+		cellmalloc.o historydb.o keyhash.o parse_aprs.o		\
+		dupecheck.o  kiss.o interface.o pbuf.o digipeater.o	\
+		valgrind.o filter.o dprsgw.o  crc.o  agwpesocket.o	\
+		netresolver.o timercmp.o #ssl.o
+
+OBJSSTAT=	erlang.o aprx-stat.o aprxpolls.o valgrind.o timercmp.o
+
+# man page sources, will be installed as $(PROGAPRX).8 / $(PROGSTAT).8
+MANAPRX := 	aprx.8
+MANSTAT := 	aprx-stat.8
+
+OBJS=		$(OBJSAPRX) $(OBJSSTAT)
+MAN=		$(MANAPRX) $(MANSTAT)
+
+# -------------------------------------------------------------------- #
+
+.PHONY: 	all
+all:		$(PROGAPRX) $(PROGSTAT) man aprx.conf aprx-complex.conf
+
+valgrind:
+		@echo "Did you do 'make clean' before 'make valgrind' ?"
+		make all CFLAGS="${CFLAGS} -D_FOR_VALGRIND_"
+
+profile:
+		@echo "Did you do 'make clean' before 'make profile' ?"
+		make all PROF="-pg"
+
+
+$(PROGAPRX):	$(OBJSAPRX) VERSION Makefile
+		$(LD) $(LDFLAGS) -o $@ $(OBJSAPRX) $(LIBS)
+
+$(PROGSTAT):	$(OBJSSTAT) VERSION Makefile
+		$(LD) $(LDFLAGS) -o $@ $(OBJSSTAT) $(LIBS)
+
+.PHONY:		man
+man:		$(MAN)
+
+.PHONY:		doc html pdf
+doc:		html pdf
+pdf:		$(MAN:=.pdf)
+html:		$(MAN:=.html)
+
+# -------------------------------------------------------------------- #
+
+.PHONY:	install install-deb
+install: all
+	$(INSTALL_PROGRAM) $(PROGAPRX) $(DESTDIR)$(SBINDIR)/$(PROGAPRX)
+	$(INSTALL_PROGRAM) $(PROGSTAT) $(DESTDIR)$(SBINDIR)/$(PROGSTAT)
+	$(INSTALL_DATA) $(MANAPRX) $(DESTDIR)$(MANDIR)/man8/$(PROGAPRX).8
+	$(INSTALL_DATA) $(MANSTAT) $(DESTDIR)$(MANDIR)/man8/$(PROGSTAT).8
+	if [ ! -f  $(DESTDIR)$(CFGFILE) ] ; then \
+		$(INSTALL_DATA) aprx.conf $(DESTDIR)$(CFGFILE) ; \
+	else true ; fi
+
+.PHONY: clean
+clean:
+	rm -f $(PROGAPRX) $(PROGSTAT)
+	rm -f $(MAN) $(MAN:=.html) $(MAN:=.ps) $(MAN:=.pdf)	\
+	rm -f aprx.conf	 logrotate.aprx
+	rm -f *~ *.o *.d
+
+.PHONY: distclean
+distclean: clean
+	rm -f config.log config.status config.h
+	rm -rf autom4te.cache *.log* doc/.~*#
+
+# -------------------------------------------------------------------- #
+
+%.o: %.c VERSION Makefile
+	$(CC) $(CFLAGS)  $(PROF) $(DEFS) -c $<
+	@$(CC) -MM $(CFLAGS) $(PROF) $(DEFS) $< > $(@:.o=.d)
+
+$(MAN:=.html): %.html : %
+	sh man-to-html.sh $< > $@
+
+$(MAN:=.ps): %.ps : %
+	groff -man $< > $@
+
+$(MAN:=.pdf): %.pdf : %.ps
+	ps2pdf $<
+
+logrotate.aprx $(MAN) aprx-complex.conf aprx.conf: % : %.in VERSION Makefile
+	perl -ne "s{\@DATEVERSION\@}{$(VERSION) - $(DATE)}g;	\
+	          s{\@VARRUN\@}{$(VARRUN)}g;			\
+	          s{\@VARLOG\@}{$(VARLOG)}g;			\
+	          s{\@CFGFILE\@}{$(CFGFILE)}g;			\
+		  print;"					\
+	 < $< > $@
+
+# -------------------------------------------------------------------- #
+
+#
+# Following is for the original author only...
+#
+
+DISTVERSION:=aprx-$(VERSION).svn$(SVNVERSION)
+DISTTARGET:=../$(DISTVERSION)
+RPMVERSION:=$(shell echo "${DISTVERSION}" | sed -e 's/aprx-//')
+.PHONY: dist svnversion-test
+
+svnversion-test:
+	# Special for the source maintainer only..
+	@sh svnversion-test.sh $(SVNVERSION)
+
+dist:	svnversion-test
+	if [ ! -d $(DISTTARGET) ] ; then	\
+		mkdir $(DISTTARGET) ;		\
+	fi
+	tar cf - --exclude-backups --exclude-vcs --exclude=windows --exclude=*.log* --exclude=*.conf . | (cd $(DISTTARGET) ; tar xf -)
+	echo "$(DISTVERSION)" > $(DISTTARGET)/VERSION
+	perl -ne "\$$ver = '$(DISTVERSION)'; 	\
+		  \$$ver =~ tr/0-9.//cd;	\
+		  \$$ver .= '-1';		\
+		  s{\@VERSION\@}{\$$ver}g;	\
+		  s{\@RFCDATE\@}{$(RFCDATE)}g;	\
+		  print;"			\
+		  < $(DISTTARGET)/debian/changelog.release	\
+		  > $(DISTTARGET)/debian/changelog
+	rm -f $(DISTTARGET)/debian/changelog.release
+	rm -f $(DISTTARGET)/aprx.spec
+	perl -ne "s{\@VERSION\@}{$(RPMVERSION)}g;	\
+		  s{\@DATE0\@}{$(DATE0)}g;		\
+		  print;"				\
+		  < $(DISTTARGET)/rpm/aprx.spec.in	\
+		  > $(DISTTARGET)/aprx.spec
+	rm -f $(DISTTARGET)/rpm/aprx.spec.in
+	make -C $(DISTTARGET) distclean
+	cd .. && 	\
+	tar czvf $(DISTVERSION).tar.gz $(DISTVERSION)
+
+# -------------------------------------------------------------------- #
+
+.PHONY: make-deb make-rpm
+
+make-deb:
+	if [ -f debian/changelog.release ] ; then \
+	perl -ne "\$$ver = '$(DISTVERSION)'; 	\
+		  \$$ver =~ tr/0-9.//cd;	\
+		  \$$ver .= '-1';		\
+		  s{\@VERSION\@}{\$$ver}g;	\
+		  s{\@RFCDATE\@}{$(RFCDATE)}g;	\
+		  print;"			\
+		  < debian/changelog.release	\
+		  > debian/changelog ; \
+	fi
+	dpkg-buildpackage -b -us -uc -rfakeroot
+
+make-rpm: # actually just a reminder of how to do it..
+	rpmbuild --target i386 -ta ../$(DISTVERSION).tar.gz 
+
+# -------------------------------------------------------------------- #
+
+# include object depencies if available
+-include $(OBJS:.o=.d)
diff --git a/PROTOCOLS b/PROTOCOLS
new file mode 100644
index 0000000..51ea167
--- /dev/null
+++ b/PROTOCOLS
@@ -0,0 +1,258 @@
+
+			Protocols spoken by APRX
+
+There are a few protocols spoken by the APRX:
+
+      1) APRS-IS interchange
+
+      2) Proprietary monitoring via shared memory segment
+
+      3) APRX-APRXC linkage
+
+
+APRS-IS interchange
+
+	This protocol is fairly simple.
+
+	    http://wiki.ham.fi/IGate_properties
+
+
+
+			APRS iGate Common Properties
+
+	Communication is over TCP streams of text lines terminating
+        at CR+LF pair.    No CR or LF is permitted inside the text
+        line, however.
+
+	APRS-IS user authentication:
+
+	    user USERID pass PASSCODE vers VERS STRINGS  \
+	    	  filter FILTER STRINGS
+
+        where 'USERID' is uppercase callsign plus possible "-SSID" tail.
+	The 'PASSCODE' is calculated with semi-secret algorithm out of
+	the uppercase callsign characters without '-' and SSID tail.
+	The 'VERS STRINGS' are free to be anything, except string 'filter',
+	and the 'FILTER STRINGS' are explained in document:
+	   http://www.aprs-is.net/ServerCmds.htm
+	   http://www.aprs-is.net/javAPRSSrvr/javaprsfilter.htm
+
+
+	Messages:
+
+	Lines beginning with '#' character are line noise (usually
+	something that the server replies..)
+
+
+	After successfull login, communication carries "TNC2" format
+	APRS messages.  Namely text encoding of AX.25 UI frames in
+	what became known as "TNC2 monitor style":
+
+	    SOURCE>DESTIN:payload
+	    SOURCE>DESTIN,VIA,VIA:payload
+
+	The SOURCE, DESTIN, and VIA fields are AX.25 address fields,
+        and have "-SSID" value annexed if the SSID is not zero.
+	Also in VIA-fields, if the "HAS BEEN DIGIPEATED" bit is set
+	(AX.25 v2 protocol feature) a star ('*') character is appended.
+        VIA-fields are separated by comma (',') from DESTIN, and each
+        other.
+
+	A double-colon (':') separates address data from payload.
+	The payload is passed _AS_IS_ without altering any message
+	content bytes, however ending at first CR or LF character
+	encountered in the packet.
+
+
+			APRS-RX iGate Basic Rules
+
+
+	Packets with source addresses:  NOCALL*, N0CALL*, WIDE*, TRACE*,
+        TCP*, are dropped and not relayed to APRS-IS.
+
+	Packets with VIA addresses: RFONLY, NOGATE, TCPIP, TCPXX are not
+        to be relayed to APRS-IS.  Sometimes the VIA fields have '*' on
+	their tails.
+
+	Packets with payload beginning with character '?' are not to be
+	relayed to APRS-IS.
+
+	Packets with payload beginning with character '}' are so called
+	3rd-party frames, and they are to be re-processed starting from
+	character following the '}' character.
+
+
+	When packet is sent to APRS-IS, the address gets appended
+	either a "q-construct", or equivalent:
+
+                ,qAR,gatecallsign
+		,gatecallsign,I
+
+	The "qAR" et.al. are explained at: http://www.aprs-is.net/q.aspx
+
+
+			APRS-TX iGate has additional rules:
+
+	All rules:
+	    http://www.aprs-is.net/IGateDetails.aspx
+
+	Specifically forbidden to relay to RF is "qAX", maybe some others too.
+	(See: http://www.aprs-is.net/q.aspx)
+
+	If the packet VIA-path received from APRS-IS contains TCPXX,
+	NOGATE, RFONLY, then the packet is to be dropped, and not relayed
+	to radio network.  (Note: TCPIP is permitted.)
+
+	Packets relayed from APRS-IS to radio must use so called 3rd-party
+	format.  Signature is '}' character.
+
+	Rules on re-sending recently heard packets are a bit more complex,
+	and are covered adequately in above referenced document.
+
+
+
+
+
+Proprietary monitoring mechanism
+
+	There is a tool for monitoring channel activity.
+	See  aprx-stat(8)
+
+
+
+APRX-APRXC linkage
+
+	(For a feature in planning...)
+
+
+
+	With introduction of APRX-Cluster (APRXC) mode, multiple APRX
+	instances are used as remote attachments to TNCs, and one central
+	system runs more complicated business logic deciding which messages
+	to pass where, what beacons to send, etc.  The central business-logic
+	server runs also connection with APRS-IS, and all things that it
+	implies.
+
+	Actually the APRX-Cluster-Server is APRX program version with
+	embedded Perl for business logic.  Some very flexibly configurable
+	APRS digi software has practical limitations of what the config
+	can do.
+
+	Environmental pre-requisite: APRXC and APRX nodes are in NTP sync!
+
+	The Protocol:
+
+	Communication is of text lines over TCP stream, they are canonic
+	Internet format ending with CRLF pairs.  However no embedded CR,
+	nor LF is permitted.
+
+	(detail under study: UDP frames, or SCTP SEQPACKET ?)
+
+	The protocol is bidirectional, and is intended to be connected from
+	edge systems to cluster server.  Upon receiving a connection the
+	server sends a greeting containing time-varying string.  This will
+	be used by the connecting party to do authentication in APOP-style.
+
+	The timestamps in this protocol are "U" format:
+	    sprintf(timestamp, "U%ld", (long)time(NULL));
+	which is to say, integer presentation of UNIX internal time in whole
+	seconds.
+
+
+	In following ">>" mean data sent by central system and received by
+	the edge, whereas "<<" means data sent by edge system to central
+	system.
+
+		<< (connection formation from edge to the server)
+
+		>> <timestamp> Hello <++counter> some greeting string
+
+		<< <timestamp> LOGIN <userid> <authenticator>
+
+		>> <timestamp> OK
+
+		<< <timestamp> SERVICE <ifname> <speed> { RX | TX <areaspecifiers> }
+
+		>> <timestamp> OK
+
+	The <authenticator> is formed by hex (lower case) encoding of 16 byte
+	MD5() checksum over the whole greeting string (sans CRLF), plus userid,
+	plus shared plaintext password.
+
+	Replies can also be "FAIL", if "LOGIN" or "SERVICE" is somehow bad.
+
+	The  <ifname> is local interface name in given node.  The <speed> is
+	radio channel bitrate.  The <areaspecifiers> are filter statements
+	in APRS-IS style.
+
+
+	The edge system compares every received timestamp (aside of the
+	login-sequence above) with its internal time reference, and if
+	the time varies more than 3 seconds from expected, the received
+	frame is discarded.
+
+	If APRXC Server notes that the time stamp it received is more than
+	3 seconds in future or in past, it rejects the message.
+	(This does not apply to ERLANG verbs.)
+
+	The APRXC server acknowledges every received message with:
+
+		>> <timestamp> OK
+
+	Link idle jabber is by done by both systems by sending "TIME" verbs.
+	They are sent every 20 seconds since previous transmit of anything
+	on the connection, and if either notes that link has not received
+	anything for 120 seconds, the link is considered to be down, closed,
+	and re-initiated.
+
+		<< <timestamp> TIME
+		>> <timestamp> OK
+
+		>> <timestamp> TIME
+		<< <timestamp> OK
+
+	Either system can initiate the "heartbeat", sometimes even both
+	may send the TIME verbs at the same time, but both are not required
+	to do so.
+
+
+	The edge system sends received APRS frames to the central system
+	in "TNC2" format in a command:
+
+		<< <timestamp> APRS <ifname> <TNC2frame>
+
+	The <TNC2frame> is the data received from radio as is without any
+	APRS-IS -type additional parameters inserted into address field.
+
+
+	When central system wants that a TX capable edge system transmits
+	something, it sends following message:
+
+		>> <timestamp> APRSTX <ifname> <TNC2frame>
+
+	the edge system will transmit the frame as is (the APRXC will format
+	the message to be ready for transmit.)  If the edge system can not
+	transmit on given interface, it reports:
+
+		<< <timestamp> FAILTX <ifname>
+
+	which results from APRXC and/or APRX software bug listing/flagging
+	tx-interface to be non-tx-interface..  Otherwise it acks the packet
+	with "OK" message.
+
+		<< <timestamp> OK
+
+	Edge systems send 1 minute ERLANG data to central system with verb:
+
+		<< <timestamp> ERLANG <ifname>  <rxbytes> <rxpackets> \
+		              <txbytes> <txpackets> [ <rxerlang> <txerlang> ]
+		>> <timestamp> OK
+
+	(Long line is folded in UNIX-style in this documentation.
+	 Data is ACKed with OK.)
+
+	The APRXC collates these to 1 minute, 10 minute and 60 minute datasets
+	of given timestamp.  The measured erlang-values are optional, if edge
+        system can produce truthfull ones.
+
+	The time-series collation database is persistent, for example RRD.
diff --git a/README b/README
new file mode 100644
index 0000000..8c130bc
--- /dev/null
+++ b/README
@@ -0,0 +1,86 @@
+
+		APRX    v2.08
+
+A multitalented APRS / DPRS / APRSIS "i-gate" with following properties:
+
+   Config file (-f option) default is:  /etc/aprx.conf
+   Other runtime options are: -v,  -d,  -h/-?  (verbout, debug and help)
+
+   - Rx-IGate functionality works correctly
+   - Tx-IGate functionality works correctly
+
+   - Can do APRS New-N and generic AX.25 node digipeater functionality
+     with transmitters
+
+   - Has same-channel Viscous Digipeater functionality to not to digipeat
+     at all, if during initial wait period the packet is heard again.
+
+   - Has cross-interface Viscous Digipeater functionality to not to digipeat,
+     if during the initial wait period the packet is heard on destination
+     interface at least once, and at least once from other sources.
+
+   - Can receive data from multiple receivers/modems on local machine
+     serial ports, both classical and USB.
+
+   - Can receive data from remote TCP stream connectable serial ports
+     over the internet.
+
+   - Understands on serial ports (local and remote TCP ones):
+       - several KISS protocol variants, checksummed variants preferred
+       - TNC2 debug style text (Rx-iGate receive only.)
+       - D-STAR data side-channel "D-PRS"
+
+   - Connects with one  callsign-ssid  pair to APRS-IS core for all
+     received radio ports (the "mycall" parameter), but reports
+     receiving radio port at each Rx-iGated packet
+
+   - Knows that messages with following tokens in VIA fields of the
+     path are not to be relayed into network:
+              RFONLY, NOGATE, TCPIP, TCPXX
+
+   - Knows that following source address prefixes are bogus and thus
+     to be junked at Rx-iGate:
+              WIDE, RELAY, TRACE, TCPIP, TCPXX, NOCALL, N0CALL
+     (Actually these are string prefixes, so any WIDE*-* will block, etc.)
+
+   - Has integrated D-PRS -> APRS/APRSIS Rx-iGate.
+     Can even do D-PRS -> APRS RF conversion.
+     This is experimental quality for "GPS" packets, the "GPS-A" is OK.
+
+   - Does not require machine to have AX.25 protocol support internally!
+
+   - On Linux machine with kernel internal AX.25 protocol support, does
+     listen on internal AX.25 network in promiscuous form, and requires
+     to be running as root to do that.   Does not fail to start in case
+     the port fails to open (running as non-root.)
+
+   - Built-in "erlang-monitor" actually counts bytes per time interval
+     (1 min, 10 min, and 20 min)  on each receiving interface, including
+     all that feed internal AX.25 network.
+
+   - Telemetry reported erlang data is sent out every 20 minutes, and
+     contains summarized data from 10 minute round-robin memory arrays.
+     These are _not_ sent at exact 10 minutes of wall-clock, but exact
+     20 minutes from previous telemetry reporting, and first one is sent
+     20 minutes after program start.
+
+   - Telemetry reported erlang data can be sent also over APRS radio
+     port, but only for ports with valid AX.25 callsigns. See aprx-manual.pdf
+
+   - The netbeacons are distributed timewise more evenly around the interval,
+     and even the interval length is varied at random in between 20 and 30
+     minutes.  Number of netbeacons are unlimited, but their minimum transmit
+     interval is 3 seconds making the amount of beacons sendable in 20 minutes
+     to be: 20*60/3 = 400.  All will be sent, but the cycle will just take
+     longer.
+
+   - Source code is at SVN repository:   http://repo.ham.fi/svn/aprx
+   - A Wiki page of this package:        http://wiki.ham.fi/Aprx.en
+   - A google-group for Aprx:   http://groups.google.com/group/aprx-software
+
+   - This program is also compilable as "EMBEDDED" target without
+     any statistics buffer required at the system disk (or RAM-disk).
+     See the INSTALL file.
+
+
+by Matti Aarnio - OH2MQK - oh2mqk-at-sral-fi - 2007-2014
diff --git a/ROADMAP b/ROADMAP
new file mode 100644
index 0000000..95f70c4
--- /dev/null
+++ b/ROADMAP
@@ -0,0 +1,26 @@
+		Aprx Roadmap and Future Directions
+
+
+Version 1
+    - APRS Rx-only iGate				- Complete, working
+    - channel activity monitoring and telemetry		- Complete, working
+
+
+Version 2
+    - Digipeater					- Working
+      - Analyze and detect station distance             - Working
+    - Radio beacons					- Working
+    - Bidirection (Rx/Tx) APRS iGate			- Working
+    - DPRS->APRS GW	       				- Working
+
+Version 2+
+
+    - Port to ucLinux	       				- Planned (pthread OK)
+
+    - Port to Windows
+
+    - Automated coverage statistics analyzer, and
+      reporting it via digi node identity beacons.
+            "ALOHA circles"
+
+    - Automated coverage plotting
diff --git a/SVNVERSION b/SVNVERSION
new file mode 100644
index 0000000..651c401
--- /dev/null
+++ b/SVNVERSION
@@ -0,0 +1 @@
+593
diff --git a/TIMESTAMP-AT-APRSIS b/TIMESTAMP-AT-APRSIS
new file mode 100644
index 0000000..9350b50
--- /dev/null
+++ b/TIMESTAMP-AT-APRSIS
@@ -0,0 +1,264 @@
+
+		A PROPOSAL FOR TIMESTAMPS AT APRSIS
+
+It can be taken as granted that today at least server systems are
+running with NTP service keeping their system clocks within a few
+milliseconds of UTC time.
+
+Systems utilized as APRS IGATE should be able to utilize NTP service
+as well, and keep their internal time well disciplined.
+
+SimpleNTP clients are available even for embedded system code bases
+making all kinds of internet capable systems able to have high quality
+time management.
+
+Timestamps are added on APRS text lines as prefixes of 8 characters.
+Eighth character is always ':'.  Details are in "ENCODING" part.
+
+
+
+		TRANSPORT COMPATIBILITY
+
+As APRSIS clients would not know at first what to do with the timestamps,
+a transport compatibility must be introduced:
+
+	* APRSIS server announces on its connection message that it
+	  is TIMESTAMP capable, and clients MUST NOT send timestamps
+	  to APRSIS server without that capability
+
+		# telnet aprsisserver 14580
+		Connected to aprsisserver
+		Escape character is '^]'.
+		# javAPRSSrvr 4.0b1 [APRSIS TIMESTAMP]
+
+	  Capability announcements follow style of IMAPv4 protocol,
+	  where capability tokens are in square brackets, and are
+	  separated by space character.
+
+	* If a client does not send timestamped data to APRSIS, APRSIS
+	  server adds the timestamp upon receiving the line.
+
+	  APRSIS server does this conditional timestamping also for packets
+	  received via UDP for initial deployment compatibility.
+
+	* An APRSIS server connected to upstream with TCP is a client,
+	  and must strip received/internal timestamps from packets sent to
+	  upstream, if the upstream does not announce TIMESTAMP capability.
+
+	  If upstream does not send timestamps for any reason, APRSIS server
+	  adds it locally.
+
+	* A client that has not announced timestamp awareness does
+	  not receive timestamps from APRSIS, and furthermore, APRSIS is
+	  filtering all packets with maximum age of 15 seconds.
+
+	* A client that sends to APRSIS a text line with recognized
+	  timestamp will get also timestampped lines sent up to itself.
+
+	  No maximum age filtering is applied to clients that are timestamp
+	  capable, and therefore those clients must be able to do timestamp
+	  age analysis themselves.
+
+	  Special timestamp-line  "AAAAAAA:\n"  tells APRSIS server, that
+	  the client is APRSIS aware, and while it has nothing to actually
+          send to APRSIS at this time, it does want all data sent to it to
+	  contain timestamps.
+
+
+APRSIS server software needs a configuration parameter
+
+       udptimestamps = <boolean>
+
+which defaults to "false".  When the value is "false" the software will
+not send timestampped data to core peer machines over UDP.
+
+
+There probably is no need for an Adjunct Filter that knows about timestamps.
+
+
+
+		INITIAL DEPLOYMENT OF TIMESTAMP CAPABILITY
+
+Because APRSIS core uses UDP protocol, and thus can not be aware of remote
+node capabilities, the deployment of timestamp aware APRSIS servers at
+APRSIS core has two phases:
+
+	1) Software has configuration parameter   "udptimestamps"
+	   non defined or defined as "false".
+
+	2) After all core APRSIS systems are running timestamp
+	   aware software, the configuration parameter can be
+	   changed to   "udptimestamps = true"  and APRSIS server
+	   starts to send timestamped packets over UDP to all of
+           its peers.  -->  peer machines do not need to locally
+	   add timestamps at reception time.
+
+
+Everybody else can take TIMESTAMP capable system into use at any time
+that is convenient to them, unless communication involves UDP.
+
+
+		ENCODING
+
+Use NTP timestamp (see RFC 2030) based time abstraction:
+
+   Since NTP timestamps are cherished data and, in fact, represent the
+   main product of the protocol, a special timestamp format has been
+   established. NTP timestamps are represented as a 64-bit unsigned
+   fixed-point number, in seconds relative to 0h on 1 January 1900. The
+   integer part is in the first 32 bits and the fraction part in the
+   last 32 bits. In the fraction part, the non-significant low order can
+   be set to 0.
+
+Take highest 32+10 bits of the timestamp, and encode those in BASE64
+characters, most significant character first.  This produces 7 encoded
+characters with time resolution of 1/1024 seconds.  With 6 encoded
+characters the time resolution would be 1/16, which is felt to be
+too coarse.
+
+A hex encoded byte sequence of NTP timestamp looks like this:
+
+	cf b4 ff a4 b5 a8 8b f9
+
+it represent timestamp 3484745636.709603071 (2010/06/05 19:53:56)
+and encoded timestamp value is: 
+
+	z7T/pLW
+
+
+The APRSIS passes around APRS messages as lines of text:
+
+	OH2JCQ>APX195,TCPIP*,qAC,T2FINLAND:=6013.63N/02445.59E-Jani
+
+Adding 7 character encoded timestamp + ":" character in the beginning
+of a line would make this:
+
+	z7T/pLW:OH2JCQ>APX195,TCPIP*,qAC,T2FINLAND:=6013.63N/02445.59E-Jani
+
+There 8th character is always ':', and preceding 7 bytes present _current_
+timestamp at 1/1024 second resolution.
+
+Timestamp value "AAAAAAA:" is "no timestamp" (decodes as time 0.0) and
+a client can use it to tell that it has no idea of timestamp, but it
+wants to receive timestamped data.  An APRSIS data collector can enable
+timestamp reception by sending line: "AAAAAAA:\n".
+
+
+Packets with timestamps outside -1 to +N seconds limits are sign that
+communication is retrying too much, or otherwise delayed, and such packets
+are to be discarded.  (Services like APRSFI, FINDU et.al. may want even
+older packets!)
+
+To be compatible with NTP Era roll-over, the timestamp must really be
+treated as 64-bit unsigned long integer, and compared with twos complement
+arithmetic using overflows.
+
+
+		TIMESTAMP ENCODING CODE EXAMPLE
+
+Example UNIX system C code to produce and encode a timestamp:
+
+  // Time Base Conversion Macros
+  //
+  // The NTP timebase is 00:00 Jan 1 1900.  The local
+  // time base is 00:00 Jan 1 1970.  Convert between
+  // these two by added or substracting 70 years
+  // worth of time.  Note that 17 of these years were
+  // leap years.
+  
+  #define TIME_BASEDIFF           (((70U*365U + 17U) * 24U*3600U))
+  #define TIME_LOCAL_TO_NTP(t)    ((t)+TIME_BASEDIFF)
+  
+  void unix_tv_to_ntp(struct timeval *tv, uint64_t *ntp) {
+    // Reciprocal conversion of tv_usec to fractional NTP seconds
+    // Multiply tv_usec by  ((2^64)/1_000_000) / (2^32)
+    uint64_t fract =  18446744073709ULL * (uint32_t)(tv->tv_usec);
+    // Scale it back by 32 bit positions
+    fract >>= 32;
+    // Place seconds on upper 32 bits
+    fract += ((uint64_t)TIME_LOCAL_TO_NTP(tv->tv_sec)) << 32;
+    // Deliver time to caller
+    *ntp  = fract;
+  }
+
+  static const char *BASE64EncodingDictionary =
+    "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+    "abcdefghijklmnopqrstuvwxyz"
+    "0123456789"
+    "+/";
+  
+  void encode_aprsis_ntptimestamp(uint64_t ntptime, char timestamp[8])
+  {
+  	int i;
+  
+  	ntptime >>= 22; // scale to 1/1024 seconds
+  	for (i = 6; i >= 0; --i) {
+  	    int n = (((int)ntptime) & 0x3F); // lowest 6 bits
+  	    // printf("  [n=%d]\n", n);
+  	    ntptime >>= 6;
+  	    timestamp[i] = BASE64EncodingDictionary[n];
+  	}
+  	timestamp[7] = 0;
+  }
+  
+  static const int8_t BASE64DecodingDictionary[128] =
+    { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+      -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+      -1, -1, -1, -1,  // ' ', '!', '"', '#'
+      -1, -1, -1, -1,  // '$', '%', '&'', '\''
+      -1, -1, -1, 62,  // '(', ')', '*', '+',
+      -1, -1, -1, 63,  // ',', '-', '.', '/'
+      52, 53, 54, 55, 56, 57, 58, 59, 60, 61, // '0' .. '9'
+      -1, -1, -1, -1, -1, -1, // ':', ';', '<', '=', '>', '?'
+      -1,  0,  1,  2,  3,  4,  5,  6, // '@', 'A' .. 'G'
+       7,  8,  9, 10, 11, 12, 13, 14, // 'H' .. 'O'
+      15, 16, 17, 18, 19, 20, 21, 22, // 'P' .. 'W'
+      23, 24, 25, -1, -1, -1, -1, -1, // 'X'..'Z', '[', '\\', ']', '^', '_'
+      -1, 26, 27, 28, 29, 30, 31, 32, // '`', 'a' .. 'g'
+      33, 34, 35, 36, 37, 38, 39, 40, // 'h' .. 'o'
+      41, 42, 43, 44, 45, 46, 47, 48, // 'p' .. 'w'
+      49, 50, 51, -1, -1, -1, -1, -1 }; // 'x'..'z', ...
+  
+  
+  int decode_aprsis_ntptimestamp(char timestamp[8], uint64_t *ntptimep)
+  {
+  	uint64_t ntptime = 0;
+  
+  	int i, n;
+  	char c;
+  
+  	for (i = 0; i < 7; ++i) {
+  	  c = timestamp[i];
+  	  if (c <= 0 || c > 127) return -1; // BARF!
+  	  n = BASE64DecodingDictionary[(int)c];
+  	  // printf("  [n=%d]\n", n);
+  	  if (n < 0) {
+  	    // Should not happen!
+  	    return -1; // Decode fail!
+  	  }
+  
+  	  ntptime <<= 6;
+  	  ntptime |= n;
+  	}
+  	ntptime <<= 22;
+  	*ntptimep = ntptime;
+  	return 0; // Decode OK
+  }
+
+
+You may choose to produce timestamps with coarser resolution than 1/1024
+seconds. Let least significant bits to be zero.  The about 1 millisecond
+resolution is a compromise in between 1 second, and sub-nanosecond
+resolutions.
+
+A heavy producer and consumer of timestamps, like an APRSIS server, may have
+single thread waking up 10 times per second and producing a new timestamp
+object every time, and overwriting global storage pointer to "current" one.
+For access there is no need to do any sort of synchronizations.
+Then received messages just copy that timestamp if necessary, and not run
+its production by themselves.
+
+Note: There is no need to convert NTP timestamps to local time in this
+application.  It is quite enough that system receiving NTP timestamps
+does regularly create current reference NTP timestamp to be able to
+determine offset from received timestamp to reference time.
diff --git a/TODO b/TODO
new file mode 100644
index 0000000..81f5824
--- /dev/null
+++ b/TODO
@@ -0,0 +1,109 @@
+				 APRX   2.08
+
+				TODO / Wishlist
+
+- "[Aprx] Re: WIDE2-2/NOGATE - trace not working?"
+
+- "[Aprx] Re: Bi-Directional Cross-band Digipeater"
+  Probably heard sources accounting bucket initializing as zero,
+  which was fixed recently.
+
+
+- SSL mode to talk to APRS-IS. (Aprsc speaks SSL very efficiently.)
+
+- SCTP communication protocol to APRS-IS matching Aprsc's code
+
+- Embedded Perl and/or Python?  That would allow folks to cook up
+  arbitrary action scripts for who knows what purposes...
+
+- Socket API to send/receive/monitor packets?
+  To get Protocol Buffer or JSON/BSON wrapped datasets of parsed frame
+  including lat/lon of the packet, type info, etc. ?
+   - BPQ32 protocol?
+   - AWGPE protocol?
+   - Copy-of-APRSIS ?  (okay(ish) for monitor + transmit to APRS-IS..)
+
+- Message destined to $MYCALL to be logged at at syslog INFO level,
+  and acknowledged(?)
+
+- Tx-IGate filter rules (interface.c)
+  Tx-IGate is lacking following things, but it is already doing most
+  important ones ('recipient heard recently in my service area')
+   - figure out (at parse_aprs() ?) the number of hops a packet has
+     traversed so far, and log that on historydb (for recipient "locality"
+     analysis)
+   - test that message recipients known coordinates are within
+     "my service area" 
+      -->  separate filter from adjunct-style areas or distances?
+   - for position-less packets, send at first a position packet for
+     same source callsign, if available
+
+
+- Digipeater behaviour on "requested wideness exceeds allowed
+  max limit" and this is a directly heard packet:
+   - now mark all H-bits set
+   - ADDITION: inject transmitter callsign into first VIA slot.
+
+
+- Digipeating details of non-APRS UI protocols?  Some way to handle
+  "WIDEn-N" on selected PIDs?
+- OpenTRAC support ?  (UI, PID=0x77)
+  - Yes, on DIGIPEATER ONLY - what about WIDEn-N ? Y/N ?
+
+- Windows port?
+
+- Colorize debug printout (or make another tool to colorize aprx-rf.log)
+    - rx-packets green (or blue), tx-packets red
+    - port names/callsigns bolded, same with packet source callsigns
+
+- Use internal APRS packet parser to validate beacon configurations.
+  This should be able to flag bad input on RAW beacon data.
+
+- Calculate and note APRS DXes (like digi_ned does) ?
+- Calculate ALOHA range, and publish it?
+
+- Embedded SNTP client?
+  (Reads NTP time from 127.0.0.1:123 - or configured external source)
+
+  Supports Aprx-Aprx clustered protocol where all messages are equipped
+  with NTP timestamp and if in receiver's opinnion the time is too far off,
+  the network delays have been excessive and message is discarded.
+
+  This SNTP client _does_ _not_ adjust host system clock, only tracks
+  difference of it against a high(er)-quality NTP service elsewere.
+  The difference and drift parameters are used to convert current system
+  gettimeofday() result to NTP timestamp within the code, and to determine
+  how old something is, a NTP timestamp is compared against "current time."
+
+  If Aprx System has no time at all, one SNTP probe is made to determine
+  "initial system time".
+
+  This SNTP client will have two time management states:
+    - "current time"
+    - "new time"
+  If SNTP probes return times that agree with "current time",
+  the "new time" accumulator is discarded, and possible minor
+  drift sync is done on "current time."
+
+  If SNTP probes return times that do not agree with "current time", then
+  a "new time" accumulator is used to track the time. If the "new time" is
+  consistently tracked for 5 samples, "new time" becomes "current time".
+
+
+BoB:
+	Shucks, it would sure be nice if EVERY DIGIPEATER also had a
+	little smarts and could also report on its own RSSI.
+
+	That would give some people a clue what the digipeater is
+	hearing on its input.  In its 10 minute beacon it could report:
+
+		"176RX, 109TX, 243 busy"
+
+	ON a ten minute basis (total 600 1 sec slots) this tells us that
+	176 packets were decoded at this site, 109 were elegible for
+	further digipeating, and another 243 seconds the channel was
+	busy with other collisions and non decodable traffic.  Leaving
+	72 secnds the channel was clear.
+
+
+by Matti Aarnio - OH2MQK - oh2mqk-at-sral-fi - 2007-2014
diff --git a/VER b/VER
new file mode 100644
index 0000000..135b797
--- /dev/null
+++ b/VER
@@ -0,0 +1 @@
+542
diff --git a/VERSION b/VERSION
new file mode 100644
index 0000000..35e5e7b
--- /dev/null
+++ b/VERSION
@@ -0,0 +1 @@
+aprx-2.08.svn593
diff --git a/ViscousDigipeater.README b/ViscousDigipeater.README
new file mode 100644
index 0000000..bd04668
--- /dev/null
+++ b/ViscousDigipeater.README
@@ -0,0 +1,60 @@
+
+		    Viscous Digipeater in APRX
+
+The Viscous Digipeater is variation of AX.25 Digipeater, which puts
+arriving packets into a time delay probation pipe (up to 9 seconds),
+before digipeating them.
+
+One can use a Viscous Digipeater as a fill-in system, which does not
+repeat on band a packet that it hears having already been repeated.
+It does have also benefits on Tx-IGate, which will not re-transmit
+to band something that already was heard there within the small window
+of a few seconds that the probation pipe takes.
+
+
+
+
+
+The trick is that duplicate accounting is done right up front at
+arrival packet arrival time, and depending on what kind of source
+a similar packet arrives from (or none at all), that delayed packet
+may get bumped off the delay pipe, or even be sent out.
+
+
+The rules are a bit more complicated than for plain simple digipeater,
+but not impossibly so:
+
+  Packets arriving from non-viscous sources trump those waiting in
+  viscous queues.  First one arriving will be transmitted, unless
+  the viscous queue has no longer this packet (but it was there.)
+  ( delayed_seen > 0,  seen == 1, pbuf == NULL  -> drop this )
+  ( delayed_seen > 0,  seen == 1, pbuf != NULL  -> clean pbuf, transmit this )
+  ( delayed_seen == 0, seen == 1                -> transmit this )
+
+  Subsequent packets arriving from non-viscous sources are dropped
+  as duplicates ( seen > 1  ->  drop this )
+
+  Packets arriving from any viscous source are dropped, if there
+  already was some direct delivery packet
+  ( delayed_seen > 0, seen > 0   -> drop )
+
+  First packet arriving from any viscous source is put on viscous queue,
+  unless there was non-viscous packet previously.
+  ( delayed_seen == 1, seen == 0  ->  put this on viscous queue )
+
+  Then among viscous sources:
+   - "Transmitter" kind source: an <interface> which is same as
+     that of <digipeater>'s  transmitter  <interface>.
+   - "Elsewhere" kind source: an <interface> which is some other
+     than that of transmitter's, but has  viscous-delay > 0
+
+  Account the number of viscous sourced packets sourced from "transmitter"
+     if (source_is_transmitter)
+         seen_on_transmitter += 1;
+
+  For second and subsequent viscous sourced packets, if any of observed
+  packets came from transmitter (seen_on_transmitter > 0), then drop
+  current packet, and clear possible viscous queued pbuf.
+
+
+Matti Aarnio,  OH2MQK,   2009-10-21
diff --git a/ViscousDigipeaterTxEffect.png b/ViscousDigipeaterTxEffect.png
new file mode 100644
index 0000000..ea0ae3e
Binary files /dev/null and b/ViscousDigipeaterTxEffect.png differ
diff --git a/agwpesocket.c b/agwpesocket.c
new file mode 100644
index 0000000..86955f3
--- /dev/null
+++ b/agwpesocket.c
@@ -0,0 +1,731 @@
+/* **************************************************************** *
+ *                                                                  *
+ *  APRX -- 2nd generation receive-only APRS-i-gate with            *
+ *          minimal requirement of esoteric facilities or           *
+ *          libraries of any kind beyond UNIX system libc.          *
+ *                                                                  *
+ * (c) Matti Aarnio - OH2MQK,  2007-2014                            *
+ *                                                                  *
+ * **************************************************************** */
+#include "aprx.h"
+#ifdef ENABLE_AGWPE
+
+/***  AGWPE interface description from Xastir + AGWPE documents.
+ ***  As those documents are unclear, I am using Xastir to supply
+ ***  clue as to what really needs to be done.
+
+
+// How to Start your application and register with AGW Packet Engine
+
+// First of all create a stream socket and connect with
+// AGW Packet Engine ip address at port 8000.
+// If your application is running at the same machine with
+// AGWPE then as ip address use localhost (127.0.0.1).
+//
+// After connecting you need to register your application's
+// callsign if your application need to establish AX.25 connections.
+// If your application just do monitoring and sends Unproto frames,
+// no need for callsign registration.
+// You can register as many as 100 different callsigns.
+// If you register a callsign then AGW Packet Engine accepts AX.25
+// connections for this call.
+// You then ask AGWPE to send you the radioport information.
+// How many radioports are with their description.
+// After that you can create your windows or anything else.
+//
+// Now you are ready.
+// If you wish to do monitoring then you must enable monitoring.
+
+
+// Transmit a special frame in Raw AX25 format
+//
+// The frame must be in RAW AX25 format as should be txed by
+//  the modem (no need for bit stuffing etc)
+// You can use this function to tx for instance an unproto
+// frame with a special PID or any other frame different from normal AX25 Format.
+// 
+// Port field is the port where we want the data to tx
+// DataKind field = MAKELONG('K',0); The ASCII value of letter K
+// CallFrom empty (NULL)
+// CallTo empty (NULL)
+// DataLen is the length of the data that follow
+// USER is Undefined
+//
+// the whole frame with the header is
+//
+// [ HEADER                                   ]
+// [port][DataKind][CallFrom][CallTo ][DataLen][USER][Data         ]
+//  4bytes  4bytes     10bytes  10bytes   4bytes      4bytes  DataLen Bytes
+//
+
+
+// ASK RadioPorts Number and descriptions
+//
+// Port field must be 0
+// DataKind field =MAKELONG('G',0); The ASCII value of letter G
+// CallFrom is empty (NULL)
+// CallTo is empty(NULL)
+// DataLen must be 0
+// USER is undefined
+// No data field must exists
+// [ HEADER                                   ]
+// [port][DataKind][CallFrom][CallTo ][DataLen][USER]
+//  4bytes  4bytes     10bytes  10bytes   4bytes     4bytes
+//
+
+// ASK To start receiving AX25 RAW Frames
+//
+// Sending again thos command will disable this service.
+// You can start and stop this service any times you needed
+//
+// Port field no needed set it to 0
+// DataKind field =MAKELONG('k',0); The ASCII value of lower case letter k
+// CallFrom is empty no needed
+// CallTo is empty no needed
+// DataLen must be 0
+// USER is undefined
+// No data field must be present
+//
+// the whole frame with the header is
+//
+// [ HEADER                                   ]
+// [port][DataKind][CallFrom][CallTo ][DataLen][USER]
+//  4bytes  4bytes     10bytes  10bytes   4bytes     4bytes
+
+
+// Raw AX25  Frames
+//
+// You can receive RAW AX25 frames if you enable this service.
+// Those frames are all the packet valid frames received from
+// any radioport. The frame is exactly the same as the pure
+// AX25 frame with the follow additions.
+// 
+// The first byte always contains the radioport number 0 for 1st radioport.
+// There is no FCS field at the end of the frame.
+// There is no bit stuffing.
+// The LOWORD Port field is the port which heard the frame
+// The LOWORD DataKind field ='K'; The ASCII value of letter K
+// CallFrom the callsign of the station who TX the frame(Source station)
+// CallTo The callsign of the destination station
+// DataLen is the length of the DATA field(the length of the frame
+// USER is undefined.
+// the whole frame with the header is
+//   [port][DataKind][CallFrom][CallTo ][DataLen][USER][DATA   ]
+//    4bytes  4bytes     10bytes  10bytes   4bytes      4bytes    DataLen Bytes
+
+
+// 1.UNPROTO monitor frame
+// 
+// The LOWORD Port field is the port which heard the frame
+// The LOWORD DataKind field ='U'; The ASCII value of letter U
+// CallFrom= is the call from the station we heard the Packet
+// CallTo =is the destination call (CQ,BEACON etc)
+// DataLen= is the length of the data that follow
+// the whole frame with the header is
+// [port][DataKind][CallFrom][CallTo ][DataLen][USER][Data         ]
+//  4bytes  4bytes     10bytes  10bytes   4bytes      4bytes  DataLen Bytes
+
+
+// 4.RadioPort information
+// 
+// The LOWORD Port field is always 0
+// The LOWORD DataKind field ='G'; The ASCII value of letter G
+// CallFrom  empty(NULL)
+// CallTo    empty(NULL)
+// DataLen is the length of the data that follow
+// USER is undefined
+// the whole frame with the header is
+// [port][DataKind][CallFrom][CallTo ][DataLen][USER][Data         ]
+//  4bytes  4bytes     10bytes  10bytes   4bytes     4bytes    DataLen Bytes
+// the data field format is as follow in plain text
+// howmany ports ;1st radioport description;2nd radioport;....;last radioport describtion
+// like
+// 2;TNC2 on serialport 1;OE5DXL on serialport2;
+// We have here 2 radioports. The separator is the ';'
+
+// 10. Reply to a 'G' command. This frame returns the radioport number
+//     and description
+//
+// Port field is always 0
+// LOWORD DataKind field ='G'. The ASCII value of letter G
+// CallFrom is empty (NULL)
+// CallTo is empty(NULL)
+// DataLen =The number of bytes of DATA field
+// USER is undefined
+// DATA field conatins the radioport description
+// [ HEADER                                   ]
+// [port][DataKind][CallFrom][CallTo ][DataLen][USER] [DATA]
+//  4bytes  4bytes     10bytes  10bytes   4bytes     4bytes    Datalen bytes.
+//
+// The DATA field is organised as follow and is in plain ASCII.
+//
+// Number of Radioports;First radioport description(Friendlyname);Second radioport description(Friendly name)...........
+//
+// Number of radioports=a Decimal Value. A value of 3 means 3 radioports
+// Radioport description= A string that describes the radioport.
+// The separator between fields is the letter ';'.
+// Just parse the whole DATA field and use as separator the ';'
+
+
+
+//
+// Xastir parses integer data like this:  That is, it is LITTLE ENDIAN
+// 
+// Fetch the length of the data portion of the packet
+//    data_length = (unsigned char)(input_string[31]);
+//    data_length = (data_length << 8) + (unsigned char)(input_string[30]);
+//    data_length = (data_length << 8) + (unsigned char)(input_string[29]);
+//    data_length = (data_length << 8) + (unsigned char)(input_string[28]);
+//
+
+***/
+
+// Socket communication packet header
+struct agwpeheader {
+	uint32_t	radioPort;	// 0..3
+	uint32_t	dataKind;	// 4..7
+	uint8_t		fromCall[10];	// 8..17
+	uint8_t		toCall[10];	// 18..27
+	uint32_t	dataLength;	// 28..31
+	uint32_t	userField;	// 32..35
+};
+
+
+struct agwpesocket; // forward declarator
+
+// One agwpecom per connection to AGWPE
+struct agwpecom {
+	int		fd;
+	struct timeval	wait_until;
+
+	const struct netresolver *netaddr;
+
+	int			   socketscount;
+	const struct agwpesocket **sockets;
+
+	int		wrlen;
+	int		wrcursor;
+
+	int		rdneed;  // this much in rdbuf before decision
+	int		rdlen;
+	int		rdcursor;
+
+	uint8_t		wrbuf[4196];
+	uint8_t		rdbuf[4196];
+};
+
+// One agwpesocket per interface
+struct agwpesocket {
+	int			portnum;
+	const struct aprx_interface *iface;
+	struct agwpecom  *com;
+};
+
+
+static struct agwpecom **pecom;
+static int               pecomcount;
+
+
+static uint32_t get_le32(uint8_t *u) {
+	return (u[3] << 24 |
+		u[2] << 16 |
+		u[1] <<  8 |
+		u[0]);
+}
+
+static void set_le32(uint8_t *u, uint32_t value) {
+	u[0] = (uint8_t)value;
+	value >>= 8;
+	u[1] = (uint8_t)value;
+	value >>= 8;
+	u[2] = (uint8_t)value;
+	value >>= 8;
+	u[3] = (uint8_t)value;
+}
+
+
+static struct agwpecom *agwpe_find_or_add_com(const char *hostname, const char *hostport)
+{
+	struct agwpecom *com;
+	int i;
+	
+	for (i = 0; i < pecomcount; ++i) {
+	  com = pecom[i];
+	  if (strcasecmp(hostname,com->netaddr->hostname) == 0 &&
+	      strcasecmp(hostport,com->netaddr->port) == 0) {
+	    return com; // Found it!
+	  }
+	}
+
+	// Did not find it, create it..
+
+	com = calloc(1, sizeof(*com));
+	com->fd = -1;
+	com->netaddr = netresolv_add(hostname, hostport);
+	com->rdneed = sizeof(struct agwpeheader);
+	tv_timeradd_millis(&com->wait_until, &tick, 30000); // redo in 30 seconds or so
+
+	++pecomcount;
+	pecom = realloc(pecom, sizeof(void*)*pecomcount);
+	pecom[pecomcount-1] = com;
+
+	return com;
+}
+
+void *agwpe_addport(const char *hostname, const char *hostport, const char *agwpeport, const struct aprx_interface *interface)
+{
+	int agwpeportnum = atoi(agwpeport);
+	struct agwpesocket *S;
+	struct agwpecom *com;
+
+	if (agwpeportnum < 1 || agwpeportnum > 999) {
+	  if (debug)
+	    printf("ERROR: Bad AGWPE port number value, accepted range: 1 to 999\n");
+	  return NULL;
+	}
+
+	S = calloc(1, sizeof(*S));
+
+	com = agwpe_find_or_add_com(hostname, hostport);
+
+	com->socketscount++;
+	com->sockets = realloc(com->sockets, sizeof(void*)*com->socketscount);
+	com->sockets[com->socketscount-1] = S;
+
+	S->iface   = interface;
+	S->com     = com;
+	S->portnum = agwpeportnum-1;
+
+	return S;
+}
+
+
+// close the AGWPE communication socket, retry its call at some point latter
+static void agwpe_reset(struct agwpecom *com, const char *why)
+{
+	com->wrlen = com->wrcursor = 0;
+	tv_timeradd_millis(&com->wait_until, &tick, 30000); // redo in 30 seconds or so
+
+	if (debug>1)
+	  printf("Resetting AGWPE socket; %s\n", why);
+
+	if (com->fd < 0) {
+	  // Should not happen..
+	  return;
+	}
+
+	close(com->fd);
+	com->fd = -1;
+}
+
+
+/*
+ *  agwpe_flush()  -- write out buffered data - at least partially
+ */
+static void agwpe_flush(struct agwpecom *com)
+{
+	int i, len;
+
+	if (com->fd < 0) return; // nothing to do!
+
+	if ((com->wrlen == 0) || (com->wrlen > 0 && com->wrcursor >= com->wrlen)) {
+	  com->wrlen = com->wrcursor = 0;	/* already all written */
+	  return;
+	}
+
+	/* Now there is some data in between wrcursor and wrlen */
+
+#ifndef MSG_NOSIGNAL
+# define MSG_NOSIGNAL 0 /* This exists only on Linux  */
+#endif
+
+	len = com->wrlen - com->wrcursor;
+	if (len > 0) {
+	  i = send(com->fd, com->wrbuf + com->wrcursor, len, MSG_NOSIGNAL);
+	  /* No SIGPIPE if the
+	     receiver is out,
+	     or pipe is full
+	     because it is doing
+	     slow reconnection. */
+	} else
+	  i = 0;
+	if (i < 0 && (errno == EPIPE ||
+		      errno == ECONNRESET ||
+		      errno == ECONNREFUSED ||
+		      errno == ENOTCONN)) {
+	  /* Sending failed, reset it.. */
+	  agwpe_reset(com,"write to remote closed socket");
+	  return;
+	}
+	if (i > 0) {		/* wrote something */
+		com->wrcursor += i;
+		len = com->wrlen - com->wrcursor;
+		if (len == 0) {
+			com->wrcursor = com->wrlen = 0;	/* wrote all ! */
+		} else {
+			/* compact the buffer a bit */
+			memcpy(com->wrbuf, com->wrbuf + com->wrcursor, len);
+			com->wrcursor = 0;
+			com->wrlen = len;
+		}
+	}
+}
+
+
+void agwpe_sendto(const void *_ap, const uint8_t *axaddr, const int axaddrlen, const char *axdata, const int axdatalen) {
+
+	struct agwpesocket *agwpe = (struct agwpesocket*)_ap;
+	struct agwpecom *com = agwpe->com;
+	int space = sizeof(com->wrbuf) - com->wrlen;
+	struct agwpeheader hdr;
+
+	if (debug) {
+	  // printf("agwpe_sendto(->%s, axlen=%d)", S->ttycallsign[tncid], ax25rawlen);
+	}
+	if (com->fd < 0) {
+	  if (debug)
+	    printf("NOTE: Write to non-open AGWPE socket discarded.");
+	  return;
+	}
+
+	agwpe_flush(com); // write out buffered data, if any
+
+	if (space < (sizeof(struct agwpeheader) + axaddrlen + axdatalen)) {
+	  // Uh, no space at all!
+	  if (debug)
+	    printf("ERROR: No buffer space to send data to AGWPE socket");
+	  return;
+	}
+
+	memset(&hdr, 0, sizeof(hdr));
+	set_le32((uint8_t*)(&hdr.radioPort), agwpe->portnum);
+	set_le32((uint8_t*)(&hdr.dataKind), 'K');
+	set_le32((uint8_t*)(&hdr.dataLength), axaddrlen + axdatalen);
+
+	memcpy(com->wrbuf + com->wrlen, &hdr, sizeof(hdr));
+	com->wrlen += sizeof(hdr);
+	memcpy(com->wrbuf + com->wrlen, axaddr, axaddrlen);
+	com->wrlen += axaddrlen;
+	memcpy(com->wrbuf + com->wrlen, axdata, axdatalen);
+	com->wrlen += axdatalen;
+
+	agwpe_flush(com); // write out buffered data
+
+	// Account transmission
+	erlang_add(agwpe->iface->callsign, ERLANG_TX, axaddrlen+axdatalen + 10, 1);  // agwpe_sendto()
+}
+
+
+
+static int agwpe_controlwrite(struct agwpecom *com, const uint32_t oper) {
+
+	int space = sizeof(com->wrbuf) - com->wrlen;
+	struct agwpeheader hdr;
+
+	if (debug) {
+	  printf("agwpe_controlwrite(oper=%x (%c))\n", oper, oper);
+	}
+	if (com->fd < 0) {
+	  if (debug)
+	    printf("NOTE: Write to non-open AGWPE socket discarded.\n");
+	  return -1;
+	}
+
+	agwpe_flush(com); // write out buffered data, if any
+
+	if (space < sizeof(hdr)) {
+	  // No room :-(
+	  return -1;
+	}
+
+	memset(&hdr, 0, sizeof(hdr));
+	set_le32((uint8_t*)(&hdr.dataKind), oper);
+
+	if (debug)
+	  hexdumpfp(stdout, (const uint8_t *)&hdr, sizeof(hdr), 0);
+
+	
+	memcpy(com->wrbuf + com->wrlen, &hdr, sizeof(hdr));
+	com->wrlen += sizeof(hdr);
+
+	agwpe_flush(com); // write out buffered data
+	return 0;
+}
+
+
+static void agwpe_parse_raw_ax25(struct agwpecom *com,
+				 struct agwpeheader *hdr, const uint8_t *rxbuf)
+{
+#warning "WRITEME: AGWPE Raw AX.25 reception"
+}
+
+
+static void agwpe_parsereceived(struct agwpecom *com,
+				struct agwpeheader *hdr, const uint8_t *rxbuf)
+{
+
+	uint8_t frameType = hdr->dataKind;
+
+	if (debug) {
+	  int i;
+	  int rcvlen = hdr->dataLength;
+
+	  printf("AGWPE hdr radioPort=%d dataKind=0x%x fromcall='%s' tocall='%s'"
+		 " datalen=%d userfield=%x\n",
+		 hdr->radioPort, hdr->dataKind, hdr->fromCall, hdr->toCall,
+		 rcvlen,  hdr->userField);
+
+	  if (rcvlen > 512) rcvlen=512;
+	  printf("AGWPE Data: ");
+	  for (i = 0; i < rcvlen; ++i)
+	    printf(" %02x", rxbuf[i]);
+	  printf("\n");
+	  printf("AGWPE Text: ");
+	  for (i = 0; i < rcvlen; ++i) {
+	    uint8_t c = rxbuf[i];
+	    if (32 <= c && c <= 126)
+	      printf("  %c", c);
+	    else
+	      printf(" %02x", c);
+	  }
+	  printf("\n");
+	  printf("AGWPE AX25: ");
+	  for (i = 0; i < rcvlen; ++i) {
+	    uint8_t c = rxbuf[i] >> 1;
+	    if (32 <= c && c <= 126)
+	      printf("  %c", c);
+	    else
+	      printf(" %02x", c);
+	  }
+	  printf("\n");
+	}
+
+
+	switch (frameType) {
+	case 'K': // Raw AX.25 frame received
+		agwpe_parse_raw_ax25(com, hdr, rxbuf);
+		break;
+
+	default:  // Everything else: discard
+		break;
+	}
+}
+
+
+
+static void agwpe_read(struct agwpecom *com) {
+
+	int rcvspace = sizeof(com->rdbuf) - com->rdlen;
+	int rcvlen;
+	struct agwpeheader hdr;
+
+	if (com->fd < 0) {
+	  // Should not happen..
+	  return;
+	}
+
+	if (com->rdlen > com->rdcursor) {
+	  memcpy(com->rdbuf, com->rdbuf + com->rdcursor,
+		 com->rdlen - com->rdcursor);
+	  com->rdlen -= com->rdcursor;
+	}
+	com->rdcursor = 0;
+
+
+	rcvlen = read(com->fd, com->rdbuf + com->rdlen, rcvspace);
+	if (rcvlen > 0)
+	  com->rdlen += rcvlen;
+	if (com->rdlen < com->rdneed) {
+	  // insufficient amount received, continue with it latter
+	  return;
+	}
+
+	while (com->rdlen >= com->rdneed) {
+
+	  hdr.radioPort = get_le32(com->rdbuf + 0);
+	  hdr.dataKind  = get_le32(com->rdbuf + 4);
+	  memcpy(hdr.fromCall, com->rdbuf + 8, 10);
+	  memcpy(hdr.toCall,   com->rdbuf + 18, 10);
+	  hdr.dataLength = get_le32(com->rdbuf + 28);
+	  hdr.userField  = get_le32(com->rdbuf + 32);
+
+	  if (com->rdneed < (sizeof(hdr) + hdr.dataLength)) {
+	    // recalculate needed data size
+	    com->rdneed = sizeof(hdr) + hdr.dataLength;
+	  }
+	  if (com->rdneed > sizeof(com->rdbuf)) {
+	    // line noise or something...
+	    agwpe_reset(com,"received junk data");
+	    return;
+	  }
+	  if (com->rdlen < com->rdneed) {
+	    // insufficient amount received..
+	    break;
+	  }
+	  
+	  // Process received frame
+	  agwpe_parsereceived(com, &hdr, com->rdbuf + sizeof(hdr));
+
+	  com->rdcursor += sizeof(hdr) + hdr.dataLength;
+	  if (com->rdlen > com->rdcursor) {
+	    memcpy(com->rdbuf, com->rdbuf + com->rdcursor,
+		   com->rdlen - com->rdcursor);
+	    com->rdlen -= com->rdcursor;
+	  }
+	  com->rdcursor = 0;
+	  com->rdneed = sizeof(hdr);
+	}
+}
+
+
+static void agwpe_connect(struct agwpecom *com) {
+	int i;
+
+	// Initial protocol reading parameters
+	com->rdcursor = 0;
+	com->rdneed = sizeof(struct agwpeheader);
+
+	// Create socket
+	if (debug>1) {
+	  printf("AGWPE socket(%d %d %d)\n",
+		 com->netaddr->ai.ai_family, com->netaddr->ai.ai_socktype,
+		 com->netaddr->ai.ai_protocol);
+	}
+	com->fd = socket(com->netaddr->ai.ai_family, com->netaddr->ai.ai_socktype,
+			 com->netaddr->ai.ai_protocol);
+	if (com->fd < 0) {
+	  if (debug)
+	    printf("ERROR at AGWPE socket creation: errno=%d %s\n",errno,strerror(errno));
+	  agwpe_reset(com,"error at socket() creation");
+	  return;
+	}
+	// Put it on non-blocking mode
+	fd_nonblockingmode(com->fd);
+
+	// Connect
+	i = connect(com->fd, com->netaddr->ai.ai_addr, com->netaddr->ai.ai_addrlen);
+	// Should result "EINPROGRESS"
+	if (i < 0 && (errno != EINPROGRESS && errno != EINTR)) {
+	  // Unexpected fault!
+	  if (debug)
+	    printf("ERROR on non-blocking connect(): errno=%d (%s)\n", errno, strerror(errno));
+	  agwpe_reset(com,"connect failure");
+	  return;
+	}
+
+	// Aprx will snoop everything that happens on radio ports,
+	// and receive frames in raw AX.25.
+
+	// Queue necessary configuration parameters on newly constructed socket
+
+	agwpe_controlwrite(com, 'k'); // Ask for raw AX.25 frames
+	agwpe_controlwrite(com, 'm'); // Ask for full monitoring of all interfaces
+}
+
+
+/*
+ *  agwpe_init()
+ */
+
+void agwpe_init(void)
+{
+	/* nothing.. */
+}
+
+/*
+ *  agwpe_start()
+ */
+
+void agwpe_start(void)
+{
+	/* nothing.. */
+}
+
+
+
+/*
+ *  agwpe_prepoll()  --  prepare system for next round of polling
+ */
+
+int agwpe_prepoll(struct aprxpolls *app)
+{
+	int idx = 0;		/* returns number of *fds filled.. */
+	int i;
+	struct agwpecom *S;
+	struct pollfd *pfd;
+
+	for (i = 0; i < pecomcount; ++i) {
+          S = pecom[i];
+          if (S->fd < 0) {
+            /* Not an open TTY, but perhaps waiting ? */
+            if ((S->wait_until.tv_sec != 0) && tv_timercmp(&S->wait_until, &tick) > 0) {
+              if (tv_timerdelta_millis(&S->wait_until, &tick) > 60000) {
+                // Verify that wait is not too long -- system time jumped backwards?  (but not 68 years..)
+                S->wait_until = tick;
+              }
+
+              /* .. waiting for future! */
+              if (tv_timercmp(&app->next_timeout, &S->wait_until) > 0)
+                app->next_timeout = S->wait_until;
+              /* .. but only until our timeout,
+                 if it is sooner than global one. */
+              continue;	/* Waiting on this one.. */
+            }
+
+            /* Waiting or not, FD is not open, and deadline is past.
+               Lets try to open! */
+
+            agwpe_connect(S);
+
+          }
+          /* .. No open FD */
+          /* Still no open FD ? */
+          if (S->fd < 0)
+            continue;
+
+          // FD is open, lets mark it for poll read..
+          pfd = aprxpolls_new(app);
+          pfd->fd = S->fd;
+          pfd->events = POLLIN | POLLPRI;
+          pfd->revents = 0;
+          // .. and if needed, poll write.
+          if (S->wrlen > S->wrcursor)
+            pfd->events |= POLLOUT;
+
+          ++idx;
+	}
+	return idx;
+}
+
+/*
+ *  agwpe_postpoll()  -- Done polling, what happened ?
+ */
+
+int agwpe_postpoll(struct aprxpolls *app)
+{
+	int idx, i;
+
+	struct agwpecom *S;
+	struct pollfd *P;
+	for (idx = 0, P = app->polls; idx < app->pollcount; ++idx, ++P) {
+
+		if (!(P->revents & (POLLIN | POLLPRI | POLLERR | POLLHUP)))
+			continue;	/* No read event we are interested in... */
+
+		for (i = 0; i < pecomcount; ++i) {
+			S = pecom[i];
+			if (S->fd != P->fd)
+				continue;	/* Not this one ? */
+			/* It is this one! */
+
+			if (P->revents & POLLOUT)
+				agwpe_flush(S);
+
+			agwpe_read(S);
+		}
+	}
+
+	return 0;
+}
+
+#endif
diff --git a/apparmor.aprx b/apparmor.aprx
new file mode 100644
index 0000000..00b878f
--- /dev/null
+++ b/apparmor.aprx
@@ -0,0 +1,17 @@
+#include <tunables/global>
+
+/sbin/aprx {
+  #include <abstractions/base>
+  #include <abstractions/nameservice>
+
+
+  capability setgid,
+  capability setuid,
+  capability sys_chroot,
+
+
+  /etc/aprx.conf r,
+  owner /var/run/aprx.pid rwk,
+  owner /var/run/aprx.state rwk,
+  owner /var/log/aprx/* rwk,
+}
diff --git a/aprsis.c b/aprsis.c
new file mode 100644
index 0000000..85d3706
--- /dev/null
+++ b/aprsis.c
@@ -0,0 +1,1279 @@
+/* **************************************************************** *
+ *								    *
+ *  APRX -- 2nd generation receive-only APRS-i-gate with	    *
+ *	    minimal requirement of esoteric facilities or	    *
+ *	    libraries of any kind beyond UNIX system libc.	    *
+ *								    *
+ * (c) Matti Aarnio - OH2MQK,  2007-2014			    *
+ *								    *
+ * **************************************************************** */
+
+/* This code works only with single  aprsis-server  instance! */
+
+#include "aprx.h"
+
+#ifndef DISABLE_IGATE
+
+#include <sys/socket.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <signal.h>
+
+#ifdef HAVE_NETINET_SCTP_H
+#include <netinet/sctp.h>
+#endif
+
+#if defined(HAVE_PTHREAD_CREATE) && defined(ENABLE_PTHREAD)
+#include <pthread.h>
+pthread_t aprsis_thread;
+pthread_attr_t pthr_attrs;
+#endif
+
+/*
+ * $aprsserver = "rotate.aprs.net:14580";
+ *
+ * re-resolve the $aprsserver at each connection setup!
+ *
+ * The APRS-IS system connection runs as separate sub-process, once it starts.
+ * This way the main-loop is independent from uncertainties of DNS resolving
+ * delay times in this part of the code.
+ *
+ */
+
+enum aprsis_mode {
+	MODE_TCP,
+	MODE_SSL,
+	MODE_SCTP,
+	MODE_DTLS
+};
+
+static char default_passcode[] = "-1";
+
+struct aprsis_host {
+	char *server_name;
+	char *server_port;
+	char *login;
+	char *pass;
+	char *filterparam;
+	int heartbeat_monitor_timeout;
+	enum aprsis_mode mode;
+};
+
+struct aprsis {
+	int server_socket;
+	struct aprsis_host *H;
+	time_t next_reconnect;
+	time_t last_read;
+	int wrbuf_len;
+	int wrbuf_cur;
+	int rdbuf_len;
+	int rdbuf_cur;
+	int rdlin_len;
+
+	char wrbuf[16000];
+	char rdbuf[3000];
+	char rdline[500];
+};
+
+char * const aprsis_loginid;
+static struct aprsis *AprsIS;
+static struct aprsis_host **AISh;
+static int AIShcount;
+static int AIShindex;
+static int aprsis_up = -1;	/* up & down talking socket(pair),
+				   The aprsis talker (thread/child)
+				   uses this socket. */
+static int aprsis_down = -1;	/* down talking socket(pair),
+				   The aprx main loop uses this socket */
+//static dupecheck_t *aprsis_rx_dupecheck;
+
+//int  aprsis_dupecheck_storetime = 30;
+
+
+extern int log_aprsis;
+extern int die_now;
+
+void aprsis_init(void)
+{
+	aprsis_up   = -1;
+	aprsis_down = -1;
+}
+
+//void enable_aprsis_rx_dupecheck(void) {
+//	aprsis_rx_dupecheck = dupecheck_new(aprsis_dupecheck_storetime);
+//}
+#if !(defined(HAVE_PTHREAD_CREATE) && defined(ENABLE_PTHREAD))
+static void sig_handler(int sig)
+{
+	die_now = 1;
+	signal(sig, sig_handler);
+}
+#endif
+
+/*
+ *Close APRS-IS server_socket, clean state..
+ */
+// APRS-IS communicator
+static void aprsis_close(struct aprsis *A, const char *why)
+{
+	if (A->server_socket >= 0)
+		close(A->server_socket);	/* close, and flush write buffers */
+
+	A->server_socket = -1;
+
+	A->wrbuf_len = A->wrbuf_cur = 0;
+	A->next_reconnect = tick.tv_sec + 10;
+	A->last_read = tick.tv_sec;
+
+	if (!A->H)
+		return;		/* Not connected, nor defined.. */
+
+	aprxlog("CLOSE APRSIS %s:%s %s", 
+		A->H->server_name, A->H->server_port,
+		why ? why : "");
+}
+
+
+/*
+ *  aprsis_queue_() - internal routine - queue data to specific APRS-IS instance
+ */
+// APRS-IS communicator
+static int aprsis_queue_(struct aprsis *A, const char * const addr, const char qtype,
+			 const char *gwcall, const char * const text, int textlen)
+{
+	int i;
+	char addrbuf[1000];
+	int addrlen, len;
+	char * p;
+
+	/* Queue for sending to APRS-IS only when the socket is operational */
+	if (A->server_socket < 0)
+		return 1;
+
+	/* Here the A->H->login is always set. */
+
+	/*
+	 * Append stuff on the writebuf, if it fits.
+	 * If it does not fit, something is broken already
+	 * and we just drop it..
+	 *
+	 * Just to make sure that the write pointer is not left
+	 * rewound when all has been done...
+	 */
+
+	if (A->wrbuf_cur >= A->wrbuf_len && A->wrbuf_len > 0)
+		A->wrbuf_cur = A->wrbuf_len = 0;
+
+	addrlen = 0;
+	if (addr)
+		addrlen = sprintf(addrbuf, "%s,qA%c,%s:", addr, qtype,
+				  (gwcall
+				   && *gwcall) ? gwcall : A->H->login);
+	aprsis_login = A->H->login;
+
+	len = addrlen + textlen;
+
+
+	/* Does it fit in ? */
+
+	if ((sizeof(A->wrbuf) - 10) <= (A->wrbuf_len + len)) {
+		/* The string does not fit in, perhaps it needs compacting ? */
+		if (A->wrbuf_cur > 0) { /* Compacting is possible ! */
+			memcpy(A->wrbuf, A->wrbuf + A->wrbuf_cur,
+			       A->wrbuf_len - A->wrbuf_cur);
+			A->wrbuf_len -= A->wrbuf_cur;
+			A->wrbuf_cur = 0;
+		}
+
+		/* Check again if it fits in.. */
+		if ((sizeof(A->wrbuf) - 10) <= (A->wrbuf_len + len)) {
+			/* NOT!	 Too bad, drop it.. */
+			return 2;
+		}
+	}
+
+
+	/* Place it on our send buffer */
+
+	if (addrlen > 0) {
+		memcpy(A->wrbuf + A->wrbuf_len, addrbuf, addrlen);
+		A->wrbuf_len += addrlen;
+	}
+
+	/* If there is CR or LF within the packet, terminate packet at it.. */
+	p = memchr(text, '\r', textlen);
+	if (p != NULL) {
+	  textlen = p - text;
+	}
+	p = memchr(text, '\n', textlen);
+	if (p != NULL) {
+	  textlen = p - text;
+	}
+
+	/* Append CR+LF at the end of the packet */
+	p = (char*)(text + textlen);
+	*p++ = '\r';
+	*p++ = '\n';
+	textlen += 2;
+
+	memcpy(A->wrbuf + A->wrbuf_len, text, textlen);
+	A->wrbuf_len += textlen;	/* Always supplied with tail newline.. */
+
+	/* -- debug --
+	  fwrite(A->wrbuf,A->wrbuf_len,1,stdout);
+	  return 0;
+	*/
+
+	/* Try writing it right away: */
+
+	i = write(A->server_socket, A->wrbuf + A->wrbuf_cur,
+		  A->wrbuf_len - A->wrbuf_cur);
+	if (i > 0) {
+		// the buffer's last character is \n, don't write it
+		if (log_aprsis)
+		  aprxlog(A->wrbuf + A->wrbuf_cur, (A->wrbuf_len - A->wrbuf_cur) -1,
+			  "<< %s:%s << ", A->H->server_name, A->H->server_port);
+
+		A->wrbuf_cur += i;
+		if (A->wrbuf_cur >= A->wrbuf_len) {	/* Wrote all ! */
+			A->wrbuf_cur = A->wrbuf_len = 0;
+		}
+	}
+
+	return 0;
+}
+
+
+/*
+ *  THIS CONNECT ROUTINE WILL BLOCK  (At DNS resolving)
+ *  
+ *  This is why APRSIS communication is run at either
+ *  a fork()ed child, or separate pthread from main loop.
+ */
+
+// APRS-IS communicator
+static void aprsis_reconnect(struct aprsis *A)
+{
+	struct addrinfo req, *ai, *a, *ap[21];
+	int i, n;
+	char *s;
+	char aprsislogincmd[3000];
+	const char *errstr;
+	int errcode;
+
+	memset(aprsislogincmd, 0, sizeof(aprsislogincmd)); // please valgrind
+
+	aprsis_close(A, "reconnect");
+
+	if (!A->H) {
+		A->H = AISh[0];
+	} else {
+		++AIShindex;
+		if (AIShindex >= AIShcount)
+			AIShindex = 0;
+		A->H = AISh[AIShindex];
+	}
+
+	if (!A->H->login) {
+		if (log_aprsis)
+		  aprxlog("FAIL - APRSIS-LOGIN not defined, no APRSIS connection!");
+
+		return;		/* Will try to reconnect in about 60 seconds.. */
+	}
+	aprsis_login = A->H->login;
+
+	memset(&req, 0, sizeof(req));
+	req.ai_socktype = SOCK_STREAM;
+	req.ai_protocol = IPPROTO_TCP;
+	req.ai_flags = 0;
+#if 1
+	req.ai_family = AF_UNSPEC;	/* IPv4 and IPv6 are both OK */
+#else
+	req.ai_family = AF_INET;	/* IPv4 only */
+#endif
+	ai = NULL;
+
+
+	i = getaddrinfo(A->H->server_name, A->H->server_port, &req, &ai);
+	errstr = "address resolution failure";
+	errcode = errno;
+
+	if (i != 0) {
+
+	      fail_out:;
+		/* Discard stuff and redo latter.. */
+
+		if (ai)
+			freeaddrinfo(ai);
+
+		aprsis_close(A, "fail on connect");
+
+		aprxlog("FAIL - Connect to %s:%s failed: %s - errno=%d - %s",
+			A->H->server_name, A->H->server_port, errstr, errno, strerror(errcode));
+		return;
+	}
+
+	/* Count the addresses */
+	memset(ap, 0, sizeof(ap));
+	for (n = 0, a = ai; a; a = a->ai_next, ++n) {
+		if (n < 20)
+			ap[n] = a;
+		else
+			break;
+	}
+	ap[n] = NULL;
+
+	if (n > 1) {		/* more than one ?  choose one at random as the first address,
+				   then go through the address list in new sequence. */
+		n = rand() % n;
+		if (n > 0) {
+			a = ap[n];
+			ap[n] = ap[0];
+			ap[0] = a;
+		}
+	}
+
+	for (n = 0; (a = ap[n]) && A->server_socket < 0; ++n) {
+
+		errstr = "socket formation failed";
+
+		A->server_socket =
+			socket(a->ai_family, a->ai_socktype,
+			       a->ai_protocol);
+		errcode = errno;
+
+		if (A->server_socket < 0)
+			continue;
+
+		errstr = "connection failed";
+		i = connect(A->server_socket, a->ai_addr, a->ai_addrlen);
+		errcode = errno;
+
+		if (i < 0) {
+			/* If connection fails, try next possible address */
+			close(A->server_socket);
+			A->server_socket = -1;
+			continue;
+		}
+	}
+
+	if (A->server_socket < 0)
+		goto fail_out;
+
+	freeaddrinfo(ai);
+	ai = NULL;
+
+
+	timetick(); // unpredictable time since system did last poll..
+
+        if (time_reset) {
+          if (debug) printf("In time_reset mode, no touching yet!\n");
+          A->next_reconnect = tick.tv_sec + 10;
+          return;
+        }
+
+	aprxlog("CONNECT APRSIS %s:%s",
+		A->H->server_name, A->H->server_port);
+
+	/* From now the socket will be non-blocking for its entire lifetime.. */
+	fd_nonblockingmode(A->server_socket);
+
+	/* We do at first sync writing of login, and such.. */
+	s = aprsislogincmd;
+	s += sprintf(s, "user %s pass %s vers %s %s", A->H->login,
+		    A->H->pass, swname, swversion);
+	if (A->H->filterparam)
+		s += sprintf(s, " filter %s", A->H->filterparam);
+
+	A->last_read = tick.tv_sec;
+
+	aprsis_queue_(A, NULL, qTYPE_LOCALGEN, "", aprsislogincmd, strlen(aprsislogincmd));
+
+	return;			/* just a place-holder */
+}
+
+
+// APRS-IS communicator
+static int aprsis_sockreadline(struct aprsis *A)
+{
+	int i, c;
+
+	/* Reads multiple lines from buffer,
+	   Last one is left into incomplete state */
+
+	for (i = A->rdbuf_cur; i < A->rdbuf_len; ++i) {
+	    c = 0xFF & (A->rdbuf[i]);
+	    if (c == '\r' || c == '\n') {
+		/* End of line, process.. */
+		if (A->rdlin_len > 0) {
+		    A->rdline[A->rdlin_len] = 0;
+		    /* */
+		    A->last_read = tick.tv_sec; /* Time stamp me ! */
+
+		    if (log_aprsis)
+		      aprxlog(A->rdline, A->rdlin_len,
+			      ">> %s:%s >> ", A->H->server_name, A->H->server_port);
+
+		    /* Send the A->rdline content to main program */
+		    c = send(aprsis_up, A->rdline, A->rdlin_len, 0);
+		    /* This may fail with SIGPIPE.. */
+		    if (c < 0 && (errno == EPIPE ||
+				  errno == ECONNRESET ||
+				  errno == ECONNREFUSED ||
+				  errno == ENOTCONN)) {
+		      die_now = 1; // upstream socket send failed
+		    }
+		}
+		A->rdlin_len = 0;
+		continue;
+	    }
+	    if (A->rdlin_len < sizeof(A->rdline) - 2) {
+	      A->rdline[A->rdlin_len++] = c;
+	    }
+	}
+	A->rdbuf_cur = 0;
+	A->rdbuf_len = 0;	/* we ignore line reading */
+	return 0;		/* .. this is placeholder.. */
+}
+
+// APRS-IS communicator
+static int aprsis_sockread(struct aprsis *A)
+{
+	int i;
+
+	int rdspace = sizeof(A->rdbuf) - A->rdbuf_len;
+
+	if (A->rdbuf_cur > 0) {
+		/* Read-out cursor is not at block beginning,
+		   is there unread data too ? */
+		if (A->rdbuf_cur > A->rdbuf_len) {
+			memcpy(A->rdbuf, A->rdbuf + A->rdbuf_cur,
+			       A->rdbuf_len - A->rdbuf_cur);
+			A->rdbuf_len -= A->rdbuf_cur;
+		} else
+			A->rdbuf_len = 0;	/* all processed, mark its size zero */
+		A->rdbuf_cur = 0;
+
+		/* recalculate */
+		rdspace = sizeof(A->rdbuf) - A->rdbuf_len;
+	}
+
+	i = read(A->server_socket, A->rdbuf + A->rdbuf_len, rdspace);
+
+	if (i > 0) {
+
+		A->rdbuf_len += i;
+
+		/* we just ignore the readback.. but do time-stamp the event */
+		A->last_read = tick.tv_sec;
+
+		aprsis_sockreadline(A);
+	}
+
+	return i;
+}
+
+struct aprsis_tx_msg_head {
+	time_t then;
+	int addrlen;
+	int gwlen;
+	int textlen;
+	char qtype;
+};
+
+/*
+ * Read frame from a socket in between main-program and
+ * APRS-IS interface subprogram.  (At APRS-IS side.)
+ * 
+ */
+// APRS-IS communicator
+static void aprsis_readup(void)
+{
+	int i;
+	char buf[10000];
+	const char *addr;
+	const char *gwcall;
+	const char *text;
+	int textlen;
+	struct aprsis_tx_msg_head head;
+
+	i = recv(aprsis_up, buf, sizeof(buf), 0);
+	if (i == 0) {		/* EOF ! */
+	  if (debug>1) printf("Upstream fd read resulted eof status.\n");
+	  die_now = 1;
+	  return;
+	}
+	if (i < 0) {
+		return;		/* Whatever was the reason.. */
+	}
+	buf[i] = 0;		/* String Termination NUL byte */
+
+	memcpy(&head, buf, sizeof(head));
+	if (head.then + 10 < tick.tv_sec)
+		return;		/* Too old, discard */
+	addr = buf + sizeof(head);
+
+	gwcall = addr + head.addrlen + 1;
+
+	text = gwcall + head.gwlen + 1;
+
+	textlen = head.textlen;
+	if (textlen <= 2)
+	  return;		// BAD!
+	if ((text + textlen) > (buf + i)) {
+	  return;		// BAD!
+	}
+
+	/*
+	  printf("addrlen=%d addr=%s\n",head.addrlen, addr);
+	  printf("gwlen=%d  gwcall=%s\n",head.gwlen,gwcall);
+	  printf("textlen=%d text=%s",head.textlen, text);
+	  return;
+	*/
+
+	/* Now queue the thing! */
+
+	if (AprsIS != NULL)
+		aprsis_queue_(AprsIS, addr, head.qtype, gwcall, text, textlen);
+}
+
+
+// main program side
+int aprsis_queue(const char *addr, int addrlen, const char qtype, const char *gwcall, const char *text,	 int textlen)
+{
+	static char *buf;	/* Dynamically allocated buffer... */
+	static int buflen;
+	int i, len, gwlen = strlen(gwcall);
+	char *p;
+	struct aprsis_tx_msg_head head;
+	int newlen;
+//	dupe_record_t *dp;
+
+	if (aprsis_down < 0) return -1; // No socket!
+
+	if (addrlen == 0)      /* should never be... */
+		addrlen = strlen(addr);
+
+//	if (aprsis_rx_dupecheck != NULL) {
+//	  dp = dupecheck_aprs( aprsis_rx_dupecheck, 
+//			       addr, addrlen,
+//			       text, textlen );
+//	  if (dp != NULL) return 1; // Bad either as dupe, or due to alloc failure
+//	}
+
+	newlen = sizeof(head) + addrlen + gwlen + textlen + 6;
+	if (newlen > buflen) {
+		buflen = newlen;
+		buf = realloc(buf, buflen);
+		memset(buf, 0, buflen); // (re)init it to silence valgrind
+	}
+
+	memset(&head, 0, sizeof(head));
+	head.then    = tick.tv_sec;
+	head.addrlen = addrlen;
+	head.gwlen   = gwlen;
+	head.textlen = textlen;
+	head.qtype   = qtype;
+
+	memcpy(buf, &head, sizeof(head));
+	p = buf + sizeof(head);
+
+	memcpy(p, addr, addrlen);
+	p += addrlen;
+	*p++ = 0;		/* string terminating 0 byte */
+	memcpy(p, gwcall, gwlen);
+	p += gwlen;
+	*p++ = 0;		/* string terminating 0 byte */
+	memcpy(p, text, textlen);
+	p += textlen;
+	len = p - buf;
+	*p++ = 0;
+
+#ifndef MSG_NOSIGNAL
+# define MSG_NOSIGNAL 0 /* This exists only on Linux  */
+#endif
+	i = send(aprsis_down, buf, len, MSG_NOSIGNAL);	/* No SIGPIPE if the
+							   receiver is out,
+							   or pipe is full
+							   because it is doing
+							   slow reconnection. */
+
+	return (i != len);
+	/* Return 0 if ANY of the queue operations was successfull
+	   Return 1 if there was some error.. */
+}
+
+
+// APRS-IS communicator
+static int aprsis_prepoll_(struct aprxpolls *app)
+{
+	struct pollfd *pfd;
+	struct aprsis *A = AprsIS;
+
+	if (A->last_read == 0)
+		A->last_read = tick.tv_sec;	/* mark it non-zero.. */
+
+	if (A->server_socket < 0)
+		return -1;	/* Not open, do nothing */
+
+	if (debug>3) printf("aprsis_prepoll_()\n");
+
+	if (time_reset) {
+		aprsis_close(A, "time_reset!");
+	}
+
+
+	/* Not all aprs-is systems send "heartbeat", but when they do.. */
+	if ((A->H->heartbeat_monitor_timeout > 0) &&
+	    ((A->last_read + A->H->heartbeat_monitor_timeout - tick.tv_sec) < 0)) {
+
+		/*
+		 * More than 120 seconds (2 minutes) since last time
+		 * that APRS-IS systems told us something on the connection.
+		 * There is a heart-beat ticking every 20 or so seconds.
+		 */
+
+		aprsis_close(A, "heartbeat timeout");
+	}
+
+	/* FD is open, lets mark it for poll read.. */
+
+	pfd = aprxpolls_new(app);
+
+	pfd->fd = A->server_socket;
+	pfd->events = POLLIN | POLLPRI | POLLERR | POLLHUP;
+	pfd->revents = 0;
+
+	/* Do we have something for writing ?  */
+	if (A->wrbuf_len) {
+		pfd->events |= POLLOUT;
+	}
+
+	return 0;
+}
+
+// APRS-IS communicator
+static int aprsis_postpoll_(struct aprxpolls *app)
+{
+	int i;
+	struct pollfd *pfd = app->polls;
+	struct aprsis *A = AprsIS;
+
+	if (debug>3) printf("aprsis_postpoll_() cnt=%d\n", app->pollcount);
+
+	for (i = 0; i < app->pollcount; ++i, ++pfd) {
+		if (pfd->fd == A->server_socket && pfd->fd >= 0) {
+			/* This is APRS-IS socket, and we may have some results.. */
+
+			if (pfd->revents & (POLLERR)) { /* Errors ? */
+				aprsis_close(A,"postpoll_ POLLERR");
+				continue;
+			}
+			if (pfd->revents & (POLLHUP)) { /* Errors ? */
+				aprsis_close(A,"postpoll_ POLLHUP");
+				continue;
+			}
+
+			if (pfd->revents & (POLLIN | POLLPRI)) { /* Ready for reading */
+				for (;;) {
+					i = aprsis_sockread(A);
+					if (i == 0) {	/* EOF ! */
+						aprsis_close(A,"postpoll_ EOF");
+						continue;
+					}
+					if (i < 0)
+						break;
+				}
+			}
+
+			if (pfd->revents & POLLOUT) {	/* Ready for writing  */
+				/* Normal queue write processing */
+
+				if (A->wrbuf_len > 0 &&
+				    A->wrbuf_cur < A->wrbuf_len) {
+					i = write(A->server_socket,
+						  A->wrbuf +
+						  A->wrbuf_cur,
+						  A->wrbuf_len -
+						  A->wrbuf_cur);
+					if (debug>2)
+					  printf("%ld << %s:%s << write() rc= %d\n",
+						 tick.tv_sec, A->H->server_name, A->H->server_port, i);
+
+					if (i < 0)
+						continue;	/* Argh.. nothing */
+					// if (i == 0); /* What ? */
+
+					if (log_aprsis)
+					  aprxlog(A->wrbuf + A->wrbuf_cur,
+						  (A->wrbuf_len - A->wrbuf_cur) -1,
+						  "<< %s:%s << ", A->H->server_name,
+						  A->H->server_port);
+
+					A->wrbuf_cur += i;
+					if (A->wrbuf_cur >= A->wrbuf_len) {	/* Wrote all! */
+						A->wrbuf_len = A->wrbuf_cur = 0;
+					} else {
+						/* partial write .. do nothing.. */
+					}
+				}
+				/* .. normal queue */
+			}	/* .. POLLOUT */
+		}	/* .. if fd == server_socket */
+	}			/* .. for .. nfds .. */
+	return 1;		/* there was something we did, maybe.. */
+}
+
+
+// APRS-IS communicator
+static void aprsis_cond_reconnect(void)
+{
+	if (AprsIS &&	/* First time around it may trip.. */
+	    AprsIS->server_socket < 0 && (AprsIS->next_reconnect - tick.tv_sec) <= 0) {
+		aprsis_reconnect(AprsIS);
+	}
+}
+
+
+/*
+ * Main-loop of subprogram handling communication with
+ * APRS-IS network servers.
+ *
+ * This starts only when we have at least one <aprsis> defined without errors.
+ */
+// APRS-IS communicator
+static void aprsis_main(void)
+{
+#if !(defined(HAVE_PTHREAD_CREATE) && defined(ENABLE_PTHREAD))
+	int ppid = getppid();
+#endif
+	struct aprxpolls app = APRXPOLLS_INIT;
+
+
+#if !(defined(HAVE_PTHREAD_CREATE) && defined(ENABLE_PTHREAD))
+	signal(SIGHUP, sig_handler);
+	signal(SIGPIPE, SIG_IGN);
+#endif
+
+	/* The main loop */
+	while (!die_now) {
+		struct pollfd *pfd;
+		int i;
+
+		timetick();
+
+		aprsis_cond_reconnect(); // may take unpredictable time..
+
+		timetick();
+
+#if !(defined(HAVE_PTHREAD_CREATE) && defined(ENABLE_PTHREAD))
+		// Parent-pid makes no sense in threaded setup
+		i = getppid();
+		if (i != ppid)
+			break;	/* die now, my parent is gone.. */
+		if (i == 1)
+			break;	/* a safety fallback case.. */
+#endif
+
+		aprxpolls_reset(&app);
+		tv_timeradd_seconds( &app.next_timeout, &tick, 5 );
+
+		if (aprsis_up >= 0) {
+			pfd = aprxpolls_new(&app);
+
+			pfd->fd = aprsis_up;
+			pfd->events = POLLIN | POLLPRI | POLLERR | POLLHUP;
+			pfd->revents = 0;
+		}
+
+		i = aprsis_prepoll_(&app);
+
+		// Prepolls are done
+		time_reset = 0;
+
+		if (tv_timercmp(&app.next_timeout, &tick) <= 0) {
+			tv_timeradd_seconds( &app.next_timeout, &tick, 1 ); // Just to be on safe side..
+		}
+
+		i = poll(app.polls, app.pollcount, aprxpolls_millis(&app));
+
+		timetick();
+
+		assert(app.polls != NULL);
+		if (app.polls[0].
+		    revents & (POLLIN | POLLPRI | POLLERR | POLLHUP)) {
+			/* messaging channel has something for us, if
+			   the channel reports EOF, we exit there and then. */
+			aprsis_readup();
+		}
+		i = aprsis_postpoll_(&app);
+	}
+	aprxpolls_free(&app); // valgrind..
+	/* Got "DIE NOW" signal... */
+	// exit(0);
+}
+
+
+/*
+ *  aprsis_add_server() - old style configuration
+ */
+
+int aprsis_add_server(const char *server, const char *port)
+{
+	struct aprsis_host *H;
+
+	if (AprsIS == NULL) {
+		AprsIS = calloc(1,sizeof(*AprsIS));
+	}
+
+	H = calloc(1,sizeof(*H));
+	AISh = realloc(AISh, sizeof(AISh[0]) * (AIShcount + 1));
+	AISh[AIShcount] = H;
+
+	++AIShcount;
+	/* No inc on AprsIScount */
+
+
+	H->server_name = strdup(server);
+	H->server_port = strdup(port);
+	H->heartbeat_monitor_timeout = 120; // Default timeout 120 seconds
+	H->login       = strdup(aprsis_login);	// global aprsis_login
+	H->pass	       = default_passcode;
+	if (H->login == NULL) H->login = strdup(mycall);
+
+	AprsIS->server_socket = -1;
+	AprsIS->next_reconnect = tick.tv_sec +10;	/* perhaps somewhen latter.. */
+
+	return 0;
+}
+
+// old style configuration
+int aprsis_set_heartbeat_timeout(const int tout)
+{
+	int i = AIShcount;
+	struct aprsis_host *H;
+
+	if (i > 0)
+		--i;
+	H = AISh[i];
+
+	H->heartbeat_monitor_timeout = tout;
+
+	return 0;
+}
+
+// old style configuration
+int aprsis_set_filter(const char *filter)
+{
+	int i = AIShcount;
+	struct aprsis_host *H;
+
+	if (i > 0)
+		--i;
+	H = AISh[i];
+
+	H->filterparam = strdup(filter);
+
+	return 0;
+}
+
+// old style configuration
+int aprsis_set_login(const char *login)
+{
+	int i = AIShcount;
+	struct aprsis_host *H;
+
+	if (i > 0)
+		--i;
+	H = AISh[i];
+
+	H->login = strdup(login);
+
+	return 0;
+}
+
+#if defined(HAVE_PTHREAD_CREATE) && defined(ENABLE_PTHREAD)
+static void aprsis_runthread(void)
+{
+	sigset_t sigs_to_block;
+
+	sigemptyset(&sigs_to_block);
+	sigaddset(&sigs_to_block, SIGALRM);
+	sigaddset(&sigs_to_block, SIGINT);
+	sigaddset(&sigs_to_block, SIGTERM);
+	sigaddset(&sigs_to_block, SIGQUIT);
+	sigaddset(&sigs_to_block, SIGHUP);
+	sigaddset(&sigs_to_block, SIGURG);
+	sigaddset(&sigs_to_block, SIGPIPE);
+	sigaddset(&sigs_to_block, SIGUSR1);
+	pthread_sigmask(SIG_BLOCK, &sigs_to_block, NULL);
+
+	// generally the cancelability is enabled
+	pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
+
+	if (debug) printf("aprsis_runthread()\n");
+
+	aprsis_main();
+}
+
+
+void aprsis_start(void)
+{
+	int i;
+	int pipes[2];
+
+	if (AISh == NULL || AprsIS == NULL) {
+	  fprintf(stderr,"***** NO APRSIS SERVER CONNECTION DEFINED *****");
+	  return;
+	}
+
+	i = socketpair(AF_UNIX, SOCK_DGRAM, PF_UNSPEC, pipes);
+	if (i != 0) {
+		return;		/* FAIL ! */
+	}
+
+	fd_nonblockingmode(pipes[0]);
+	fd_nonblockingmode(pipes[1]);
+	aprsis_down = pipes[0];
+	aprsis_up   = pipes[1];
+
+	if (debug)printf("aprsis_start() PTHREAD  socketpair(up=%d,down=%d)\n", aprsis_up, aprsis_down);
+
+	pthread_attr_init(&pthr_attrs);
+	/* 64 kB stack is enough for this thread (I hope!)
+	   default of 2 MB is way too much...*/
+	pthread_attr_setstacksize(&pthr_attrs, 64*1024);
+
+	i = pthread_create(&aprsis_thread, &pthr_attrs, (void*)aprsis_runthread, NULL);
+	if (i == 0) {
+	  if (debug) printf("APRSIS pthread_create() OK!\n");
+	} else {  // FAIL!
+		close(pipes[0]);
+		close(pipes[1]);
+		aprsis_down = -1;
+		aprsis_up   = -1;
+	}
+}
+
+// Shutdown the aprsis thread
+void aprsis_stop(void)
+{
+	die_now = 1;
+	pthread_cancel(aprsis_thread);
+	pthread_join(aprsis_thread, NULL);
+}
+
+
+#else  // No pthread(3p)
+void aprsis_start(void)
+{
+	int i;
+	int pipes[2];
+
+	if (AISh == NULL || AprsIS == NULL) {
+	  fprintf(stderr,"***** NO APRSIS SERVER CONNECTION DEFINED *****");
+	  return;
+	}
+
+
+	i = socketpair(AF_UNIX, SOCK_DGRAM, PF_UNSPEC, pipes);
+	if (i != 0) {
+		return;		/* FAIL ! */
+	}
+
+	i = fork();
+	if (i < 0) {
+		close(pipes[0]);
+		close(pipes[1]);
+		return;		/* FAIL ! */
+	}
+
+	if (i == 0) {
+		/* Child -- the APRSIS talker */
+		aprsis_up = pipes[1];
+		fd_nonblockingmode(pipes[1]);
+		close(pipes[0]);
+		aprsis_main();
+		exit(0);
+	}
+
+
+	/* Parent */
+	close(pipes[1]);
+	fd_nonblockingmode(pipes[0]);
+	aprsis_down = pipes[0];
+}
+
+
+void aprsis_stop(void)
+{
+}
+#endif
+
+
+/*
+ * main-program side pre-poll
+ */
+int aprsis_prepoll(struct aprxpolls *app)
+{
+	int idx = 0;		/* returns number of *fds filled.. */
+
+	struct pollfd *pfd;
+
+	// if (debug>3) printf("aprsis_prepoll()\n");
+
+	pfd = aprxpolls_new(app);
+
+	pfd->fd = aprsis_down;	/* APRS-IS communicator server Sub-process */
+	pfd->events = POLLIN | POLLPRI;
+	pfd->revents = 0;
+
+	/* We react only for reading, if write fails because the socket is
+	   jammed,  that is just too bad... */
+
+	++idx;
+
+	return idx;
+
+}
+
+/*
+ * main-program side reading of aprsis_down
+ */
+static int aprsis_comssockread(int fd)
+{
+	int i;
+	char buf[10000];
+
+	i = recv(fd, buf, sizeof(buf), 0);
+	if (debug>3) printf("aprsis_comsockread(fd=%d) -> i = %d\n", fd, i);
+	if (i == 0)
+		return 0;
+
+	/* TODO: do something with the data ?
+	   A receive-only iGate does nothing, but Rx/Tx would do... */
+
+	/* Send the frame to Tx-IGate function */
+	if (i > 0)
+		igate_from_aprsis(buf, i);
+
+	return 1;
+}
+
+
+/*
+ * main-program side post-poll
+ */
+int aprsis_postpoll(struct aprxpolls *app)
+{
+	int i;
+	struct pollfd *pfd = app->polls;
+
+
+	// if (debug>3) printf("aprsis_postpoll()\n");
+
+	for (i = 0; i < app->pollcount; ++i, ++pfd) {
+		if (pfd->fd == aprsis_down) {
+			/* This is APRS-IS communicator subprocess socket,
+			   and we may have some results.. */
+
+			if (pfd->revents) {	/* Ready for reading */
+				i = aprsis_comssockread(pfd->fd);
+				if (i == 0) {	/* EOF ! */
+					printf("APRS-IS coms subprocess socket EOF from main program side!\n");
+
+					continue;
+				}
+				if (i < 0)
+					continue;
+			}
+		}
+	}			/* .. for .. nfds .. */
+	return 1;		/* there was something we did, maybe.. */
+}
+
+
+// main program side
+int aprsis_config(struct configfile *cf)
+{
+	char *name, *param1;
+	char *str = cf->buf;
+	int has_fault = 0;
+	int line0 = cf->linenum;
+
+	struct aprsis_host *AIH = calloc(1,sizeof(*AIH));
+	AIH->login		= strdup(mycall);
+	AIH->pass		= default_passcode;
+	AIH->heartbeat_monitor_timeout = 120;
+	AIH->mode = MODE_TCP; // default mode
+
+	while (readconfigline(cf) != NULL) {
+		if (configline_is_comment(cf))
+			continue;	/* Comment line, or empty line */
+
+		// It can be severely indented...
+		str = config_SKIPSPACE(cf->buf);
+
+		name = str;
+		str = config_SKIPTEXT(str, NULL);
+		str = config_SKIPSPACE(str);
+		config_STRLOWER(name);
+
+		param1 = str;
+		str = config_SKIPTEXT(str, NULL);
+		str = config_SKIPSPACE(str);
+
+		if (strcmp(name, "</aprsis>") == 0) {
+		  // End of this interface definition block
+		  break;
+		}
+
+		// APRSIS parameters
+
+		// login
+		// server
+		// filter
+		// heartbeat-timeout
+		// mode
+
+		if (strcmp(name, "login") == 0) {
+		  if (strcasecmp("$mycall",param1) != 0) {
+		    // If not "$mycall" ..
+		    config_STRUPPER(param1);
+		    if (!validate_callsign_input(param1,0)) {
+		      // bad input...
+		    }
+		    if (debug)
+		      printf("%s:%d: INFO: LOGIN = '%s' '%s'\n",
+			     cf->name, cf->linenum, param1, str);
+		    if (AIH->login) free(AIH->login);
+		    AIH->login = strdup(param1);
+		  }
+
+		} else if (strcmp(name, "passcode") == 0) {
+		    if (debug)
+		      printf("%s:%d: INFO: PASSCODE = '%s' '%s'\n",
+			     cf->name, cf->linenum, param1, str);
+		    AIH->pass = strdup(param1);
+
+		} else if (strcmp(name, "server") == 0) {
+
+		  if (AIH->server_name) free(AIH->server_name);
+		  AIH->server_name = strdup(param1);
+
+		  param1 = str;
+		  str = config_SKIPTEXT(str, NULL);
+		  // coverity[returned_pointer]
+		  str = config_SKIPSPACE(str);
+		  if ('1' <= *param1 && *param1 <= '9') {
+		    // fixme: more input analysis?
+		    int port = atoi(param1);
+		    if (port < 1 || port > 65535) {
+		      printf("%s:%d INFO: SERVER = '%s' port='%s' is not supplying valid TCP port number, defaulting to '14580'\n",
+			     cf->name, cf->linenum, AIH->server_name, param1);
+		      param1 = "14580";
+		    }
+		    AIH->server_port = strdup(param1);
+		  } else if (*param1 == 0) {
+		    // Default silently!
+		    AIH->server_port = strdup("14580");
+		  } else {
+		    AIH->server_port = strdup("14580");
+		    printf("%s:%d INFO: SERVER = '%s' port='%s' is not supplying valid TCP port number, defaulting to '14580'\n",
+			   cf->name, cf->linenum, AIH->server_name, param1);
+		  }
+
+		  if (debug)
+		    printf("%s:%d: INFO: SERVER = '%s':'%s'\n",
+			   cf->name, cf->linenum, AIH->server_name, AIH->server_port);
+
+		} else if (strcmp(name, "heartbeat-timeout") == 0) {
+		  int i = 0;
+		  if (config_parse_interval(param1, &i)) {
+		    // FIXME: Report parameter failure ...
+		    printf("%s:%d: ERROR: HEARTBEAT-TIMEOUT = '%s'  - bad parameter'\n",
+			   cf->name, cf->linenum, param1);
+		    has_fault = 1;
+		  }
+		  if (i < 0) {	/* param failure ? */
+		    i = 0;	/* no timeout */
+		    printf("%s:%d: ERROR: HEARTBEAT-TIMEOUT = '%s'  - bad parameter'\n",
+			   cf->name, cf->linenum, param1);
+		    has_fault = 1;
+		  }
+		  AIH->heartbeat_monitor_timeout = i;
+		  
+		  if (debug)
+		    printf("%s:%d: INFO: HEARTBEAT-TIMEOUT = '%d' '%s'\n",
+			   cf->name, cf->linenum, i, str);
+
+		} else if (strcmp(name, "filter") == 0) {
+		  int l1 = (AIH->filterparam != NULL) ? strlen(AIH->filterparam) : 0;
+		  int l2 = strlen(param1);
+
+		  AIH->filterparam = realloc( AIH->filterparam, l1 + l2 +2 );
+
+		  if (l1 > 0) {
+		    AIH->filterparam[l1] = ' ';
+		    memcpy(&(AIH->filterparam[l1+1]), param1, l2+1);
+		  } else {
+		    memcpy(&(AIH->filterparam[0]), param1, l2+1);
+		  }
+
+		  if (debug)
+		    printf("%s:%d: INFO: FILTER = '%s' -->  '%s'\n",
+			   cf->name, cf->linenum, param1, AIH->filterparam);
+
+		} else if (strcmp(name, "mode") == 0) {
+		  if (strcmp(param1,"tcp") == 0) {
+		    AIH->mode = MODE_TCP;
+		  } else if (strcmp(param1,"ssl") == 0) {
+		    AIH->mode = MODE_SSL;
+		  } else if (strcmp(param1,"sctp") == 0) {
+		    AIH->mode = MODE_SCTP;
+		  } else if (strcmp(param1,"dtls") == 0) {
+		    AIH->mode = MODE_DTLS;
+		  } else {
+		    printf("%s:%d: ERROR: Unknown mode keyword in <aprsis> block: '%s'\n",
+			 cf->name, cf->linenum, param1);
+		    has_fault = 1;
+		  }
+
+		} else	{
+		  printf("%s:%d: ERROR: Unknown configuration keyword in <aprsis> block: '%s'\n",
+			 cf->name, cf->linenum, name);
+		  has_fault = 1;
+		}
+	}
+	if (AIH->server_name == NULL) {
+	  printf("%s:%d ERROR: This <aprsis> block does not define server!\n",
+		 cf->name, line0);
+	  has_fault = 1;
+	}
+	if (has_fault) {
+		if (AIH->server_name != NULL) free(AIH->server_name);
+		if (AIH->server_port != NULL) free(AIH->server_port);
+		if (AIH->filterparam != NULL) free(AIH->filterparam);
+		if (AIH->login	     != NULL) free(AIH->login);
+		free(AIH);
+
+	} else {
+		if (AprsIS == NULL) {
+			AprsIS = calloc(1, sizeof(*AprsIS));
+			AprsIS->server_socket = -1;
+			AprsIS->next_reconnect = tick.tv_sec +10;
+		}
+                if (AIH->pass == default_passcode) {
+                  printf("%s:%d WARNING: This <aprsis> block does not define passcode!\n",
+                         cf->name, line0);
+                  printf("%s:%d WARNING: Your beacons and RF received will not make it to APRS-IS.\n",
+                         cf->name, line0);
+                }
+
+		AISh = realloc(AISh, sizeof(AISh[0]) * (AIShcount + 1));
+		AISh[AIShcount] = AIH;
+	}
+	return has_fault;
+}
+
+#endif
diff --git a/aprx-complex.conf.in b/aprx-complex.conf.in
new file mode 100644
index 0000000..fd0a4de
--- /dev/null
+++ b/aprx-complex.conf.in
@@ -0,0 +1,528 @@
+#
+#  Sample configuration file for the APRX-2  -- an APRS iGate and Digipeater
+#
+# This configuration is structured with Apache HTTPD style tags
+# which then contain subsystem parameters.
+#
+# Define the parameters in following order:
+#   1)  <aprsis>     ** zero to many
+#   2)  <logging>    ** zero or one
+#   3)  <interface>  ** there can be multiple!
+#   4)  <beacon>     ** zero to many
+#   5)  <telemetry>  ** zero to many
+#   5)  <digipeater> ** zero to many (at most one for each Tx)
+#
+
+
+#
+# Global macro for simplified callsign definition:
+# Usable for 99+% of cases.
+#
+
+mycall  N0CALL-1
+
+#
+# Global macro for simplified "my location" definition in
+# place of explicit "lat nn lon mm" at beacons. Will also
+# give "my location" reference for "filter m/100".
+#
+#myloc lat ddmm.mmN lon dddmm.mmE
+
+
+#  Define possibly multiple APRSIS servers, they are connected to
+#  in Round-Robin fashion.  There also exist DNS RR servers for
+#  this use, one of them is "rotate.aprsis.net".
+<aprsis>
+# The  aprsis-login  parameter: 
+# Station callsignSSID used for relaying APRS frames into APRS-IS.
+#
+#login     $mycall	# login defaults to $mycall macro
+
+#
+# Passcode for your callsign
+#
+passcode -1
+
+# APRS-IS server name and optional portnumber.
+#
+# WARNING: Do not change from default port number [14580]
+#          unless you are absolutely certain you want
+#          something else, and you allow that something
+#          else also affect your tx-igate behaviour!
+#
+server    rotate.aprs2.net
+#server   euro.aprs2.net
+#server   asia.aprs2.net
+#server   noam.aprs2.net
+#server   soam.aprs2.net
+#server   aunz.aprs2.net
+
+# Some APRS-IS servers tell every about 20 seconds to all contact
+# ports that they are there and alive. Others are just silent.
+# Default value 3*"heartbeat" + some  --> 120 (seconds)
+#
+#heartbeat-timeout   0    # Disabler in case your server does not do heartbeat
+#heartbeat-timeout   1m   # Interval of one minute (60 seconds)
+
+# APRS-IS server may support some filter commands.
+# See:  http://www.aprs-is.net/javAPRSFilter.aspx
+#
+# You can define the filter as single long quoted string, or as
+# many short segments with explaining comments following them.
+#
+# Usability of these filters for a Tx-iGate is dubious, but
+# they exist in case you for example want to Tx-iGate packets
+# from some source callsigns in all cases even when they are
+# not in your local area.
+#
+#filter "possibly multiple filter specs in quotes"
+#
+#filter "m/100"	     # My-Range filter: positions within 100 km from my location
+#filter "f/OH2XYZ-3/50"  # Friend-Range filter: 50 km of friend's last beacon position
+</aprsis>
+
+<logging>
+
+# pidfile is UNIX way to tell that others that this program is
+# running with given process-id number.  This has compiled-in
+# default value of:  pidfile @VARRUN@/aprx.pid
+#
+pidfile @VARRUN@/aprx.pid
+
+
+# rflog defines a rotatable file into which all RF-received packets
+# are logged.  The host system can rotate it at any time without
+# need to signal the aprx that the file has been moved.
+#
+rflog @VARLOG@/aprx-rf.log
+
+# aprxlog defines a rotatable file into which most important 
+# events on APRS-IS connection are logged, namely connects and
+# disconnects.  The host system can rotate it at any time without
+# need to signal the aprx that the file has been moved.
+#
+aprxlog @VARLOG@/aprx.log
+
+# dprslog defines a rotatable file into which most important 
+# events on DPRS receiver gateways are logged.
+# The host system can rotate it at any time without need to
+# signal the aprx that the file has been moved.
+#
+#dprslog @VARLOG@/dprs.log
+
+# erlangfile defines a mmap():able binary file, which stores
+# running sums of interfaces upon which the channel erlang
+# estimator runs, and collects data.
+# Depending on the system, it may be running on a filesystem
+# that actually retains data over reboots, or it may not.
+# With this backing store, the system does not loose cumulating
+# erlang data over the current period, if the restart is quick,
+# and does not stradle any exact minute.
+# (Do restarts at 15 seconds over an even minute..)
+# This file is around 0.7 MB per each interface talking APRS.
+# If this file is not defined or can not be created, internal
+# non-persistent in-memory storage will be used.
+#
+# Built-in default value is: @VARRUN@/aprx.state
+#
+#erlangfile @VARRUN@/aprx.state
+
+# erlang-loglevel is config file version of the "-l" option
+# pushing erlang data to syslog(3).
+# Valid values are (possibly) following: NONE, LOG_DAEMON,
+# LOG_FTP, LOG_LPR, LOG_MAIL, LOG_NEWS, LOG_USER, LOG_UUCP,
+# LOG_LOCAL0, LOG_LOCAL1, LOG_LOCAL2, LOG_LOCAL3, LOG_LOCAL4,
+# LOG_LOCAL5, LOG_LOCAL6, LOG_LOCAL7.  If the parameter value is
+# not acceptable, list of accepted values are printed at startup.
+#
+#erlang-loglevel NONE
+
+# erlanglog defines a rotatable file into which erlang data
+# is written in text form.
+#
+#erlanglog @VARLOG@/erlang.log
+
+# erlang-log1min option logs to syslog/file also 1 minute
+# interval data from the program. (In addition to 10m and 60m.)
+#
+#erlang-log1min
+
+</logging>
+
+
+# ***********  Multiple <interface>  definitions follow   *********
+
+# ax25-device  Lists AX.25 ports by their callsigns that in Linux
+#              systems receive APRS packets.  If none are defined,
+#              or the system is not Linux, the AX.25 network receiver
+#              is not enabled.  Used technologies need at least
+#              Linux kernel 2.4.x
+#
+# tx-ok        Boolean telling if this device is able to transmit.
+#
+#<interface>
+#   ax25-device   $mycall
+#   tx-ok true    # There be transmitter there!
+#  #alias         RELAY,WIDE,TRACE
+#  #telem-to-is   true # set to 'false' to disable
+#</interface>
+
+# The  radio serial  option.  Parameters are:
+#   - /dev/ttyUSB1    -- tty device
+#   - 19200           -- baud rate, supported ones are:
+#                        1200, 2400, 4800, 9600, 19200, 38400
+#   - 8n1             -- 8-bits, no parity, one stop-bit,
+#                        no other supported modes
+#   - KISS/XORSUM/SMACK -- KISS mode variants
+#     TNC2            -- non-KISS text format variant
+#     DPRS            -- DPRS (RX) Gateway
+#
+#
+
+### KISS mode example with KISS TNC using TNCID 0
+#<interface>
+#   serial-device   /dev/ttyUSB0  19200 8n1    KISS
+#  #alias         RELAY,WIDE,TRACE
+#   callsign N0CALL-14
+#  #telem-to-is   true # set to 'false' to disable
+#</interface>
+
+### KISS mode example with multiple sub-interfaces via TNCID multiplexing
+#<interface>
+#   serial-device   /dev/ttyUSB0  19200 8n1    KISS
+#  #alias         RELAY,WIDE,TRACE
+#   ## kiss-subif 0 == KISS TNCID 0
+#   <kiss-subif 0>
+#      callsign N0CALL-14
+#      tx-ok    true
+#      #telem-to-is   true # set to 'false' to disable
+#   </kiss-subif>
+#   ## kiss-subif 3 == KISS TNCID 3
+#   <kiss-subif 3>
+#      callsign N0CALL-15
+#      tx-ok    false
+#      #telem-to-is   true # set to 'false' to disable
+#   </kiss-subif>
+#</interface>
+
+#<interface>
+#   serial-device   /dev/ttyUSB1  19200 8n1    TNC2
+#   callsign N0CALL-13
+#   #telem-to-is   true # set to 'false' to disable
+#</interface>
+
+#<interface>
+#   serial-device /dev/ttyUSB1  19200 8n1    DPRS
+#   callsign     dprsgwcallsign  # must define actual callsign
+#   #tx-ok       false           # DPRS monitor can not do transmit
+#   #telem-to-is   true # set to 'false' to disable
+#</interface>
+
+#
+#  "KISS"                  - plain basic KISS mode
+#  "XORSUM" alias "BPQCRC" - KISS with BPQ "CRC" byte
+#  "SMACK"  alias "CRC16"  - KISS with better CRC
+#  "FLEXNET"               - KISS with better CRC
+#  "TNC2"                  - TNC2 monitor format
+#  "DPRS"                  - DPRS (RX) GW
+#
+# Additional/alternate options for the serial-device
+#
+# "timeout 15m" sets a timeout monitor (an interval) to make
+#    reopen/reconnect if the serial port/connection to radio
+#    has failed somehow and nothing is heard. Local serial
+#    ports do not in general need this.  At APRS silent sites
+#    this may cause repeated reconnects, but it should not
+#    harm either.  At busy sites this will handle reconnect
+#    gracefully in case of network failures, and timeout
+#    value can be shortened.
+#
+# "<kiss-subif 0>" sets optional multiplexer index on KISS type
+#    connections. This id is specific for the multiplexer connection
+#    on given port, and can be in range of 0 thru 7 for SMACK type
+#    links, and up to 15 for KISS, and BPQ type links. 
+#    The kiss-subif is settable only for KISS-type connections.
+#    The subif 0 is settable for TNC2 monitor format.
+#
+# "callsign NAME" sets callsign used in statistics displays,
+#    and when the message is sent to APRS-IS.
+#    If none are given, then it will use physical port name.
+#    There can be multiple callsign parameters, if each are
+#    prefixed with their own  tncid  setting.
+#
+# "tx-ok true" enables transmit. System will then also require
+#    that used callsign is valid for AX.25.
+#
+# "initstring" is of two parts, the keyword, and then a string.
+#    initstring "\xC0\xC0\xFF\xC0\r\nMO 0\rKISS $01\r"
+#    The initstring is a binary string,  "\x00" is encodable.
+#    Of the usual C-style codes only "\r" and "\n" are understood.
+#    The initstring is kiss-subif level option.
+#
+#</interface>
+
+
+# The  tcp-device  option defines a connection to remote socket
+# beyond which is a binary transparent connection to a serial
+# port.  The parameter fields:  literal IP address (IPv4 or IPv6),
+# then literal port number, and finally protocol mode.
+# KISS-protocol parameters are same as with normal serial port.
+#
+#<interface>
+#   tcp-device  12.34.56.78  4001  KISS
+#   timeout 15m  # 15 minutes
+#  #alias         RELAY,WIDE,TRACE
+#   <kiss-subif 0>
+#      callsign N0CALL-12
+#      tx-ok    false
+#   </kiss-subif>
+#</interface>
+#
+#<interface>
+#   tcp-device  12.34.56.78  4002  TNC2
+#   timeout 5m   # 5 minutes
+#  #alias         RELAY,WIDE,TRACE
+#   <kiss-subif 0>
+#      callsign N0CALL-12
+#      tx-ok    false
+#   </kiss-subif>
+#</interface>
+
+
+# ***********  Multiple <beacon>  definitions follow   *********
+
+<beacon>
+#
+#  Beacons are sent out to radio transmitters AND/OR APRSIS.
+#  Default is "both", other modes are settable.
+#
+#beaconmode { aprsis | both | radio }
+#
+#  Beacons are sent from a circullar transmission queue, total cycle time
+#  of that queue is 20 minutes by default, and beacons are "evenly"
+#  distributed along it.  Actual intervals are randomized to be anything
+#  in between 80% and 100% of the  cycle-size / number-of-beacons.
+#  First beacon is sent out 30 seconds after system start.
+#  Tune the cycle-size to be suitable to your number of defined beacons.
+#
+#cycle-size  20m
+#
+#
+# Basic beaconed thing is positional message of type "!":
+#
+#beacon symbol "R&" lat "0000.00N" lon "00000.00E" comment "Rx-only iGate"
+#beacon symbol "R&" $myloc comment "Rx-only iGate"
+#
+# Following are basic options:
+#  'symbol'    no default, must be defined!
+#  'lat'       coordinate latitude:   ddmm.mmN  (no default!)
+#  'lon'       coordinate longitude: dddmm.mmE  (no default!)
+#  '$myloc'    coordinate values taken from global 'myloc' entry,
+#              and usable in place of explicit 'lat'+'lon'.
+#  'comment'   optional tail part of the item, default is nothing
+#
+# Sample symbols:
+#   R&   is for "Rx-only iGate"
+#   I&   is for "Tx-iGate"
+#   /#   is for "Digipeater"
+#   I#   is for "Tx-iGate + Digipeater""
+#
+# Additional options are:
+#  'srccall'   parameter sets claimed origination address.
+#  'dstcall'   sets destination address, default "APRXnn"
+#  'interface' parameter picks an interface (must be "tx-ok true" type)
+#  'via'       sets radio distribution pattern, default: none.
+#  'timefix'   On APRS messages with HMS timestamp (hour:min:sec), the
+#              system fixes appropriate field with transmit time timestamp.
+#
+# Message type is by default '!', which is positional no timestamp format.
+# Other possible formats are definable with options:
+#  'type'      Single character setting type:  ! = / @, default: !
+#  'item'      Defines a name of Item (')') type beacons.
+#  'object'    Defines a name of Object (';') type beacons.
+#
+#  'file' option tells a file at which a _raw_ APRS message content is
+#         expected to be found as first line of text. Line ending newline
+#         is removed, and no escapes are supported.  The timefix is
+#         available, though probably should not be used.
+#         No \-processing is done on read text line.
+#
+# 'exec' option tells a computer program which returns to stdout _raw_ APRS
+#        message content without newline. The timefix is
+#        available, though probably should not be used.
+#        No \-processing is done on read text line.
+# 'timeout' defines number of seconds the exec:ed program has to produce
+#        a single text line of APRS data + ending newline, until it is
+#        considered overdue and will be killed + processing moves to next
+#        beacon item.
+#
+# The parameter sets can vary:
+#  a) 'srccall nnn-n dstcall "string" symbol "R&" lat "ddmm.mmN" lon "dddmm.mmE" [comment "any text"]
+#  b) 'srccall nnn-n dstcall "string" symbol "R&" $myloc [comment "any text"]
+#  c) 'srccall nnn-n dstcall "string" raw "string"'
+#
+# The a) form flags on some of possible syntax errors in parameters.
+# It will also create only "!" type messages.  The dest parameter
+# defaults to "APRS", but can be used to give other destinations.
+# The via parameter can be used to add other keywords, like "NOGATE".
+#
+# Writing correct RAW format beacon message is very hard,
+# which is evidenced by the frequency of bad syntax texts
+# people so often put there...   If you can not be persuaded
+# not to do it, then at least VERIFY the beacon result on
+# web service like  findu.com,  or  aprs.fi
+#
+# Do remember that the \ -character has special treatment in the
+# Aprx configuration parser.  If you want a '\' on APRS content,
+# then you encode it on configuration file as:  '\\'
+#
+# Stranger combinations with explicite "transmit this to interface X":
+#
+#
+#beacon                     file /tmp/wxbeacon.txt
+#beacon interface N0CALL-3 srccall N0CALL-3 \
+#                           raw "!0000.00NR00000.00E&aprx - an Rx-only iGate"
+#beacon interface $mycall   symbol "R&" lat "0000.00N" lon "00000.00E" \
+#                           comment "aprx - an Rx-only iGate"
+#beacon interface $mycall   symbol "R&" $myloc \
+#                           comment "aprx - an Rx-only iGate"
+#beacon interface $mycall   symbol "I&" $myloc \
+#                           comment "Tx-iGate"
+#
+</beacon>
+
+# ***********  <telemetry>  definition(s) follow   *********
+#
+# The system will always send telemetry for all of its interfaces
+# to APRSIS, but there is an option to define telemetry to be sent
+# to radio channel by using following sections for each transmitter
+# that is wanted to send out the telemetry.
+#
+#   transmitter   -  callsign referring to <interface>
+#   via           -  optional via-path, only 1 callsign!
+#   source        -  one or more of <interface> callsigns for which
+#                    the telemetry transmission is wanted for
+#
+#<telemetry>
+#	transmitter	$mycall
+#	via		TRACE1-1
+#	source		$mycall
+#</telemetry>
+
+
+#<rx-igate>  ## FIXME: to be written
+# AX.25 filters block selected messages matching on selected regular
+# expressions.  The expressions are case sensitive, and AX.25 address
+# elements are in all uppercase text.  There can be unlimited number
+# of patterns, type fields are four: "source", "destination", "via",
+# and "data".  These patterns can be used in addition to built-in
+# hard-coded reject rules listed in documentation.
+#
+#   ax25-reject-filter source      "^NOCALL"
+#   ax25-reject-filter destination "^NOCALL"
+#   ax25-reject-filter via         "^NOGATE"
+#   ax25-reject-filter data        "^\\?"
+#
+# Source interfaces from which the IGATE functionality feeds the data out
+# By default it feeds from all configured <interface>s.
+#
+#   source   IFCALL-1
+#   source   IFCALL-2
+#</rx-igate>
+
+
+# ***********  Multiple <digipeater>  definitions follow   *********
+
+#  The digipeater definitions tell transmitters that receive
+#  AX.25 packets from possibly multiple sources, and then what
+#  to do on the AX.25 headers of those messages.
+#
+#  There is one transmitter per digipeater -- and inversely, there
+#  can be at most one digipeater for each transmitter.
+#
+#  In each digipeater there is at least one <source>, usually same
+#  as the transmitter.  You may use same <source> on multiple
+#  <digipeater>s. Using multiple instances of same <source> on
+#  a single <digipeater> does not crash the system, but it can cause
+#  packet duplication in case of non-APRS protocols (like AX.25 CONS)
+#
+#  Use only at most two levels of viscous-delay in your <digipeater>.
+#  Immediate sending is by "0", and a delayed sending is any value
+#  from 1 to 9.  This system does not correctly support other than
+#  immediate sending and one level of delay.
+#
+#  Note: In order to igate correct when multiple receivers and
+#        transmitters are used on single channel, the <interface>
+#        definitions of each radio port must have associated
+#        "igate-group N" parameter which has N of value 1 to 3.
+#        See the aprx-manual.pdf for details.
+#        (Default software compilation allows you to have up to
+#         three channels of APRS operation.)
+#
+#
+#<digipeater>
+#    transmitter  TXCALL-1
+#    #ratelimit      60 120      # default: average 60 packets/minute,
+#    #                           #          burst max 120 packets/minute
+#    #srcratelimit   10 20       # Example: by sourcecall:
+#                                #          average 10 packets/minute,
+#                                #          burst max 20 packets/minute
+#
+#    #<trace>
+#    #    maxreq     4
+#    #    maxdone    4
+#    #    keys       TRACE,WIDE,RELAY
+#    #</trace>
+#    #<wide>
+#    #    maxreq     4
+#    #    maxdone    4
+#    #    keys       WIDE
+#    #</wide>
+#
+#    <source>
+#        interface   TXCALL-1
+#    #   ratelimit      60 120      # default: average 60 packets/minute,
+#    #                              #          burst max 120 packets/minute
+#    #   #relay-type    digipeat # default mode is "digipeat"
+#    #   viscous-delay    0      # default: no viscous delay
+#    #   #regex-filter  source       "RE-pattern" # can define multiple patterns
+#    #   #regex-filter  destination  "RE-pattern" # --"--; generic
+#    #   #regex-filter  via          "RE-pattern" # --"--; generic VIA
+#    #   #regex-filter  data         "RE-pattern" # --"--; APRS payload
+#    #	 ##filter      "javAPRSSrvr adjunct filters"
+#    </source>
+#
+#    #<source>                   # Extra receiver(s)
+#    #   interface   RXCALL-1
+#    #   ratelimit      60 120      # default: average 60 packets/minute,
+#    #                              #          burst max 120 packets/minute
+#    #   #relay-type    digipeat # default mode is "digipeat"
+#    #   #regex-filter  source       "RE-pattern" # can define multiple patterns
+#    #   #regex-filter  destination  "RE-pattern" # --"--; generic
+#    #   #regex-filter  via          "RE-pattern" # --"--; generic VIA
+#    #   #regex-filter  data         "RE-pattern" # --"--; APRS payload
+#    #	 ##filter      "javAPRSSrvr adjunct filters"
+#    #</source>
+#
+#    #<source>                  # APRSIS source makes this tx-igate
+#    #   interface    APRSIS
+#    #   ratelimit      60 120      # default: average 60 packets/minute,
+#    #                              #          burst max 120 packets/minute
+#    #   relay-type   third-party  # Must define this for APRSIS source!
+#    #   viscous-delay 5      # recommendation: 5 seconds delay to give
+#    #                        # RF delivery time make itself known.
+#    #   #via-path    WIDE2-2 # You can define a via-path for this source
+#    #</source>
+#
+#    #<source>              # DPRS source makes this DPRS->APRS RF gate
+#    #   interface    DPRS
+#    #   ratelimit    60 120       # default: average 60 packets/minute,
+#    #                             #          burst max 120 packets/minute
+#    #   relay-type   third-party  # Must define this for DPRS source!
+#    #   #viscous-delay 5     # recommendation: 5 seconds delay to give
+#    #                        # RF delivery time make itself known.
+#    #   #via-path    WIDE2-2 # You can define a via-path for this source
+#    #</source>
+#
+#</digipeater>
+
diff --git a/aprx-config.xsd b/aprx-config.xsd
new file mode 100644
index 0000000..cb01cc4
--- /dev/null
+++ b/aprx-config.xsd
@@ -0,0 +1,263 @@
+<?xml version="1.0" encoding="utf-8"?> <!-- -*- xml -*- -->
+<xs:schema targetNamespace="uri:aprx:config"
+           xmlns:ax="uri:aprx:config"
+           xmlns:xs="http://www.w3.org/2001/XMLSchema"
+           xmlns:ht="uri:apache:config"
+           elementFormDefault="qualified"> 
+
+  <xs:annotation>
+    <xs:documentation>
+
+       The Aprx uses following configuration schema, which took its model very much
+       from how Apache HTTPD configuration is done.
+
+       To denote elements without < .. > around them as Apache does, we use
+       "uri:apache:config" style bits, like:  <ht:element>
+
+       Because Apache's configuration predates XML and schemas, there has never been
+       proper XML-like schema for it or anything alike it, nor is this intended to be
+       validatable by XML tools.
+
+       The overall syntax is line oriented, along with \ -characters at the end of line
+       as continuation markers to append next line in place of that character plus the
+       end-of-line character(s).
+
+       Anywhere (except when previous line ends with \ -character) if the first non-white-space
+       character is '#' the whole line is comment, and is discarded.
+
+       Lines containing only white-space characters are also comments and are discarded.
+
+       Presence of non-quoted '#' at the tails of parameter lines should also behave as
+       comment, but it is not universal.
+
+       Presence of extra parameter values is not always flagged as an error.
+
+    </xs:documentation>
+  </xs:annotation>
+   
+
+  <xs:complexType name="AprxConfig">
+    <xs:annotation>
+      <xs:documentation>
+        The overall Aprx config contains parameter groups, and one top-level
+        parameter label.
+        
+        The "mycall" parameter label must be before anything else.
+        The <interface> and <aprsis> groups follow, and
+        the rest that use those interfaces then follow.
+        The <logging> group can be anywhere.
+        Each group can occur multiple times.
+      </xs:documentation>
+    </xs:annotation>
+    <xs:sequence>
+      <ht:element Name="mycall"     type="ax:Ax25CallsignType" />
+      <xs:choice minOccurs="0" maxOccurs="unbounded">
+        <xs:element Name="aprsis"     type="ax:AprsisGroupType"       />
+        <xs:element Name="interface"  type="ax:InterfaceGroupType"    />
+        <xs:element Name="logging"    type="ax:LoggingGroupType"      />
+      </xs:choice>
+      <xs:choice minOccurs="0" maxOccurs="unbounded">
+        <xs:element Name="telemetry"  type="ax:TelemetryGroupType"    />
+        <xs:element Name="digipeater" type="ax:DigipeaterGroupType"   />
+        <xs:element Name="beacon"     type="ax:BeaconGroupType"       />
+        <xs:element Name="logging"    type="ax:LoggingGroupType"      />
+      </xs:choice>
+    </xs:sequence>
+  </xs:complexType>
+
+  <!--  
+       Primitive data types
+  -->
+
+
+  <xs:complexType name="Interval">
+    <xs:annotation>
+      <xs:documentation>
+        The Aprx configuration has flexible time interval definitions.
+        
+        A string of  decimal numbers followed by multiplier character:
+        
+             12 d 2 h 20 m 24 s
+             50 h 70 m 200 s
+             200 s 3 h
+        
+        Whatever notation is easiest to understand for the use.
+
+        The multipliers are single characters and case insensitive.
+        Embedding white-space is permitted for readability.
+        ("d" = days, "h" = hours, "m" = minutes, "s" = seconds)
+
+      </xs:documentation>
+    </xs:annotation>
+    <xs:simpleContent>
+      <xs:extension base="xs:string">
+      </xs:extension>
+    </xs:simpleContent>
+  </xs:complexType>
+
+  <xs:complexType name="Ax25CallsignType">
+    <xs:annotation>
+      <xs:documentation>
+        This is ASCII representation of AX.25 callsign.
+        Up to 6 upper-case letters (A-Z) and digits (0-9), then
+        possibly a minus ('-') and decimal number 0 to 15.
+        By convention a "-0" is never used.
+      </xs:documentation>
+    </xs:annotation>
+    <xs:simpleContent>
+      <xs:extension base="xs:string">
+      </xs:extension>
+    </xs:simpleContent>
+  </xs:complexType>
+
+
+  <xs:complexType name="AprsisCallsignType">
+    <xs:annotation>
+      <xs:documentation>
+        This is more relaxed form of AX.25 callsign:
+        Regular expression:
+            [a-zA-Z0-9]{1,6}($|-[a-zA-Z0-9]{1,2})
+        Or verbally:
+            Up to 6 alphanumeric characters + optional
+            tail of a minus ('-') followed by one or two
+            alphanumeric characters. Also lowercase letters
+            are allowed in alphanumerics.
+      </xs:documentation>
+    </xs:annotation>
+    <xs:simpleContent>
+      <xs:extension base="xs:string">
+      </xs:extension>
+    </xs:simpleContent>
+  </xs:complexType>
+
+
+  <!--  
+       Group types
+  -->
+
+  <xs:complexType name="AprsisGroupType">
+    <xs:annotation>
+      <xs:documentation>
+        The APRSIS group defines communication parameters to APRS-IS network.
+      </xs:documentation>
+    </xs:annotation>
+    <xs:sequence>
+      <xs:choice minOccurs="0" maxOccurs="unbounded">
+        <ht:element Name="login"   type="ax:AprsisCallsignType">
+          <xs:annotation>
+            <xs:documentation>
+              The Login parameter for APRS-IS network.
+
+              The Aprx will calculate correct authentication parameter
+              for that login value.
+            </xs:documentation>
+          </xs:annotation>
+        </ht:element>
+        <ht:element Name="server"  type="ax:AprsisServerParameterType">
+          <xs:annotation>
+            <xs:documentation>
+              Defines server to which the Aprx connects for the APRS-IS
+              service.
+
+                    serverhost [portnum]
+
+              Chosen servers should be regional round-robin ones, see
+              http://www.aprs2.net/
+                   noam.aprs2.net
+                   soam.aprs2.net
+                   euro.aprs2.net
+                   asia.aprs2.net
+                   aunz.aprs2.net
+              or the global pool:
+                   rotate.aprs2.net
+
+              You SHOULD NOT connect to any specific one, as none of
+              the servers are behind a load-balancing fail-over mechanisms.
+
+            </xs:documentation>
+          </xs:annotation>
+        </ht:element>
+        <ht:element Name="heartbeat-timeout" type="ax:IntervalType">
+          <!-- default value: 120 second -->
+        </ht:element>
+        <ht:element Name="filter"  type="ax:AprsisFilterParameterType">
+          <xs:annotation>
+            <xs:documentation>
+              One white-space terminated parameter that is fed to APRS-IS
+              server immediately after a login.
+
+              If multiple filters are needed, they are defined with
+              successive 'filter' parameter entries.
+            </xs:documentation>
+          </xs:annotation>
+        </ht:element>
+      </xs:choice>
+    </xs:sequence>
+  </xs:complexType>
+
+  <xs:complexType name="InterfaceGroupType">
+    <xs:annotation>
+      <xs:documentation>
+      </xs:documentation>
+    </xs:annotation>
+  </xs:complexType>
+
+  <xs:complexType name="TelemetryGroupType">
+    <xs:annotation>
+      <xs:documentation>
+      </xs:documentation>
+    </xs:annotation>
+  </xs:complexType>
+
+  <xs:complexType name="DigipeaterGroupType">
+    <xs:annotation>
+      <xs:documentation>
+      </xs:documentation>
+    </xs:annotation>
+  </xs:complexType>
+
+  <xs:complexType name="BeaconGroupType">
+    <xs:annotation>
+      <xs:documentation>
+      </xs:documentation>
+    </xs:annotation>
+  </xs:complexType>
+
+  <xs:complexType name="LoggingGroupType">
+    <xs:annotation>
+      <xs:documentation>
+        The Logging group defines how the Aprx does logs.
+        Without it, or any parameters inside it, no logging happens.
+      </xs:documentation>
+    </xs:annotation>
+    <xs:sequence>
+      <xs:choice minOccurs="0" maxOccurs="unbounded">
+        <ht:element Name="aprxlog"     type="ax:filename">
+        </ht:element>
+        <ht:element Name="dprslog"     type="ax:filename">
+        </ht:element>
+        <ht:element Name="rflog"       type="ax:filename">
+        </ht:element>
+        <ht:element Name="pidfile"     type="ax:filename">
+        </ht:element>
+        <ht:element Name="erlangfile"  type="ax:filename">
+        </ht:element>
+        <ht:element Name="erlang-loglevel"  type="ax:???">
+        </ht:element>
+        <ht:element Name="erlanglog"        type="ax:???">
+        </ht:element>
+        <ht:element Name="erlang-log1min"   type="ax:???">
+        </ht:element>
+      </xs:choice>
+    </xs:sequence>
+  </xs:complexType>
+  
+
+  <!--
+      <xs:annotation>
+        <xs:documentation>
+        </xs:documentation>
+      </xs:annotation>
+  -->
+
+</xs:schema>
diff --git a/aprx-rxigate.conf.in b/aprx-rxigate.conf.in
new file mode 100644
index 0000000..9aa633f
--- /dev/null
+++ b/aprx-rxigate.conf.in
@@ -0,0 +1,118 @@
+#
+# Minimal sample configuration file for the APRX-2 as Rx-only iGate.
+#
+# This configuration is structured with Apache HTTPD style tags
+# which then contain subsystem parameters.
+#
+
+#
+# For simple case, you need to adjust 4 things:
+#   - Mycall parameter
+#   - Select correct type of interface (ax25-device or serial-device)
+#   - Optionally set a beacon telling where this system is
+#   - Optionally enable digipeater with or without tx-igate
+#
+
+#
+# Define the parameters in following order:
+#   1)  mycall
+#   2)  <aprsis>     ** one
+#   3)  <logging>    ** one
+#   4)  <interface>  ** possibly multiple for each of radio receivers
+#
+
+#
+# Global macro for simplified callsign definition:
+# Usable for 99+% of cases.
+#
+
+mycall  N0CALL-1
+
+<aprsis>
+#login     OTHERCALL-7	# login defaults to $mycall
+
+# APRS-IS server name and optional portnumber.
+# Default port is 14580, and it should be enough for you.
+
+server    rotate.aprs2.net
+
+#server   euro.aprs2.net
+#server   asia.aprs2.net
+#server   noam.aprs2.net
+#server   soam.aprs2.net
+#server   aunz.aprs2.net
+
+#
+# Passcode for your callsign
+#
+passcode -1
+
+</aprsis>
+
+<logging>
+
+# rflog defines a rotatable file into which all RF-received packets
+# are logged.  The host system can rotate it at any time without
+# need to signal the aprx that the file has been moved.
+#
+# rflog @VARLOG@/aprx-rf.log
+
+# aprxlog defines a rotatable file into which most important 
+# events on APRS-IS connection are logged, namely connects and
+# disconnects.  The host system can rotate it at any time without
+# need to signal the aprx that the file has been moved.
+#
+# aprxlog @VARLOG@/aprx.log
+
+</logging>
+
+
+# ***********  Multiple <interface> definitions can follow   *********
+
+# ax25-device  Lists AX.25 ports by their callsigns that in Linux
+#              systems receive APRS packets.  If none are defined,
+#              or the system is not Linux, the AX.25 network receiver
+#              is not enabled.  Used technologies need at least
+#              Linux kernel 2.4.x
+#
+# tx-ok        Boolean telling if this device is able to transmit.
+#
+
+#<interface>
+#   ax25-device $mycall
+#   #tx-ok      false  # transmitter enable defaults to false
+#</interface>
+
+
+#
+# The  TNC serial  options.  Parameters are:
+#   - /dev/ttyUSB1    -- tty device
+#   - 19200           -- baud rate, supported ones are:
+#                        1200, 2400, 4800, 9600, 19200, 38400
+#   - 8n1             -- 8-bits, no parity, one stop-bit,
+#                        no other supported modes
+#   - "KISS"                  - plain basic KISS mode
+#   - "XORSUM" alias "BPQCRC" - KISS with BPQ "CRC" byte
+#   - "SMACK"  alias "CRC16"  - KISS with real CRC
+#   - "FLEXNET"               - KISS with real CRC
+#   - "TNC2"                  - TNC2 monitor format
+#   - "DPRS"                  - DPRS (RX) GW
+#
+
+#<interface>
+#   serial-device /dev/ttyUSB0  19200 8n1    KISS
+#   #callsign     $mycall  # callsign defaults to $mycall
+#   #tx-ok        false    # transmitter enable defaults to false
+#</interface>
+
+#<interface>
+#   serial-device /dev/ttyUSB1  19200 8n1    TNC2
+#   #callsign     $mycall  # callsign defaults to $mycall
+#   #tx-ok        false    # TNC2 monitor can not have transmitter
+#</interface>
+
+#<interface>
+#   serial-device /dev/ttyUSB1  19200 8n1    DPRS
+#   callsign     dprsgwcallsign  # must define actual callsign
+#   #tx-ok       false           # DPRS monitor can not do transmit
+#</interface>
diff --git a/aprx-stat.8.in b/aprx-stat.8.in
new file mode 100644
index 0000000..06284ad
--- /dev/null
+++ b/aprx-stat.8.in
@@ -0,0 +1,217 @@
+.TH aprx\-stat 8 "@DATEVERSION@"
+.LO 8
+.SH NAME
+.B aprx\-stat
+\- statistics utility for
+.BR aprx (8)
+.SH SYNOPSIS
+.B aprx\-stat
+.RB [ \-t ]
+.RB [ \-f \fI at VARRUN@/aprx.state\fR]
+.RB { \-S | \-x | \-X }
+.SH DESCRIPTION
+.B aprx\-stat
+is a statistics utility for
+.BR aprx (8)
+program.
+
+.SH OPTIONS
+The
+.B aprx\-stat
+has following runtime options:
+.TP
+.B "\-f \fI at VARRUN@/aprx.state\fR"
+Turn on verbose debugging, outputs data to STDOUT.
+.TP
+.B "\-S"
+SNMP data mode, current counter and gauge values.
+.TP
+.B "\-t"
+Use UNIX
+.I time_t
+for timestamps, instead of human readable text format.
+.TP
+.B "\-x"
+Lattest of extended historical gauge values.
+This gives for each input interface
+.RS
+.IP \(bu 2
+SNMP data
+.IP \(bu 2
+last 90 of 1 minute values,
+.IP \(bu 2
+10 of 10 minute values,
+.IP \(bu 2
+3 of 60 minute values.
+.RE
+.TP
+.B "\-X"
+Full extended historical gauge values.
+This gives all the contents of historical value data ring-buffers.
+.RS
+.IP \(bu 2
+SNMP data
+.IP \(bu 2
+1 minute resolution: 24 hours
+.IP \(bu 2
+10 minute resolution: 7 days
+.IP \(bu 2
+60 minute resolution: 3 months
+.RE
+
+.SH SNMP DATA OUTPUT
+For each interface feeding AX.25 packets and/or KISS frames to this program,
+there are following kind of 
+.nf
+\fC
+SNMP  /dev/ttyUSB1   798282 11088   0  0     3
+SNMP  ax0   798282 11088   0  0     7
+SNMP  ax1   798282 11088   0  0     94
+.fi
+.PP
+where columns are:
+.IP \(bu 2
+"SNMP" - keyword
+.IP \(bu 2
+Interface (AX.25 IF name, or serial port device name)
+.IP \(bu 2
+Received byte counter
+.IP \(bu 2
+Received frame (packet) counter
+.IP \(bu 2
+.\" Transmitted byte counter (will stay zero)
+.I Dropped
+byte counter
+.IP \(bu 2
+.\" Transmitted frame counter (will stay zero)
+.I Dropped
+frame counter
+.IP \(bu 2
+Age in seconds of last update of this statistics.
+
+.SH EXTENDED DATA OUTPUT
+Extended data output gives formatted historical periodic accumulates of interface traffic
+counters, and Erlang value estimates based on that.
+.PP
+.nf
+\fC
+
+SNMP  /dev/ttyUSB1   816675 11332   0  0     15
+
+1min data
+2007-12-24 14:10  /dev/ttyUSB1  1m    374    6      0    0   0.047  0.000
+2007-12-24 14:09  /dev/ttyUSB1  1m    377    5      0    0   0.047  0.000
+2007-12-24 14:08  /dev/ttyUSB1  1m    347    5      0    0   0.043  0.000
+2007-12-24 14:07  /dev/ttyUSB1  1m    140    2      0    0   0.018  0.000
+\(bu\(bu\(bu
+
+10min data
+2007-12-24 14:10  /dev/ttyUSB1 10m   3829   55      0    0   0.048  0.000
+2007-12-24 14:00  /dev/ttyUSB1 10m   2182   28      0    0   0.027  0.000
+2007-12-24 13:50  /dev/ttyUSB1 10m   3205   44      0    0   0.040  0.000
+2007-12-24 13:40  /dev/ttyUSB1 10m   3811   50      0    0   0.048  0.000
+\(bu\(bu\(bu
+
+60min data
+2007-12-24 14:00  /dev/ttyUSB1 60m  22510  295      0    0   0.047  0.000
+2007-12-24 13:00  /dev/ttyUSB1 60m  24886  347      0    0   0.052  0.000
+\(bu\(bu\(bu
+.fi
+.PP
+The output repeats for all interfaces.
+.PP
+The SNMP dataset is given in the beginning, and described above.
+Then each extended output line has following fields:
+.IP \(bu 2
+Timestamp is two fields, date and time (in minute resolution) is in UTC.
+.IP \(bu 2
+Alternate timestamp format is UNIX
+.I time_t
+as an integer, counting seconds from epoch, and as single field.
+.IP \(bu 2
+Interface name is same as in SNMP case.
+.IP \(bu 2
+Data qualifier tells what integration period the data is valid for:
+.IR 1m ", " 10m ", " 60m .
+.IP \(bu 2
+Counter of received bytes on interface (including KISS flags etc.)
+.IP \(bu 2
+Counter of received frames.
+.IP \(bu 2
+.\" Counter of transmitted bytes on interface
+Counter of dropped bytes.
+.IP \(bu 2
+.\" Counter of transmitted frames.
+Counter of dropped frames.
+.IP \(bu 2
+Reception
+.I Erlang 
+value estimate.
+.IP \(bu 2
+.\" Transmission
+Dropped bytes
+.I Erlang
+value estimate.
+.PP
+.SH TODO
+.SH BUGS
+.SH SEE ALSO
+.BR aprx (8)
+
+.SH CONFIGURATION FILE
+There is no configuration file.
+
+.SH NOTES: ERLANG
+The
+.I Erlang
+is telecom measurement of channel occupancy, and in this application sense
+it does tell how much traffic there is on the radio channel.
+.PP
+Most radio transmitters are not aware of all transmitters on channel,
+and thus there can happen a collision causing loss of both messages.
+The higher the channel activity, the more likely that collision is.
+For further details, refer to statistical mathematics books, or perhaps
+on Wikipedia.
+.PP
+In order to measure channel activity, the
+.B aprx
+program suite has these built-in statistics counter and summary estimators.
+.PP
+The
+.I Erlag
+value that the estimators present are likely somewhat
+.I underestimating
+the true channel occupancy simply because it calculates estimate of channel
+bit transmit rate, and thus a per-minute character capacity.
+It does not know true frequency of bit-stuffing events of the HDLC framing,
+nor each transmitter pre- and port frame PTT times. The transmitters need to
+stabilize their transmit oscillators in many cases, which may take up to
+around 500 ms!
+The counters are not aware of this preamble-, nor postamble-times.
+.PP
+The HDLC bit stuffing ratio is guessed to be 8.2 bits for each 8 bits of payload.
+
+
+.SH NOTES: SUID ROOT
+This program needs probably to be run as
+.I "suid\-root" 
+!
+It is considered safe to do so, as this checks that the
+.B "\-f"
+parameter file is of correct "magic value", and will not try to create
+it if it does not exist, nor modify that file under any circumstances,
+nor reveal content of "wrong magic kind" of file.
+
+.SH AUTHOR
+This little piece was written by
+.I "Matti Aarnio, OH2MQK"
+during a dark and rainy fall and winter of 2007-2008 after a number
+of discussions grumbling about current breed of available software
+for APRS iGate use in Linux (or of any UNIX) platforms.
+Fall and winter 2009-2010 saw appearance of digipeater functionality.
+.PP
+Principal contributors and test users include:
+.IR "Pentti Gronlund, OH3BK" ,
+.IR "Reijo Hakala, OH1GWK" .
+Debian packaging by
+.IR "Kimmo Jukarinen, OH3GNU" .
diff --git a/aprx-stat.c b/aprx-stat.c
new file mode 100644
index 0000000..0773813
--- /dev/null
+++ b/aprx-stat.c
@@ -0,0 +1,258 @@
+/* **************************************************************** *
+ *                                                                  *
+ *  APRX -- 2nd generation receive-only APRS-i-gate with            *
+ *          minimal requirement of esoteric facilities or           *
+ *          libraries of any kind beyond UNIX system libc.          *
+ *                                                                  *
+ * (c) Matti Aarnio - OH2MQK,  2007-2014                            *
+ *                                                                  *
+ * **************************************************************** */
+
+
+#include "aprx.h"
+
+
+int time_reset;
+int debug;			/* linkage dummy */
+int erlangout;
+int epochtime;
+const char *aprxlogfile;	/* linkage dummy */
+const char *mycall;		/* linkage dummy */
+
+#ifdef ERLANGSTORAGE
+
+void printtime(char *buf, int buflen)
+{
+	struct tm *t = gmtime(&now.tv_sec);
+	// strftime(timebuf, 60, "%Y-%m-%d %H:%M:%S", t);
+	sprintf(buf, "%04d-%02d-%02d %02d:%02d:%02d",
+		t->tm_year+1900,t->tm_mon+1,t->tm_mday,
+		t->tm_hour,t->tm_min,t->tm_sec);
+}
+
+
+void erlang_snmp(void)
+{
+	int i;
+
+	/* SNMP data output - continuously growing counters
+	 */
+
+	printf("APRX.pid     %8ld\n", (long) ErlangHead->server_pid);
+	printf("APRX.uptime  %8ld\n",
+	       (long) (time(NULL) - ErlangHead->start_time));
+	printf("APRX.mycall  %s\n", ErlangHead->mycall);
+
+	for (i = 0; i < ErlangLinesCount; ++i) {
+		struct erlangline *E = ErlangLines[i];
+
+		printf("%s", E->name);
+		printf("   %ld %ld   %ld  %ld  %ld  %ld    %d\n",
+		       E->SNMP.bytes_rx, E->SNMP.packets_rx,
+		       E->SNMP.bytes_rxdrop, E->SNMP.packets_rxdrop,
+		       E->SNMP.bytes_tx, E->SNMP.packets_tx,
+		       (int) (now.tv_sec - E->last_update));
+	}
+}
+
+void erlang_xml(int topmode)
+{
+	int i, j, k, t;
+
+	/* What this outputs is not XML, but a mild approximation
+	   of the data that XML version would output.. 
+	   It is not even the whole dataset, just last 60 samples
+	   of each type.
+	 */
+
+
+	printf("APRX.pid     %8ld\n", (long) ErlangHead->server_pid);
+	printf("APRX.uptime  %8ld\n",
+	       (long) (time(NULL) - ErlangHead->start_time));
+	printf("APRX.mycall  %s\n", ErlangHead->mycall);
+
+	for (i = 0; i < ErlangLinesCount; ++i) {
+		struct erlangline *E = ErlangLines[i];
+		char logtime[40];
+		struct tm *wallclock;
+
+		printf("\nSNMP  %s", E->name);
+		printf("   %ld %ld   %ld  %ld  %ld  %ld   %d\n",
+		       E->SNMP.bytes_rx, E->SNMP.packets_rx,
+		       E->SNMP.bytes_rxdrop, E->SNMP.packets_rxdrop,
+		       E->SNMP.bytes_tx, E->SNMP.packets_tx,
+		       (int) (now.tv_sec - E->last_update));
+
+		printf("\n1min data\n");
+		k = E->e1_cursor;
+		t = E->e1_max;
+		if (topmode)
+			t = 90;
+		for (j = 0; j < t; ++j) {
+			--k;
+			if (k < 0)
+				k = E->e1_max - 1;
+			if (E->e1[k].update == 0)
+				continue;
+			if (epochtime) {
+				sprintf(logtime, "%ld",
+					(long) E->e1[k].update);
+			} else {
+				wallclock = gmtime(&E->e1[k].update);
+				strftime(logtime, sizeof(logtime),
+					 "%Y-%m-%d %H:%M", wallclock);
+			}
+			printf("%s  %s", logtime, E->name);
+			printf(" %2dm  %5ld  %3ld  %5ld  %3ld  %5ld  %3ld %5.3f  %5.3f  %5.3f\n",
+			       1,
+			       E->e1[k].bytes_rx,     E->e1[k].packets_rx,
+			       E->e1[k].bytes_rxdrop, E->e1[k].packets_rxdrop,
+			       E->e1[k].bytes_tx,     E->e1[k].packets_tx,
+			       (float) E->e1[k].bytes_rx /
+			       ((float) E->erlang_capa * 60.0),
+			       (float) E->e1[k].bytes_rxdrop /
+			       ((float) E->erlang_capa * 60.0),
+			       (float)E->e1[k].bytes_tx/((float)E->erlang_capa*60.0)
+				);
+		}
+
+
+		printf("\n10min data\n");
+		k = E->e10_cursor;
+		t = E->e10_max;
+		if (topmode)
+			t = 10;
+		for (j = 0; j < t; ++j) {
+			--k;
+			if (k < 0)
+				k = E->e10_max - 1;
+			if (E->e10[k].update == 0)
+				continue;
+			if (epochtime) {
+				sprintf(logtime, "%ld",
+					(long) E->e10[k].update);
+			} else {
+				wallclock = gmtime(&E->e10[k].update);
+				strftime(logtime, sizeof(logtime),
+					 "%Y-%m-%d %H:%M", wallclock);
+			}
+			printf("%s  %s", logtime, E->name);
+			printf(" %2dm  %5ld  %3ld  %5ld  %3ld  %5ld  %3ld %5.3f  %5.3f  %5.3f\n",
+			       10,
+			       E->e10[k].bytes_rx,     E->e10[k].packets_rx,
+			       E->e10[k].bytes_rxdrop, E->e10[k].packets_rxdrop,
+			       E->e10[k].bytes_tx,     E->e10[k].packets_tx,
+			       (float) E->e10[k].bytes_rx /
+			       ((float) E->erlang_capa * 60.0),
+			       (float) E->e10[k].bytes_rxdrop /
+			       ((float) E->erlang_capa * 60.0),
+			       (float)E->e10[k].bytes_tx/((float)E->erlang_capa*60.0)
+				);
+		}
+
+
+		printf("\n60min data\n");
+		k = E->e60_cursor;
+		t = E->e60_max;
+		if (topmode)
+			t = 3;
+		for (j = 0; j < t; ++j) {
+			--k;
+			if (k < 0)
+				k = E->e60_max - 1;
+			if (E->e60[k].update == 0)
+				continue;
+			if (epochtime) {
+				sprintf(logtime, "%ld",
+					(long) E->e60[k].update);
+			} else {
+				wallclock = gmtime(&E->e60[k].update);
+				strftime(logtime, sizeof(logtime),
+					 "%Y-%m-%d %H:%M", wallclock);
+			}
+			printf("%s  %s", logtime, E->name);
+			printf(" %2dm  %5ld  %3ld  %5ld  %3ld  %5ld  %3ld %5.3f  %5.3f  %5.3f\n",
+			       60,
+			       E->e60[k].bytes_rx,     E->e60[k].packets_rx,
+			       E->e60[k].bytes_rxdrop, E->e60[k].packets_rxdrop,
+			       E->e60[k].bytes_tx,     E->e60[k].packets_tx,
+			       (float) E->e60[k].bytes_rx /
+			       ((float) E->erlang_capa * 60.0),
+			       (float) E->e60[k].bytes_rxdrop /
+			       ((float) E->erlang_capa * 60.0),
+			       (float)E->e60[k].bytes_tx/((float)E->erlang_capa*60.0)
+				);
+		}
+
+	}
+
+
+	exit(0);
+}
+
+
+void usage(void)
+{
+	printf("Usage: aprx-stat [-t] [-f arpx-erlang.dat] {-S|-x|-X}\n");
+	exit(64);
+}
+
+int main(int argc, char **argv)
+{
+	int opt;
+	int mode_snmp = 0;
+	int mode_xml = 0;
+
+        gettimeofday(&now, NULL);
+
+	while ((opt = getopt(argc, argv, "f:StxX?h")) != -1) {
+		switch (opt) {
+		case 'f':
+			erlang_backingstore = optarg;
+			break;
+		case 'S':	/* SNMP */
+			++mode_snmp;
+			break;
+		case 'X':
+			mode_xml = 1;
+			break;
+		case 'x':
+			mode_xml = 2;
+			break;
+		case 't':
+			epochtime = 1;
+			break;
+		default:
+			usage();
+			break;
+		}
+	}
+
+	erlang_start(0);	/* Open the backing-store */
+
+	if (!ErlangHead)
+		exit(1);
+
+	if (mode_snmp) {
+		erlang_snmp();
+	} else if (mode_xml == 1) {
+		erlang_xml(0);
+	} else if (mode_xml == 2) {
+		erlang_xml(1);
+	} else
+		usage();
+
+	return 0;
+}
+
+#else
+
+void printtime(char *buf, int buflen) {} /* linkage dummy */
+void aprx_syslog_init(const char *p) {}
+
+int main(int argc, char **argv)
+{
+  fprintf(stderr,"Sorry - aprx-stat program not available in system configured without ERLANGSTORAGE\n");
+  return 1;
+}
+#endif
diff --git a/aprx.8.in b/aprx.8.in
new file mode 100644
index 0000000..abd3a58
--- /dev/null
+++ b/aprx.8.in
@@ -0,0 +1,1428 @@
+.TH aprx 8 "@DATEVERSION@"
+.LO 8
+.SH NAME
+.B Aprx-2
+\- An APRS iGate application with integrated Digipeater.
+.SH SYNOPSIS
+.B aprx
+.RB [ \-d [ d [ d ]]]
+.RB [ \-e ]
+.RB [ \-i ]
+.RB [ \-v ]
+.RB [ \-V ]
+.RB [ \-l " \fIsyslogfacilityname\fR]"
+.RB [ \-f " \fI at CFGFILE@\fR]"
+.SH DESCRIPTION
+The
+.B aprx
+program is a special purpose Ham-radio application supplying
+infrastructure services for APRS protocol use.
+.PP
+A more detailed manual is available at:
+.br
+http://ham.zmailer.org/oh2mqk/aprx/aprx-manual.pdf
+.PP
+.SH FEATURES
+The Aprx begun as a receive-only APRS iGate application with minimum system
+support technology requirements.
+This version has also multi-port digipeater support, transmit iGate,
+and experimental D-PRS-to-APRS RF/Rx-iGate.
+.PP
+.IP \(bu 3
+The Aprx does not require machine to have any other software in it, than things
+in UNIX standard libc. In particular no special AX.25 libraries at all, nor
+widgets or even C++ runtime.
+.IP \(bu 3
+Important goal has been to keep R/W memory footprint as small as possible,
+and on general purpose i386 Linux a single radio port iGate+digipeater is
+now around 250 kB of R/W memory allocations.
+.IP \(bu 3
+Any UNIX (and UNIX like) platform should work for the Aprx, or be trivially ported.
+.IP \(bu 3
+The Aprx can listen "TNC2 monitor" and "KISS" speaking TNCs on any serial ports.
+.IP \(bu 3
+For Aprx the serial port can be ordinary host computer port, a USB serial port,
+or remote port on a remote server behind the internet, like cisco router AUX
+ports (port 4001, TCP STREAM without TELNET escapes.)
+.IP \(bu 3
+The Aprx does not require machine to have AX.25 protocol support internally!
+(Thus this works also on e.g. Solaris and BSD machines without PF\_AX25 sockets.)
+.IP \(bu 3
+On Linux machine with kernel internal AX.25 protocol support,
+the Aprx can listen on it with promiscuous mode and in order to use that,
+the Aprx must be started as
+.I root
+user, and be configured to list interface callsigns that APRS packets are
+coming in.
+The AX.25 socket listening is not in itself configurable, it is always exists
+in Linux systems, and related configuration parameters are ignored in other
+platforms.
+This socket listening does not need auxiliary "libax25" to function.
+.IP \(bu 3
+The Aprx program can be run without root privileges at least against remote
+serial port servers.  One must change local serial port ownership or
+access-groups (if any are used) to userid that runs the program and possibly
+do several changes of file paths in configuration file beginning
+with its location (startup parameter).
+How that is done is up to the user or system integrator of this program.
+.IP \(bu 3
+The Aprx connects with one callsign-ssid pair to APRS-IS core for all received
+radio ports.
+.IP \(bu 3
+The Aprx Rx-iGate knows that messages with following tokens in AX.25 VIA
+fields are not to be relayed into APRS-IS network:
+.RS 9
+.B "RFONLY, NOGATE, TCPIP, TCPXX"
+.RE
+.IP \(bu 3
+The Aprx Rx-iGate knows that following source address prefixes are bogus and
+thus messages with them are to be junked:
+.RS 9
+.B "WIDE, RELAY, TRACE, TCPIP, TCPXX, NOCALL, N0CALL"
+.RE
+.IP \(bu 3
+The Aprx Rx-iGate Drops all
+.I query
+messages ("?").
+.IP \(bu 3
+The Aprx Rx-iGate opens up all 3rd party messages ("}"), and checks the internal
+data if it is OK to be gated out to APRS-IS.
+.IP \(bu 3
+The Aprx has built-in "Erlang monitor" mechanism that telemeters each receiving
+interface to APRS-IS. It can also syslog the interface specific channel occupancy,
+and optionally can output to STDOUT.
+.IP \(bu 3
+The Aprx (since version 1.91) can do digipeater functions.
+.IP \(bu 3
+The Aprx (since version 1.99) does have experimental D-STAR D-PRS to APRS
+gateway functionality.  See the
+.I aprx-manual.pdf
+for details.
+.IP \(bu 3
+The Aprx can be run on systems without writable storage, even with very little
+memory, like on NSLU2, and OpenWrt platforms.
+The experiments have shown that a single radio Tx-iGate+digipeater works
+with less than 300 kB of writable RAM for the Aprx itself.
+Additional memory is necessary for operating system services of TCP/IP
+networking, and serial port drivers.
+.PP
+.SH OPTIONS
+The
+.B aprx
+has following runtime options:
+.TP
+.B "\-i"
+Keep the program foreground without debugging outputs.
+.TP
+.B "\-d"
+Turn on verbose debugging, outputs data to STDOUT.
+.TP
+.B "\-dd"
+the "more debug" mode shows also details of network interaction with
+the APRS-IS network service.
+.TP
+.B "\-ddd"
+the "even more debug" mode shows also detail classification of
+every kind of frame received in KISS variants.
+.TP
+.B "\-e"
+.I "Erlang output"
+prints 10 minute and 60 minute traffic accumulation byte counts, and guestimates
+on channel occupancy, alias "Erlang".
+These outputs are sent to STDOUT, which system operator may choose to log elsewere.
+This is independent if the "\-l" option below.
+.TP
+.BI "\-f " "@CFGFILE@"
+Configuration file, given path is built-in default, and can be overridden by the program runner.
+.TP
+.BR "\-l" " \fIsyslogfacilityname\fR"
+Defines
+.RB syslog (3)
+facility code used by the erlang reporter by defining its name.
+Default value is:
+.BR NONE ,
+and accepted values are:
+.BR LOG_DAEMON ,
+.BR LOG_FTP ,
+.BR LOG_LPR ,
+.BR LOG_MAIL ,
+.BR LOG_NEWS ,
+.BR LOG_USER ,
+.BR LOG_UUCP ,
+.BR LOG_LOCAL0 ,
+.BR LOG_LOCAL1 ,
+.BR LOG_LOCAL2 ,
+.BR LOG_LOCAL3 ,
+.BR LOG_LOCAL4 ,
+.BR LOG_LOCAL5 ,
+.BR LOG_LOCAL6 ,
+.BR LOG_LOCAL7 .
+That list is subject to actual facility code set in the system,
+and in any case if you specify a code that is not known, then the program
+will complain during the startup, and report it.
+This is independent of the "\-e" option above.
+.TP
+.B "\-v"
+Verbose logging of received traffic to STDOUT.
+Lines begin with reception timestamp (UNIX time_t seconds), then TAB,
+and either data as is, or with prefix byte: "*" for "discarded due to data content",
+or possibly "#" for "discarded due to APRS-IS being unreachable".
+.TP
+.B "\-V"
+Print source version compiled to this binary, and exit.
+.PP
+.SS DEBUGGING SYSTEM
+Use parameter set 
+.B "\-ddv"
+(or
+.BR "\-dddv" )
+to test new configuration by running it synchronously to console.
+.PP
+.SS NORMAL OPERATION
+Running the
+.B aprx
+program without any of option flags:
+.BR "\-d" ,
+.BR "\-v" ", or"
+.B "\-e"
+reads possibly given configuration, then automatically backgrounds the process, and writes
+.IR pidfile .
+When the process whose number written in
+.I pidfile
+is then sent a SIGTERM signal, it automatically shuts down itself, and removes the
+.IR pidfile .
+The
+.I pidfile
+can be runtime configured with the
+.BI \-f " @CFGFILE@"
+file, and it has default name of:
+.IR "@VARRUN@/aprx.pid" .
+.PP
+
+.SH CONFIGURATION FILE
+The configuration file is used to setup the program to do its job.
+.PP
+You can construct following configurations:
+.PP
+.IP \(bu 3
+A
+.I receive-only
+iGate server.
+.IP \(bu 3
+A digipeater with bi-directional iGate server.
+.IP \(bu 3
+A
+.I "single radio"
+digipeater.  (The most common type of digipeater.)
+.IP \(bu 3
+A
+.I multi-interfaced
+digipeater relaying traffic in between multiple radios.  (On same or on separate frequencies.)
+.IP \(bu 3
+A
+.I "viscuous digipeater,"
+which relays a packet it heard from viscuous source after the viscuous delay,
+.I unless it was heard more times than only once,
+or it was heard from non-viscuous source before the viscuous one was digipeated.
+This allows of making fill-in digipeaters that will not digipeat the packet,
+if that same packet was heard twice or more before the viscuos delay expired.
+.PP
+In the configuration file a line ending backslash (\\) character concatenates
+next input line into itself. Combined result can be up to 8000 bytes long.
+This combination can be a bit surprising:
+.RS 3em
+.nf
+\fC#beacon .... long text  \\
+       continuation\fR
+.fi
+.RE
+results in single long input line that begins with '#' (it is comment) and all
+continuations following it have been folded in.
+Presented line number of combined continuation is the line number of the
+.I last
+line segment in this type of multi-line input.
+.PP
+In the configuration file there is special treatment for quoted strings.
+They are stripped of the outer quotes, and "\fC\\\fR" character is processed within
+the source string to produce an output string.
+The escapes are:
+.TP
+.B "\fC\\\\n"
+Produces newline character (Control-J) on the output string.
+.TP
+.B "\fC\\\\r"
+Produces carriage return character (Control-M) on the output string.
+.TP
+.B "\fC\\\\\\\\"
+Places a back-slash on the output string.
+.TP
+.B "\fC\\\\""
+.\" foo "
+Places a double-quote on the output string.
+.TP
+.B "\fC\\\\'"
+Places a single-quote on the output string.
+.TP
+.B "\fC\\\\xHH"
+Lower-case "x" precedes two hex digits which ensemble is then converted to a single byte in the output string.
+.PP
+The complex encodings are for possible initstrings of the external devices,
+and in particular for initstrings even a nul byte ( \\x00 ) is supported.
+.PP
+A configuration token without surrounding quotes does not understand the backslash escapes.
+.PP
+.nf
+\fC
+#
+#  Sample configuration file for the APRX -- an Rx-only APRS iGate with
+#  Digipeater functionality.
+#
+#
+# Simple sample configuration file for the APRX-2
+#
+# This configuration is structured with Apache HTTPD style tags
+# which then contain subsystem parameters.
+#
+
+#
+# For simple case, you need to adjust 4 things:
+#   - Mycall parameter
+#   - Select correct type of interface (ax25-device or serial-device)
+#   - Optionally set a beacon telling where this system is
+#   - Optionally enable digipeater with or without tx-igate
+#
+
+#
+#
+# Define the parameters in following order:
+#   1)  <aprsis>     ** zero to many
+#   2)  <logging>    ** zero or one
+#   3)  <interface>  ** one to many
+#   4)  <beacon>     ** zero to many
+#   5)  <telemetry   ** zero to many
+#   6)  <digipeater> ** zero to many (at most one for each Tx)
+#
+
+#
+# Global macro for simplified callsign definition:
+# Usable for 99+% of cases.
+#
+
+mycall  N0CALL-1
+
+#
+# Global macro for simplified "my location" definition in
+# place of explicit "lat nn lon mm" at beacons. Will also
+# give "my location" reference for "filter m/100".
+#
+#myloc lat ddmm.mmN lon dddmm.mmE
+
+<aprsis>
+# The  login  parameter: 
+# Station call\-id used for relaying APRS frames into APRS\-IS.
+# Use this only to define other callsign for APRS\-IS login.
+#
+#login      OTHERCALL-7  # login defaults to $mycall
+
+#
+# The passcode parameter:
+# Unique code for your callsign to allow transmitting packets
+# into the APRS-IS.
+#
+passcode -1
+
+
+
+# APRS-IS server name and portnumber.
+# Every reconnect does re\-resolve the name to IP address.
+# Some alternates are shown below, choose something local to you.
+#
+server    rotate.aprs2.net    14580
+#server    noam.aprs2.net     14580
+#server    soam.aprs2.net     14580
+#server    euro.aprs2.net     14580
+#server    asia.aprs2.net     14580
+#server    aunz.aprs2.net     14580
+
+# Some APRS\-IS servers tell every about 20 seconds to all contact
+# ports that they are there and alive. Others are just silent.
+# Recommended value 3*"heartbeat" + some  \-> 120 (seconds)
+#
+#heartbeat\-timeout  0  # Disabler of heartbeat timeout
+
+# APRS-IS server may support some filter commands.
+# See:  http://www.aprs-is.net/javAPRSFilter.aspx
+#
+# You can define the filter as single long quoted string, or as
+# many short segments with explaining comments following them.
+#
+# Usability of these filters for a Tx-iGate is dubious, but
+# they exist in case you for example want to Tx-iGate packets
+# from some source callsigns in all cases even when they are
+# not in your local area.
+#
+#filter "possibly multiple filter specs in quotes"
+#
+#filter "m/100"          # My-Range filter
+#filter "f/OH2XYZ\-3/50"  # Friend-Range filter
+</aprsis>
+
+
+<logging>
+# pidfile is UNIX way to tell that others that this program is
+# running with given process-id number.  This has compiled-in
+# default value of:  pidfile @VARRUN@/aprx.pid
+#
+#pidfile @VARRUN@/aprx.pid
+
+# rflog defines a rotatable file into which all RF-received packets
+# are logged.
+#
+#rflog @VARLOG@/aprx\-rf.log
+
+# aprxlog defines a rotatable file into which most important 
+# events on APRS\-IS connection are logged, namely connects and
+# disconnects.
+#
+#aprxlog @VARLOG@/aprx.log
+
+# erlangfile defines a mmap():able binary file, which stores
+# running sums of interfaces upon which the channel erlang
+# estimator runs, and collects data.
+# Depending on the system, it may be running on a filesystem
+# that actually retains data over reboots, or it may not.
+# With this backing store, the system does not loose cumulating
+# erlang data over the current period, if the restart is quick,
+# and does not stradle any exact minute.
+# (Do restarts at 15 seconds over an even minute..)
+# This file is around 0.7 MB per each interface talking APRS.
+# If this file is not defined and can not be created,
+# internal non-persistent in-memory storage will be used.
+#
+# Built-in default value is: @VARRUN@/aprx.state
+#
+#erlangfile @VARRUN@/aprx.state
+
+# erlang\-loglevel is config file edition of the "\-l" option
+# pushing erlang data to syslog(3).
+# Valid values are (possibly) following: NONE, LOG_DAEMON,
+# LOG_FTP, LOG_LPR, LOG_MAIL, LOG_NEWS, LOG_USER, LOG_UUCP,
+# LOG_LOCAL0, LOG_LOCAL1, LOG_LOCAL2, LOG_LOCAL3, LOG_LOCAL4,
+# LOG_LOCAL5, LOG_LOCAL6, LOG_LOCAL7.  If the parameter value is
+# not acceptable, list of accepted values are printed at startup.
+#
+#erlang\-loglevel NONE
+
+# erlanglog defines a rotatable file into which erlang data
+# is written in text form.
+#
+#erlanglog @VARLOG@/erlang.log
+
+# erlang\-log1min option logs to syslog/file also 1 minute
+# interval data from the program. (In addition to 10m and 60m.)
+#
+#erlang\-log1min
+</logging>
+
+
+
+# ***********  Multiple <interface> definitions can follow   *********
+
+# ax25\-device  Lists AX.25 ports by their callsigns that in Linux
+#              systems receive APRS packets.  If none are defined,
+#              or the system is not Linux, the AX.25 network receiver
+#              is not enabled.  Used technologies need at least
+#              Linux kernel 2.4.x
+#
+# tx\-ok        Boolean telling if this device is able to transmit.
+#
+#<interface>
+#   ax25\-device $mycall  # Either $mycall macro, or actual callsign
+#   #tx\-ok      false  # transmitter enable defaults to false
+#   #telem\-to\-is true # set to false to disable
+#</interface>
+
+# The  TNC serial  options.  Parameters are:
+#   \- /dev/ttyUSB1    \-\- tty device
+#   \- 19200           \-\- baud rate, supported ones are:
+#                        1200, 2400, 4800, 9600, 19200, 38400, ...
+#   \- 8n1             \-\- 8\-bits, no parity, one stop\-bit,
+#                        no other supported modes
+#   \- "KISS"                  \- plain basic KISS mode
+#   \- "XORSUM" alias "BPQCRC" \- KISS with BPQ "CRC" byte
+#   \- "SMACK"  alias "CRC16"  \- KISS with real CRC
+#   \- "FLEXNET"               \- KISS with real CRC
+#   \- "TNC2"                  \- TNC2 monitor format
+#   \- "DPRS"                  \- DPRS (rx) Gateway
+#
+#<interface>
+#   serial\-device /dev/ttyUSB0  19200 8n1    KISS
+#   #callsign     $mycall  # Either $mycall macro, or actual callsign
+#   #tx\-ok        false    # transmitter enable defaults to false
+#   #telem\-to\-is true # set to false to disable
+#</interface>
+#
+#<interface>
+#   serial\-device /dev/ttyUSB1  19200 8n1    TNC2
+#   #callsign     $mycall  # Either $mycall macro, or actual callsign
+#   #tx\-ok        false    # TNC2 monitor can not have transmitter
+#   #telem\-to\-is true # set to false to disable
+#</interface>
+#
+#<interface>
+#   serial\-device /dev/ttyUSB1  19200 8n1    DPRS
+#   callsign     dprsgwcallsign  # must define actual callsign
+#   #tx\-ok        false    # DPRS monitor can not do transmit
+#   #telem\-to\-is true # set to false to disable
+#</interface>
+#
+
+
+# ***********  Multiple <beacon>  definitions can follow   *********
+<beacon>
+#
+#  Beacons are sent out to radio transmitters AND/OR APRSIS.
+#  Default is "both", other modes are settable.
+#
+#beaconmode { aprsis | both | radio }
+#
+#  Beacons are sent from a circullar transmission queue, total cycle time
+#  of that queue is 20 minutes by default, and beacons are "evenly"
+#  distributed along it.  Actual intervals are randomized to be anything
+#  in between 80% and 100% of the  cycle-size / number-of-beacons.
+#  First beacon is sent out 30 seconds after system start.
+#  Tune the cycle-size to be suitable to your number of defined beacons.
+#
+#cycle-size  20m
+#
+#
+# Basic beaconed thing is positional message of type "!":
+#
+#beacon symbol "R&" lat "0000.00N" lon "00000.00E" comment "Rx-only iGate"
+#beacon symbol "R&" $myloc comment "Rx-only iGate"
+#
+# Following are basic options:
+#  'symbol'    no default, must be defined!
+#  'lat'       coordinate latitude:   ddmm.mmN  (no default!)
+#  'lon'       coordinate longitude: dddmm.mmE  (no default!)
+#  '$myloc'    coordinate values taken from global 'myloc' entry,
+#              and usable in place of explicit 'lat'+'lon'.
+#  'comment'   optional tail part of the item, default is nothing
+#
+# Sample symbols:
+#   R&   is for "Rx-only iGate"
+#   I&   is for "Tx-iGate"
+#   /#   is for "Digipeater"
+#   I#   is for "Tx-iGate + Digipeater"
+#
+# Additional options are:
+# 'srccall'   parameter sets claimed origination address.
+# 'dstcall'   sets destination address, default "APRXnn"
+# 'interface' parameter picks an interface (must be "tx-ok true" type)
+# 'via'       sets radio distribution pattern, default: none.
+# 'timefix'  On APRS messages with HMS timestamp (hour:min:sec), the
+#            system fixes appropriate field with transmit time timestamp.
+#
+# Message type is by default '!', which is positional no timestamp format.
+# Other possible formats are definable with options:
+# 'type'   Single character setting type:  ! = / @ 
+# 'item'   Defines a name of Item (')') type beacons.
+# 'object' Defines a name of Object (';') type beacons.
+#
+# 'file' option tells a file at which a _raw_ APRS message content is
+#        expected to be found as first line of text. Line ending newline
+#        is removed, and no escapes are supported.  The timefix is
+#        available, though probably should not be used.
+#
+# 'exec' option defines program path for a program whose stdout is
+#        read up to first newline (which must be present), and then
+#        transmit as beacon content. No format helpers are supplied,
+#        although 'timefix' can be used.
+# 'timeout' option is associated with 'exec', and defines when the
+#        exec must by latest produce the output, or the subprogram
+#        execution is killed. Default value is 10 seconds.
+#
+# The parameter sets can vary:
+#  a) 'srccall nnn-n dstcall "string" symbol "R&" lat "ddmm.mmN" lon "dddmm.mmE" [comment "any text"]
+#  b) 'srccall nnn-n dstcall "string" raw "string"'
+#
+# The a) form flags on some of possible syntax errors in parameters.
+# It will also create only "!" type messages.  The dest parameter
+# defaults to "APRS", but can be used to give other destinations.
+# The via parameter can be used to add other keywords, like "NOGATE".
+#
+# Writing correct RAW format beacon message is very hard,
+# which is evidenced by the frequency of bad syntax texts
+# people so often put there...   If you can not be persuaded
+# not to do it, then at least VERIFY the beacon result on
+# web service like  findu.com,  or  aprs.fi
+#
+#beacon                 file /tmp/wxbeacon.txt
+#beacon srccall N0CALL\-3 raw "!0000.00NR00000.00E&aprx \- an Rx\-only iGate"
+#beacon srccall N0CALL\-3 raw "!0000.00NI00000.00E&aprx \- an iGate"
+#beacon srccall $mycall symbol "R&" lat "0000.00N" lon "00000.00E"  \\
+                        comment "aprx \- an Rx\-only iGate"
+#beacon srccall $mycall symbol "I&" lat "0000.00N" lon "00000.00E"  \\
+                        comment "aprx iGate"
+</beacon>
+
+# ***********  <telemetry>  definition(s) follow   *********
+#
+# The system will always send telemetry for all of its interfaces
+# to APRSIS, but there is an option to define telemetry to be sent
+# to radio channel by using following sections for each transmitter
+# that is wanted to send out the telemetry.
+#
+#   transmitter   -  callsign referring to <interface>
+#   via           -  optional via-path, only 1 callsign!
+#   source        -  one or more of <interface> callsigns for which
+#                    the telemetry transmission is wanted for
+#
+#<telemetry>
+#	transmitter	$mycall
+#	via		TRACE1-1
+#	source		$mycall
+#</telemetry>
+
+
+# ***********  <digipeater>  definition(s) follow   *********
+#
+#  The digipeater definitions tell transmitters that receive
+#  AX.25 packets from possibly multiple sources, and then what
+#  to do on the AX.25 headers of those messages.
+#
+#  There is one transmitter per digipeater \-\- and inversely, there
+#  can be at most one digipeater for each transmitter.
+#
+#  In each digipeater there is at least one <source>, usually same
+#  as the transmitter.
+#
+#<digipeater>
+#    transmitter     $mycall
+#    #ratelimit      60 120      # default: average 60 packets/minute,
+#                                #          burst max 120 packets/minute
+#    #srcratelimit   10 20       # Example: by sourcecall:
+#                                #          average 10 packets/minute,
+#                                #          burst max 20 packets/minute
+#
+#    <source>
+#        source         $mycall
+#    #   ratelimit      60 120      # default: average 60 packets/minute,
+#    #                              #          burst max 120 packets/minute
+#    #   viscous\-delay  0     # no viscous delay for RF\->RF digipeat
+#    #   ratelimit      120   # default: max 120 packets/minute
+#    </source>
+#
+#    #<source>          # Adding APRSIS source makes this tx-igate
+#    #   source        APRSIS
+#    #   ratelimit      60 120      # default: average 60 packets/minute,
+#    #                              #          burst max 120 packets/minute
+#    #   relay\-type    third\-party  # Must define this for APRSIS source!
+#    #   viscous\-delay  5 # Recommendation: 5 seconds delay to give
+#    #                    # RF delivery time make itself known.
+#    #   filter         t/m  # Tx-iGate only messages sent to me by APRSIS
+#    #</source>
+#
+#</digipeater>
+\fR
+.fi
+.PP
+.SH GLOBAL MYCALL PARAMETER
+In majority of usage models, system needs single configured callsign.
+This is set by using the
+.B mycall
+configuration option, and latter referred to in configurations as
+.B $mycall
+parameter in place of callsigns.
+.PP
+.SH GLOBAL MYLOC PARAMETER
+Usually multiple beacons, and simple filter rules are wanted to be using
+same reference coordinate for this system.
+This is set by using the
+.B myloc
+configuration option, and latter referred to in configurations as
+.B $myloc
+parameter in place of "lat nn lon mm" coordinate pair of beacons.
+.SH APRSIS SECTION FOR APRSIS CONNECTIVITY
+Settings in the
+.B <aprsis>
+section define connectivity with the APRS-IS network service.
+.PP
+Necessary option is
+.IR server ,
+and others are optional.
+.PP
+Available options are:
+.IP "\fClogin $mycall\fR" 8em
+The APRSIS network login.
+Defaults to the
+.B mycall
+configuration entry.
+.IP "\fCpasscode -1\fR" 8em
+Defining a small integer in range of 0 to 32767 authenticating your login
+to APRS-IS server. Ask for assistance from your APRS-IS managers, or calculate
+it yourself with
+.I aprspass
+program. (Web search engines do find several of them.)
+.IP "\fCserver \fIserver-name 14850\fR" 8em
+Define which APRS-IS is being connected to.
+Multiple definitions are used in round-robin style,
+if the connection with the previous one fails for some reason.
+.PP
+.IP "\fCfilter \fI'filter specs in quotes'\fC # \fIcomments" 8em
+Set filter adjunct definitions on APRS-IS server.
+Multiple entries are catenated together in entry order,
+when connecting to the server.
+.PP
+.SH LOGGING SECTION
+The
+.B <logging>
+section defines miscellaneous file names and options for state tracking and logging use.
+.PP
+.IP "\fCpidfile \fI at VARRUN@/aprx.pid\fR" 8em
+The pidfile is UNIX way to tell that others that this program is
+running with given process-id number.
+This has compiled-in default value of: \fCpidfile @VARRUN@/aprx.pid
+.IP "\fCrflog \fI at VARLOG@/aprx\-rf.log\fR" 8em
+The
+.I rflog
+defines a rotatable file into which all RF-received packets are logged.
+There is no default.
+.IP "\fCaprxlog \fI at VARLOG@/aprx.log\fR" 8em
+The
+.I aprxlog
+defines a rotatable file into which most important events on APRS-IS
+connection are logged, namely connects and disconnects.
+There is no default.
+.IP "\fCerlangfile \fI at VARRUN@/aprx.state\fR" 8em
+The
+.I erlangfile
+defines a mmap():able binary file, which stores running sums of interfaces
+upon which the channel erlang estimator runs, and collects data.
+Depending on the system, it may be running on a filesystem that actually
+retains data over reboots, or it may not.
+With this backing store, the system does not loose cumulating erlang data
+over the current period, if the restart is quick, and does not stradle
+any exact minute.
+This file is around 0.7 MB per each interface talking APRS.
+If this file is not defined and can not be created,
+internal non-persistent in-memory storage will be used.
+Built-in default value is: @VARRUN@/aprx.state
+.IP "\fCerlang\-loglevel \fINONE\fR" 8em
+The
+.I erlang\-loglevel
+is config file edition of the "\-l" option pushing erlang data to
+.IR syslog (3).
+Valid values are (possibly) following: NONE, LOG_DAEMON,
+LOG_FTP, LOG_LPR, LOG_MAIL, LOG_NEWS, LOG_USER, LOG_UUCP,
+LOG_LOCAL0, LOG_LOCAL1, LOG_LOCAL2, LOG_LOCAL3, LOG_LOCAL4,
+LOG_LOCAL5, LOG_LOCAL6, LOG_LOCAL7.
+If the parameter value is not acceptable, list of accepted
+values are printed at startup.
+.IP "\fCerlanglog \fI at VARLOG@/erlang.log\fR" 8em
+The erlanglog defines a rotatable file into which erlang data
+is written in text form.
+There is no default.
+.IP "\fCerlang\-log1min\fR" 8em
+The
+.I erlang\-log1min
+option logs to syslog/file also 1 minute interval data from the program.
+(In addition to 10m and 60m.)
+Default is off.
+.PP
+.SH INTERFACE SECTIONS FOR RADIO PORTS
+The
+.B <interface>
+sections define connections to radio modems.
+Several different styles are available:
+.IP \(bu 2
+Local serial ports in the machine
+.RB ( "device\-serial /dev/ttyS0 " "\fIspeed encapsulation\fR)"
+.IP \(bu 2
+Local USB serial ports in the machine
+.RB ( "device\-serial /dev/ttyUSB0 " "\fIspeed encapsulation\fR)"
+.IP \(bu 2
+Remote served serial ports over a TCP stream.
+Implemented to talk with Cisco AUX ports on "range 4000"
+(TCP STREAM, no TELNET escapes)
+.RB ( "tcp\-device 12.34.56.78 4001 " "\fIencapsulation\fR)"
+.IP \(bu 2
+Linux internal AX.25 network attached devices
+.RB ( "ax25\-device CALLSIGN\-1" )
+are only available when running on a Linux system.
+On a non-Linux system it connects to a null interface, never
+getting anything and can always sink everything.
+.PP
+The serial port name tells what kind of port is in question,
+and while port baud-rate (9600) and character settings (8n1)
+must always be set, they are ignored for the remote connection.
+.PP
+Following
+.I speed
+modes are available:
+.br
+.B "    " 1200,
+.I 1800,
+.B 2400, 4800, 9600, 19200,
+.I 38400, 57600,
+.br
+.I "    " 115200, 230400, 460800, 500000, 576000
+.br
+Likely available speeds are in bold, other supported values
+are listed in italics.
+.PP
+Following
+.I encapsulation
+modes are available:
+.TP 10em
+.B TNC2
+is capable only to monitor the packets reported by TNC2 type
+debug output, and Rx-iGate, but they are not acceptable as
+source for a <digipeater>.
+.TP 10em
+.B DPRS
+is special mode for gateway from D-STAR D-PRS to APRS.
+This must always have a callsign definition for the gateway.
+.TP 10em
+.B KISS
+Basic KISS encapsulation.
+No checksums.
+Will autodetect (sometimes) packets with SMACK or FLEXNET characteristics.
+.TP 10em
+.B SMACK
+.IR "Stuttgart Modified Amateurradio-CRC-KISS" ,
+which runs CRC-16 checksum on KISS datastream much in the same
+way as HDLC has CCITT-CRC checksum on it.
+.TP 10em
+.B FLEXNET
+.IR "FLEXNET"
+which runs a CRC checksum of its own polynomial on KISS datastream
+much in the same way as HDLC has CCITT-CRC checksum on it.
+.TP 10em
+.B BPQCRC
+XOR "checksum" on dataframes.
+Also known as "XKISS", and "XORSUM".
+This detects single bit failure, but weakly any multibit failures.
+Extra 0x00 bytes have no effect on checksum, etc.
+.PP
+On
+.BI "<kiss\-subif " "tncid" ">"
+sub-options the parameter is
+.IR tncid ,
+which sets up KISS multiplexer parameter so that subsequent
+options applies only on designated KISS sub-port.
+.PP
+The
+.I callsign
+option sets port specific callsign when relaying to APRS-IS.
+.PP
+The
+.I "telem\-to\-is true"
+option can be used to disable (by explicitly setting it to 'false')
+radio interface telemetry transmission to APRS-IS.
+By default it is on.
+This is separate from <telemetry> sections, which send telemetry
+to RF interfaces.
+.PP
+.nf
+\fC<interface>
+   serial\-device /dev/ttyUSB1 19200 8n1 KISS
+   tx\-ok         false          # receive only (default)
+   callsign      OH2XYZ\-R2      # KISS subif 0
+   initstring    "...."         # initstring option
+   timeout       900            # 900 seconds of no Rx
+</interface>
+
+<interface>
+   serial\-device /dev/ttyUSB1 19200 8n1 SMACK
+   tx\-ok         false          # receive only (default)
+   callsign      OH2XYZ\-R2      # KISS subif 0
+   initstring    "...."         # initstring option
+   timeout       900            # 900 seconds of no Rx
+</interface>
+
+<interface>
+   serial\-device /dev/ttyUSB2 19200 8n1 KISS
+   initstring    "...."
+   timeout       900            # 900 seconds of no Rx
+   <kiss\-subif 0>
+      callsign OH2XYZ\-2
+      tx\-ok    true             # This is our transmitter
+   </kiss\-subif>
+   <kiss\-subif 1>
+      callsign OH2XYZ\-R3        # This is receiver
+      tx\-ok    false            # receive only (default)
+   </kiss\-subif>
+</interface>
+
+<interface>
+   tcp\-device   172.168.1.1 4001 KISS
+   tx\-ok         false          # receive only (default)
+   callsign      OH2XYZ\-R4      # KISS subif 0
+   initstring    "...."         # initstring option
+   timeout       900            # 900 seconds of no Rx
+</interface>
+
+<interface>
+   ax25\-device OH2XYZ\-6         # Works only on Linux systems
+   tx\-ok       true             # This is also transmitter
+</interface>
+
+<interface> # \fBRX-IGATE ONLY, NOT USABLE AS DIGIPEATER SOURCE\fR\fC
+   serial\-device /dev/ttyUSB1 19200 8n1 TNC2
+   callsign      OH2XYZ\-R6      # TNC2 has no sub-ports
+   initstring    "...."         # initstring option
+   timeout       900            # 900 seconds of no Rx
+</interface>
+.fi
+
+.SH BEACON DEFINITIONS
+The beacons are defined using
+.B <beacon>
+configuration sections.
+.PP
+Because classical beacon definitions are highly error\-prone, this program
+has a new way to define them:
+.IP \(bu 2
+The new way to define beacons:
+.nf
+\fCbeacon symbol "R&" lat "0000.00N" lon "00000.00E"  \\\fR
+\fC       comment "aprx \- iGate" \fR
+.fi
+.IP \(bu 2
+Semi-clasical definition of raw APRS packet:
+.nf
+\fCbeacon raw "!0000.00NR00000.00E&aprx \- iGate"\fR
+.fi
+.IP \(bu 2
+Load beacon text from a file, path data is configurable:
+.nf
+\fCbeacon file \fR\fI/path/to/file\fR
+.fi
+.IP \(bu 2
+Run a program to produce beacon data in raw format:
+.nf
+\fCbeacon exec \fR\fI/path/to/file\fR\fC timeout \fR\fI10\fR 
+.fi
+.PP
+The fields and parameters:
+.TP 12em
+.B interface
+An
+.I optional
+"interface" parameter tells that this beacon shall be sent only to
+interface whose callsign is named.
+Default is to send to all interfaces that have "tx\-ok true" setting.
+
+.TP 12em
+.B type
+An
+.I optional
+one character string parameter, with one of following
+contents:  "!", "=", "/", "@", ";" and ")".
+
+.TP 12em
+.B srccall
+An
+.I optional
+"srccall" parameter tells callsign which is claimed as this particular
+beacon source.
+It must be valid AX.25 callsign in text format.
+When this "srccall" parameter is not given, value of "mycall" configuration
+entry is used.
+.TP 12em
+.B dstcall
+An
+.I optional
+"dstcall" parameter has built-in software version dependent value,
+but it can be used to define another value.
+.TP 12em
+.B via
+An
+.I optional
+"via" parameter defaults to nothing, but can be used to define additional
+"VIA" path tokens, for example: "WIDE1\-1".
+.TP 12em
+.B item
+An
+.I optional
+"item" parameter is for defining a name for an item type APRS packet.
+.TP 12em
+.B object
+An
+.I optional
+"object" parameter is for defining a name for an object type APRS packet.
+.TP 12em
+.B symbol
+A
+.I mandatory
+"symbol" parameter is two character code, which for Rx-only iGate is pair: "R&"
+.TP 12em
+.B lat
+This
+.I mandatory
+parameter defines
+.I latitude
+coordinate (that is: north/south.)
+It is expected to be of format: "ddmm.mmN" where "dd" defines
+.I two digits
+of
+.I degrees
+of latitude, and "mm.mm" defines two digits + decimal dot + two digits of
+.I minutes
+of latitude.
+Then comes literal "N" or "S" indicating hemisphere.
+.TP 12em
+.B lon
+This 
+.I mandatory
+parameter defines
+.I longitude
+coordinate (that is: east/west.)
+It is expected to be of format: "dddmm.mmE" where "ddd" defines
+.I three digits
+of
+.I degrees
+of longitude, and "mm.mm" defines two digits + decimal dot + two digits of
+.I minutes
+of longitude.
+Then comes literal "E" or "W" indicating hemisphere.
+.TP 12em
+.B comment
+This
+.I optional
+parameter defines commentary text tail on the beacon packet.
+If you need characters outside US-ASCII character set, use of UTF-8 encoded
+UNICODE character set is recommended.
+
+.TP 12em
+.B raw
+This
+.I alternate
+format defines whole APRS packet content in raw text format.
+.I Currently this type of packets are not validated for syntax at all!
+.TP 12em
+.B file
+This
+.I alternative
+way defines path to a file with single text line defining
+content of
+.I raw
+message data.
+.TP 12em
+.B exec
+This
+.I alternative
+mode runs designated program, and waits for at most a
+.I timeout
+number of seconds (default 10) for the program to produce the result.
+.TP 12em
+.B timeout
+This is optional parameter for
+.I exec
+allowing altered timeout (number of seconds) for waiting the program to respond.
+Default is 10 seconds.
+.PP
+The type/symbol/lat/lon/comment-format supports only
+a few types of APRS packets.
+It splits input into small slices that are possible
+to validate in detail.
+(See "DEBUGGING SYSTEM" above.)
+.PP
+.SH RF-TELEMETRY
+The
+.I aprx
+system will always send telemetry for all of its interfaces
+to APRSIS, but there is an option to define telemetry to be sent
+to radio channel by using following sections for each transmitter
+that is wanted to send out the telemetry.
+.PP
+The parameters of
+.B <telemetry>
+configuration section are:
+.TP 12em
+.B transmitter
+A mandatory callsign referring to an
+.I interface.
+.TP 12em
+.B via
+An optional
+.I via-path
+parameter.  Only 1 callsign!
+.TP 12em
+.B source
+One or more of
+.I interface
+callsigns for which the telemetry transmission is made.
+.SH DIGIPEATER
+The
+.I aprx
+is possible to configure as a AX.25 digipeater with APRS twists.
+This is done with
+.B <digipeater>
+configuration section and its subsections.
+.PP
+.I There can be at most one <digipeater> definition per each
+.I transmit capable interface in the system.
+.I On a system with multiple transmitters, this means there can
+.I be multiple digipeaters, each with different behaviour rules.
+.PP
+Minimalistic setup for a digipeater will be as follows:
+.PP
+.nf
+\fC<digipeater>
+    transmitter     $mycall
+    <source>
+        source      $mycall
+    </source>
+</digipeater>\fR
+.fi
+.PP
+In minimalistic approach the system does digipeating of packets heard
+on the
+.I $mycall
+interface back to same interface.
+Single requirement is that the
+.I <interface>
+block has
+.I "tx\-ok true"
+setting on it.
+.PP
+In more complicated approaches it is possible to define multiple sources
+for packets:
+.IP \(bu 3
+Multiple device ports.
+.IP \(bu 3
+APRSIS pseudoport, which creates the Tx-iGate functionality.
+.PP
+.SS <digipeater> options
+Main-level <digipeater> options are:
+.PP
+.IP \(bu 3
+.I transmitter
+defines which interface the digipeater will output to.
+.IP \(bu 3
+.IR <trace> " and " <wide>
+sub-options are explained below.
+.IP \(bu 3
+.I <source>
+sub-option is explained below.
+.PP
+.SS <trace> and <wide> sub-options
+The
+.I <trace>
+sub-option has priority over the
+.I <wide>
+sub-option, otherwise they are configured the same way.
+.PP
+The
+.I <trace>
+sub-option defines which AX.25 address contained keywords
+are treated with APRS "New-N paradigm" rules in a way
+where each processing node always marks its transmitter
+callsign on the transmitted AX.25 packet address header.
+.PP
+The
+.I <wide>
+sub-option defines which AX.25 address contained keywords
+are treated with APRS "New-N paradigm" rules in a way where
+processing node does not mark its transmitter callsign
+on the transmitted AX.25 packet address header.
+.PP
+Available parameters are:
+.TP 9em
+.B keys
+A string of comma-separated set of string tokens:
+.br
+\fC   keys "TRACE,WIDE"\fR
+.br
+Alternative form for this entry is:
+.br
+\fC   keys "TRACE"\fR
+.br
+\fC   keys "WIDE"\fR
+.TP 9em
+.B maxdone
+Defines maximum number of redistribution hops that these keywords
+can have completed when reaching here.
+If accounting finds more done, the system will just drop the packet
+instead of digipeating it onwards.
+.TP 9em
+.B maxreq
+Defines maximum number of redistribution hops that these keywords
+can define.
+If accounting finds more requested, the system will just drop
+the packet instead of digipeating it onwards.
+.PP
+.SS <source> sub-options
+Primary definer option is
+.B source
+which gives callsign of an
+.I <interface>
+from which the AX.25 packets are received for this
+.I <source>
+block.
+.PP
+Available
+.B relay\-type
+modes on <source> definitions are:
+.TP 14em
+.B digipeater
+Normal AX.25 digipeater behaviour with APRS New-N paradigm support.
+This is default mode.
+.TP 14em
+.B directonly
+Digipeat only directly heard packets.
+Useful for systems that are designated as "fill-in".
+See also "viscous\-delay".
+.TP 14em
+.B third\-party
+Special mode for Tx-iGate.
+.PP
+The
+.B ratelimit
+defines two parameters:
+.I average
+and
+.I limit
+number of packets sent in 60 seconds.
+Its definitions can be both in
+.I <digipeater>
+and in
+digipeater's
+.I <source>
+sections, and therefore you can limit each individual source to
+a max accepted rate as well as define separate rate limits for
+the transmitter.
+.PP
+The
+.B viscous\-delay
+defines a number of seconds from 0 (default) maximum of 9 that
+the source will put the message on duplicate detector delay processing.
+All occurrances of same packet per duplicate detector during that time
+will be accounted on duplicate detection, and if at the end of the delay
+period there are more than one hit, the packet is discarded.
+Use delay of 0 seconds for normal digipeater, 5 seconds for a fill-in,
+or a Tx-iGate.
+.PP
+A javAPRSSrvr filter-adjunct style rules are possible with the
+.B filter
+options.
+When you want multiple filters, use multiple options with associated parameters:
+.nf
+\fC
+    filter t/m            # APRS messaging type packets
+    filter a/la/lo/la/lo  # APRS positional packets within this area
+\fR
+.fi
+.LP
+Also negative filters are possible (prefixed with minus character),
+which upon match cause rejection of the packet.
+Filters are evaluated in definition order, and first matching one will
+terminate the evaluation.
+When no filters are defined, everything is passed thru.
+When any filter is defined, only those matching non-negative filters
+are passed thru, and no default "pass everything else" behaviour exists.
+.LP
+Supported "adjunct filters" are following:
+.TP 8em
+.B A/latN/lonW/latS/lonE
+Area filter, defined as area enclosing within latS/latN and lonW/lonE.
+Latitude and longitude are entered as degrees and decimals.
+.TP 8em
+.B B/call1/call2...
+Budlist filter.  Supports *-wildcards.
+.TP 8em
+.B D/digi1/digi2...
+.I Not supported at APRX internal filters
+.TP 8em
+.B E/call1/call2/...
+.I Not supported at APRX internal filters
+.TP 8em
+.B F/call/dist_km
+Great-circle distance in kilometers from friend's coordinates.
+No wildcarding.
+.br
+.I (TODO: check that it really works!)
+.TP 8em
+.B M/dist
+The
+.I "range around my location"
+filter requires that you have defined also the "myloc" configuration entry.
+It defines acceptance of positions and messages with senders within
+.I dist
+kilometers of the "myloc" position.
+.TP 8em
+.B O/object1/obj2...
+Object name filter.  Supports *-wildcards.
+.TP 8em
+.B P/aa/bb/cc...
+Prefix filter.
+.TP 8em
+.B Q/con/ana
+.I The Q-construct filter is not supported.
+.TP 8em
+.B R/lat/lon/dist
+Range filter.
+Latitude and longitude are in degrees and decimals.
+Distance is in kilometers.
+No wildcards.
+.TP 8em
+.B S/pri/alt/over
+Symbol filter
+.TP 8em
+.B T/..../call/km
+.RS
+Type filter.
+Couple possible usages:
+.IP "\fC  -t/c\fR" 22em
+Everything except CWOP
+.IP "\fC   t/*/OH2RDY/50\fR" 22em
+Everything within 50 km of OH2RDY's last known position
+.PP
+Type code characters are:
+.TP 3em
+.B *
+An "all" wild-card.
+.TP 3em
+.B C
+A CWOP.
+.TP 3em
+.B I
+An ITEM.
+.TP 3em
+.B M
+A MESSAGE.
+.TP 3em
+.B N
+A NWS message.
+.TP 3em
+.B O
+An OBJECT.
+.TP 3em
+.B Q
+A QUERY.
+.TP 3em
+.B S
+A STATUS response.
+.TP 3em
+.B T
+A TELEMETRY packet or parameter message.
+.TP 3em
+.B U
+A USERDEF message.
+.TP 3em
+.B W
+A WX data packet
+.RE
+.TP 8em
+.B U/unproto1/unproto2...
+Filters by value in destination address field, supports wildcard.
+.PP
+The
+.B <trace>
+and
+.B <wide>
+sub-options exist also within each <source>.
+Where such occur, the <source> specific <trace> sub-option
+trumps the definition on <digipeater> level, and same with
+<wide> sub-options.
+This allows things like overriding flooding control keywords
+on source basis, should such be necessary.
+.PP
+A set of
+.B regex\-filter
+rules can be used to reject packets that are not of approved kind.
+Available syntax is:
+.IP "regex\-filter source RE"
+source address field
+.IP "regex\-filter destination RE"
+destination address field
+.IP "regex\-filter via RE"
+any via path field
+.IP "regex\-filter data RE"
+payload content
+.PP
+The regex\-filter exists as ad-hoc method when all else fails.
+.PP
+.SH NOTES: ERLANG
+The
+.I Erlang
+is telecom measurement of channel occupancy, and in this application sense
+it does tell how much traffic there is on the radio channel.
+.PP
+Most radio transmitters are not aware of all transmitters on channel,
+and thus there can happen a collision causing loss of both messages.
+The higher the channel activity, the more likely that collision is.
+For further details, refer to statistical mathematics books, or perhaps
+on Wikipedia.
+.PP
+In order to measure channel activity, the
+.B aprx
+program suite has these built-in statistics counter and summary estimators.
+.PP
+The
+.I Erlag
+value that the estimators present are likely somewhat
+.I underestimating
+the true channel occupancy simply because it calculates estimate of channel
+bit transmit rate, and thus a per-minute character capacity.
+It does not know true frequency of bit-stuffing events of the HDLC framing,
+nor each transmitter pre- and port frame PTT times. The transmitters need to
+stabilize their transmit oscillators in many cases, which may take up to
+around 500 ms!
+The counters are not aware of this preamble-, nor postamble-times.
+.PP
+The HDLC bit stuffing ratio is guessed to be 1:1.025 (1 extra bit every 5 bytes)
+
+.SH NOTES: PROGRAM NAME
+Initially this program had name
+.IR aprsg-ng ,
+which was too close to another (a less low-tech C++ approach) program had.
+
+.SH BUGS/WARTS
+The
+.IR Erlang -monitor
+mechanisms are of rudimentary quality, and can seriously underestimate
+the channel occupancy by ignoring pre- and postample transmissions,
+which can be as high as 50 centiseconds for preample, and 20 centiseconds
+for postample!
+When entire packet takes 50 centiseconds, such preample alone doubles channel
+occupancy.
+A 6pack protocol on serial link (instead of KISS) could inform receiver
+better on carrier presense times, however even that underestimates RF power
+presense (RSSI) signal.  (6pack is not supported.)
+.PP
+On serial lines supports really only 8n1 mode, not at all like: 7e1.
+On the other hand, there really is no sensible usage for anything but 8n1...
+
+.SH SEE ALSO
+Couple web sites:
+.br
+.IR "http://www.aprs2.net/" ,
+.br
+.IR "http://www.aprs-is.net/" ,
+.br
+.IR "http://wiki.ham.fi/Aprx.en" ,
+.br
+.I "http://ham.zmailer.org/oh2mqk/aprx/aprx-manual.pdf"
+.PP
+.BR aprx-stat (8)
+
+.SH AUTHOR
+This little piece was written by
+.I "Matti Aarnio, OH2MQK"
+during a dark and rainy fall and winter of 2007-2008 after a number
+of discussions grumbling about current breed of available software
+for APRS iGate use in Linux (or of any UNIX) platforms.
+Fall and winter 2009-2010 saw appearance of digipeater functionality.
+.PP
+Principal contributors and test users include:
+.IR "Pentti Gronlund, OH3BK" ,
+.IR "Reijo Hakala, OH1GWK" .
+Debian packaging by
+.IR "Kimmo Jukarinen, OH3GNU" .
+Testing of SMACK variant of KISS by
+.IR "Patrick Hertenstein, DL1GHN" .
+The beacon exec functionality prototype by
+.IR "Kamil Palkowiski SQ8KFH" .
diff --git a/aprx.c b/aprx.c
new file mode 100644
index 0000000..7e1bc7d
--- /dev/null
+++ b/aprx.c
@@ -0,0 +1,635 @@
+/* **************************************************************** *
+ *                                                                  *
+ *  APRX -- 2nd generation receive-only APRS-i-gate with            *
+ *          minimal requirement of esoteric facilities or           *
+ *          libraries of any kind beyond UNIX system libc.          *
+ *                                                                  *
+ * (c) Matti Aarnio - OH2MQK,  2007-2014                            *
+ *                                                                  *
+ * **************************************************************** */
+#include "aprx.h"
+
+/* Bits used only in the main program.. */
+#include <signal.h>
+#ifdef HAVE_SYS_TIME_H
+# include <sys/time.h>
+#endif
+#ifdef HAVE_TIME_H
+# include <time.h>
+#endif
+#include <fcntl.h>
+#ifdef HAVE_SYS_WAIT_H
+#include <sys/wait.h>
+#endif
+
+int debug;
+int verbout;
+int erlangout;
+const char *rflogfile;
+const char *aprxlogfile;
+const char *mycall;
+float myloc_lat;
+float myloc_coslat;
+float myloc_lon;
+const char *myloc_latstr;
+const char *myloc_lonstr;
+
+const char *tocall = "APRX28";
+const uint8_t tocall25[7] = {'A'<<1,'P'<<1,'R'<<1,'X'<<1,'2'<<1,'8'<<1,0x60};
+
+#ifndef CFGFILE
+#define CFGFILE "/etc/aprx.conf"
+#endif
+
+const char *pidfile = VARRUN "/aprx.pid";
+
+int die_now;
+int log_aprsis;
+
+const char *swname = "aprx";
+const char *swversion = APRXVERSION;
+
+
+static void sig_handler(int sig)
+{
+	die_now = 1;
+	signal(sig, sig_handler);
+	if (debug) {
+          // Avoid stdio FILE* interlocks within signal handler
+          char buf[64];
+	  sprintf(buf, "SIGNAL %d - DYING!\n", sig);
+          write(1, buf, strlen(buf));
+        }
+}
+
+static void sig_child(int sig)
+{
+	int status;
+        int pid;
+        while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
+        	beacon_childexit(pid);
+        }
+}  
+
+static void usage(void)
+{
+	printf("aprx: [-d[d[d]]][-e][-i][-v][-L][-l logfacility] [-f %s]\n",
+	       CFGFILE);
+	printf("    version: %s\n", swversion);
+	printf("    -f %s:  where the configuration is\n", CFGFILE);
+	printf("    -v:  Outputs textual format of received packets, and data on STDOUT.\n");
+	printf("    -e:  Outputs raw ERLANG-report lines on SYSLOG.\n");
+	printf("    -i:  Keep the program foreground without debugging printouts.\n");
+	printf("    -l ...: sets syslog FACILITY code for erlang reports, default: LOG_DAEMON\n");
+	printf("    -d:  turn debug printout on, use to verify config file!\n");
+	printf("         twice: prints also interaction with aprs-is system..\n");
+	printf("    -L:  Log also all of APRS-IS traffic on relevant log.\n");
+	exit(64);		/* EX_USAGE */
+}
+
+static void versionprint()
+{
+	printf("aprx: %s\n", swversion);
+        exit(1);
+}
+
+void fd_nonblockingmode(int fd)
+{
+	int __i = fcntl(fd, F_GETFL, 0);
+	if (__i >= 0) {
+		/* set up non-blocking I/O */
+		__i |= O_NONBLOCK;
+		__i = fcntl(fd, F_SETFL, __i);
+	}
+	// return __i;
+}
+
+int time_reset = 1;             // observed time jump, initially as "reset is happening!"
+static struct timeval old_tick; // monotonic
+// static struct timeval old_now;  // wall-clock
+
+static int timetick_count;
+
+void timetick(void)
+{
+	++timetick_count;
+        old_tick  = tick;
+        //old_now = now;
+
+	// Monotonic (or as near as possible) clock..
+	// .. which is NOT wall clock time.
+#ifdef HAVE_CLOCK_GETTIME
+	struct timespec ts;
+	clock_gettime(CLOCK_MONOTONIC, &ts);
+	tick.tv_usec = ts.tv_nsec/1000;
+	tick.tv_sec  = ts.tv_sec;
+        // if (debug) printf("newtick: %d.%6d\n", tick.tv_sec, tick.tv_usec);
+#else
+	gettimeofday(&tick, NULL); // fallback when no clock_gettime() is available
+#endif
+        // Wall clock time
+        // gettimeofday(&tick, NULL);
+
+        // Main program clears this when appropriate
+        int delta = 0;
+        if (old_tick.tv_sec != 0) {
+          delta = tv_timerdelta_millis(&old_tick, &tick);
+          if (delta < -1) { // Up to 0.99999 seconds backwards for a leap second
+            if (debug) {
+              printf("MONOTONIC TIME JUMPED BACK BY %g SECONDS. ttcallcount=%d\n", delta/1000.0, timetick_count);
+            }
+            time_reset = 1;
+          } else if (delta > 32000) { // 30.0 + leap second + margin
+            if (debug) {
+              printf("MONOTONIC TIME JUMPED FORWARD BY %g SECONDS. ttcallcount=%d mypid=%d\n", delta/1000.0, timetick_count, getpid());
+            }
+            time_reset = 1;
+          } else {
+            // Time is OK.
+            // time_reset = 0;
+          }
+        } else {
+          time_reset = 1;
+          // This happens before argv is parsed, thus debug is never set.
+          // But if it sets happens afterwards...
+          if (debug) printf("Initializing MONOTONIC time\n");
+        }
+        // if (debug>1) printf("TIMETICK %ld:%6d  %d delta=%d ms\n", tick.tv_sec, tick.tv_usec, timetick_count, delta);
+}
+
+int main(int argc, char *const argv[])
+{
+	int i;
+	const char *cfgfile = "/etc/aprx.conf";
+	const char *syslog_facility = "NONE";
+	int foreground = 0;
+        int millis;
+        int can_clear_timereset;
+
+	/* Init the poll(2) descriptor array */
+	struct aprxpolls app = APRXPOLLS_INIT;
+
+        timetick(); // init global time references
+
+        setvbuf(stdout, NULL, _IOLBF, BUFSIZ);
+        setvbuf(stderr, NULL, _IOLBF, BUFSIZ);
+
+	while ((i = getopt(argc, argv, "def:hiLl:vV?")) != -1) {
+		switch (i) {
+		case '?':
+		case 'h':
+			usage();
+			break;
+		case 'd':
+			++debug;
+			++foreground;
+			break;
+		case 'e':
+			++erlangout;
+			++foreground;
+			break;
+		case 'i':
+			++foreground;
+			break;
+		case 'L':
+			log_aprsis = 1;
+			break;
+		case 'l':
+			syslog_facility = optarg;
+			break;
+		case 'v':
+			++verbout;
+			++foreground;
+			break;
+		case 'f':
+			cfgfile = optarg;
+			break;
+                case 'V':
+                	versionprint();
+                	break;
+		default:
+			break;
+		}
+	}
+
+	interface_init(); // before any interface system and aprsis init !
+	erlang_init(syslog_facility);
+	ttyreader_init();
+#ifdef PF_AX25			/* PF_AX25 exists -- highly likely a Linux system ! */
+	netax25_init();
+#endif
+#ifdef ENABLE_AGWPE
+	agwpe_init();
+#endif
+	dupecheck_init(); // before aprsis_init() !
+#ifndef DISABLE_IGATE
+	aprsis_init();
+#endif
+	filter_init();
+	pbuf_init();
+
+	i = readconfig(cfgfile);
+	if (i) {
+	  fflush(stdout);
+	  fprintf(stderr, "Seen configuration errors. Aborting!\n");
+	  fflush(stderr);
+	  exit(1); // CONFIION ERRORS SEEN! ABORT!
+	}
+
+	erlang_start(1);
+#ifndef DISABLE_IGATE
+	historydb_init();
+#endif
+
+	if (debug || verbout) {
+	  if (!mycall
+#ifndef DISABLE_IGATE
+	      && !aprsis_login
+#endif
+	      ) {
+		fflush(stdout);
+		fprintf(stderr,
+			"APRX: NO GLOBAL  MYCALL=  PARAMETER CONFIGURED, WILL NOT CONNECT APRS-IS\n(This is OK, if no connection to APRS-IS is needed.)\n");
+	  } else if (!mycall
+#ifndef DISABLE_IGATE
+		     && !aprsis_login
+#endif
+		     ) {
+		fflush(stdout);
+		fprintf(stderr,
+			"APRX: NO GLOBAL  APRSIS-LOGIN=  PARAMETER CONFIGURED, WILL NOT CONNECT APRS-IS\n(This is OK, if no connection to APRS-IS is needed.)\n");
+	  }
+	}
+
+	if (!foreground) {
+		/* See if pidfile exists ? */
+		FILE *pf = fopen(pidfile, "r");
+		if (pf) {	/* See if the pid exists ? */
+			int rc, er;
+			int pid = -1;
+			fscanf(pf, "%d", &pid);
+			fclose(pf);
+
+			if (pid > 0) {
+				rc = kill(pid, 0);
+				er = errno;
+
+				if ((rc == 0) || (er == EPERM)) {
+					fflush(stdout);
+					fprintf(stderr,
+						"APRX: PIDFILE '%s' EXISTS, AND PROCESSID %d INDICATED THERE EXISTS TOO. FURTHER INSTANCES CAN ONLY BE RUN ON FOREGROUND!\n",
+						pidfile, pid);
+					fflush(stderr);
+					exit(1);
+				}
+			}
+		}
+	}
+
+
+	if (!foreground) {
+		int pid = fork();
+		if (pid > 0) {
+			/* This is parent */
+			exit(0);
+		}
+		/* child and error cases continue on main program.. */
+		poll((void*)&pid, 0, 500);
+
+	}
+
+	if (1) {
+		/* Open the pidfile, if you can.. */
+
+		FILE *pf = fopen(pidfile, "w");
+
+		setsid();	/* Happens or not ... */
+
+		if (!pf) {
+			/* Could not open pidfile! */
+			fflush(stdout);
+			fprintf(stderr, "COULD NOT OPEN PIDFILE: '%s'\n",
+				pidfile);
+			pidfile = NULL;
+		} else {
+			int f = fileno(pf);
+			if (flock(f, LOCK_EX|LOCK_NB) < 0) {
+				if (errno == EWOULDBLOCK) {
+					printf("Could not lock pid file file %s, another process has a lock on it. Another process running - bailing out.\n", pidfile);
+				} else {
+					printf("Failed to lock pid file %s: %s\n", pidfile, strerror(errno));
+				}
+				exit(1);
+			}
+			
+			fprintf(pf, "%ld\n", (long) getpid());
+			// Leave it open - flock will prevent double-activation
+			dup(f); // don't care what the fd number is
+			fclose(pf);
+		}
+	}
+
+
+	erlang_start(2);	// reset PID, etc..
+
+	// Do following as late as possible..
+
+	// In all cases we close STDIN/FD=0..
+	// .. and replace it with reading from /dev/null..
+	i = open("/dev/null", O_RDONLY, 0);
+	if (i >= 0) { dup2(i, 0); close(i); }
+	
+	// Leave STDOUT and STDERR open
+
+	if (!foreground) {
+	  // when daemoning, we close also stdout and stderr..
+	  dup2(0, 1);
+	  dup2(0, 2);
+	}
+
+	// .. but not latter than this.
+
+
+	// Set default signal handling
+
+	signal(SIGTERM, sig_handler);
+	signal(SIGINT,  sig_handler);
+	signal(SIGHUP,  sig_handler);
+	signal(SIGPIPE, SIG_IGN);
+	signal(SIGCHLD, sig_child);
+
+	// Must be after config reading ...
+	netresolv_start();
+#ifndef DISABLE_IGATE
+	aprsis_start();
+#endif
+#ifdef PF_AX25			/* PF_AX25 exists -- highly likely a Linux system ! */
+	netax25_start();
+#endif
+#ifdef ENABLE_AGWPE
+	agwpe_start();
+#endif
+	telemetry_start();
+#ifndef DISABLE_IGATE
+	igate_start();
+#endif
+
+        aprxlog("APRX start");
+
+	// The main loop
+
+        can_clear_timereset = 0;
+
+	while (!die_now) {
+
+        	timetick(); // pre-poll
+
+		aprxpolls_reset(&app);
+                tv_timeradd_millis( &app.next_timeout, &tick, 30000 ); // 30 seconds
+
+		i = ttyreader_prepoll(&app);
+                // if (debug>3)printf("after ttyreader prepoll - timeout millis=%d\n",aprxpolls_millis(&app));
+#ifndef DISABLE_IGATE
+		i = aprsis_prepoll(&app);
+                // if (debug>3)printf("after aprsis prepoll - timeout millis=%d\n",aprxpolls_millis(&app));
+#endif
+		i = beacon_prepoll(&app);
+                // if (debug>3)printf("after beacon prepoll - timeout millis=%d\n",aprxpolls_millis(&app));
+#ifdef PF_AX25			/* PF_AX25 exists -- highly likely a Linux system ! */
+		i = netax25_prepoll(&app);
+                // if (debug>3)printf("after netax25 prepoll - timeout millis=%d\n",aprxpolls_millis(&app));
+#endif
+#ifdef ENABLE_AGWPE
+		i = agwpe_prepoll(&app);
+                // if (debug>3)printf("after agwpe prepoll - timeout millis=%d\n",aprxpolls_millis(&app));
+#endif
+		i = erlang_prepoll(&app);
+                // if (debug>3)printf("after erlang prepoll - timeout millis=%d\n",aprxpolls_millis(&app));
+		i = telemetry_prepoll(&app);
+                // if (debug>3)printf("after telemetry prepoll - timeout millis=%d\n",aprxpolls_millis(&app));
+		i = dupecheck_prepoll(&app);
+                // if (debug>3)printf("after dupecheck prepoll - timeout millis=%d\n",aprxpolls_millis(&app));
+		i = digipeater_prepoll(&app);
+                // if (debug>3)printf("after digipeater prepoll - timeout millis=%d\n",aprxpolls_millis(&app));
+#ifndef DISABLE_IGATE
+		i = historydb_prepoll(&app);
+                // if (debug>3)printf("after historydb prepoll - timeout millis=%d\n",aprxpolls_millis(&app));
+		i = dprsgw_prepoll(&app);
+                // if (debug>3)printf("after dprsgw prepoll - timeout millis=%d\n",aprxpolls_millis(&app));
+#endif
+
+                // All pre-polls are done
+                if (can_clear_timereset) {
+                  // if (time_reset) {
+                  //   printf("Clearing time_reset.\n");
+                  // }
+                  time_reset = 0;
+                } else {
+                  can_clear_timereset = 1;
+                }
+
+		// if (app.next_timeout <= now.tv_sec)
+                // app.next_timeout = now.tv_sec + 1;	// Just to be on safe side..
+
+                millis = aprxpolls_millis(&app);
+                if (millis < 10)
+                  millis = 10;
+
+		i = poll(app.polls, app.pollcount, millis);
+                timetick(); // post-poll
+
+
+		i = beacon_postpoll(&app);
+		i = ttyreader_postpoll(&app);
+#ifdef PF_AX25			/* PF_AX25 exists -- highly likely a Linux system ! */
+		i = netax25_postpoll(&app);
+#endif
+#ifdef ENABLE_AGWPE
+		i = agwpe_postpoll(&app);
+#endif
+#ifndef DISABLE_IGATE
+		i = aprsis_postpoll(&app);
+#endif
+		i = erlang_postpoll(&app);
+		i = telemetry_postpoll(&app);
+		i = dupecheck_postpoll(&app);
+		i = digipeater_postpoll(&app);
+#ifndef DISABLE_IGATE
+		i = historydb_postpoll(&app);
+		i = dprsgw_postpoll(&app);
+#endif
+
+	}
+	aprxpolls_free(&app); // valgrind..
+
+#ifndef DISABLE_IGATE
+	aprsis_stop();
+#endif
+	netresolv_stop();
+
+	if (pidfile) {
+		unlink(pidfile);
+	}
+
+	exit(0);
+}
+
+
+void printtime(char *buf, int buflen)
+{
+	struct timeval tv;
+	struct tm t;
+
+        // Wall lock time for printouts
+	gettimeofday(&tv, NULL);
+        gmtime_r(&tv.tv_sec, &t);
+	// strftime(timebuf, 60, "%Y-%m-%d %H:%M:%S", t);
+	sprintf(buf, "%04d-%02d-%02d %02d:%02d:%02d.%03d",
+		t.tm_year+1900,t.tm_mon+1,t.tm_mday,
+		t.tm_hour,t.tm_min,t.tm_sec,
+		(int)(tv.tv_usec / 1000));
+}
+
+static struct syslog_facs {
+	const char *name;
+	int fac_code;
+} syslog_facs[] = {
+	{
+	"NONE", -1}, {
+	"LOG_DAEMON", LOG_DAEMON},
+#ifdef LOG_FTP
+	{
+	"LOG_FTP", LOG_FTP},
+#endif
+#ifdef LOG_LPR
+	{
+	"LOG_LPR", LOG_LPR},
+#endif
+#ifdef LOG_MAIL
+	{
+	"LOG_MAIL", LOG_MAIL},
+#endif
+#ifdef LOG_USER
+	{
+	"LOG_USER", LOG_USER},
+#endif
+#ifdef LOG_UUCP
+	{
+	"LOG_UUCP", LOG_UUCP},
+#endif
+	{
+	"LOG_LOCAL0", LOG_LOCAL0}, {
+	"LOG_LOCAL1", LOG_LOCAL1}, {
+	"LOG_LOCAL2", LOG_LOCAL2}, {
+	"LOG_LOCAL3", LOG_LOCAL3}, {
+	"LOG_LOCAL4", LOG_LOCAL4}, {
+	"LOG_LOCAL5", LOG_LOCAL5}, {
+	"LOG_LOCAL6", LOG_LOCAL6}, {
+	"LOG_LOCAL7", LOG_LOCAL7}, {
+	NULL, 0}
+};
+
+void aprx_syslog_init(const char *syslog_facility_name)
+{
+	static int done_once = 0;
+	int syslog_fac = LOG_DAEMON, i;
+
+	if (done_once) {
+		closelog();	/* We reconfigure from config file! */
+	} else
+		++done_once;
+	for (i = 0;; ++i) {
+		if (syslog_facs[i].name == NULL) {
+			fprintf(stderr,
+				"Sorry, unknown erlang syslog facility code name: %s, not supported in this system.\n",
+				syslog_facility_name);
+			fprintf(stderr, "Accepted list is:");
+			for (i = 0;; ++i) {
+				if (syslog_facs[i].name == NULL)
+					break;
+				fprintf(stderr, " %s",
+					syslog_facs[i].name);
+			}
+			fprintf(stderr, "\n");
+			break;
+		}
+		if (strcasecmp(syslog_facs[i].name, syslog_facility_name)
+		    == 0) {
+			syslog_fac = syslog_facs[i].fac_code;
+			break;
+		}
+	}
+
+	if (syslog_fac >= 0) {
+		erlangsyslog = 1;
+		openlog("aprx", LOG_NDELAY | LOG_PID, syslog_fac);
+	}
+}
+
+#ifdef HAVE_STDARG_H
+#ifdef __STDC__
+void aprxlog(const char *fmt, ...)
+#else
+void aprxlog(fmt)
+#endif
+#else
+/* VARARGS */
+void aprxlog(va_list)
+va_dcl
+#endif
+{
+	va_list ap;
+	char timebuf[60];
+
+        printtime(timebuf, sizeof(timebuf));
+	if (verbout) {
+#ifdef 	HAVE_STDARG_H
+          va_start(ap, fmt);
+#else
+          const char *fmt;
+          va_start(ap);
+          fmt    = va_arg(ap, const char *);
+#endif
+
+	  fprintf(stdout, "%s ", timebuf);
+	  vfprintf(stdout, fmt, ap);
+          (void)fprintf(stdout, "\n");
+
+#ifdef 	HAVE_STDARG_H
+          va_end(ap);
+#endif
+	}
+
+        if (aprxlogfile) {
+          FILE *fp;
+
+#ifdef 	HAVE_STDARG_H
+          va_start(ap, fmt);
+#else
+          const char *fmt;
+          va_start(ap);
+          fmt    = va_arg(ap, const char *);
+#endif
+
+
+#if defined(HAVE_PTHREAD_CREATE) && defined(ENABLE_PTHREAD)
+          pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
+#endif
+          fp = fopen(aprxlogfile, "a");
+          if (fp != NULL) {
+            setlinebuf(fp);
+            fprintf(fp, "%s ", timebuf);
+            vfprintf(fp, fmt, ap);
+            (void)fprintf(fp, "\n");
+            fclose(fp);
+          }
+#if defined(HAVE_PTHREAD_CREATE) && defined(ENABLE_PTHREAD)
+          pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
+#endif
+
+#ifdef 	HAVE_STDARG_H
+          va_end(ap);
+#endif
+        }
+}
+
diff --git a/aprx.conf.in b/aprx.conf.in
new file mode 100644
index 0000000..ae78413
--- /dev/null
+++ b/aprx.conf.in
@@ -0,0 +1,390 @@
+#
+# Simple sample configuration file for the APRX-2  -- an APRS iGate and Digipeater
+#
+# This configuration is structured with Apache HTTPD style tags
+# which then contain subsystem parameters.
+#
+
+#
+# For simple case, you need to adjust 4 things:
+#   - Mycall parameter
+#   - passcode parameter in APRS-IS configuration
+#   - Select correct type of interface (ax25-device or serial-device)
+#   - Optionally set a beacon telling where this system is
+#   - Optionally enable digipeater with or without tx-igate
+#
+
+#
+#
+# Define the parameters in following order:
+#   1)  <aprsis>     ** zero or one
+#   2)  <logging>    ** zero or one
+#   3)  <interface>  ** there can be multiple!
+#   4)  <beacon>     ** zero to many
+#   5)  <telemetry>  ** zero to many
+#   6)  <digipeater> ** zero to many (at most one for each Tx)
+#
+
+#
+# Global macro for simplified callsign definition:
+# Usable for 99+% of cases.
+#
+
+mycall  N0CALL-1
+
+#
+# Global macro for simplified "my location" definition in
+# place of explicit "lat nn lon mm" at beacons. Will also
+# give "my location" reference for "filter m/100".
+#
+#myloc lat ddmm.mmN lon dddmm.mmE
+
+<aprsis>
+# The  aprsis login  parameter: 
+# Station callsignSSID used for relaying APRS frames into APRS-IS.
+# Use this only to define other callsign for APRS\-IS login.
+#
+#login     OTHERCALL-7	# login defaults to $mycall
+
+#
+# Passcode for your callsign:
+# Unique code for your callsign to allow transmitting packets
+# into the APRS-IS.
+#
+passcode -1
+
+# APRS-IS server name and optional portnumber.
+#
+# WARNING: Do not change from default port number [14580]
+#          unless you are absolutely certain you want
+#          something else, and you allow that something
+#          else also affect your tx-igate behaviour!
+#
+server    rotate.aprs2.net
+#server   euro.aprs2.net
+#server   asia.aprs2.net
+#server   noam.aprs2.net
+#server   soam.aprs2.net
+#server   aunz.aprs2.net
+
+# Some APRS-IS servers tell every about 20 seconds to all contact
+# ports that they are there and alive. Others are just silent.
+# Default value is 3*"heartbeat" + some  --> 120 (seconds)
+#
+#heartbeat-timeout   0    # Disabler of heartbeat timeout
+
+# APRS-IS server may support some filter commands.
+# See:  http://www.aprs-is.net/javAPRSFilter.aspx
+#
+# You can define the filter as single long quoted string, or as
+# many short segments with explaining comments following them.
+#
+# Usability of these filters for a Tx-iGate is dubious, but
+# they exist in case you for example want to Tx-iGate packets
+# from some source callsigns in all cases even when they are
+# not in your local area.
+#
+#filter "possibly multiple filter specs in quotes"
+#
+#filter "m/100"	     # My-Range filter: positions within 100 km from my location
+#filter "f/OH2XYZ-3/50"  # Friend-Range filter: 50 km of friend's last beacon position
+</aprsis>
+
+<logging>
+
+# pidfile is UNIX way to tell that others that this program is
+# running with given process-id number.  This has compiled-in
+# default value of:  pidfile @VARRUN@/aprx.pid
+#
+pidfile @VARRUN@/aprx.pid
+
+
+# rflog defines a rotatable file into which all RF-received packets
+# are logged.  The host system can rotate it at any time without
+# need to signal the aprx that the file has been moved.
+#
+rflog @VARLOG@/aprx-rf.log
+
+# aprxlog defines a rotatable file into which most important 
+# events on APRS-IS connection are logged, namely connects and
+# disconnects.  The host system can rotate it at any time without
+# need to signal the aprx that the file has been moved.
+#
+aprxlog @VARLOG@/aprx.log
+
+# dprslog defines a rotatable file into which most important 
+# events on DPRS receiver gateways are logged.
+# The host system can rotate it at any time without need to
+# signal the aprx that the file has been moved.
+#
+#dprslog @VARLOG@/dprs.log
+
+# erlangfile defines a mmap():able binary file, which stores
+# running sums of interfaces upon which the channel erlang
+# estimator runs, and collects data.
+# Depending on the system, it may be running on a filesystem
+# that actually retains data over reboots, or it may not.
+# With this backing store, the system does not loose cumulating
+# erlang data over the current period, if the restart is quick,
+# and does not stradle any exact minute.
+# (Do restarts at 15 seconds over an even minute..)
+# This file is around 0.7 MB per each interface talking APRS.
+# If this file is not defined and it can not be created,
+# internal non-persistent in-memory storage will be used.
+#
+# Built-in default value is: @VARRUN@/aprx.state
+#
+#erlangfile @VARRUN@/aprx.state
+
+</logging>
+
+
+# ***********  Multiple <interface> definitions can follow   *********
+
+# ax25-device  Lists AX.25 ports by their callsigns that in Linux
+#              systems receive APRS packets.  If none are defined,
+#              or the system is not Linux, the AX.25 network receiver
+#              is not enabled.  Used technologies need at least
+#              Linux kernel 2.4.x
+#
+# tx-ok        Boolean telling if this device is able to transmit.
+#
+
+#<interface>
+#   ax25-device   $mycall
+#   #tx-ok        false  # transmitter enable defaults to false
+#   #telem-to-is  true # set to 'false' to disable
+#</interface>
+
+
+#
+# The  TNC serial  options.  Parameters are:
+#   - /dev/ttyUSB1    -- tty device
+#   - 19200           -- baud rate, supported ones are:
+#                        1200, 2400, 4800, 9600, 19200, 38400
+#   - 8n1             -- 8-bits, no parity, one stop-bit,
+#                        no other supported modes
+#   - "KISS"                  - plain basic KISS mode
+#   - "XORSUM" alias "BPQCRC" - KISS with BPQ "CRC" byte
+#   - "SMACK"  alias "CRC16"  - KISS with real CRC
+#   - "FLEXNET"               - KISS with real CRC
+#   - "TNC2"                  - TNC2 monitor format
+#   - "DPRS"                  - DPRS (RX) GW
+#
+
+#<interface>
+#   serial-device /dev/ttyUSB0  19200 8n1    KISS
+#   #callsign     $mycall  # callsign defaults to $mycall
+#   #tx-ok        false    # transmitter enable defaults to false
+#   #telem-to-is  true # set to 'false' to disable
+#</interface>
+
+#<interface>
+#   serial-device /dev/ttyUSB1  19200 8n1    TNC2
+#   #callsign     $mycall  # callsign defaults to $mycall
+#   #tx-ok        false    # TNC2 monitor can not have transmitter
+#   #telem-to-is  true # set to 'false' to disable
+#</interface>
+
+#<interface>
+#   serial-device /dev/ttyUSB1  19200 8n1    DPRS
+#   callsign     dprsgwcallsign  # must define actual callsign
+#   #tx-ok       false           # DPRS monitor can not do transmit
+#   #telem-to-is true # set to 'false' to disable
+#</interface>
+
+
+# ***********  Multiple <beacon>  definitions can follow   *********
+<beacon>
+#
+#  Beacons are sent out to radio transmitters AND/OR APRSIS.
+#  Default is "both", other modes are settable.
+#
+#beaconmode { aprsis | both | radio }
+#
+#  Beacons are sent from a circullar transmission queue, total cycle time
+#  of that queue is 20 minutes by default, and beacons are "evenly"
+#  distributed along it.  Actual intervals are randomized to be anything
+#  in between 80% and 100% of the  cycle-size / number-of-beacons.
+#  First beacon is sent out 30 seconds after system start.
+#  Tune the cycle-size to be suitable to your number of defined beacons.
+#
+#cycle-size  20m
+#
+# Basic beaconed thing is positional message of type "!":
+#
+#beacon symbol "R&" lat "0000.00N" lon "00000.00E" comment "Rx-only iGate"
+#beacon symbol "R&" $myloc comment "Rx-only iGate"
+#
+#Following are basic options:
+# 'symbol'    no default, must be defined!
+# 'lat'       coordinate latitude:   ddmm.mmN  (no default!)
+# 'lon'       coordinate longitude: dddmm.mmE  (no default!)
+# '$myloc'    coordinate values taken from global 'myloc' entry,
+#             and usable in place of explicit 'lat'+'lon'.
+# 'comment'   optional tail part of the item, default is nothing
+#
+# Sample symbols:
+#   R&   is for "Rx-only iGate"
+#   I&   is for "Tx-iGate"
+#   /#   is for "Digipeater"
+#   I#   is for "Tx-iGate + Digipeater""
+#
+#Additional options are:
+# 'srccall'   parameter sets claimed origination address.
+# 'dstcall'   sets destination address, default "APRXnn"
+# 'interface' parameter picks an interface (must be "tx-ok true" type)
+# 'via'       sets radio distribution pattern, default: none.
+# 'timefix'   On APRS messages with HMS timestamp (hour:min:sec), the
+#             system fixes appropriate field with transmit time timestamp.
+#
+# Message type is by default '!', which is positional no timestamp format.
+# Other possible formats are definable with options:
+# 'type'      Single character setting type:  ! = / @, default: !
+# 'item'      Defines a name of Item (')') type beacons.
+# 'object'    Defines a name of Object (';') type beacons.
+#
+# 'file' option tells a file at which a _raw_ APRS message content is
+#        expected to be found as first line of text. Line ending newline
+#        is removed, and no escapes are supported.  The timefix is
+#        available, though probably should not be used.
+#        No \-processing is done on read text line.
+#
+# 'exec' option tells a computer program which returns to stdout _raw_ APRS
+#        message content without newline. The timefix is
+#        available, though probably should not be used.
+#        No \-processing is done on read text line.
+#
+# The parameter sets can vary:
+#  a) 'srccall nnn-n dstcall "string" symbol "R&" lat "ddmm.mmN" lon "dddmm.mmE" [comment "any text"]
+#  b) 'srccall nnn-n dstcall "string" symbol "R&" $myloc [comment "any text"]
+#  c) 'srccall nnn-n dstcall "string" raw "string"'
+#
+# The a) form flags on some of possible syntax errors in parameters.
+# It will also create only "!" type messages.  The dest parameter
+# defaults to "APRS", but can be used to give other destinations.
+# The via parameter can be used to add other keywords, like "NOGATE".
+#
+# Writing correct RAW format beacon message is very hard,
+# which is evidenced by the frequency of bad syntax texts
+# people so often put there...   If you can not be persuaded
+# not to do it, then at least VERIFY the beacon result on
+# web service like  findu.com,  or  aprs.fi
+#
+# Do remember that the \ -character has special treatment in the
+# Aprx configuration parser.  If you want a '\' on APRS content,
+# then you encode it on configuration file as:  '\\'
+#
+# Stranger combinations with explicite "transmit this to interface X":
+#
+#beacon                     file /tmp/wxbeacon.txt
+#beacon interface N0CALL-3 srccall N0CALL-3 \
+#                           raw "!0000.00NR00000.00E&Rx-only iGate"
+#beacon interface N0CALL-3 srccall N0CALL-3 \
+#                           raw "!0000.00NI00000.00E&Tx-iGate"
+#beacon interface $mycall   symbol "R&" $myloc \
+#                           comment "Rx-only iGate"
+#beacon interface $mycall   symbol "I&" $myloc \
+#                           comment "Tx-iGate"
+#beacon                     exec /usr/bin/telemetry.pl
+#beacon                     timeout 20 exec /usr/bin/telemetry.pl
+#beacon interface N0CALL-3 srccall N0CALL-3 \
+#                           timeout 20 exec /usr/bin/telemetry.pl
+#
+</beacon>
+
+# ***********  <telemetry>  definition(s) follow   *********
+#
+# The system will always send telemetry for all of its interfaces
+# to APRSIS, but there is an option to define telemetry to be sent
+# to radio channel by using following sections for each transmitter
+# that is wanted to send out the telemetry.
+#
+#   transmitter   -  callsign referring to <interface>
+#   via           -  optional via-path, only 1 callsign!
+#   source        -  one or more of <interface> callsigns for which
+#                    the telemetry transmission is wanted for
+#
+#<telemetry>
+#	transmitter	$mycall
+#	via		TRACE1-1
+#	source		$mycall
+#</telemetry>
+
+# ***********  <digipeater>  definition(s) follow   *********
+#
+#  The digipeater definitions tell transmitters that receive
+#  AX.25 packets from possibly multiple sources, and then what
+#  to do on the AX.25 headers of those messages.
+#
+#  There is one transmitter per digipeater -- and inversely, there
+#  can be at most one digipeater for each transmitter.
+#
+#  In each digipeater there is at least one <source>, usually same
+#  as the transmitter.  You may use same <source> on multiple
+#  <digipeater>s. Using multiple instances of same <source> on
+#  a single <digipeater> does not crash the system, but it can cause
+#  packet duplication in case of non-APRS protocols (like AX.25 CONS)
+#
+#  Use only at most two levels of viscous-delay in your <digipeater>.
+#  Immediate sending is by "0", and a delayed sending is any value
+#  from 1 to 9.  This system does not correctly support other than
+#  immediate sending and one level of delay.
+#
+#  Note: In order to igate correct when multiple receivers and
+#        transmitters are used on single channel, the <interface>
+#        definitions of each radio port must have associated
+#        "igate-group N" parameter which has N of value 1 to 3.
+#        See the aprx-manual.pdf for details.
+#        (Default software compilation allows you to have up to
+#         three channels of APRS operation.)
+#
+#<digipeater>
+#    transmitter     $mycall
+#    #ratelimit      60 120      # default: average 60 packets/minute,
+#    #                           #          burst max 120 packets/minute
+#    #srcratelimit   10 20       # Example: by sourcecall:
+#                                #          average 10 packets/minute,
+#                                #          burst max 20 packets/minute
+#
+#    <source>
+#        source         $mycall
+#    #   #relay-type    digipeated # default mode is "digipeated"
+#    #   viscous-delay  0     # no viscous delay for RF->RF digipeating
+#    #   ratelimit      60 120      # default: average 60 packets/minute,
+#    #                              #          burst max 120 packets/minute
+#    ##  filter         a/la/lo/la/lo  # service area filter
+#    ##  filter         -b/CALL        # always block these
+#    </source>
+#
+#    #  Diversity receiver which combines to the primary
+#    #  Tx/Rx transmitter.  There can be as many of these
+#    #  as you can connect on this machine.
+#    #<source>
+#    #   source         RXPORT-1
+#    #   #relay-type    digipeated # default mode is "digipeated"
+#    #   viscous-delay  0     # no viscous delay for RF->RF digipeating
+#    #   ratelimit      60 120      # default: average 60 packets/minute,
+#    #                              #          burst max 120 packets/minute
+#    ##  filter         a/la/lo/la/lo  # service area filter
+#    ##  filter         -b/CALL        # always block these
+#    </source>
+#
+#    #<source>                # APRSIS source adds a TX-IGATE behaviour
+#    #   source        APRSIS
+#    #   relay-type    third-party  # Must define this for APRSIS source!
+#    #   viscous-delay  5    # Recommendation: 5 seconds delay to give
+#    #                       # RF delivery time make itself known.
+#    #   ratelimit      60 120      # default: average 60 packets/minute,
+#    #                              #          burst max 120 packets/minute
+#    ##  filter         a/la/lo/la/lo  # service area filter
+#    ##  filter         -b/CALL        # always block these
+#    #</source>
+#
+#    #<source>              # DPRS source adds a DPRS->APRS RF gate
+#    #   interface    DPRS
+#    #   ratelimit    60 120       # default: average 60 packets/minute,
+#    #                             #          burst max 120 packets/minute
+#    #   relay-type   third-party  # Must define this for DPRS source!
+#    #</source>
+#</digipeater>
diff --git a/aprx.h b/aprx.h
new file mode 100644
index 0000000..b48ff34
--- /dev/null
+++ b/aprx.h
@@ -0,0 +1,784 @@
+/* **************************************************************** *
+ *                                                                  *
+ *  APRX -- 2nd generation receive-only APRS-i-gate with            *
+ *          minimal requirement of esoteric facilities or           *
+ *          libraries of any kind beyond UNIX system libc.          *
+ *                                                                  *
+ * (c) Matti Aarnio - OH2MQK,  2007-2014                            *
+ *                                                                  *
+ * **************************************************************** */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/file.h>
+#include <signal.h>
+#include <fcntl.h>
+#include <poll.h>
+#include <assert.h>
+#ifdef HAVE_SYS_TIME_H
+# include <sys/time.h>
+#endif
+#ifdef HAVE_TIME_H
+# include <time.h>
+#endif
+#include <unistd.h>
+#ifdef HAVE_STDLIB_H
+# include <stdlib.h>
+#endif
+#define __need_size_t
+#define __need_NULL
+#ifdef HAVE_STDDEF_H
+# include <stddef.h>
+#endif
+#ifdef HAVE_STDARG_H
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+
+#if defined(HAVE_PTHREAD_CREATE) && defined(ENABLE_PTHREAD)
+#include <pthread.h>
+pthread_t aprsis_thread;
+pthread_attr_t pthr_attrs;
+#endif
+
+#ifdef _FOR_VALGRIND_
+#define strdup  aprx_strdup
+#define strcmp  aprx_strcmp
+#define strncmp aprx_strncmp
+#define memcmp  aprx_memcmp
+#define memcpy  aprx_memcpy
+#define memchr  aprx_memchr
+#define memrchr aprx_memrchr
+#define strlen  aprx_strlen
+#define strcpy  aprx_strcpy
+#define strncpy aprx_strncpy
+#define strchr  aprx_strchr
+
+// Single char at the time naive implementations for valgrind runs
+extern int     memcmp(const void *p1, const void *p2, size_t n);
+extern void   *memcpy(void *dest, const void *src, size_t n);
+extern size_t  strlen(const char *p);
+extern char   *strdup(const char *s);
+extern int     strcmp(const char *s1, const char *s2);
+extern int     strncmp(const char *s1, const char *s2, size_t n);
+extern char   *strcpy(char *dest, const char *src);
+extern char   *strncpy(char *dest, const char *src, size_t n);
+extern void   *memchr(const void *s, int c, size_t n);
+extern char   *strchr(const char *s, int c);
+
+// extern declarators for standard functions
+extern void *memset(void *s, int c, size_t n);
+extern char *strerror(const int n);
+extern void *memmove(void *dest, const void *src, size_t n);
+extern char *strtok(char *str, const char *delim);
+extern int   strcasecmp(const char *s1, const char *s2);
+
+#else
+#ifdef HAVE_STRING_H
+# include <string.h>
+#endif
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif
+#endif
+
+extern void   *memrchr(const void *s, int c, size_t n);
+
+#include <termios.h>
+#include <errno.h>
+#include <syslog.h>
+#include <regex.h>
+#ifdef HAVE_ALLOCA_H
+# include <alloca.h>
+#endif
+
+#include <ctype.h>
+#ifdef HAVE_STDINT_H
+#include <stdint.h>
+#endif
+#include <math.h>
+
+#include <sys/socket.h>
+#include <netdb.h>
+#include <netinet/in.h>
+
+/* Radio interface groups on igate receiption history tracking.
+ * Value range:  1 to MAX_IF_GROUP-1.
+ * Value 0 is reserved for APRSIS.
+ */
+#define MAX_IF_GROUP 4
+
+#define CALLSIGNLEN_MAX 9
+
+struct aprxpolls; // forward declarator
+
+#include "cellmalloc.h"
+#include "historydb.h"
+#include "keyhash.h"
+#include "pbuf.h"
+
+#if 0
+#define static			/*ignore statics during debug */
+#endif
+
+struct aprx_interface; // Forward declarator
+
+
+struct configfile {
+	const char *name;
+	FILE	*fp;
+	int	linenum_i; // internal linenum
+	int	linenum;   // externally presented, first line of folded multilines
+	char	buf[8010];
+};
+
+/* aprxpolls.c */
+struct aprxpolls {
+	struct pollfd *polls;
+	int pollcount;
+	int pollsize;
+	struct timeval next_timeout;
+};
+#define APRXPOLLS_INIT { NULL, 0, 0, {0,0} }
+
+extern int  aprxpolls_millis(struct aprxpolls *app);
+extern void aprxpolls_reset(struct aprxpolls *app);
+extern struct pollfd *aprxpolls_new(struct aprxpolls *app);
+extern void aprxpolls_free(struct aprxpolls *app);
+
+/* aprx.c */
+#ifndef DISABLE_IGATE
+extern const char *aprsis_login;
+#endif
+extern int die_now;
+extern const char *mycall;
+extern const char *tocall;
+extern const uint8_t tocall25[7];
+extern float myloc_lat;
+extern float myloc_coslat;
+extern float myloc_lon;
+extern const char *myloc_latstr;
+extern const char *myloc_lonstr;
+
+extern void fd_nonblockingmode(int fd);
+
+extern const char *swname;
+extern const char *swversion;
+
+extern void timetick(void);
+extern struct timeval now; // Public wall lock time that can jump around
+extern struct timeval tick;  // Monotonic clock, progresses regularly from boot. NOT wall clock time.
+extern int time_reset;      // Set during ONE call cycle of prepolls
+extern int debug;
+extern int verbout;
+extern int erlangout;
+extern const char *rflogfile;
+extern const char *aprxlogfile;
+extern const char *dprslogfile;
+extern const char *erlanglogfile;
+extern const char *pidfile;
+
+extern void printtime(char *buf, int buflen);
+extern void aprx_syslog_init(const char *syslog_fac);
+
+#ifdef HAVE_STDARG_H
+#ifdef __STDC__
+extern void aprxlog(const char *fmt, ...);
+#endif
+#else
+/* VARARGS */
+extern void aprxlog(va_list);
+#endif
+
+/* netresolver.c */
+extern void netresolv_start(void); // separate thread working on this!
+extern void netresolv_stop(void);
+
+struct netresolver {
+	char const	*hostname;
+	char const	*port;
+	time_t	re_resolve_time;
+	struct addrinfo ai;
+	struct sockaddr sa;
+};
+
+extern struct netresolver *netresolv_add(const char *hostname, const char *port);
+
+/* ttyreader.c */
+typedef enum {
+	LINETYPE_KISS,		/* all KISS variants without CRC on line */
+	LINETYPE_KISSSMACK,	/* KISS/SMACK variants with CRC on line */
+	LINETYPE_KISSFLEXNET,	/* KISS/FLEXNET with CRC on line */
+	LINETYPE_KISSBPQCRC,	/* BPQCRC - really XOR sum of data bytes,
+				   also "AEACRC"                        */
+	LINETYPE_TNC2,		/* text line from TNC2 in monitor mode  */
+	LINETYPE_AEA,		/* not implemented...                   */
+
+	LINETYPE_DPRSGW		/* Special DPRS RX GW mode              */
+} LineType;
+
+typedef enum {
+	KISSSTATE_SYNCHUNT = 0,
+	KISSSTATE_COLLECTING,
+	KISSSTATE_KISSFESC
+} KissState;
+
+struct serialport {
+	int fd;			/* UNIX fd of the port                  */
+
+	struct timeval wait_until;
+	time_t last_read_something;	/* Used by serial port functionality
+					   watchdog */
+	int read_timeout;	/* seconds                              */
+	int poll_millis;        /* milliseconds (0 = none.)             */
+
+	LineType linetype;
+
+	KissState kissstate;	/* state for KISS frame reader,
+				   also for line collector              */
+
+	/* NOTE: The smack_probe is separate on all
+	**       sub-tnc:s on SMACK loop
+	*/
+	time_t smack_probe[8];	/* if need to send SMACK probe, use this
+				   to limit their transmit frequency.	*/
+	int    smack_subids;    /* bitset; 0..7; could use char...	*/
+
+
+	struct termios tio;	/* tcsetattr(fd, TCSAFLUSH, &tio)       */
+	/*  stty speed 19200 sane clocal pass8 min 1 time 5 -hupcl ignbrk -echo -ixon -ixoff -icanon  */
+
+	const char *ttyname;	/* "/dev/ttyUSB1234-bar22-xyz7" --
+				   Linux TTY-names can be long..        */
+	const char *ttycallsign[16]; /* callsign                             */
+	const void *netax25[16];
+
+	char *initstring[16];	/* optional init-string to be sent to
+				   the TNC, NULL OK                     */
+	int initlen[16];	/* .. as it can have even NUL-bytes,
+				   length is important!                 */
+
+	struct aprx_interface	*interface[16];
+
+
+	uint8_t rdbuf[2000];	/* buffering area for raw stream read */
+	int rdlen, rdcursor;	/* rdlen = last byte in buffer,
+				   rdcursor = next to read.
+				   When rdlen == 0, buffer is empty.    */
+
+	time_t  rdline_time;	/* last time something was added there  */
+	uint8_t rdline[2000];	/* processed into lines/records         */
+	int rdlinelen;		/* length of this record                */
+
+	uint8_t wrbuf[4000];	/* buffering area for raw stream read */
+	int wrlen, wrcursor;	/* wrlen = last byte in buffer,
+				   wrcursor = next to write.
+				   When wrlen == 0, buffer is empty.    */
+
+	void *dprsgw;		/* opaque DPRS GW data */
+};
+
+
+extern int  ttyreader_prepoll(struct aprxpolls *);
+extern int  ttyreader_postpoll(struct aprxpolls *);
+extern void ttyreader_init(void);
+// Old style init: ttyreader_serialcfg()
+extern const char *ttyreader_serialcfg(struct configfile *cf, char *param1, char *str);
+// New style init: ttyreader_new()
+extern struct serialport *ttyreader_new(void);
+extern void ttyreader_register(struct serialport *tty);
+extern int  ttyreader_getc(struct serialport *tty);
+// extern void               ttyreader_setlineparam(struct serialport *tty, const char *ttyname, const int baud, int const kisstype);
+// extern void               ttyreader_setkissparams(struct serialport *tty, const int tncid, const char *callsign, const int timeout);
+extern int  ttyreader_parse_ttyparams(struct configfile *cf, struct serialport *tty, char *str);
+extern void ttyreader_linewrite(struct serialport *S);
+extern int  ttyreader_parse_nullparams(struct configfile *cf, struct serialport *tty, char *str);
+
+extern void hexdumpfp(FILE *fp, const uint8_t *buf, const int len, int axaddr);
+extern void aprx_cfmakeraw(struct termios *, int f);
+
+extern void tv_timerbounds(const char *, struct timeval *tv, const int margin, void (*resetfunc)(void*), void *resetarg );
+extern void tv_timeradd_millis(struct timeval *res, struct timeval * const a, const int millis);
+extern void tv_timeradd_seconds(struct timeval *res, struct timeval * const a, const int seconds);
+extern int  tv_timerdelta_millis(struct timeval * const _now, struct timeval * const _target);
+extern int  tv_timercmp(struct timeval * const a, struct timeval * const b);
+extern int  timecmp(time_t a, time_t b);
+
+
+/* ax25.c */
+extern int  ax25_to_tnc2_fmtaddress(char *dest, const uint8_t *src,
+				    int markflag);
+extern int  ax25_to_tnc2(const struct aprx_interface *aif, const char *portname,
+			 const int tncid, const int cmdbyte,
+			 const uint8_t *frame, const int framelen);
+extern void ax25_filter_add(const char *p1, const char *p2);
+extern int  ax25_format_to_tnc(const uint8_t *frame, const int framelen,
+			       char *tnc2buf, const int tnc2buflen,
+			       int *frameaddrlen, int *tnc2addrlen,
+			       int *is_aprs, int *ui_pid);
+extern int  parse_ax25addr(uint8_t ax25[7], const char *text,
+			   int ssidflags);
+
+
+#ifndef DISABLE_IGATE
+/* aprsis.c */
+extern int  aprsis_add_server(const char *server, const char *port);
+extern int  aprsis_set_heartbeat_timeout(const int tout);
+extern int  aprsis_set_filter(const char *filter);
+extern int  aprsis_set_login(const char *login);
+#define qTYPE_IGATED   'R'
+#define qTYPE_LOCALGEN 'S'
+extern int  aprsis_queue(const char *addr, int addrlen,
+			 const char qtype, const char *gwcall,
+			 const char *text, int textlen);
+extern int  aprsis_prepoll(struct aprxpolls *app);
+extern int  aprsis_postpoll(struct aprxpolls *app);
+extern void aprsis_init(void);
+extern void aprsis_start(void);
+extern void aprsis_stop(void);
+extern int  aprsis_config(struct configfile *cf);
+extern char * const aprsis_loginid;
+#endif
+
+/* beacon.c */
+extern int  beacon_prepoll(struct aprxpolls *app);
+extern int  beacon_postpoll(struct aprxpolls *app);
+extern int  beacon_config(struct configfile *cf);
+extern void beacon_childexit(int pid);
+
+/* config.c */
+extern void *readconfigline(struct configfile *cf);
+extern int   configline_is_comment(struct configfile *cf);
+extern int   readconfig(const char *cfgfile);
+extern char *config_SKIPSPACE(char *Y);
+extern char *config_SKIPTEXT(char *Y, int *lenp);
+extern void  config_STRLOWER(char *Y);
+extern void  config_STRUPPER(char *Y);
+extern int   validate_callsign_input(char *callsign, int strict); // this modifies callsign string!
+extern int   config_parse_interval(const char *par, int *resultp);
+extern int   config_parse_boolean(const char *par, int *resultp);
+extern const char *scan_int(const char *p, int len, int*val, int*seen_space);
+extern int   validate_degmin_input(const char *s, int maxdeg);
+
+
+/* dprsgw.c */
+extern int  dprsgw_pulldprs(struct serialport *S);
+extern int  dprsgw_prepoll(struct aprxpolls *app);
+extern int  dprsgw_postpoll(struct aprxpolls *app);
+
+
+/* erlang.c */
+extern void erlang_init(const char *syslog_facility_name);
+extern void erlang_start(int do_create);
+extern int  erlang_prepoll(struct aprxpolls *app);
+extern int  erlang_postpoll(struct aprxpolls *app);
+
+/* igate.c */
+#ifndef DISABLE_IGATE
+extern void igate_start(void);
+extern void igate_from_aprsis(const char *ax25, int ax25len);
+extern void igate_to_aprsis(const char *portname, const int tncid, const char *tnc2buf, int tnc2addrlen, int tnc2len, const int discard, const int strictax25);
+extern void enable_tx_igate(const char *, const char *);
+#endif
+extern void rflog(const char *portname, char direction, int discard, const char *tnc2buf, int tnc2len);
+extern const char *tnc2_verify_callsign_format(const char *t, int starok, int strictax25, const char *e);
+
+/* netax25.c */
+#ifdef PF_AX25			/* PF_AX25 exists -- highly likely a Linux system ! */
+extern void        netax25_init(void);
+extern void        netax25_start(void);
+extern const void* netax25_open(const char *ifcallsign);
+extern int         netax25_prepoll(struct aprxpolls *);
+extern int         netax25_postpoll(struct aprxpolls *);
+extern void      * netax25_addrxport(const char *callsign, const struct aprx_interface *aif);
+extern void        netax25_sendax25(const void *nax25, const void *ax25, int ax25len);
+extern void        netax25_sendto(const void *nax25, const uint8_t *axaddr, const int axaddrlen, const char *axdata, const int axdatalen);
+#endif
+
+/* telemetry.c */
+
+#define USE_ONE_MINUTE_DATA 0
+
+extern void telemetry_start(void);
+extern int  telemetry_prepoll(struct aprxpolls *app);
+extern int  telemetry_postpoll(struct aprxpolls *app);
+extern int  telemetry_config(struct configfile *cf);
+
+
+typedef enum {
+	ERLANG_RX,
+	ERLANG_DROP,
+	ERLANG_TX
+} ErlangMode;
+
+extern void erlang_add(const char *portname, ErlangMode erl, int bytes, int packets);
+extern void erlang_set(const char *portname, int bytes_per_minute);
+
+extern int erlangsyslog;
+extern int erlanglog1min;
+extern const char *erlang_backingstore;
+
+/* The   struct erlangline  is shared in between the aprx, and
+   erlang reporter application: aprx-stat */
+
+struct erlang_rxtxbytepkt {
+	long packets_rx, packets_rxdrop, packets_tx ;
+	long bytes_rx,   bytes_rxdrop,   bytes_tx ;
+	time_t update;
+};
+
+
+struct erlangline {
+	const void *refp;
+	int index;
+	char name[31];
+	uint8_t __subport;
+	time_t last_update;
+
+	int erlang_capa;	/* bytes, 1 minute                      */
+
+	struct erlang_rxtxbytepkt SNMP;	/* SNMPish counters             */
+
+#ifdef ERLANGSTORAGE
+	struct erlang_rxtxbytepkt erl1m;	/*  1 minute erlang period    */
+	struct erlang_rxtxbytepkt erl10m;	/* 10 minute erlang period    */
+	struct erlang_rxtxbytepkt erl60m;	/* 60 minute erlang period    */
+#else
+#if (USE_ONE_MINUTE_DATA == 1)
+	struct erlang_rxtxbytepkt erl1m;	/*  1 minute erlang period    */
+#else
+	struct erlang_rxtxbytepkt erl10m;	/* 10 minute erlang period    */
+#endif
+#endif
+
+#ifdef ERLANGSTORAGE
+	int e1_cursor, e1_max;	/* next store point + max cursor index */
+	int e10_cursor, e10_max;
+	int e60_cursor, e60_max;
+#else
+#if (USE_ONE_MINUTE_DATA == 1)
+	int e1_cursor, e1_max;	/* next store point + max cursor index */
+#else
+	int e10_cursor, e10_max;
+#endif
+#endif
+
+#ifdef ERLANGSTORAGE
+
+#define APRXERL_1M_COUNT   (60*24)    // 1 day of 1 minute data
+#define APRXERL_10M_COUNT  (60*24*7)  // 1 week of 10 minute data
+#define APRXERL_60M_COUNT  (24*31*3)  // 3 months of hourly data
+	struct erlang_rxtxbytepkt e1[APRXERL_1M_COUNT];
+	struct erlang_rxtxbytepkt e10[APRXERL_10M_COUNT];
+	struct erlang_rxtxbytepkt e60[APRXERL_60M_COUNT];
+#else /* EMBEDDED */		/* When making very small memory footprint,
+				   like embedding on Linksys WRT54GL ... */
+
+#define APRXERL_1M_COUNT   (22)	      // 22 minutes of 1 minute data
+#define APRXERL_10M_COUNT  (3)	      // 30 minutes of 10 minute data
+#if (USE_ONE_MINUTE_DATA == 1)
+	struct erlang_rxtxbytepkt e1[APRXERL_1M_COUNT];
+#else
+	struct erlang_rxtxbytepkt e10[APRXERL_10M_COUNT];
+#endif
+#endif
+};
+
+struct erlanghead {
+	char title[32];
+	int version;		/* format version                       */
+	int linecount;
+	time_t last_update;
+
+	pid_t server_pid;
+	time_t start_time;
+
+	char mycall[16];
+
+	double align_filler;
+};
+
+#define ERLANGLINE_STRUCT_VERSION ((sizeof(struct erlanghead)<<16)+sizeof(struct erlangline))
+
+extern struct erlanghead *ErlangHead;
+extern struct erlangline **ErlangLines;
+extern int ErlangLinesCount;
+
+
+/* dupecheck.c */
+
+
+typedef struct dupe_record_t {
+	struct dupe_record_t *next;
+	uint32_t hash;
+	time_t	 t;	// creation time
+	time_t	 t_exp;	// expiration time
+
+	struct pbuf_t *pbuf;	// To send packet out of delayed processing,
+				// this pointer must be non-NULL.
+        int16_t  seen;          // Count of times this packet has been seen
+                                // on non-delayed processing.  First one will
+                                // be sent when pbuf is != NULL.
+        int16_t  delayed_seen;  // Count of times this packet has been seen
+                                // on delayed processing.  The packet may get
+                                // sent, if "seen" count is zero at delay end.
+	int16_t  seen_on_transmitter; // Source of where it was seen is same
+				// as this digipeater transmitter.
+	int16_t  refcount; // number of references on this entry
+	
+	int16_t	 alen;	// Address length
+	int16_t	 plen;	// Payload length
+
+	char	 addresses[20];
+	char	*packet;
+	char	 packetbuf[200]; /* 99.9+ % of time this is enough.. */
+} dupe_record_t;
+
+#define DUPECHECK_DB_SIZE 16     /* Hash index table size - per dupechecker */
+
+typedef struct dupecheck_t {
+	int	storetime;
+	struct dupe_record_t *dupecheck_db[DUPECHECK_DB_SIZE]; /* Hash index table */
+} dupecheck_t;
+
+extern void           dupecheck_init(void); /* Inits the dupechecker subsystem */
+extern dupecheck_t   *dupecheck_new(const int storetime);  /* Makes a new dupechecker  */
+extern dupe_record_t *dupecheck_get(dupe_record_t *dp); // increment refcount
+extern void           dupecheck_put(dupe_record_t *dp); // decrement refcount
+extern dupe_record_t *dupecheck_aprs(dupecheck_t *dp, const char *addr, const int alen, const char *data, const int dlen);     /* aprs checker */
+extern dupe_record_t *dupecheck_pbuf(dupecheck_t *dp, struct pbuf_t *pb, const int viscous_delay); /* pbuf checker */
+extern int            dupecheck_prepoll(struct aprxpolls *app);
+extern int            dupecheck_postpoll(struct aprxpolls *app);
+
+
+/* crc.c */
+
+// kissencoder() needs direct access to CRC tables..
+extern const uint16_t crc16_table[256];
+extern const uint16_t crc_flex_table[256];
+
+extern uint16_t calc_crc_16(const uint8_t *buf, int n);    /* SMACK's CRC-16 */
+extern uint16_t calc_crc_flex(const uint8_t *buf, int n);  /* FLEXNET's CRC */
+extern uint16_t calc_crc_ccitt(uint16_t crc, const uint8_t *buf, int len); // X.25's FCS a.k.a. CRC-CCITT a.k.a. CCITT-CRC
+extern int      check_crc_16(const uint8_t *buf, int n);   /* SMACK's CRC-16 */
+extern int      check_crc_flex(const uint8_t *buf, int n); /* FLEXNET's CRC */
+extern int      check_crc_ccitt(const uint8_t *buf, int n);
+
+/* KISS protocol encoder/decoder specials */
+
+#define KISS_FEND  (0xC0)
+#define KISS_FESC  (0xDB)
+#define KISS_TFEND (0xDC)
+#define KISS_TFESC (0xDD)
+
+extern int  kissencoder(void *, int, LineType, const void *, int, int);
+extern void kiss_kisswrite(struct serialport *S, const int tncid, const uint8_t *ax25raw, const int ax25rawlen);
+extern int  kiss_pullkiss(struct serialport *S);
+extern void kiss_poll(struct serialport *S);
+
+
+/* digipeater.c */
+typedef enum {
+	DIGIRELAY_UNSET,
+	DIGIRELAY_DIGIPEAT,
+	DIGIRELAY_DIGIPEAT_DIRECTONLY,
+	DIGIRELAY_THIRDPARTY
+} digi_relaytype;
+
+struct filter_t;       // Forward declarator
+struct digipeater;     // Forward declarator
+
+struct tracewide {
+	int    maxreq;
+	int    maxdone;
+	int    is_trace;
+
+	int    nkeys;
+	char **keys;
+	int   *keylens;
+};
+
+struct digipeater_source {
+	struct digipeater     *parent;
+	digi_relaytype	       src_relaytype;
+	struct aprx_interface *src_if;
+	struct filter_t       *src_filters;
+	struct tracewide      *src_trace;
+	struct tracewide      *src_wide;
+#ifndef DISABLE_IGATE
+	char		      *via_path; // for APRSIS only
+	char		      *msg_path; // for APRSIS only
+	uint8_t		       ax25viapath[7]; // APRSIS
+	uint8_t		       msgviapath[7];  // APRSIS
+#endif
+
+	float		       tokenbucket;
+	float		       tbf_increment;
+	float		       tbf_limit;
+
+	// Viscous queue is at <source>, but used dupechecker
+	// is <digipeater> -wide, common to all sources in that
+	// digipeater.
+	int                    viscous_delay;
+	int	               viscous_queue_size;
+	int	               viscous_queue_space;
+	struct dupe_record_t **viscous_queue;
+
+	int sourceregscount;
+	regex_t **sourceregs;
+
+	int destinationregscount;
+	regex_t **destinationregs;
+
+	int viaregscount;
+	regex_t **viaregs;
+
+	int dataregscount;
+	regex_t **dataregs;
+};
+
+struct digipeater {
+	struct aprx_interface *transmitter;
+	float		       tokenbucket;  // Per transmitter TokenBucket filter
+	float		       tbf_increment;
+	float		       tbf_limit;
+	float		       src_tbf_increment; // Source call specific TokenBucket rules
+        float                  src_tbf_limit;
+
+	dupecheck_t           *dupechecker; // Per transmitter dupecheck
+#ifndef DISABLE_IGATE
+	historydb_t	      *historydb;   // Per transmitter HistoryDB
+#endif
+
+	const struct tracewide *trace;
+	const struct tracewide *wide;
+
+	int                        sourcecount;
+	struct digipeater_source **sources;
+};
+
+extern int  digipeater_prepoll(struct aprxpolls *app);
+extern int  digipeater_postpoll(struct aprxpolls *app);
+extern int  digipeater_config(struct configfile *cf);
+extern void digipeater_receive(struct digipeater_source *src, struct pbuf_t *pb);
+extern int  digipeater_receive_filter(struct digipeater_source *src, struct pbuf_t *pb);
+extern dupecheck_t *digipeater_find_dupecheck(const struct aprx_interface *aif);
+
+/* interface.c */
+
+typedef enum {
+	IFTYPE_UNSET,
+	IFTYPE_AX25,
+	IFTYPE_SERIAL,
+	IFTYPE_TCPIP,
+	IFTYPE_AGWPE,
+	IFTYPE_NULL,
+	IFTYPE_APRSIS
+} iftype_e;
+
+
+struct aprx_interface {
+	iftype_e    iftype;
+	int	    timeout;
+	int16_t	    ifindex;       // Absolute index on this interface
+	int16_t	    ifgroup;	   // Group definition on this interface
+
+	char       *callsign;      // Callsign of this interface
+	uint8_t     ax25call[7];   // AX.25 address field format callsign
+
+	int	    aliascount;
+	char	  **aliases;	   // Alias callsigns for this interface
+
+	int8_t	    subif;	   // Sub-interface index - for KISS uses
+	uint8_t	    txrefcount;    // Number of digipeaters using this as Tx
+	unsigned    tx_ok:1;	   // This is Tx interface
+	unsigned    telemeter_to_is:1; // Telemeter this to APRS-IS
+	unsigned    telemeter_to_rf:1; // Telemeter this to this radio port
+	unsigned    telemeter_newformat:1; // Telemeter in "new format"
+
+	int	    initlength;
+	char	   *initstring;
+
+	const void        *nax25p; // used on IFTYPE_AX25
+#ifdef ENABLE_AGWPE
+	const void	  *agwpe;  // used on IFTYPE_AGWPE
+#endif
+	struct serialport *tty;    // used on IFTYPE_SERIAL, IFTYPE_TCPIP
+
+	int	                   digisourcecount;
+	struct digipeater_source **digisources;
+};
+
+extern struct aprx_interface aprsis_interface;
+
+extern int                     top_interfaces_group;
+extern int                     all_interfaces_count;
+extern struct aprx_interface **all_interfaces;
+
+extern void interface_init(void);
+extern int  interface_config(struct configfile *cf);
+extern struct aprx_interface *find_interface_by_callsign(const char *callsign);
+
+extern int interface_is_beaconable( const struct aprx_interface *iface );
+extern int interface_is_telemetrable(const struct aprx_interface *iface );
+
+extern void interface_receive_ax25( const struct aprx_interface *aif, const char *ifaddress, const int is_aprs, const int ui_pid, const uint8_t *axbuf, const int axaddrlen, const int axlen, const char *tnc2buf, const int tnc2addrlen, const int tnc2len);
+extern void interface_transmit_ax25(const struct aprx_interface *aif, uint8_t *axaddr, const int axaddrlen, const char *axdata, const int axdatalen);
+extern void interface_receive_3rdparty(const struct aprx_interface *aif, const char *fromcall, const char *origtocall, const char *gwtype, const char *tnc2data, const int tnc2datalen);
+extern int  interface_transmit_beacon(const struct aprx_interface *aif, const char *src, const char *dest, const char *via, const char *tncbuf, const int tnclen);
+extern int process_message_to_myself(const struct aprx_interface*const srcif, const struct pbuf_t*const pb);
+
+
+/* pbuf.c */
+extern void           pbuf_init(void);
+extern struct pbuf_t *pbuf_get(struct pbuf_t *pb);
+extern void           pbuf_put(struct pbuf_t *pb);
+extern struct pbuf_t *pbuf_new(const int is_aprs, const int digi_like_aprs, const int tnc2addrlen, const char *tnc2buf, const int tnc2len, const int ax25addrlen, const void *ax25buf, const int ax25len );
+
+
+/* parse_aprs.c */
+extern int parse_aprs(struct pbuf_t*const pb, historydb_t*const historydb);
+
+struct aprs_message_t {
+        const char *body;          /* message body */
+        const char *msgid;
+        
+        int body_len;
+        int msgid_len;
+        int is_ack;
+        int is_rej;
+};
+
+extern int parse_aprs_message(const struct pbuf_t*const pb, struct aprs_message_t*const am);
+
+
+/* filter.c */
+struct filter_t;  // Forward declarator
+struct client_t;  // Forward declarator
+struct worker_t;  // Forward declarator
+
+extern void filter_init(void);
+extern int  filter_parse(struct filter_t **ffp, const char *filt);
+extern void filter_free(struct filter_t *c);
+extern int  filter_process(struct pbuf_t *pb, struct filter_t *f, historydb_t *historydb);
+
+extern void filter_preprocess_dupefilter(struct pbuf_t *pb);
+extern void filter_postprocess_dupefilter(struct pbuf_t *pb, historydb_t *historydb);
+
+extern float filter_lat2rad(float lat);
+extern float filter_lon2rad(float lon);
+
+#ifdef ENABLE_AGWPE
+/* agwpesocket.c */
+extern void *agwpe_addport(const char *hostname, const char *hostport, const char *agwpeport, const struct aprx_interface *interface);
+extern void agwpe_sendto(const void *_ap, const uint8_t *axaddr, const int axaddrlen, const char *axdata, const int axdatalen);
+
+extern int  agwpe_prepoll(struct aprxpolls *);
+extern int  agwpe_postpoll(struct aprxpolls *);
+extern void agwpe_init(void);
+extern void agwpe_start(void);
+#endif
diff --git a/aprx.spec b/aprx.spec
new file mode 100644
index 0000000..f620b8e
--- /dev/null
+++ b/aprx.spec
@@ -0,0 +1,118 @@
+Name:           aprx
+Version:        2.08.svn593
+Release:        1%{?dist}
+Summary:        Hamradio APRS iGate / Digipeater
+License:        BSD
+URL:            http://ham.zmailer.org/oh2mqk/aprx/
+Source0:        http://ham.zmailer.org/oh2mqk/aprx/%{name}-%{version}.tar.gz
+
+
+%if 0%{?rhel} >= 7 || 0%{?fedora} >= 16
+BuildRequires:  systemd-units
+%endif
+
+%if 0%{?fedora} >= 18
+Requires(post): systemd
+Requires(preun): systemd
+Requires(postun): systemd
+
+%post
+%systemd_post %{name}.service
+
+%preun
+%systemd_preun %{name}.service
+
+%postun
+%systemd_postun_with_restart %{name}.service 
+
+%else 0%{?fedora} = 17
+Requires(post): systemd-units
+Requires(preun): systemd-units
+Requires(postun): systemd-units
+
+%post
+if [ $1 -eq 1 ] ; then 
+    # Initial installation 
+    /bin/systemctl daemon-reload >/dev/null 2>&1 || :
+fi
+
+%preun
+if [ $1 -eq 0 ] ; then
+    # Package removal, not upgrade
+    /bin/systemctl --no-reload disable aprx.service > /dev/null 2>&1 || :
+    /bin/systemctl stop aprx.service > /dev/null 2>&1 || :
+fi
+
+%postun
+/bin/systemctl daemon-reload >/dev/null 2>&1 || :
+if [ $1 -ge 1 ] ; then
+    # Package upgrade, not uninstall
+    /bin/systemctl try-restart aprx.service >/dev/null 2>&1 || :
+fi
+
+%endif
+
+%description
+Aprx is an APRS iGate that has minimal system requirements. It can handle
+an arbitrary number of radio modems, optionally relay APRS packets from radio
+to the APRS-IS network, optionally digipeat AX25 with or without NEWn-N
+rules, optionally relay APRS packets from APRS-IS to radio (TX-iGate)
+
+%prep
+%setup -q
+
+%build
+%configure --with-erlangstorage CFLAGS="-m32 -march=i386" LDFLAGS="-m32 -march=i386"
+make %{?_smp_mflags}
+make logrotate.aprx
+
+%install
+mkdir -p $RPM_BUILD_ROOT/etc/sysconfig
+mkdir -p $RPM_BUILD_ROOT/etc/logrotate.d
+mkdir -p $RPM_BUILD_ROOT/var/log/aprx
+
+make install DESTDIR=$RPM_BUILD_ROOT
+
+install -m 644 logrotate.aprx   $RPM_BUILD_ROOT%{_sysconfdir}/logrotate.d/aprx
+install -m 644 rpm/aprx.default $RPM_BUILD_ROOT%{_sysconfdir}/sysconfig/aprx
+
+%if 0%{?rhel} >= 7 || 0%{?fedora} >= 16
+mkdir -p $RPM_BUILD_ROOT%{_unitdir}
+install -m 644 rpm/aprx.service $RPM_BUILD_ROOT%{_unitdir}/%{name}.service
+%else
+mkdir -p $RPM_BUILD_ROOT%{_initddir}
+install -m 755 rpm/aprx.init    $RPM_BUILD_ROOT%{_initddir}/aprx
+%endif
+
+%clean
+rm -rf $RPM_BUILD_ROOT
+
+%files
+%defattr(-,root,root,-)
+# INSTALL not bundled
+%doc LICENSE README TODO PROTOCOLS
+%doc ChangeLog
+%doc aprx.conf aprx-complex.conf
+%doc doc/aprx-manual.pdf
+%doc ViscousDigipeater.README ViscousDigipeaterTxEffect.png
+%dir /var/log/aprx
+%if 0%{?rhel} >= 7 || 0%{?fedora} >= 16
+%{_unitdir}/%{name}.service
+%else
+%{_initddir}/%{name}
+%endif
+%config(noreplace) %{_sysconfdir}/aprx.conf
+%config(noreplace) %{_sysconfdir}/sysconfig/aprx
+%config(noreplace) %{_sysconfdir}/logrotate.d/aprx
+%{_sbindir}/aprx
+%{_sbindir}/aprx-stat
+%doc %{_mandir}/man8/aprx.8.gz
+%doc %{_mandir}/man8/aprx-stat.8.gz
+
+
+%changelog
+* Thu Oct 11 2012 Andrew Elwell <Andrew.Elwell at gmail.com> - 2.08.svn593
+- Packaging for Fedora
+
+* Sat Jan 12 2008 Matti Aarnio - OH2MQK - KP20NG <oh2mqk at sral.fi> - 
+- RPM framework added
diff --git a/aprxpolls.c b/aprxpolls.c
new file mode 100644
index 0000000..bb73032
--- /dev/null
+++ b/aprxpolls.c
@@ -0,0 +1,51 @@
+/* **************************************************************** *
+ *                                                                  *
+ *  APRX -- 2nd generation receive-only APRS-i-gate with            *
+ *          minimal requirement of esoteric facilities or           *
+ *          libraries of any kind beyond UNIX system libc.          *
+ *                                                                  *
+ * (c) Matti Aarnio - OH2MQK,  2007-2014                            *
+ *                                                                  *
+ * **************************************************************** */
+
+
+#include "aprx.h"
+
+
+/* aprxpolls libary functions.. */
+
+
+void aprxpolls_reset(struct aprxpolls *app)
+{
+	app->pollcount = 0;
+}
+
+int aprxpolls_millis(struct aprxpolls *app)
+{
+	return tv_timerdelta_millis(&tick,&app->next_timeout);
+}
+
+struct pollfd *aprxpolls_new(struct aprxpolls *app)
+{
+	struct pollfd *p;
+	app->pollcount += 1;
+	if (app->pollcount >= app->pollsize) {
+		app->pollsize += 8;
+		app->polls = realloc(app->polls,
+				     sizeof(struct pollfd) * app->pollsize);
+		// valgrind polishing..
+		p = &(app->polls[app->pollcount - 1]);
+		memset(p, 0, sizeof(struct pollfd) * 8);
+	}
+	
+        assert(app->polls);
+
+	p = &(app->polls[app->pollcount - 1]);
+	memset(p, 0, sizeof(struct pollfd));
+	return p;
+}
+
+void aprxpolls_free(struct aprxpolls *app) {
+	free(app->polls);
+	app->polls = NULL;
+}
diff --git a/ax25.c b/ax25.c
new file mode 100644
index 0000000..2d94605
--- /dev/null
+++ b/ax25.c
@@ -0,0 +1,295 @@
+/* **************************************************************** *
+ *                                                                  *
+ *  APRX -- 2nd generation receive-only APRS-i-gate with            *
+ *          minimal requirement of esoteric facilities or           *
+ *          libraries of any kind beyond UNIX system libc.          *
+ *                                                                  *
+ * (c) Matti Aarnio - OH2MQK,  2007-2014                            *
+ *                                                                  *
+ * **************************************************************** */
+
+
+#include "aprx.h"
+
+/*
+ * --
+ * C0 00
+ * 82 A0 B4 9A 88 A4 60
+ * 9E 90 64 90 A0 9C 72
+ * 9E 90 64 A4 88 A6 E0
+ * A4 8C 9E 9C 98 B2 61
+ * 03 F0
+ * 21 36 30 32 39 2E 35 30 4E 2F 30 32 35 30 35 2E 34 33 45 3E 20 47 43 53 2D 38 30 31 20
+ * C0
+ * --
+ */
+
+int ax25_to_tnc2_fmtaddress(char *dest, const uint8_t *src, int markflag)
+{
+	int i, c;
+	int ssid;
+	int seen_space = 0;
+
+	/* 6 bytes of station callsigns in shifted ASCII format.. */
+	for (i = 0; i < 6; ++i, ++src) {
+		c = (*src) & 0xFF;
+		if (c & 1) {
+			*dest = 0;
+			return ~c;	/* Bad address-end flag ? */
+		}
+
+		/* Don't copy spaces or 0 bytes */
+		c = c >> 1;
+		if (c == 0 || c == 0x20) {
+			seen_space = 1;
+			continue;
+		}
+		if (!seen_space &&
+		    (('A' <= c && c <= 'Z') ||
+		     ('0' <= c && c <= '9'))) {
+			*dest++ = c;
+		} else {
+			*dest = 0;
+			return ~c; // Bad character in callsign
+		}
+	}
+	/* 7th byte carries SSID et.al. bits */
+	c = (*src) & 0xFF;
+	/* (c & 1) can be non-zero - at last address! */
+
+	ssid = (c >> 1) & 0x0F;
+	if (ssid) {	/* don't print SSID==0 value */
+		dest += sprintf(dest, "-%d", ssid);
+	}
+
+	if ((c & 0x80) && markflag) {
+		*dest++ = '*';	/* Has been digipeated.. */
+	}
+	*dest = 0;
+
+	return c;
+}
+
+// Return 0 on OK, != 0 on errors
+int parse_ax25addr(uint8_t ax25[7], const char *text, int ssidflags)
+{
+	int i = 0;
+	int ssid = 0;
+	char c;
+
+	while (i < 6) {
+		c = *text;
+
+		if (c == '-' || c == '*' || c == '\0')
+			break;
+		if (!(('A' <= c && c <= 'Z') || ('0' <= c && c <= '9'))) {
+			// Valid chars: [A-Z0-9]
+			return 1;
+		}
+
+		ax25[i] = c << 1;
+
+		++text;
+		++i;
+	}
+
+	while (i < 6) {
+		ax25[i] = ' ' << 1; // they are wanted as spaces..
+		++i;
+	}
+
+	ax25[6] = ssidflags;
+	if (*text == 0) return 0;
+
+	if (*text == '-') {
+		++text;
+	} else if ( *text != '*' && *text != 0) {
+		return 1;
+	}
+
+	for (; (*text != '\0') && (*text != '*') &&
+	       ('0' <= *text) && (*text <= '9'); ++text) {
+
+		ssid = ssid * 10 + (*text - '0');
+	}
+
+	if (*text == '*') {
+		++text;
+		ssidflags |= 0x80; // Set H-bit..
+		ax25[6]   |= 0x80; // Set H-bit..
+	}
+
+	if (ssid > 15 || *text != '\0') {
+		return 1; // Bad values
+	}
+	ssid &= 0x0F; // Limit it to 4 bits
+
+	ax25[6] = (ssid << 1) | ssidflags;
+
+	return 0;
+}
+
+int ax25_format_to_tnc(const uint8_t *frame, const int framelen,
+		       char *tnc2buf, const int tnc2buflen,
+		       int *frameaddrlen, int *tnc2addrlen,
+		       int *is_aprs, int *ui_pid)
+{
+	int i, j;
+	const uint8_t *s = frame;
+	const uint8_t *e = frame + framelen;
+	char *t = tnc2buf;
+	int viacount = 0;
+
+	if (debug>1) {
+	  printf("ax25_format_to_tnc() len=%d ",framelen);
+	  hexdumpfp(stdout, frame, framelen, 1);
+	  printf("\n");
+	}
+
+	if (framelen > sizeof(tnc2buf) - 80) {
+		/* Too much ! Too much! */
+		return 0;
+	}
+
+
+	/* Phase 1: scan address fields. */
+	/* Source and Destination addresses must be printed in altered order.. */
+
+
+	*t = 0;
+	i = ax25_to_tnc2_fmtaddress(t, frame + 7, 0);	/* source */
+	t += strlen(t);
+	*t++ = '>';
+	*t = 0; // end-string, just in case..
+
+	j = ax25_to_tnc2_fmtaddress(t, frame + 0, 0);	/* destination */
+	t += strlen(t);
+
+//	if (!((i & 0xE0) == 0x60 && (j & 0xE0) == 0xE0)) {
+//	  if (debug) printf("Ax25FmtToTNC2: %s SSID-bytes: %02x,%02x\n", tnc2buf, i,j);
+//	}
+
+	if (i < 0 /*  || ((i & 0xE0) != 0x60)*/) { // Top 3 bits should be: 011
+		/* Bad format */
+		if (debug)
+		  printf("Ax25FmtToTNC2: Bad source address; SSID-byte=0x%02x\n",i);
+		return 0;
+	}
+	if (j < 0/* || ((j & 0xE0) != 0xE0)*/) { // Top 3 bits should be: 111
+		/* Bad format */
+		if (debug)
+		  printf("Ax25FmtToTNC2: Bad destination address; SSID-byte=0x%x\n",j);
+		return 0;
+	}
+
+
+	s = frame + 14;
+
+	if ((i & 1) == 0) {	/* addresses continue after the source! */
+
+		for (; s < e;) {
+			*t++ = ',';	/* separator char */
+			*t = 0; // end-string, just in case..
+			i = ax25_to_tnc2_fmtaddress(t, s, 1); // Top 3 bits are:  H11  ( H = "has been digipeated" )
+			if (i < 0 /* || ((i & 0x60) != 0x60) */) {
+				/* Bad format */
+			  if (debug) printf("Ax25FmtToTNC2: Bad via address; addr='%s' SSID-byte=0x%x\n",t,i);
+				return 0;
+			}
+
+			t += strlen(t);
+			s += 7;
+			++ viacount;
+			if (i & 1)
+				break;	/* last address */
+		}
+	}
+	if (viacount > 8) {
+		if (debug)
+		  printf("Ax25FmtToTNC2: Found %d via fields, limit is 8!\n", viacount);
+		return 0;
+	}
+
+	*frameaddrlen = s - frame;
+	*tnc2addrlen  = t - tnc2buf;
+
+	/* Address completed */
+
+	if ((s + 2) >= e) // too short payload
+		return 0;		/* never happens ?? */
+
+	*t++ = ':';		/* end of address */
+	*t = 0; // end-string, just in case..
+
+	if (s[0] != 0x03) {
+		// Not AX.25 UI frame
+		*ui_pid = -1; 
+		return t - tnc2buf;
+		/* But say that the frame is OK, and
+		   let it be possibly copied to Linux
+		   internal AX.25 network. */
+	}
+	if (s[0] == 0x03 && s[1] != 0xF0) {
+		// AX.25 UI frame, but no with APRS's PID value
+		*ui_pid = s[1];
+		return t - tnc2buf;
+	}
+
+	s += 2; // Skip over Control and PID bytes
+	*ui_pid = 0xF0; // This was previously verified
+
+	/* Copy payload - stop at first LF char */
+	for (; s < e; ++s) {
+		if (*s == '\n') /* Stop at first LF */
+			break;
+		*t++ = *s;
+	}
+	*t = 0;
+
+	/* Chop off possible immediately trailing CR characters */
+	for ( ;t > tnc2buf; --t ) {
+		int c = t[-1];
+		if (c != '\r') {
+			break;
+		}
+		t[-1] = 0;
+	}
+
+	*is_aprs = 1;
+	return t - tnc2buf;
+}
+
+/* Convert the binary packet to TNC2 monitor text format.
+   Return 0 if conversion fails (format errors), 1 when format is OK. */
+
+int ax25_to_tnc2(const struct aprx_interface *aif, const char *portname,
+		 const int tncid, const int cmdbyte,
+		 const uint8_t *frame, const int framelen)
+{
+	int frameaddrlen = 0;
+
+	char tnc2buf[2800];
+	int tnc2len = 0, tnc2addrlen = 0, is_aprs = 0, ui_pid = 0;
+
+	tnc2len = ax25_format_to_tnc( frame, framelen,
+				      tnc2buf, sizeof(tnc2buf),
+				      & frameaddrlen, &tnc2addrlen,
+				      & is_aprs, &ui_pid );
+
+	if (tnc2len == 0) return 0; // Bad parse result
+
+	// APRS type packets are first rx-igated (and rflog()ed)
+#ifndef DISABLE_IGATE
+	if (is_aprs) {
+	  igate_to_aprsis(portname, tncid, tnc2buf, tnc2addrlen, tnc2len, 0, 1);
+	}
+#endif
+
+	// Send to interface system to receive it..  (digipeater!)
+	// A noop if the interface is actually NULL.
+	interface_receive_ax25(aif, portname, is_aprs, ui_pid,
+			       frame, frameaddrlen, framelen,
+			       tnc2buf, tnc2addrlen, tnc2len);
+
+	return 1;
+}
diff --git a/beacon.c b/beacon.c
new file mode 100644
index 0000000..d0c588b
--- /dev/null
+++ b/beacon.c
@@ -0,0 +1,1235 @@
+/* **************************************************************** *
+ *                                                                  *
+ *  APRX -- 2nd generation receive-only APRS-i-gate with            *
+ *          minimal requirement of esoteric facilities or           *
+ *          libraries of any kind beyond UNIX system libc.          *
+ *                                                                  *
+ * (c) Matti Aarnio - OH2MQK,  2007-2014                            *
+ *                                                                  *
+ * **************************************************************** */
+
+#include "aprx.h"
+
+struct beaconmsg {
+	time_t nexttime;
+	int    interval;
+	const struct aprx_interface *interface;
+	const char *src;
+	const char *dest;
+	const char *via;
+	const char *msg;
+	const char *filename;
+	const char *execfile;
+	int8_t	    beaconmode; // -1: net only, 0: both, +1: radio only
+	int8_t	    timefix;
+	int         timeout;
+};
+
+struct beaconset {
+	struct beaconmsg **beacon_msgs;
+
+  	struct timeval beacon_nexttime;
+	float  beacon_cycle_size;
+
+	int beacon_msgs_count;
+	int beacon_msgs_cursor;
+
+	int    exec_pid;
+	int    exec_fd;
+        time_t exec_deadline; // seconds
+  	char  *exec_buf;
+	int    exec_buf_length;
+	int    exec_buf_space;
+  	struct beaconmsg *exec_bm;
+};
+
+static struct beaconset **bsets;
+static int bsets_count;
+
+static void beacon_it(struct beaconset *bset, struct beaconmsg *bm);
+
+
+static void beacon_reset(struct beaconset *bset)
+{
+	tv_timeradd_seconds(&bset->beacon_nexttime, &tick, 30);	// start 30 seconds from now
+	bset->beacon_msgs_cursor = 0;
+}
+
+static void beacon_set(struct configfile *cf,
+                       const char *p1,
+                       char *str,
+                       const int beaconmode,
+                       struct beaconset *bset)
+{
+	const char *srcaddr  = NULL;
+	const char *destaddr = NULL;
+	const char *via      = NULL;
+	const char *name     = NULL;
+	int buflen = strlen(p1) + strlen(str ? str : "") + 10;
+	char *buf  = alloca(buflen);
+	const char *to   = NULL;
+	char *code = NULL;
+	const char *lat  = NULL;
+	const char *lon  = NULL;
+	char *comment = NULL;
+	char *type    = NULL;
+	const struct aprx_interface *aif = NULL;
+	int has_fault = 0;
+
+	struct beaconmsg *bm = calloc(1, sizeof(*bm));
+
+	*buf = 0;
+
+	if (debug) {
+	  printf("BEACON parameters: ");
+	}
+
+	while (*p1) {
+
+		/* if (debug)
+		   printf("p1='%s' ",p1); */
+
+		if (strcmp(p1, "interface") == 0 ||
+		    strcmp(p1, "to") == 0) {
+
+			if (to != NULL) {
+			  has_fault = 1;
+			  printf("%s:%d ERROR: Double definition of %s parameter\n",
+				 cf->name, cf->linenum, p1);
+			}
+
+			to = str;
+			str = config_SKIPTEXT(str, NULL);
+			str = config_SKIPSPACE(str);
+
+			if (beaconmode < 0) {
+			  printf("%s:%d ERROR: beaconmode APRSIS is incompatible with beaconing to designated interface ('%s %s')\n",
+				 cf->name, cf->linenum, p1, to);
+			  has_fault = 1;
+			  goto discard_bm; // sigh..
+			}
+
+			if (strcasecmp(to,"$mycall") == 0) {
+				to = mycall;
+			} else {
+				config_STRUPPER((void*)to);
+			}
+
+			aif = find_interface_by_callsign(to);
+			if ((aif != NULL) && (!aif->tx_ok)) {
+				aif = NULL;  // Not an TX interface :-(
+				if (debug)printf("\n");
+				printf("%s:%d ERROR: beacon interface '%s' that is not a TX capable interface.\n",
+				       cf->name, cf->linenum, to);
+				has_fault = 1;
+				goto discard_bm; // sigh..
+			} else if (aif == NULL) {
+				if (debug)printf("\n");
+				printf("%s:%d ERROR: beacon interface '%s' that is not a known interface.\n",
+				       cf->name, cf->linenum, to);
+				has_fault = 1;
+			}
+
+			if (debug)
+				printf("interface '%s' ", to);
+
+		} else if (strcmp(p1, "srccall") == 0 ||
+			   strcmp(p1, "for") == 0) {
+
+			if (srcaddr != NULL) {
+			  has_fault = 1;
+			  printf("%s:%d ERROR: Double definition of %s parameter\n",
+				 cf->name, cf->linenum, p1);
+			}
+			srcaddr = str;
+			str = config_SKIPTEXT(str, NULL);
+			str = config_SKIPSPACE(str);
+
+			if (strcasecmp(srcaddr,"$mycall") == 0) {
+				srcaddr = mycall;
+			} else {
+				config_STRUPPER((void*)srcaddr);
+			}
+
+			// What about ITEM and OBJECT ?
+
+			// if (!validate_callsign_input((char *) srcaddr),1) {
+			//   if (debug)printf("\n");
+			//   printf("Invalid rfbeacon FOR callsign");
+			// }
+
+			if (debug)
+				printf("srccall '%s' ", srcaddr);
+
+		} else if (strcmp(p1, "dstcall") == 0 ||
+			   strcmp(p1, "dest") == 0) {
+
+			if (destaddr != NULL) {
+			  has_fault = 1;
+			  printf("%s:%d ERROR: Double definition of %s parameter\n",
+				 cf->name, cf->linenum, p1);
+			}
+			destaddr = str;
+			str = config_SKIPTEXT(str, NULL);
+			str = config_SKIPSPACE(str);
+
+			config_STRUPPER((void*)destaddr);
+
+			if (debug)
+				printf("dstcall '%s' ", destaddr);
+
+		} else if (strcmp(p1, "via") == 0) {
+
+			if (via != NULL) {
+			  has_fault = 1;
+			  printf("%s:%d ERROR: Double definition of %s parameter\n",
+				 cf->name, cf->linenum, p1);
+			}
+			via  = str;
+			str = config_SKIPTEXT(str, NULL);
+			str = config_SKIPSPACE(str);
+
+			config_STRUPPER((void*)via);
+
+			if (debug)
+				printf("via '%s' ", via);
+
+		} else if (strcmp(p1, "name") == 0) {
+
+			if (name != NULL) {
+			  has_fault = 1;
+			  printf("%s:%d ERROR: Double definition of %s parameter\n",
+				 cf->name, cf->linenum, p1);
+			}
+			name  = str;
+			str = config_SKIPTEXT(str, NULL);
+			str = config_SKIPSPACE(str);
+
+			if (debug)
+				printf("name '%s' ", name);
+
+		} else if (strcmp(p1, "item") == 0) {
+			if (name != NULL) {
+			  has_fault = 1;
+			  printf("%s:%d ERROR: Double definition of %s parameter\n",
+				 cf->name, cf->linenum, p1);
+			}
+			if (type != NULL) {
+			  has_fault = 1;
+			  printf("%s:%d ERROR: Double definition of type parameter\n",
+				 cf->name, cf->linenum);
+			}
+			type = ")";
+			name  = str;
+			str = config_SKIPTEXT(str, NULL);
+			str = config_SKIPSPACE(str);
+
+			if (debug)
+				printf("item '%s' ", name);
+
+		} else if (strcmp(p1, "object") == 0) {
+			if (name != NULL) {
+			  has_fault = 1;
+			  printf("%s:%d ERROR: Double definition of %s parameter\n",
+				 cf->name, cf->linenum, p1);
+			}
+			if (type != NULL) {
+			  has_fault = 1;
+			  printf("%s:%d ERROR: Double definition of type parameter\n",
+				 cf->name, cf->linenum);
+			}
+			type = ";";
+
+			name  = str;
+			str = config_SKIPTEXT(str, NULL);
+			str = config_SKIPSPACE(str);
+
+			if (debug)
+				printf("object '%s' ", name);
+
+		} else if (strcmp(p1, "type") == 0) {
+			/* text up to .. 40 chars */
+
+			if (type != NULL) {
+			  has_fault = 1;
+			  printf("%s:%d ERROR: Double definition of %s parameter\n",
+				 cf->name, cf->linenum, p1);
+			}
+			type = str;
+			str = config_SKIPTEXT(str, NULL);
+			str = config_SKIPSPACE(str);
+			type = strdup(type);
+
+			if (debug)
+				printf("type '%s' ", type);
+			if (type[1] != 0 || (type[0] != '!' &&
+					     type[0] != '=' &&
+					     type[0] != '/' &&
+					     type[0] != '@' &&
+					     type[0] != ';' &&
+					     type[0] != ')')) {
+			  has_fault = 1;
+			  printf("%s:%d Sorry, packet constructor's supported APRS packet types are only: ! = / @ ; )\n",
+				 cf->name, cf->linenum);
+			}
+
+		} else if (strcmp(p1, "$myloc") == 0) {
+                	if (myloc_latstr != NULL) {
+                          lat = myloc_latstr;
+                          lon = myloc_lonstr;
+                        } else {
+                          has_fault = 1;
+			  printf("%s:%d ERROR: $myloc has not been defined.\n",
+				 cf->name, cf->linenum);
+
+                        }
+		} else if (strcmp(p1, "lat") == 0) {
+			/*  ddmm.mmN   */
+
+			if (lat != NULL) {
+			  has_fault = 1;
+			  printf("%s:%d ERROR: Double definition of %s parameter\n",
+				 cf->name, cf->linenum, p1);
+			}
+			lat = str;
+			str = config_SKIPTEXT(str, NULL);
+			str = config_SKIPSPACE(str);
+
+			if (!has_fault && validate_degmin_input(lat, 90)) {
+			  has_fault = 1;
+			  printf("%s:%d ERROR: Latitude input has bad format: '%s'\n",
+				 cf->name, cf->linenum, lat);
+			}
+
+			if (debug)
+				printf("lat '%s' ", lat);
+
+		} else if (strcmp(p1, "lon") == 0) {
+			/*  dddmm.mmE  */
+
+			if (lon != NULL) {
+			  has_fault = 1;
+			  printf("%s:%d ERROR: Double definition of %s parameter\n",
+				 cf->name, cf->linenum, p1);
+			}
+			lon = str;
+			str = config_SKIPTEXT(str, NULL);
+			str = config_SKIPSPACE(str);
+
+			if (validate_degmin_input(lon, 180)) {
+			  has_fault = 1;
+			  printf("Longitude input has bad format: '%s'\n",lon);
+			}
+
+			if (debug)
+				printf("lon '%s' ", lon);
+
+		} else if (strcmp(p1, "symbol") == 0) {
+			/*   R&    */
+
+			if (code != NULL) {
+			  has_fault = 1;
+			  printf("%s:%d ERROR: Double definition of %s parameter\n",
+				 cf->name, cf->linenum, p1);
+			}
+			code = str;
+			str = config_SKIPTEXT(str, NULL);
+			str = config_SKIPSPACE(str);
+			if (strlen(code) != 2) {
+			  has_fault = 1;
+			  printf("Symbol code lenth is not exactly 2 chars\n");
+			}
+
+			if (debug)
+				printf("symbol '%s' ", code);
+
+		} else if (strcmp(p1, "comment") == 0) {
+			/* text up to .. 40 chars */
+
+			if (comment != NULL) {
+			  has_fault = 1;
+			  printf("%s:%d ERROR: Double definition of %s parameter\n",
+				 cf->name, cf->linenum, p1);
+			}
+			comment = str;
+			str = config_SKIPTEXT(str, NULL);
+			str = config_SKIPSPACE(str);
+
+			if (debug)
+				printf("comment '%s' ", comment);
+
+		} else if (strcmp(p1, "raw") == 0) {
+
+			p1 = str;
+			str = config_SKIPTEXT(str, NULL);
+			str = config_SKIPSPACE(str);
+
+			if (bm->msg != NULL) {
+			  has_fault = 1;
+			  printf("%s:%d ERROR: Double definition of %s parameter\n",
+				 cf->name, cf->linenum, p1);
+			} else
+			  bm->msg = strdup(p1);
+
+			// FIXME: validate the data with APRS parser...
+
+			if (debug)
+				printf("raw '%s' ", bm->msg);
+
+		} else if (strcmp(p1, "file") == 0) {
+
+			p1 = str;
+			str = config_SKIPTEXT(str, NULL);
+			str = config_SKIPSPACE(str);
+
+			if (bm->filename != NULL) {
+			  has_fault = 1;
+			  printf("%s:%d ERROR: Double definition of %s parameter\n",
+				 cf->name, cf->linenum, p1);
+			} else
+			  bm->filename = strdup(p1);
+
+			if (debug)
+				printf("file '%s' ", bm->filename);
+
+		} else if (strcmp(p1, "exec") == 0) {
+
+			p1 = str;
+			str = config_SKIPTEXT(str, NULL);
+			str = config_SKIPSPACE(str);
+
+			if (bm->execfile != NULL) {
+			  has_fault = 1;
+			  printf("%s:%d ERROR: Double definition of %s parameter\n",
+				 cf->name, cf->linenum, p1);
+			} else
+			  bm->execfile = strdup(p1);
+
+                        // Set default timeout if not yet set.
+                        if (bm->timeout == 0)
+                          bm->timeout = 10;
+
+			if (debug)
+				printf("exec file '%s' ", bm->execfile);
+
+		} else if (strcmp(p1, "timeout") == 0) {
+
+			p1 = str;
+			str = config_SKIPTEXT(str, NULL);
+			str = config_SKIPSPACE(str);
+
+			bm->timeout = atoi(p1);
+
+			if (debug)
+				printf("timeout %d ", bm->timeout);
+
+		} else if (strcmp(p1, "timefix") == 0) {
+			if (bm->timefix) {
+			  has_fault = 1;
+			  printf("%s:%d ERROR: Double definition of %s parameter\n",
+				 cf->name, cf->linenum, p1);
+			}
+			bm->timefix = 1;
+			if (debug)
+				printf("timefix ");
+
+		} else {
+
+			has_fault = 1;
+#if 0
+			if (debug)
+				printf("Unknown keyword: '%s'", p1);
+
+			p1 = str;
+			str = config_SKIPTEXT(str, NULL);
+			str = config_SKIPSPACE(str);
+#else
+			/* Unknown keyword, a raw message ? */
+			bm->msg = strdup(p1);
+
+			if (debug)
+				printf("ASSUMING raw '%s' ", bm->msg);
+
+			break;
+#endif
+		}
+
+		p1 = str;
+		str = config_SKIPTEXT(str, NULL);
+		str = config_SKIPSPACE(str);
+	}
+	if (debug)
+		printf("\n");
+	if (has_fault)
+		goto discard_bm;
+
+	if (aif == NULL && beaconmode >= 0) {
+		if (debug)
+			printf("%s:%d Note: Lacking 'interface' keyword for this beacon definition. Beaconing to all Tx capable interfaces + APRSIS (mode depending)\n",
+			       cf->name, cf->linenum);
+	}
+
+/*
+	if (srcaddr == NULL)
+		srcaddr = mycall;
+
+	if (srcaddr == NULL) {
+		if (debug)
+			printf("%s:%d Note: Lacking the 'for' keyword for this beacon definition.\n", cf->name, cf->linenum);
+		has_fault = 1;
+		goto discard_bm;
+	}
+*/
+
+	if (destaddr == NULL)
+		destaddr = tocall;
+
+	bm->src       = srcaddr != NULL ? strdup(srcaddr) : NULL;
+	bm->dest      = strdup(destaddr);
+	bm->via       = via != NULL ? strdup(via) : NULL;
+	bm->interface = aif;
+	bm->beaconmode = beaconmode;
+
+	if (!bm->msg && !bm->filename && !bm->execfile) {
+		/* Not raw packet, perhaps composite ? */
+		if (!type) type = "!";
+		if (code && strlen(code) == 2 && lat && strlen(lat) == 8 &&
+		    lon && strlen(lon) == 9) {
+			if ( strcmp(type,"!") == 0 ||
+			     strcmp(type,"=") == 0 ) {
+				sprintf(buf, "%s%s%c%s%c%s", type, lat, code[0], lon,
+					code[1], comment ? comment : "");
+			} else if ( strcmp(type,"/") == 0 ||
+				    strcmp(type,"@") == 0) {
+				sprintf(buf, "%s111111z%s%c%s%c%s", type, lat, code[0], lon,
+					code[1], comment ? comment : "");
+			} else if ( strcmp(type,";") == 0 && name) { // Object
+				sprintf(buf, ";%-9.9s*111111z%s%c%s%c%s", name, lat, code[0], lon,
+					code[1], comment ? comment : "");
+
+			} else if ( strcmp(type,")") == 0 && name) { // Item
+				sprintf(buf, ")%-3.9s!%s%c%s%c%s", name, lat, code[0], lon,
+					code[1], comment ? comment : "");
+			}
+			bm->msg = strdup(buf);
+		} else {
+			if (!code || (code && strlen(code) != 2))
+				printf("%s:%d .. BEACON definition failure; symbol parameter missing or wrong size\n", cf->name, cf->linenum);
+			if (!lat || (lat && strlen(lat) != 8))
+				printf("%s:%d .. BEACON definition failure; lat(itude) parameter missing or wrong size\n", cf->name, cf->linenum);
+			if (!lon || (lon && strlen(lon) != 9))
+				printf("%s:%d .. BEACON definition failure; lon(gitude) parameter missing or wrong size\n", cf->name, cf->linenum);
+			/* parse failure, abandon the alloc too */
+			has_fault = 1;
+			goto discard_bm;
+		}
+	}
+
+	if (debug) {
+	  switch (beaconmode) {
+	  case 1:
+	    printf("RFONLY");
+	    break;
+	  case 0:
+	    printf("RF+NET");
+	    break;
+	  default:
+	    printf("NETONLY");
+	    break;
+	  }
+	  printf(" BEACON FOR ");
+	  if (srcaddr == NULL)
+	    printf("***>%s", destaddr);
+	  else
+	    printf("%s>%s",srcaddr,destaddr);
+	  if (via != NULL)
+	    printf(",%s", via);
+	  if (bm->filename)
+	    printf("'  file %s\n", bm->filename);
+	  else
+	    printf("'  '%s'\n", bm->msg);
+	}
+
+	/* realloc() works also when old ptr is NULL */
+	bset->beacon_msgs = realloc(bset->beacon_msgs,
+                                    sizeof(bm) * (bset->beacon_msgs_count + 3));
+
+	bset->beacon_msgs[bset->beacon_msgs_count++] = bm;
+	bset->beacon_msgs[bset->beacon_msgs_count] = NULL;
+	
+	if (bm->msg != NULL) {  // Make this into AX.25 UI frame
+	                        // with leading control byte..
+	  int len = strlen(bm->msg);
+	  char *msg = realloc((void*)bm->msg, len+3); // make room
+	  memmove(msg+2, msg, len+1); // move string end \0 also
+	  msg[0] = 0x03;  // Control byte
+	  msg[1] = 0xF0;  // PID 0xF0
+	  bm->msg = msg;
+	}
+
+	beacon_reset(bset);
+
+	if (0) {
+	discard_bm:
+	  if (bm->dest != NULL) free((void*)(bm->dest));
+	  if (bm->msg  != NULL) free((void*)(bm->msg));
+	  free(bm);
+	}
+	return;
+}
+
+static void free_beaconmsg(struct beaconmsg *bmsg) {
+	if (bmsg == NULL) return;
+        if (bmsg->src)  free((void*)bmsg->src);
+        if (bmsg->dest) free((void*)bmsg->dest);
+        if (bmsg->via)  free((void*)bmsg->via);
+        if (bmsg->msg)  free((void*)bmsg->msg);
+        if (bmsg->filename) free((void*)bmsg->filename);
+        if (bmsg->execfile) free((void*)bmsg->execfile);
+        free(bmsg);
+}
+
+static void free_beaconset(struct beaconset *bset) {
+        int i;
+	if (bset == NULL) return;
+        for (i = 0; i < bset->beacon_msgs_count; ++i) {
+          free_beaconmsg(bset->beacon_msgs[i]);
+        }
+        free(bset);
+}
+
+int beacon_config(struct configfile *cf)
+{
+	char *name, *param1;
+	char *str = cf->buf;
+	int   beaconmode = 0;
+	int   has_fault  = 0;
+
+
+        struct beaconset *bset = calloc(1, sizeof(*bset));
+        bset->beacon_cycle_size = 20.0*60.0; // 20 minutes is the default
+
+	while (readconfigline(cf) != NULL) {
+		if (configline_is_comment(cf))
+			continue;	/* Comment line, or empty line */
+
+		// It can be severely indented...
+		str = config_SKIPSPACE(cf->buf);
+
+		name = str;
+		str = config_SKIPTEXT(str, NULL);
+		str = config_SKIPSPACE(str);
+		config_STRLOWER(name);
+
+		param1 = str;
+		str = config_SKIPTEXT(str, NULL);
+		str = config_SKIPSPACE(str);
+
+		if (strcmp(name, "</beacon>") == 0)
+		  break;
+
+		if (strcmp(name, "cycle-size") == 0) {
+		  int v;
+		  if (config_parse_interval(param1, &v)) {
+		    // Error
+		    has_fault = 1;
+		    continue;
+		  }
+		  bset->beacon_cycle_size = (float)v;
+		  if (debug)
+		    printf("Beacon cycle size: %.2f\n",
+			   bset->beacon_cycle_size/60.0);
+		  continue;
+		}
+
+		if (strcmp(name, "beacon") == 0) {
+		  beacon_set(cf, param1, str, beaconmode, bset);
+
+		} else if (strcmp(name, "beaconmode") == 0) {
+		  if (strcasecmp(param1, "both") == 0) {
+		    beaconmode = 0;
+
+		  } else if (strcasecmp(param1,"radio") == 0) {
+		    beaconmode = 1;
+
+		  } else if (strcasecmp(param1,"aprsis") == 0) {
+		    beaconmode = -1;
+
+		  } else {
+		    printf("%s:%d ERROR: Unknown beaconmode parameter keyword: '%s'\n",
+			   cf->name, cf->linenum, param1);
+		    has_fault = 1;
+		  }
+
+		} else {
+		  printf("%s:%d ERROR: Unknown <beacon> block config keyword: '%s'\n",
+			 cf->name, cf->linenum, name);
+		  has_fault = 1;
+		  continue;
+		}
+	}
+        if (has_fault) {
+          // discard it..
+          free_beaconset(bset);
+        } else {
+          // save it..
+          ++bsets_count;
+          bsets = realloc( bsets,sizeof(*bsets)*bsets_count );
+          bsets[bsets_count-1] = bset;
+
+          if (debug > 0) {
+            printf("<beacon> set %d defined with %d entries\n",
+                   bsets_count, bset->beacon_msgs_count);
+          }
+        }
+
+	return has_fault;
+}
+
+static void fix_beacon_time(char *txt, int txtlen)
+{
+	int hour, min, sec;
+	char hms[8];
+
+	sec = now.tv_sec % (3600*24); // UNIX time is UTC -> no need to play with fancy timezone conversions and summer times...
+	hour = sec / 3600;
+	min  = (sec / 60) % 60;
+	sec  = sec % 60;
+	sprintf(hms, "%02d%02d%02dh", hour, min, sec);
+
+	txt += 2; txtlen -= 2; // Skip Control+PID
+
+	if (*txt == ';' && txtlen >= 36) { // Object
+
+		// ;434.775-B*111111z6044.06N/02612.79Er
+		memcpy( txt+11, hms, 7 ); // Overwrite with new time
+	} else if ((*txt == '/' || *txt == '@') && txtlen >= 27) { // Position with timestamp
+		memcpy( txt+1, hms, 7 ); // Overwrite with new time
+	}
+}
+
+
+static char *msg_read_file(const char *filename, char *buf, int buflen)
+{
+	FILE *fp = fopen(filename,"r");
+	if (!fp) return NULL;
+	if (fgets(buf, buflen, fp)) {
+		char *p = strchr(buf, '\n');
+		if (p) *p = 0;
+	} else {
+		*buf = 0;
+	}
+	fclose(fp);
+	if (*buf == 0) return NULL;
+	return buf;
+}
+
+static void beacon_resettimer(void *arg)
+{
+	const struct beaconset *bset = (struct beaconset *)arg;
+	float beacon_increment;
+	int   i;
+	time_t t = tick.tv_sec;
+
+	srand((long)t);
+        beacon_increment = (bset->beacon_cycle_size / bset->beacon_msgs_count);
+
+        if (debug)
+        	printf("beacons cycle: %.2f minutes, increment: %.2f minutes\n",
+                       bset->beacon_cycle_size/60.0, beacon_increment/60.0);
+        
+        for (i = 0; i < bset->beacon_msgs_count; ++i) {
+        	int r = rand() % 1024;
+                int interval = (int)(beacon_increment - 0.2*beacon_increment * (r*0.001));
+                if (interval < 3) interval = 3; // Minimum interval: 3 seconds
+                t += interval;
+                if (debug)
+                	printf("beacons offset: %.2f minutes\n", (t-tick.tv_sec)/60.0);
+                bset->beacon_msgs[i]->nexttime = t;
+        }
+}
+
+static void msg_exec_read(struct beaconset *bset)
+{
+	int rc;
+        int space = bset->exec_buf_space - bset->exec_buf_length;
+        if (debug) printf("msg_exec_read\n");
+
+        if (space < 1) {
+        	space += 256;
+                bset->exec_buf_space += 256;
+                bset->exec_buf = realloc(bset->exec_buf, bset->exec_buf_space);
+        }
+        
+        while ((rc = read(bset->exec_fd, bset->exec_buf + bset->exec_buf_length, space)) > 0) {
+		char *p;
+        	bset->exec_buf_length += rc;
+                space -= rc;
+                p = memrchr(bset->exec_buf, '\n', bset->exec_buf_length);
+                if (p) {
+                  if (debug) printf("found newline in exec read data\n");
+                  *p = 0;
+                  bset->exec_buf_length = p - bset->exec_buf;
+                  struct beaconmsg *bm = bset->exec_bm;
+                  if (bset->exec_buf_length > 2) {
+                    // Run that beacon!
+                    // Point it to read buffer
+                    bm->msg = bset->exec_buf;
+                    if (debug) printf(".. calling beacon_it() on buffer: %s\n", bm->msg+2);
+                    beacon_it(bset, bm);
+                  } else {
+                    if (debug) printf(".. nothing read from exec pipe\n");
+                  }
+                  // erase the read buffer pointer
+                  bm->msg = NULL;
+                  // restore the nexttime
+                  bset->beacon_nexttime.tv_sec = bm->nexttime;
+                  close(bset->exec_fd);
+                  bset->exec_fd = -1;
+                  //bset->exec_pid = 0; 
+                  return;
+                }
+                if (debug) printf("no newline in exec read data\n");
+                if (space < 1) {
+                  aprxlog("BEACON EXEC output overflowed read buffer.");
+                  rc = 0; // simulate as if..  and kill it.
+                  break;
+                }
+        }
+        if (rc == 0) { // EOF read
+		char *p;
+		if (debug) printf("Seen EOF on exec-read\n");
+                p = memrchr(bset->exec_buf, '\n', bset->exec_buf_length);
+                if (p) {
+                  *p = 0;
+                  bset->exec_buf_length = p - bset->exec_buf;
+                  struct beaconmsg *bm = bset->exec_bm;
+                  if (bset->exec_buf_length > 2) {
+                    // Run that beacon!
+                    // Point it to read buffer
+                    bm->msg = bset->exec_buf;
+                    if (debug) printf(".. calling beacon_it() on buffer: %s\n", bm->msg+2);
+                    beacon_it(bset, bm);
+                  } else {
+                    if (debug) printf(".. nothing read from exec pipe\n");
+                  }
+                  // erase the read buffer pointer
+                  bm->msg = NULL;
+                  // restore the nexttime
+                  bset->beacon_nexttime.tv_sec = bm->nexttime;
+                } else {
+                  aprxlog("BEACON EXEC abnormal close.");
+                }
+                close(bset->exec_fd);
+                bset->exec_fd = -1;
+                //bset->exec_pid = 0; 
+        }
+}
+
+static int msg_exec_file(const char *filename, int timeout, struct beaconset *bset)
+{
+	int p[2];
+        int pid;
+        int dev_null;
+	if (pipe(p)) {
+		return 0;
+	}
+
+        pid = fork();
+	if (pid < 0) {
+		close(p[0]);
+		close(p[1]);
+		return 0;
+	}
+        if (pid == 0) { //child
+
+        	if (debug) fprintf(stderr,"execing child pid %d, file: %s\n", getpid(), filename);
+
+		close(p[0]);
+                if (p[1] != 1) {
+                  dup2(p[1], 1);
+                  close(p[1]);
+                }
+                dev_null = open("/dev/null", O_WRONLY);
+		if (debug && dev_null < 0)
+                  fprintf(stderr,"child process: Failed to open file: /den/null\n");
+                if (dev_null >= 0) {
+                  if (dev_null != 2) {
+                    dup2(dev_null, 2);
+                    close(dev_null);
+                  }
+                  dup2(2, 0);
+                }
+
+		//FIXME: change second parameter
+		execl(filename, "aprx", NULL);
+		if (debug)
+                  fprintf(stderr,"child process: Failed to execute: %s\n", filename);
+		exit(255);
+
+	}
+
+        // parent
+
+        bset->exec_deadline = tick.tv_sec + timeout;
+        bset->exec_pid = pid;
+        bset->exec_fd  = p[0];
+        
+        bset->beacon_nexttime.tv_sec = bset->exec_deadline;
+        
+        close(p[1]);
+
+        return 1;
+}
+
+//        int val;
+//        waitpid(pid, &val, 0);
+//        if (WIFEXITED(val) && WEXITSTATUS(val) == 0) {
+//          return buf;
+//        }
+
+static void beacon_now(struct beaconset *bset)
+{
+	struct beaconmsg *bm;
+
+        if (bset->exec_pid > 0) {
+          if (debug) printf("beacon_now - still an exec under way.\n");
+          // Wait 3 seconds before retrying.
+          bset->beacon_nexttime.tv_sec += 3;
+          return;
+        }
+
+	if (bset->beacon_msgs_cursor >= bset->beacon_msgs_count) // Last done..
+		bset->beacon_msgs_cursor = 0;
+
+	if (bset->beacon_msgs_cursor == 0) {
+        	beacon_resettimer(bset);
+	}
+
+	/* --- now the business of sending ... */
+
+        //if (debug) printf("beacon_now idx=%d\n", bset->beacon_msgs_cursor );
+	bm = bset->beacon_msgs[bset->beacon_msgs_cursor++];
+
+	bset->beacon_nexttime.tv_sec = bm->nexttime;
+	bset->beacon_nexttime.tv_usec = 0;
+
+        beacon_it(bset, bm);
+}
+
+static void beacon_it(struct beaconset *bset, struct beaconmsg *bm)
+{
+	int  destlen;
+	int  txtlen, msglen;
+	int  i;
+	char const *txt;
+	char *msg;
+
+	if (debug)
+	  printf("BEACON: idx=%d, nexttime= +%d sec\n",
+		 bset->beacon_msgs_cursor-1, (int)(bset->beacon_nexttime.tv_sec - tick.tv_sec));
+
+	destlen = strlen(bm->dest) + ((bm->via != NULL) ? strlen(bm->via): 0) +2;
+
+	if (bm->filename != NULL) {
+		msg = alloca(256);  // This is a load-and-discard allocation
+		txt = msg+2;
+		msg[0] = 0x03;
+		msg[1] = 0xF0;
+		if (!msg_read_file(bm->filename, msg+2, 256-2)) {
+			// Failed loading
+			if (debug)
+			  printf("BEACON ERROR: Failed to load anything from file %s\n",bm->filename);
+			syslog(LOG_ERR, "Failed to load anything from beacon file %s", bm->filename);
+			return;
+		}
+        } else if (bm->msg != NULL) {
+		msg     = (char*)bm->msg;
+		txt     = bm->msg+2; // Skip Control+PID bytes
+	} else if (bm->execfile != NULL) {
+		bset->exec_buf = realloc(bset->exec_buf, 256);
+                bset->exec_buf[0] = 0x03;
+                bset->exec_buf[1] = 0xF0;
+                bset->exec_buf_length = 2;
+                bset->exec_buf_space = 256;
+                bset->exec_bm = bm;
+		if (!msg_exec_file(bm->execfile, bm->timeout, bset)) {
+			if (debug)
+			  printf("BEACON ERROR: Failed to exec file %s\n",bm->execfile);
+			syslog(LOG_ERR, "Failed to exec file %s", bm->execfile);
+			return;
+		}
+                return; // spawning done, successfull or not..
+	} else {
+          if (debug) printf("Nothing to beacon now.\n");
+          return;
+        }
+
+	txtlen  = strlen(txt);
+	msglen  = txtlen+2; // this includes the control+pid bytes
+
+	/* _NO_ ending CRLF, the APRSIS subsystem adds it. */
+
+	/* Send those (rf)beacons.. (a noop if interface == NULL) */
+	if (bm->interface != NULL) {
+		const char *callsign = bm->interface->callsign;
+		const char *src = (bm->src != NULL) ? bm->src : callsign;
+		int   len  = destlen + 12 + strlen(src); // destlen contains bm->via plus room for ",TCPIP*"
+		char *destbuf = alloca(len);
+
+                // Now it is time to beacon something, lets make sure
+                // the source callsign is not APRSIS !
+                if (strcmp(src,"APRSIS") == 0) {
+                  if (debug)
+                    printf("CONFIGURATION ERROR: Beacon with source callsign APRSIS. Skipped!\n");
+                  return;
+                }
+
+		if (bm->timefix)
+		  fix_beacon_time(msg, msglen);
+
+#ifndef DISABLE_IGATE
+		if (bm->beaconmode <= 0) {
+
+                  if (bm->via != NULL)
+                    sprintf(destbuf,"%s>%s,%s,TCPIP*", src, bm->dest, bm->via);
+                  else
+                    sprintf(destbuf,"%s>%s,TCPIP*", src, bm->dest);
+
+                  if (debug) {
+                    printf("%ld\tNow beaconing to APRSIS %s '%s' -> '%s',",
+                           tick.tv_sec, callsign, destbuf, txt);
+                    printf(" next beacon in %.2f minutes\n",
+                           ((bset->beacon_nexttime.tv_sec - tick.tv_sec)/60.0));
+                  }
+
+		  // Send them all also as netbeacons..
+		  aprsis_queue(destbuf, strlen(destbuf),
+			       qTYPE_LOCALGEN,
+			       aprsis_login, txt, txtlen);
+		}
+#endif
+
+		if (bm->beaconmode >= 0 && bm->interface->tx_ok) {
+		  // And to interfaces
+                  char *dp = destbuf; // destbuf collects ONLY the VIA data
+
+		  if (strcmp(src, callsign) != 0) {
+		    if (bm->via != NULL)
+		      dp += sprintf( dp, "%s*,%s", callsign, bm->via );
+		    else
+		      dp += sprintf( dp, "%s*", callsign );
+		  } else {
+		    if (bm->via != NULL)
+		      dp += sprintf( dp, "%s", bm->via );
+                    else
+                      *dp = 0;
+		  }
+                  
+                  if (debug) {
+                    printf("%ld\tNow beaconing to interface[1] %s(%s) '%s' -> '%s',",
+                           tick.tv_sec, callsign, src, destbuf, txt);
+                    printf(" next beacon in %.2f minutes\n",
+                           ((bset->beacon_nexttime.tv_sec - tick.tv_sec)/60.0));
+                  }
+
+		  interface_transmit_beacon(bm->interface,
+					    src,
+					    bm->dest,
+					    destbuf, // via data
+					    msg, msglen);
+		}
+	} 
+	else {
+	    for ( i = 0; i < all_interfaces_count; ++i ) {
+		const struct aprx_interface *aif = all_interfaces[i];
+		const char *callsign = aif->callsign;
+		const char *src = (bm->src != NULL) ? bm->src : callsign;
+		int len = destlen + 12 + (src != NULL ? strlen(src) : 0); // destlen contains bm->via, plus room for ",TCPIP*"
+		char *destbuf = alloca(len);
+
+                if (debug>1)
+                  printf("Beacon: aif=%p callsign='%s' src='%s' bm->dest='%s' bm->via='%s'\n",
+                         aif, callsign, src, bm->dest, bm->via);
+
+		if (!interface_is_beaconable(aif)) {
+                  if (debug>1)
+                    printf("Not a beaconable interface, skipping\n");
+		  continue; // it is not a beaconable interface
+                }
+
+		if (callsign == NULL) {
+		  // Probably KISS master interface, and subIF 0 has no definition.
+                  if (debug>1)
+                    printf("No callsign on interface interface, skipping\n");
+		  continue;
+		}
+
+		if (aif->iftype == IFTYPE_APRSIS) {
+		  // If we have no radio interfaces, we may still 
+		  // want to do beacons to APRSIS.  Ignore the
+		  // builtin APRSIS interface if there are more
+		  // interfaces available!
+		  if (all_interfaces_count > 1) {
+                    if (debug>2)
+                      printf("Beaconing to APRSIS interface ignored in presence of other interfaces. Skipping.\n");
+		    continue;  // Ignore the builtin APRSIS interface
+                  }
+		}
+
+                // Now it is time to beacon something, lets make sure
+                // the source callsign is not APRSIS !
+                if (strcmp(src,"APRSIS") == 0) {
+                  if (debug)
+                    printf("CONFIGURATION ERROR: Beaconing with source callsign APRSIS!  Skipping.\n");
+                  continue;
+                }
+
+		
+		if (bm->timefix)
+		  fix_beacon_time((char*)msg, msglen);
+		
+#ifndef DISABLE_IGATE
+		if (bm->beaconmode <= 0) {
+		  // Send them all also as netbeacons..
+
+                  if (bm->via != NULL)
+                    sprintf(destbuf,"%s>%s,%s,TCPIP*", src, bm->dest, bm->via);
+                  else
+                    sprintf(destbuf,"%s>%s,TCPIP*", src, bm->dest);
+                  
+                  if (debug) {
+                    printf("%ld\tNow beaconing to APRSIS %s(%s) '%s' -> '%s',",
+                           tick.tv_sec, callsign, src, destbuf, txt);
+                    printf(" next beacon in %.2f minutes\n",
+                           ((bset->beacon_nexttime.tv_sec - tick.tv_sec)/60.0));
+                  }
+
+		  aprsis_queue(destbuf, strlen(destbuf),
+			       qTYPE_LOCALGEN,
+			       aprsis_login, txt, txtlen);
+		}
+#endif
+
+		if (bm->beaconmode >= 0 && aif->tx_ok) {
+		  // And to transmit-capable interfaces
+                  char *dp = destbuf; // destbuf collects ONLY the VIA data
+
+		  // The 'destbuf' has a plenty of room
+		  if (strcmp(src, callsign) != 0) {
+		    if (bm->via != NULL)
+		      dp += sprintf( dp, "%s*,%s", callsign, bm->via );
+		    else
+		      dp += sprintf( dp, "%s*", callsign );
+		  } else {
+		    if (bm->via != NULL)
+		      dp += sprintf( dp, "%s", bm->via );
+                    else
+                      *dp = 0;
+		  }
+		  
+                  if (debug) {
+                    printf("%ld\tNow beaconing to interface[2] %s(%s) '%s' -> '%s',",
+                           tick.tv_sec, callsign, src, destbuf, txt);
+                    printf(" next beacon in %.2f minutes\n",
+                           ((bset->beacon_nexttime.tv_sec - tick.tv_sec)/60.0));
+                  }
+
+		  interface_transmit_beacon(aif,
+					    src,
+					    bm->dest,
+					    destbuf, // via data
+					    msg, msglen);
+		}
+	    }
+	}
+}
+
+int beacon_prepoll(struct aprxpolls *app)
+{
+	int i;
+#ifndef DISABLE_IGATE
+	if (!aprsis_login)
+		return 0;	/* No mycall !  hoh... */
+#endif
+        for (i = 0; i < bsets_count; ++i) {
+        	struct beaconset *bset = bsets[i];
+                if (bset->beacon_msgs == NULL) continue; // nothing here
+
+                if (time_reset) {
+                	// master time pickup noticed time back-tracking
+                	beacon_resettimer(bset);
+                }
+
+                if (tv_timercmp(&bset->beacon_nexttime, &app->next_timeout) < 0)
+                	app->next_timeout = bset->beacon_nexttime;
+
+                if (bset->exec_pid != 0 && bset->exec_fd >= 0) {
+                	struct pollfd *pfd;
+                        // FD is open, lets mark it for poll read..
+                        pfd = aprxpolls_new(app);
+                        pfd->fd = bset->exec_fd;
+                        pfd->events = POLLIN | POLLPRI;
+                        pfd->revents = 0;
+                }
+        }
+
+	return 0;		/* No poll descriptors, only time.. */
+}
+
+
+int beacon_postpoll(struct aprxpolls *app)
+{
+	int idx, i;
+	//struct serialport *S;
+	struct pollfd *P;
+#ifndef DISABLE_IGATE
+	if (!aprsis_login)
+		return 0;	/* No mycall !  hoh... */
+#endif
+        for (i = 0; i < bsets_count; ++i) {
+        	struct beaconset *bset = bsets[i];
+                if (bset->exec_pid > 0 && bset->exec_deadline < tick.tv_sec) {
+			// Waited too long, discard it.
+                	//printf("killing subprogram pid=%d mypid=%d\n", bset->exec_pid, getpid());
+                        if (debug) printf("Killing overdue beacon exec subprogram pid %d\n", bset->exec_pid);
+                	kill(bset->exec_pid, SIGKILL);
+                        bset->exec_pid = - bset->exec_pid;
+                }
+                for (idx = 0, P = app->polls; idx < app->pollcount; ++idx, ++P) {
+                	if (bset->exec_fd == P->fd) {
+                          if (debug) printf("revents of exec_fd = 0x%x\n", P->revents);
+                          if (P->revents & (POLLIN | POLLPRI | POLLHUP)) {
+                            msg_exec_read(bset);
+                          }
+                        }
+                }
+                if (bset->beacon_msgs == NULL) continue; // nothing..
+                if (tv_timercmp(&bset->beacon_nexttime, &tick) > 0) continue; // not yet
+
+                beacon_now(bset);
+        }
+
+        if (debug) printf("beacon_postpoll()\n");
+
+
+	return 0;
+}
+
+void beacon_childexit(int pid)
+{
+	int i;
+        for (i = 0; i < bsets_count; ++i) {
+        	struct beaconset *bset = bsets[i];
+                if (pid == bset->exec_pid) {
+                	bset->exec_pid = -pid;
+                        if (debug) {
+                          // Avoid stdio FILE* interlocks within signal handler
+                          char buf[64];
+                          sprintf(buf, "matched child exit, pid=%d\n", pid);
+                          write(1, buf, strlen(buf));
+                        }
+                        break;
+                }
+        }
+}
diff --git a/build-stamp b/build-stamp
new file mode 100644
index 0000000..e69de29
diff --git a/cellmalloc.c b/cellmalloc.c
new file mode 100644
index 0000000..b999109
--- /dev/null
+++ b/cellmalloc.c
@@ -0,0 +1,357 @@
+/********************************************************************
+ *  APRX -- 2nd generation receive-only APRS-i-gate with            *
+ *          minimal requirement of esoteric facilities or           *
+ *          libraries of any kind beyond UNIX system libc.          *
+ *                                                                  *
+ * (c) Matti Aarnio - OH2MQK,  2007-2014                            *
+ *                                                                  *
+ ********************************************************************/
+
+#include "config.h"
+
+#include <stdio.h>
+#ifdef HAVE_STDLIB_H
+# include <stdlib.h>
+#endif
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+#include <string.h>
+#include <sys/mman.h>
+#include <fcntl.h>
+// #if defined(HAVE_PTHREAD_CREATE) && defined(ENABLE_PTHREAD)
+// #include <pthread.h>
+// #endif
+
+#include "cellmalloc.h"
+
+#define NO_MMAP_ON_CELLMALLOC
+#define MEMDEBUG
+
+/*
+ *   cellmalloc() -- manages arrays of cells of data 
+ *
+ */
+
+struct cellhead;
+
+struct cellarena_t {
+	int	cellsize;
+	int	alignment;
+	int	increment; /* alignment overhead applied.. */
+	int	lifo_policy;
+  	int	minfree;
+
+	const char *arenaname;
+
+//	pthread_mutex_t mutex;  // we have a mutex-less usage environment!
+
+  	struct cellhead *free_head;
+  	struct cellhead *free_tail;
+
+	int	 freecount;
+	int	 createsize;
+
+#ifdef MEMDEBUG
+	int	 cellblocks_count;
+#define CELLBLOCKS_MAX 40 /* track client cell allocator limit! */
+	char	*cellblocks[CELLBLOCKS_MAX];	/* ref as 'char pointer' for pointer arithmetics... */
+#endif
+};
+
+#define CELLHEAD_DEBUG 0
+
+struct cellhead {
+#if CELLHEAD_DEBUG == 1
+	struct cellarena_t *ca;
+#endif
+	struct cellhead *next;
+};
+
+
+/*
+ * new_cellblock() -- must be called MUTEX PROTECTED
+ *
+ */
+
+int new_cellblock(cellarena_t *ca)
+{
+	int i;
+	char *cb;
+
+#ifdef MEMDEBUG /* External backing-store files, unique ones for each cellblock,
+		   which at Linux names memory blocks in  /proc/nnn/smaps "file"
+		   with this filename.. */
+	int fd;
+	char name[2048];
+
+	sprintf(name, "/tmp/.-%d-%s-%d.mmap", getpid(), ca->arenaname, ca->cellblocks_count );
+	unlink(name);
+	fd = open(name, O_RDWR|O_CREAT, 644);
+	unlink(name);
+	if (fd >= 0) {
+	  memset(name, 0, sizeof(name));
+	  i = 0;
+	  while (i < ca->createsize) {
+	    int rc = write(fd, name, sizeof(name));
+	    if (rc < 0) break;
+	    i += rc;
+	  }
+	}
+
+	cb = mmap( NULL, ca->createsize, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
+        if (fd >= 0)
+          close(fd);
+#else
+
+#ifndef MAP_ANON
+#  define MAP_ANON 0
+#endif
+#ifdef NO_MMAP_ON_CELLMALLOC
+	cb = malloc( ca->createsize );
+#else
+	cb = mmap( NULL, ca->createsize, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANON, -1, 0);
+#endif
+#endif
+	if (cb == NULL || cb == (char*)-1)
+	  return -1;
+
+#ifdef MEMDEBUG
+	if (ca->cellblocks_count >= CELLBLOCKS_MAX) return -1;
+	ca->cellblocks[ca->cellblocks_count++] = cb;
+#endif
+
+	for (i = 0; i <= ca->createsize-ca->increment; i += ca->increment) {
+		struct cellhead *ch = (struct cellhead *)(cb + i); /* pointer arithmentic! */
+		if (!ca->free_head) {
+		  ca->free_head = ch;
+		} else {
+		  ca->free_tail->next = ch;
+		}
+		ca->free_tail = ch;
+		ch->next = NULL;
+#if CELLHEAD_DEBUG == 1
+		ch->ca   = ca; // cellhead pointer space
+#endif
+
+		ca->freecount += 1;
+	}
+
+	return 0;
+}
+
+
+
+/*
+ * cellinit()  -- the main program calls this once for each used cell type/size
+ *
+ */
+
+
+cellarena_t *cellinit( const char *arenaname, const int cellsize, const int alignment, const int policy, const int createkb, const int minfree )
+{
+	cellarena_t *ca = calloc(1, sizeof(*ca));
+	// int n;
+
+	ca->arenaname = arenaname;
+
+#if CELLHEAD_DEBUG == 1
+	if (alignment < __alignof__(void*))
+		alignment = __alignof__(void*);   // cellhead pointer space
+#endif
+
+	ca->cellsize  = cellsize;
+	ca->alignment = alignment;
+	ca->minfree   = minfree;
+#if CELLHEAD_DEBUG == 1
+	ca->increment = cellsize + sizeof(void*); // cellhead pointer space
+#else
+	ca->increment = cellsize;
+#endif
+	if ((cellsize % alignment) != 0) {
+		ca->increment +=  alignment - cellsize % alignment;
+	}
+	ca->lifo_policy =  policy & CELLMALLOC_POLICY_LIFO;
+
+	ca->createsize = createkb * 1024;
+#if !defined(MEMDEBUG) && defined(NO_MMAP_ON_CELLMALLOC)
+	ca->createsize -= 16;
+#endif
+
+	// n = ca->createsize / ca->increment;
+	// hlog( LOG_DEBUG, "cellinit: %-12s block size %4d kB, cells/block: %d", arenaname, createkb, n );
+
+//	pthread_mutex_init(&ca->mutex, NULL);
+
+	new_cellblock(ca); /* First block of cells, not yet need to be mutex protected */
+	while (ca->freecount < ca->minfree)
+		new_cellblock(ca); /* more until minfree is full */
+
+#if CELLHEAD_DEBUG == 1
+	// hlog(LOG_DEBUG, "cellinit()  cellhead=%p", ca);
+#endif
+	return ca;
+}
+
+
+inline void *cellhead_to_clientptr(struct cellhead *ch)
+{
+	char *p = (char*)ch;
+#if CELLHEAD_DEBUG == 1
+	p += sizeof(void*);
+#endif
+	return p;
+}
+
+inline struct cellhead *clientptr_to_cellhead(void *v)
+{
+#if CELLHEAD_DEBUG == 1
+	struct cellhead *ch = (struct cellhead *)(((char*)v) - sizeof(void*));
+#else
+	struct cellhead *ch = (struct cellhead*)v;
+#endif
+	return ch;
+}
+
+
+void *cellmalloc(cellarena_t *ca)
+{
+	void *cp;
+	struct cellhead *ch;
+
+	while (!ca->free_head  || (ca->freecount < ca->minfree))
+		if (new_cellblock(ca)) {
+//			pthread_mutex_unlock(&ca->mutex);
+			return NULL;
+		}
+
+	/* Pick new one off the free-head ! */
+	ch = ca->free_head;
+	ca->free_head = ch->next;
+	ch->next = NULL;
+	cp = ch;
+	if (ca->free_head == NULL)
+	  ca->free_tail = NULL;
+
+	ca->freecount -= 1;
+
+	// hlog(LOG_DEBUG, "cellmalloc(%p at %p) freecount %d", cellhead_to_clientptr(cp), ca, ca->freecount);
+	return cellhead_to_clientptr(cp);
+}
+
+/*
+ *  cellmallocmany() -- give many cells in single lock region
+ *
+ */
+
+int   cellmallocmany(cellarena_t *ca, void **array, int numcells)
+{
+	int count;
+	struct cellhead *ch;
+
+	for (count = 0; count < numcells; ++count) {
+
+		while (!ca->free_head ||
+		       ca->freecount < ca->minfree) {
+			/* Out of free cells ? alloc new set */
+			if (new_cellblock(ca)) {
+			  /* Failed ! */
+			  break;
+			}
+		}
+
+		/* Pick new one off the free-head ! */
+
+		ch = ca->free_head;
+
+		// hlog( LOG_DEBUG, "cellmallocmany(%d of %d); freecount %d; %p at %p",
+		//       count, numcells, ca->freecount, cellhead_to_clientptr(ch), ca );
+
+                if (ch != NULL) { // should always be...
+                  ca->free_head = ch->next;
+                  ch->next = NULL;
+                }
+
+		if (ca->free_head == NULL)
+			ca->free_tail = NULL;
+
+		array[count] = cellhead_to_clientptr(ch);
+
+		ca->freecount -= 1;
+
+	}
+
+	return count;
+}
+
+
+
+void  cellfree(cellarena_t *ca, void *p)
+{
+	struct cellhead *ch = clientptr_to_cellhead(p);
+	ch->next = NULL;
+#if CELLHEAD_DEBUG == 1
+	if (ch->ca != ca) {
+	  // hlog(LOG_ERR, "cellfree(%p to %p) wrong cellhead->ca pointer %p", p, ca, ch->ca);
+	}
+#endif
+
+	// hlog(LOG_DEBUG, "cellfree() %p to %p", p, ca);
+
+	if (ca->lifo_policy) {
+	  /* Put the cell on free-head */
+	  ch->next = ca->free_head;
+	  ca->free_head = ch;
+
+	} else {
+	  /* Put the cell on free-tail */
+	  if (ca->free_tail)
+	    ca->free_tail->next = ch;
+	  ca->free_tail = ch;
+	  if (!ca->free_head)
+	    ca->free_head = ch;
+	  ch->next = NULL;
+	}
+
+	ca->freecount += 1;
+}
+
+/*
+ *  cellfreemany() -- release many cells in single lock region
+ *
+ */
+
+void  cellfreemany(cellarena_t *ca, void **array, int numcells)
+{
+	int count;
+
+	for (count = 0; count < numcells; ++count) {
+
+	  struct cellhead *ch = clientptr_to_cellhead(array[count]);
+
+#if CELLHEAD_DEBUG == 1
+	  if (ch->ca != ca) {
+	    // hlog(LOG_ERR, "cellfreemany(%p to %p) wrong cellhead->ca pointer %p", array[count], ca, ch->ca);
+	  }
+#endif
+
+	  // hlog(LOG_DEBUG, "cellfreemany() %p to %p", ch, ca);
+
+	  if (ca->lifo_policy) {
+	    /* Put the cell on free-head */
+	    ch->next = ca->free_head;
+	    ca->free_head = ch;
+
+	  } else {
+	    /* Put the cell on free-tail */
+	    if (ca->free_tail)
+	      ca->free_tail->next = ch;
+	    ca->free_tail = ch;
+	    if (!ca->free_head)
+	      ca->free_head = ch;
+	    ch->next = NULL;
+	  }
+
+	  ca->freecount += 1;
+	}
+}
diff --git a/cellmalloc.h b/cellmalloc.h
new file mode 100644
index 0000000..dd90a93
--- /dev/null
+++ b/cellmalloc.h
@@ -0,0 +1,31 @@
+/********************************************************************
+ *  APRX -- 2nd generation receive-only APRS-i-gate with            *
+ *          minimal requirement of esoteric facilities or           *
+ *          libraries of any kind beyond UNIX system libc.          *
+ *                                                                  *
+ * (c) Matti Aarnio - OH2MQK,  2007-2014                            *
+ *                                                                  *
+ ********************************************************************/
+
+#ifndef _CELLMALLOC_H_
+#define _CELLMALLOC_H_
+
+/*
+ *   cellmalloc() -- manages arrays of cells of data 
+ *
+ */
+
+typedef struct cellarena_t cellarena_t;
+
+extern cellarena_t *cellinit(const char *arenaname, const int cellsize, const int alignment, const int policy, const int createkb, const int minfree);
+
+#define CELLMALLOC_POLICY_FIFO    0
+#define CELLMALLOC_POLICY_LIFO    1
+#define CELLMALLOC_POLICY_NOMUTEX 2
+
+extern void *cellmalloc(cellarena_t *cellarena);
+extern int   cellmallocmany(cellarena_t *cellarena, void **array, const int numcells);
+extern void  cellfree(cellarena_t *cellarena, void *p);
+extern void  cellfreemany(cellarena_t *cellarena, void **array, const int numcells);
+
+#endif
diff --git a/config.c b/config.c
new file mode 100644
index 0000000..7efb98e
--- /dev/null
+++ b/config.c
@@ -0,0 +1,814 @@
+/* **************************************************************** *
+ *                                                                  *
+ *  APRX -- 2nd generation receive-only APRS-i-gate with            *
+ *          minimal requirement of esoteric facilities or           *
+ *          libraries of any kind beyond UNIX system libc.          *
+ *                                                                  *
+ * (c) Matti Aarnio - OH2MQK,  2007-2014                            *
+ *                                                                  *
+ * **************************************************************** */
+
+#include "aprx.h"
+
+#ifndef DISABLE_IGATE
+const char *aprsis_login;
+#endif
+
+
+char *config_SKIPSPACE(char *Y)
+{
+	assert(Y != NULL);
+	while (*Y == ' ' || *Y == '\t')
+		++Y;
+	return Y;
+}
+
+#if 0
+char *config_SKIPDIGIT(char *Y)
+{
+	assert(Y != NULL);
+	while ('0' <= *Y && *Y <= '9')
+		++Y;
+	return Y;
+}
+#endif
+
+// return 0 for failures, 1 for OK.
+int validate_callsign_input(char *callsign, int strict)
+{
+	int i = strlen(callsign);
+	char *p = callsign;
+	char c = 0;
+	int seen_minus = 0;
+	int ssid = 0;
+
+	for ( ; *p ; ++p ) {
+		c = *p;
+		if ('a' <= c && c <= 'z') {
+		  // Presuming ASCII
+		  c -= ('a'-'A');
+		  *p = c; // Side-effect: translates the callsign to uppercase
+		}
+		if (!seen_minus && c == '-') {
+		  if (p == callsign || p[1] == 0)
+		    return 0; // Hyphen is at beginning or at end!
+		  if ((p - callsign) > 6)
+		    return 0; // Hyphen too far!  Max 6 characters preceding it.
+		  seen_minus = 1;
+		  continue;
+		} else if (seen_minus && c == '-') {
+		  return 0; // Seen a hyphen again!
+		}
+
+		// The "SSID" value can be alphanumeric here!
+
+		if (!seen_minus) {
+		  // Callsign prefix
+		  if (('A' <= c && c <= 'Z') || ('0' <= c && c <= '9')) {
+		    // Valid character!
+		  } else {
+		    return 0; // Invalid characters in callsign part
+		  }
+		} else {
+		  // SSID tail
+		  if (strict) {
+		    if ('0' <= c && c <= '9') {
+		      // Valid character!
+		      ssid = ssid * 10 + c - '0';
+		      if (ssid > 15) { // SSID value range: 0 .. 15
+			return 0;
+		      }
+		    } else {
+		      return 0; // Invalid characters in SSID part
+		    }
+		  } else { // non-strict
+		    if (('A' <= c && c <= 'Z') || ('0' <= c && c <= '9')) {
+		      // Valid character!
+		    } else {
+		      return 0; // Invalid characters in SSID part
+		    }
+		  }
+		}
+	}
+	if (i > 3 && (callsign[i - 1] == '0' && callsign[i - 2] == '-')) {
+		callsign[i - 2] = 0;
+		/* If tailed with "-0" SSID, chop it off.. */
+	}
+	return 1;
+}
+
+/* SKIPTEXT:
+ *
+ *  Detect "/' -> scan until matching double quote
+ *    Process \-escapes on string: \xFD, \n, \", \'
+ *  Detect non-eol, non-space(tab): scan until eol, or white-space
+ *    No \-escapes
+ *
+ *  Will thus stop when found non-quoted space/tab, or
+ *  end of line/string.
+ */
+
+char *config_SKIPTEXT(char *Y, int *lenp)
+{
+	char *O;
+	char endc;
+	int  len;
+
+	assert(Y != NULL);
+
+	O = Y;
+        endc = *Y;
+        len = 0;
+
+	if (*Y == '"' || *Y == '\'') {
+		++Y;
+		while (*Y && *Y != endc) {
+			if (*Y == '\\') {
+				/* backslash escape.. */
+				++Y;
+				if (*Y == 'n') {
+					*O++ = '\n';
+					++len;
+				} else if (*Y == 'r') {
+					*O++ = '\r';
+					++len;
+				} else if (*Y == '"') {
+					*O++ = '"';
+					++len;
+				} else if (*Y == '\'') {
+					*O++ = '\'';
+				} else if (*Y == '\\') {
+					*O++ = '\\';
+				} else if (*Y == 'x') {
+					/* Hex encoded char */
+					int i;
+					char hx[3];
+					if (*Y)
+						++Y;
+					hx[0] = *Y;
+					if (*Y)
+						++Y;
+					hx[1] = *Y;
+					hx[2] = 0;
+					i = (int) strtol(hx, NULL, 16);
+					*O++ = i;
+					++len;
+				}
+			} else {
+				*O++ = *Y;
+				++len;
+			}
+			if (*Y != 0)
+				++Y;
+		}
+		if (*Y == endc)
+			++Y;
+		*O = 0;		/* String end */
+		/* STOP at the tail-end " */
+	} else {
+		while (*Y && *Y != ' ' && *Y != '\t') {
+			++Y;
+			++len;
+		}
+		/* Stop at white-space or end */
+		if (*Y)
+			*Y++ = 0;
+	}
+
+	if (lenp != NULL)
+	  *lenp = len;
+	return Y;
+}
+
+void config_STRLOWER(char *s)
+{
+	int c;
+	assert(s != NULL);
+	for (; *s; ++s) {
+		c = *s;
+		if ('A' <= c && c <= 'Z') {
+			*s = c + ('a' - 'A');
+		}
+	}
+}
+
+void config_STRUPPER(char *s)
+{
+	int c;
+	assert(s != NULL);
+	for (; *s; ++s) {
+		c = *s;
+		if ('a' <= c && c <= 'z') {
+			*s = c + ('A' - 'a');
+		}
+	}
+}
+
+static int logging_config(struct configfile *cf)
+{
+	char *name, *param1;
+	char *str = cf->buf;
+	int has_fault = 0;
+
+	while (readconfigline(cf) != NULL) {
+		if (configline_is_comment(cf))
+			continue;	/* Comment line, or empty line */
+
+		str = cf->buf;
+		str = config_SKIPSPACE(str); // arbitrary indention
+		name = str;
+		str = config_SKIPTEXT(str, NULL);
+		str = config_SKIPSPACE(str);
+		config_STRLOWER(name);
+	
+		param1 = str;
+	
+		str = config_SKIPTEXT(str, NULL);
+		str = config_SKIPSPACE(str);
+	
+		if (strcmp(name, "</logging>") == 0)
+			break;
+	
+		if (strcmp(name, "aprxlog") == 0) {
+			if (debug)
+				printf("%s:%d: INFO: APRXLOG = '%s' '%s'\n",
+				       cf->name, cf->linenum, param1, str);
+	
+			aprxlogfile = strdup(param1);
+	
+#ifndef DISABLE_IGATE
+		} else if (strcmp(name, "dprslog") == 0) {
+			if (debug)
+				printf("%s:%d: INFO: DPRSLOG = '%s' '%s'\n",
+				       cf->name, cf->linenum, param1, str);
+	
+			dprslogfile = strdup(param1);
+#endif
+	
+		} else if (strcmp(name, "rflog") == 0) {
+			if (debug)
+				printf("%s:%d: INFO: RFLOG = '%s' '%s'\n",
+				       cf->name, cf->linenum, param1, str);
+	
+			rflogfile = strdup(param1);
+	
+		} else if (strcmp(name, "pidfile") == 0) {
+			if (debug)
+				printf("%s:%d: INFO: PIDFILE = '%s' '%s'\n",
+				       cf->name, cf->linenum, param1, str);
+	
+			pidfile = strdup(param1);
+	
+		} else if (strcmp(name, "erlangfile") == 0) {
+			if (debug)
+				printf("%s:%d: INFO: ERLANGFILE = '%s' '%s'\n",
+				       cf->name, cf->linenum, param1, str);
+	
+			erlang_backingstore = strdup(param1);
+	
+		} else if (strcmp(name, "erlang-loglevel") == 0) {
+			if (debug)
+				printf("%s:%d: INFO: ERLANG-LOGLEVEL = '%s' '%s'\n",
+				       cf->name, cf->linenum, param1, str);
+			erlang_init(param1);
+	
+		} else if (strcmp(name, "erlanglog") == 0) {
+			if (debug)
+				printf("%s:%d: INFO: ERLANGLOG = '%s'\n",
+				       cf->name, cf->linenum, param1);
+	
+			erlanglogfile = strdup(param1);
+	
+		} else if (strcmp(name, "erlang-log1min") == 0) {
+			if (debug)
+				printf("%s:%d: INFO: ERLANG-LOG1MIN\n",
+				       cf->name, cf->linenum);
+	
+			erlanglog1min = 1;
+	
+		} else {
+			printf("%s:%d: ERROR: Unknown <logging> keyword: '%s' '%s'\n",
+			       cf->name, cf->linenum, name, param1);
+			has_fault = 1;
+		}
+	}
+	return has_fault;
+}
+
+static int cfgparam(struct configfile *cf)
+{
+	char *name, *param1;
+	char *str = cf->buf;
+
+	str = config_SKIPSPACE(str); // arbitrary indention
+	name = str;
+	str = config_SKIPTEXT(str, NULL);
+	str = config_SKIPSPACE(str);
+	config_STRLOWER(name);
+
+	param1 = str;
+
+	str = config_SKIPTEXT(str, NULL);
+	str = config_SKIPSPACE(str);
+
+#ifndef DISABLE_IGATE
+	if (strcmp(name, "<aprsis>") == 0) {
+	  return aprsis_config(cf);
+	}
+#endif
+	if (strcmp(name, "<interface>") == 0) {
+	  return interface_config(cf);
+	}
+	if (strcmp(name, "<telemetry>") == 0) {
+	  return telemetry_config(cf);
+	}
+	if (strcmp(name, "<digipeater>") == 0) {
+	  return digipeater_config(cf);
+	}
+	if (strcmp(name, "<beacon>") == 0) {
+	  return beacon_config(cf);
+	}
+	if (strcmp(name, "<logging>") == 0) {
+	  return logging_config(cf);
+	}
+
+
+	if (strcmp(name, "mycall") == 0) {
+		config_STRUPPER(param1);
+		// Store these always, it helps with latter error diagnostics
+		mycall       = strdup(param1);
+#ifndef DISABLE_IGATE
+		aprsis_login = mycall;
+#endif
+		if (validate_callsign_input(param1,1)) {
+		  if (debug)
+		    printf("%s:%d: MYCALL = '%s' '%s'\n",
+			   cf->name, cf->linenum, mycall, str);
+		} else {
+		  if (validate_callsign_input(param1,0)) {
+		    printf("%s:%d: MYCALL = '%s'  value is OK for APRSIS login, and Rx-IGate, but not valid AX.25 node callsign.\n",
+			   cf->name, cf->linenum, param1);
+
+		  } else {
+		    // but sometimes the parser yields an error!
+		    printf("%s:%d: MYCALL = '%s'  value is not valid AX.25 node callsign, nor valid for APRSIS login.\n",
+			   cf->name, cf->linenum, param1);
+		    return 1;
+		  }
+		}
+
+        } else if (strcmp(name, "myloc") == 0) {
+        	// lat xx lon yy
+		char *latp;
+                char *lonp;
+                float lat, lng;
+                int i, la, lo;
+                char lac, loc;
+
+                const char *const errmsg = "%s:%d: myloc parameters wrong, expected format:  'myloc' 'lat' 'ddmm.mmN' 'lon' 'dddmm.mmE'\n";
+
+                if (strcmp(param1, "lat") != 0) {
+                  printf(errmsg, cf->name, cf->linenum);
+                  printf(" .. 'lat' missing, got: '%s'\n", param1);
+                  return 1;
+                }
+
+                latp = str;
+                str = config_SKIPTEXT(str, NULL);
+                str = config_SKIPSPACE(str);
+
+                param1 = str;
+                str = config_SKIPTEXT(str, NULL);
+                str = config_SKIPSPACE(str);
+
+                if (strcmp(param1, "lon") != 0) {
+                  printf(errmsg, cf->name, cf->linenum);
+                  printf(" .. 'lon' missing, got: '%s'\n", param1);
+                  return 1;
+                }
+
+                lonp = str;
+                str = config_SKIPTEXT(str, NULL);
+                str = config_SKIPSPACE(str);
+
+                if (validate_degmin_input(latp, 90)) {
+                  printf(errmsg, cf->name, cf->linenum);
+                  printf(" got lat: '%s'\n", latp);
+                  return 1;
+                }
+                if (validate_degmin_input(lonp, 180)) {
+                  printf(errmsg, cf->name, cf->linenum);
+                  printf(" got lon: '%s'\n", lonp);
+                  return 1;
+                }
+
+                i = sscanf(latp, "%2d%5f%c,", &la, &lat, &lac);
+                if (i != 3) {
+                  printf(errmsg, cf->name, cf->linenum);
+                  printf(" got parse-field-count: %d on '%s'\n", i, latp);
+                  return 1; // parse failure
+                }
+                i = sscanf(lonp, "%3d%5f%c,", &lo, &lng, &loc);
+                if (i != 3) {
+                  printf(errmsg, cf->name, cf->linenum);
+                  printf(" got parse-field-count: %d on '%s'\n", i, lonp);
+                  return 1; // parse failure
+                }
+
+                if (lac != 'N' && lac != 'S' && lac != 'n' && lac != 's') {
+                  printf(errmsg, cf->name, cf->linenum);
+                  printf(" .. lat expected N/S tail, got: '%c'\n", lac);
+                  return 1; // bad indicator value
+                }
+                if (loc != 'E' && loc != 'W' && loc != 'e' && loc != 'w') {
+                  printf(errmsg, cf->name, cf->linenum);
+                  printf(" .. lon expected E/W tail, got: '%c'\n", loc);
+                  return 1; // bad indicator value
+                }
+
+                myloc_latstr = strdup(latp);
+                myloc_lonstr = strdup(lonp);
+
+                myloc_lat = (float)la + lat/60.0;
+                myloc_lon = (float)lo + lng/60.0;
+	
+                if (lac == 'S' || lac == 's')
+                  myloc_lat = -myloc_lat;
+                if (loc == 'W' || loc == 'w')
+                  myloc_lon = -myloc_lon;
+
+                if (debug)
+                  printf("%s:%d: MYLOC LAT %8.5f degrees  LON %8.5f degrees\n",
+                         cf->name, cf->linenum, myloc_lat, myloc_lon);
+
+                myloc_lat = filter_lat2rad(myloc_lat);
+                myloc_lon = filter_lon2rad(myloc_lon);
+                myloc_coslat = cos(myloc_lat);
+
+
+#ifndef DISABLE_IGATE
+	} else if (strcmp(name, "aprsis-login") == 0) {
+
+		printf("%s:%d WARNING: Old-style top-level 'aprsis-login' definition, it should be inside <aprsis> group tags.\n",
+		       cf->name, cf->linenum);
+
+		config_STRUPPER(param1);
+		aprsis_login = strdup(param1);
+		if (validate_callsign_input(param1,0)) {
+		  if (debug)
+		    printf("%s:%d: APRSIS-LOGIN = '%s' '%s'\n",
+			   cf->name, cf->linenum, aprsis_login, str);
+		} else {
+		    printf("%s:%d: APRSIS-LOGIN = '%s' value is not valid AX25-like node'\n",
+			   cf->name, cf->linenum, aprsis_login);
+		    return 1;
+		}
+
+	} else if (strcmp(name, "aprsis-server") == 0) {
+
+		printf("%s:%d WARNING: Old-style top-level 'aprsis-server' definition, it should be inside <aprsis> group tags.\n",
+		       cf->name, cf->linenum);
+
+		if (debug)
+			printf("%s:%d: APRSIS-SERVER = '%s':'%s'\n",
+			       cf->name, cf->linenum, param1, str);
+
+		return aprsis_add_server(param1, str);
+
+	} else if (strcmp(name, "aprsis-heartbeat-timeout") == 0) {
+		int i = atoi(param1);
+		if (i < 0)	/* param failure ? */
+			i = 0;	/* no timeout */
+
+		printf("%s:%d WARNING: Old-style top-level 'aprsis-heartbeat-timeout' definition, it should be inside <aprsis> group tags.\n",
+		       cf->name, cf->linenum);
+
+		if (debug)
+			printf("%s:%d: APRSIS-HEARTBEAT-TIMEOUT = '%d' '%s'\n",
+			       cf->name, cf->linenum, i, str);
+
+		return aprsis_set_heartbeat_timeout(i);
+
+
+	} else if (strcmp(name, "aprsis-filter") == 0) {
+
+		printf("%s:%d WARNING: Old-style top-level 'aprsis-filter' definition, it should be inside <aprsis> group tags.\n",
+		       cf->name, cf->linenum);
+
+		return aprsis_set_filter(param1);
+#endif
+
+#ifdef PF_AX25	/* PF_AX25 exists -- highly likely a Linux system ! */
+	} else if (strcmp(name, "ax25-rxport") == 0) {
+
+		printf("%s:%d WARNING: Old-style top-level 'ax25-rxport' definition.  See <interface> groups, 'ax25-device' definitions.\n",
+		       cf->name, cf->linenum);
+
+		if (debug)
+			printf("%s:%d: AX25-RXPORT '%s' '%s'\n",
+			       cf->name, cf->linenum, param1, str);
+
+		return (netax25_addrxport(param1, NULL) == NULL);
+#endif
+	} else if (strcmp(name, "radio") == 0) {
+
+		printf("%s:%d WARNING: Old-style top-level 'radio' definition.  See <interface> groups, 'serial-device' or 'tcp-device' definitions.\n",
+		       cf->name, cf->linenum);
+
+		if (debug)
+			printf("%s:%d: RADIO = %s %s..\n",
+			       cf->name, cf->linenum, param1, str);
+		return (ttyreader_serialcfg(cf, param1, str) == NULL);
+
+	} else if (strcmp(name, "ax25-device") == 0) {
+		printf("%s:%d ERROR: The 'ax25-device' entry must be inside an <interface> group tag.\n",
+		       cf->name, cf->linenum);
+		return 1;
+
+	} else if (strcmp(name, "serial-device") == 0) {
+		printf("%s:%d ERROR: The 'serial-device' entry must be inside an <interface> group tag.\n",
+		       cf->name, cf->linenum);
+		return 1;
+
+	} else if (strcmp(name, "tcp-device") == 0) {
+		printf("%s:%d ERROR: The 'tcp-device' entry must be inside an <interface> group tag.\n",
+		       cf->name, cf->linenum);
+		return 1;
+
+	} else if (strcmp(name, "beacon") == 0) {
+		printf("%s:%d ERROR: The 'beacon' entry must be inside a <beacon> group tag.\n",
+		       cf->name, cf->linenum);
+		return 1;
+
+	} else {
+		printf("%s:%d: ERROR: Unknown config keyword: '%s' '%s'\n",
+		       cf->name, cf->linenum, name, param1);
+		printf("%s:%d: Perhaps this is due to lack of some surrounding <group> tag ?\n",
+		       cf->name, cf->linenum);
+		return 1;
+	}
+	return 0;
+}
+
+
+const char* scan_int(const char *p, int len, int *val, int *seen_space)
+{
+	int i;
+	char c;
+	*val = 0;
+	for (i = 0; i < len; ++i, ++p) {
+		c = *p;
+		if (('0' <= c && c <= '9') && !(*seen_space)) {
+			*val = (*val) * 10 + (c - '0');
+		} else if (c == ' ') {
+			*val = (*val) * 10;
+			*seen_space = 1;
+		} else {
+			return NULL;
+		}
+	}
+	return p;
+}
+
+int validate_degmin_input(const char *s, int maxdeg)
+{
+	int deg;
+	int m1, m2;
+	char c;
+	const char *t;
+	int seen_space = 0;
+	if (maxdeg > 90) {
+		t = scan_int(s, 3, &deg, &seen_space);
+		if (t != s+3) return 1; // scan failure
+		if (deg > 179) return 1; // too large value
+		s = t;
+		t = scan_int(s, 2, &m1, &seen_space);
+		if (t != s+2) return 1;
+		if (m1 > 59) return 1;
+		s = t;
+		c = *s;
+		if (!seen_space && c == '.') {
+			// OK
+		} else if (!seen_space && c == ' ') {
+			seen_space = 1;
+		} else {
+			return 1; // Bad char..
+		}
+		++s;
+		t = scan_int(s, 2, &m2, &seen_space);
+		if (t != s+2) return 1;
+		s = t;
+		c = *s;
+		if (c != 'E' && c != 'e' && c != 'W' && c != 'w') return 1;
+	} else {
+		t = scan_int(s, 2, &deg, &seen_space);
+		if (t != s+2) return 1; // scan failure
+		if (deg > 89) return 1; // too large value
+		s = t;
+		t = scan_int(s, 2, &m1, &seen_space);
+		if (t != s+2) return 1;
+		if (m1 > 59) return 1;
+		s = t;
+		c = *s;
+		if (!seen_space && c == '.') {
+			// OK
+		} else if (!seen_space && c == ' ') {
+			seen_space = 1;
+		} else {
+			return 1; // Bad char..
+		}
+		++s;
+		t = scan_int(s, 2, &m2, &seen_space);
+		if (t != s+2) return 1;
+		s = t;
+		c = *s;
+		if (c != 'N' && c != 'n' && c != 'S' && c != 's') return 1;
+	}
+	return 0;		/* zero for OK */
+}
+
+
+/*
+ *  This interval parser is originally from ZMailer MTA.
+ *  Slightly expanded to permit white-spaces inside the string.
+ *  (c) Matti Aarnio, Rayan Zachariassen..
+ */
+
+static int parse_interval(const char *string, const char **restp)
+{
+	int	intvl = 0;
+	int	val;
+	int	c;
+
+	for (; *string; ++string) {
+
+	  val = 0;
+	  c = *string;
+	  while ('0' <= c && c <= '9') {
+	    val = val * 10 + (c - '0');
+	    c = *++string;
+	  }
+
+	  switch (c) {
+	  case 'd':		/* days */
+	  case 'D':		/* days */
+	    val *= (24*60*60);
+            break;
+	  case 'h':		/* hours */
+	  case 'H':		/* hours */
+	    val *= 60*60;
+            break;
+	  case 'm':		/* minutes */
+	  case 'M':		/* minutes */
+	    val *= 60;
+            break;
+	  case 's':		/* seconds */
+	  case 'S':		/* seconds */
+	    /* val *= 1; */
+	  case '\t':            /* just whitespace */
+	  case ' ':             /* just whitespace */
+	    break;
+	  default: /* Not of: "dhms" - maybe string end, maybe junk ? */
+	    if (restp) *restp = string;
+	    return intvl + val;
+	  }
+	  intvl += val;
+	}
+
+	if (restp) *restp = string;
+
+	return intvl;
+}
+
+// Return 0 on OK, != 0 on error
+int config_parse_interval(const char *par, int *resultp)
+{
+	const char *rest = NULL;
+	int ret = parse_interval(par, &rest);
+
+	if (*rest != 0) return 1; // Did not consume whole input string
+	*resultp = ret;
+	return 0;
+}
+
+// Return 0 on OK, != 0 on error
+int config_parse_boolean(const char *par, int *resultp)
+{
+	if (strcasecmp(par, "true") == 0 ||
+	    strcmp(par, "1") == 0 ||
+	    strcasecmp(par, "yes") == 0 ||
+	    strcasecmp(par, "on") == 0 ||
+	    strcasecmp(par, "y") == 0) {
+
+		*resultp = 1;
+		return 1;
+
+	} else if (strcasecmp(par, "false") == 0 ||
+		   strcmp(par, "0") == 0 ||
+		   strcasecmp(par, "no") == 0 ||
+		   strcasecmp(par, "off") == 0 ||
+		   strcasecmp(par, "n") == 0) {
+
+		*resultp = 0;
+		return 1;
+
+	} else {
+		return 0;
+	}
+}
+
+
+void *readconfigline(struct configfile *cf)
+{
+	char *bufp = cf->buf;
+	int buflen = sizeof(cf->buf);
+	//int llen;
+	cf->linenum = cf->linenum_i;
+	for (;;) {
+	  char *p = fgets(bufp, buflen, cf->fp);
+	  bufp[buflen - 1] = 0;	/* Trunc, just in case.. */
+	  if (p == NULL) {
+	    if (bufp == cf->buf)
+	      return NULL; // EOF!
+	    return cf->buf; // Got EOF, but got also data before it!
+	  }
+	  cf->linenum_i += 1;
+	  // Line ending LF ?
+	  p = strchr(bufp, '\n');
+	  if (p != NULL) {
+	    *p-- = 0;
+	    // Possible preceding CR ?
+	    if (*p == '\r')
+	      *p-- = 0;
+	    // Line ending whitespaces ?
+	    while (p > bufp && (*p == ' '||*p == '\t'))
+	      *p-- = 0;
+	    //llen = p - bufp;
+	  }
+	  if (p == NULL) {
+	    p = bufp + strlen(bufp);
+	  }
+	  if (*p == '\\') {
+	    bufp = p;
+	    buflen = sizeof(cf->buf) - (p - cf->buf) -1;
+	    continue;
+	  } else {
+	    // Not lone \ at line end.  Not a line with continuation line..
+	    break;
+	  }
+	}
+
+	if (debug > 2)
+	  printf("Config line: '%s'\n",cf->buf);
+
+	return cf->buf;
+}
+
+int configline_is_comment(struct configfile *cf)
+{
+	const char *buf = cf->buf;
+	const int buflen = sizeof(cf->buf);
+	char c = 0;
+	int i;
+
+	for (i = 0; buf[i] != 0 && i < buflen; ++i) {
+		c = buf[i];
+		if (c == ' ' || c == '\t')
+			continue;
+		/* Anything else, stop scanning */
+		break;
+	}
+	if (c == '#' || c == '\n' || c == '\r' || c == 0)
+		return 1;
+
+	return 0;
+}
+
+int readconfig(const char *name)
+{
+	struct configfile cf;
+	int has_fault = 0;
+	int i;
+
+	cf.linenum_i = 1;
+	cf.linenum   = 1;
+	cf.name      = name;
+
+	if ((cf.fp = fopen(name, "r")) == NULL) {
+		int e = errno;
+		printf("ERROR: Can not open named config file: '%s' -> %d %s\n",
+		       name, e, strerror(e)); 
+		return 1;
+	}
+
+	while (readconfigline(&cf) != NULL) {
+		if (configline_is_comment(&cf))
+			continue;	/* Comment line, or empty line */
+
+		i = cfgparam(&cf);
+		if (i) has_fault = 1;
+	}
+	fclose(cf.fp);
+
+	return has_fault;
+}
diff --git a/config.h.in b/config.h.in
new file mode 100644
index 0000000..39218d7
--- /dev/null
+++ b/config.h.in
@@ -0,0 +1,182 @@
+/* config.h.in.  Generated from configure.in by autoheader.  */
+
+/* Define if building universal (internal helper macro) */
+#undef AC_APPLE_UNIVERSAL_BUILD
+
+/* Configuration command line */
+#undef CONFIGURE_CMD
+
+/* Define to 1 if you want to disable all IGATE codes. */
+#undef DISABLE_IGATE
+
+/* Define for pthread(3p) disabling */
+#undef DISABLE_PTHREAD
+
+/* Define for an embedded target */
+#undef EMBEDDED
+
+/* Define to 1 if you want to enable AGWPE socket interface. */
+#undef ENABLE_AGWPE
+
+/* Define for pthread(3p) enabling */
+#undef ENABLE_PTHREAD
+
+/* Define for a non-embedded system with filesystem based Erlang history
+   storage */
+#undef ERLANGSTORAGE
+
+/* Define to 1 if you have the <alloca.h> header file. */
+#undef HAVE_ALLOCA_H
+
+/* Define to 1 if you have the `atan2f' function. */
+#undef HAVE_ATAN2F
+
+/* Have clock_gettime */
+#undef HAVE_CLOCK_GETTIME
+
+/* Define to 1 if you don't have `vprintf' but do have `_doprnt.' */
+#undef HAVE_DOPRNT
+
+/* Define to 1 if you have the `getaddrinfo' function. */
+#undef HAVE_GETADDRINFO
+
+/* Define to 1 if you have the `gettimeofday' function. */
+#undef HAVE_GETTIMEOFDAY
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#undef HAVE_INTTYPES_H
+
+/* Define to 1 if you have the `memchr' function. */
+#undef HAVE_MEMCHR
+
+/* Define to 1 if you have the <memory.h> header file. */
+#undef HAVE_MEMORY_H
+
+/* Define to 1 if you have the `memrchr' function. */
+#undef HAVE_MEMRCHR
+
+/* Define to 1 if you have the <netinet/sctp.h> header file. */
+#undef HAVE_NETINET_SCTP_H
+
+/* Define to 1 if you have the `openpty' function. */
+#undef HAVE_OPENPTY
+
+/* Define to 1 if you have the <openssl/ssl.h> header file. */
+#undef HAVE_OPENSSL_SSL_H
+
+/* Define to 1 if you have the <poll.h> header file. */
+#undef HAVE_POLL_H
+
+/* Have pthread_create() function */
+#undef HAVE_PTHREAD_CREATE
+
+/* Define to 1 if you have the <pthread.h> header file. */
+#undef HAVE_PTHREAD_H
+
+/* Define to 1 if you have the <pty.h> header file. */
+#undef HAVE_PTY_H
+
+/* Define to 1 if you have the `socket' function. */
+#undef HAVE_SOCKET
+
+/* Define to 1 if you have the `socketpair' function. */
+#undef HAVE_SOCKETPAIR
+
+/* Define to 1 if you have the <stdarg.h> header file. */
+#undef HAVE_STDARG_H
+
+/* Define to 1 if you have the <stddef.h> header file. */
+#undef HAVE_STDDEF_H
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#undef HAVE_STDINT_H
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#undef HAVE_STDLIB_H
+
+/* Define to 1 if you have the <strings.h> header file. */
+#undef HAVE_STRINGS_H
+
+/* Define to 1 if you have the <string.h> header file. */
+#undef HAVE_STRING_H
+
+/* Define to 1 if you have the <sys/epoll.h> header file. */
+#undef HAVE_SYS_EPOLL_H
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#undef HAVE_SYS_STAT_H
+
+/* Define to 1 if you have the <sys/time.h> header file. */
+#undef HAVE_SYS_TIME_H
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#undef HAVE_SYS_TYPES_H
+
+/* Define to 1 if you have the <sys/wait.h> header file. */
+#undef HAVE_SYS_WAIT_H
+
+/* Define to 1 if you have the <time.h> header file. */
+#undef HAVE_TIME_H
+
+/* OpenSSL 0.9.7 or later */
+#undef HAVE_TLSV1_SERVER_METHOD
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#undef HAVE_UNISTD_H
+
+/* Define to 1 if you have the <varargs.h> header file. */
+#undef HAVE_VARARGS_H
+
+/* Define to 1 if you have the `vprintf' function. */
+#undef HAVE_VPRINTF
+
+/* OpenSSL 0.9.7 or later */
+#undef HAVE_X509_FREE
+
+/* Define to the address where bug reports for this package should be sent. */
+#undef PACKAGE_BUGREPORT
+
+/* Define to the full name of this package. */
+#undef PACKAGE_NAME
+
+/* Define to the full name and version of this package. */
+#undef PACKAGE_STRING
+
+/* Define to the one symbol short name of this package. */
+#undef PACKAGE_TARNAME
+
+/* Define to the home page for this package. */
+#undef PACKAGE_URL
+
+/* Define to the version of this package. */
+#undef PACKAGE_VERSION
+
+/* The size of `double', as computed by sizeof. */
+#undef SIZEOF_DOUBLE
+
+/* The size of `int', as computed by sizeof. */
+#undef SIZEOF_INT
+
+/* The size of `long', as computed by sizeof. */
+#undef SIZEOF_LONG
+
+/* The size of `short', as computed by sizeof. */
+#undef SIZEOF_SHORT
+
+/* The size of `void *', as computed by sizeof. */
+#undef SIZEOF_VOID_P
+
+/* Define to 1 if you have the ANSI C header files. */
+#undef STDC_HEADERS
+
+/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most
+   significant byte first (like Motorola and SPARC, unlike Intel). */
+#if defined AC_APPLE_UNIVERSAL_BUILD
+# if defined __BIG_ENDIAN__
+#  define WORDS_BIGENDIAN 1
+# endif
+#else
+# ifndef WORDS_BIGENDIAN
+#  undef WORDS_BIGENDIAN
+# endif
+#endif
diff --git a/configure b/configure
new file mode 100755
index 0000000..cccfc02
--- /dev/null
+++ b/configure
@@ -0,0 +1,6245 @@
+#! /bin/sh
+# Guess values for system-dependent variables and create Makefiles.
+# Generated by GNU Autoconf 2.69.
+#
+#
+# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc.
+#
+#
+# This configure script is free software; the Free Software Foundation
+# gives unlimited permission to copy, distribute and modify it.
+## -------------------- ##
+## M4sh Initialization. ##
+## -------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+  emulate sh
+  NULLCMD=:
+  # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+  # is contrary to our usage.  Disable this feature.
+  alias -g '${1+"$@"}'='"$@"'
+  setopt NO_GLOB_SUBST
+else
+  case `(set -o) 2>/dev/null` in #(
+  *posix*) :
+    set -o posix ;; #(
+  *) :
+     ;;
+esac
+fi
+
+
+as_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+# Prefer a ksh shell builtin over an external printf program on Solaris,
+# but without wasting forks for bash or zsh.
+if test -z "$BASH_VERSION$ZSH_VERSION" \
+    && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
+  as_echo='print -r --'
+  as_echo_n='print -rn --'
+elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+  as_echo='printf %s\n'
+  as_echo_n='printf %s'
+else
+  if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+    as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+    as_echo_n='/usr/ucb/echo -n'
+  else
+    as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+    as_echo_n_body='eval
+      arg=$1;
+      case $arg in #(
+      *"$as_nl"*)
+	expr "X$arg" : "X\\(.*\\)$as_nl";
+	arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+      esac;
+      expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+    '
+    export as_echo_n_body
+    as_echo_n='sh -c $as_echo_n_body as_echo'
+  fi
+  export as_echo_body
+  as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+  PATH_SEPARATOR=:
+  (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+    (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+      PATH_SEPARATOR=';'
+  }
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order.  Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+IFS=" ""	$as_nl"
+
+# Find who we are.  Look in the path if we contain no directory separator.
+as_myself=
+case $0 in #((
+  *[\\/]* ) as_myself=$0 ;;
+  *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+  done
+IFS=$as_save_IFS
+
+     ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+  as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+  $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+  exit 1
+fi
+
+# Unset variables that we do not need and which cause bugs (e.g. in
+# pre-3.0 UWIN ksh).  But do not cause bugs in bash 2.01; the "|| exit 1"
+# suppresses any "Segmentation fault" message there.  '((' could
+# trigger a bug in pdksh 5.2.14.
+for as_var in BASH_ENV ENV MAIL MAILPATH
+do eval test x\${$as_var+set} = xset \
+  && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+# Use a proper internal environment variable to ensure we don't fall
+  # into an infinite loop, continuously re-executing ourselves.
+  if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then
+    _as_can_reexec=no; export _as_can_reexec;
+    # We cannot yet assume a decent shell, so we have to provide a
+# neutralization value for shells without unset; and this also
+# works around shells that cannot unset nonexistent variables.
+# Preserve -v and -x to the replacement shell.
+BASH_ENV=/dev/null
+ENV=/dev/null
+(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
+case $- in # ((((
+  *v*x* | *x*v* ) as_opts=-vx ;;
+  *v* ) as_opts=-v ;;
+  *x* ) as_opts=-x ;;
+  * ) as_opts= ;;
+esac
+exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"}
+# Admittedly, this is quite paranoid, since all the known shells bail
+# out after a failed `exec'.
+$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2
+as_fn_exit 255
+  fi
+  # We don't want this to propagate to other subprocesses.
+          { _as_can_reexec=; unset _as_can_reexec;}
+if test "x$CONFIG_SHELL" = x; then
+  as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then :
+  emulate sh
+  NULLCMD=:
+  # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which
+  # is contrary to our usage.  Disable this feature.
+  alias -g '\${1+\"\$@\"}'='\"\$@\"'
+  setopt NO_GLOB_SUBST
+else
+  case \`(set -o) 2>/dev/null\` in #(
+  *posix*) :
+    set -o posix ;; #(
+  *) :
+     ;;
+esac
+fi
+"
+  as_required="as_fn_return () { (exit \$1); }
+as_fn_success () { as_fn_return 0; }
+as_fn_failure () { as_fn_return 1; }
+as_fn_ret_success () { return 0; }
+as_fn_ret_failure () { return 1; }
+
+exitcode=0
+as_fn_success || { exitcode=1; echo as_fn_success failed.; }
+as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; }
+as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; }
+as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; }
+if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then :
+
+else
+  exitcode=1; echo positional parameters were not saved.
+fi
+test x\$exitcode = x0 || exit 1
+test -x / || exit 1"
+  as_suggested="  as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO
+  as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO
+  eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" &&
+  test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1
+test \$(( 1 + 1 )) = 2 || exit 1"
+  if (eval "$as_required") 2>/dev/null; then :
+  as_have_required=yes
+else
+  as_have_required=no
+fi
+  if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then :
+
+else
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+as_found=false
+for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  as_found=:
+  case $as_dir in #(
+	 /*)
+	   for as_base in sh bash ksh sh5; do
+	     # Try only shells that exist, to save several forks.
+	     as_shell=$as_dir/$as_base
+	     if { test -f "$as_shell" || test -f "$as_shell.exe"; } &&
+		    { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then :
+  CONFIG_SHELL=$as_shell as_have_required=yes
+		   if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then :
+  break 2
+fi
+fi
+	   done;;
+       esac
+  as_found=false
+done
+$as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } &&
+	      { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then :
+  CONFIG_SHELL=$SHELL as_have_required=yes
+fi; }
+IFS=$as_save_IFS
+
+
+      if test "x$CONFIG_SHELL" != x; then :
+  export CONFIG_SHELL
+             # We cannot yet assume a decent shell, so we have to provide a
+# neutralization value for shells without unset; and this also
+# works around shells that cannot unset nonexistent variables.
+# Preserve -v and -x to the replacement shell.
+BASH_ENV=/dev/null
+ENV=/dev/null
+(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
+case $- in # ((((
+  *v*x* | *x*v* ) as_opts=-vx ;;
+  *v* ) as_opts=-v ;;
+  *x* ) as_opts=-x ;;
+  * ) as_opts= ;;
+esac
+exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"}
+# Admittedly, this is quite paranoid, since all the known shells bail
+# out after a failed `exec'.
+$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2
+exit 255
+fi
+
+    if test x$as_have_required = xno; then :
+  $as_echo "$0: This script requires a shell more modern than all"
+  $as_echo "$0: the shells that I found on your system."
+  if test x${ZSH_VERSION+set} = xset ; then
+    $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should"
+    $as_echo "$0: be upgraded to zsh 4.3.4 or later."
+  else
+    $as_echo "$0: Please tell bug-autoconf at gnu.org about your system,
+$0: including any error possibly output before this
+$0: message. Then install a modern shell, or manually run
+$0: the script under such a shell if you do have one."
+  fi
+  exit 1
+fi
+fi
+fi
+SHELL=${CONFIG_SHELL-/bin/sh}
+export SHELL
+# Unset more variables known to interfere with behavior of common tools.
+CLICOLOR_FORCE= GREP_OPTIONS=
+unset CLICOLOR_FORCE GREP_OPTIONS
+
+## --------------------- ##
+## M4sh Shell Functions. ##
+## --------------------- ##
+# as_fn_unset VAR
+# ---------------
+# Portably unset VAR.
+as_fn_unset ()
+{
+  { eval $1=; unset $1;}
+}
+as_unset=as_fn_unset
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+  return $1
+} # as_fn_set_status
+
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+  set +e
+  as_fn_set_status $1
+  exit $1
+} # as_fn_exit
+
+# as_fn_mkdir_p
+# -------------
+# Create "$as_dir" as a directory, including parents if necessary.
+as_fn_mkdir_p ()
+{
+
+  case $as_dir in #(
+  -*) as_dir=./$as_dir;;
+  esac
+  test -d "$as_dir" || eval $as_mkdir_p || {
+    as_dirs=
+    while :; do
+      case $as_dir in #(
+      *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+      *) as_qdir=$as_dir;;
+      esac
+      as_dirs="'$as_qdir' $as_dirs"
+      as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+	 X"$as_dir" : 'X\(//\)[^/]' \| \
+	 X"$as_dir" : 'X\(//\)$' \| \
+	 X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_dir" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)[^/].*/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\).*/{
+	    s//\1/
+	    q
+	  }
+	  s/.*/./; q'`
+      test -d "$as_dir" && break
+    done
+    test -z "$as_dirs" || eval "mkdir $as_dirs"
+  } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
+
+
+} # as_fn_mkdir_p
+
+# as_fn_executable_p FILE
+# -----------------------
+# Test if FILE is an executable regular file.
+as_fn_executable_p ()
+{
+  test -f "$1" && test -x "$1"
+} # as_fn_executable_p
+# as_fn_append VAR VALUE
+# ----------------------
+# Append the text in VALUE to the end of the definition contained in VAR. Take
+# advantage of any shell optimizations that allow amortized linear growth over
+# repeated appends, instead of the typical quadratic growth present in naive
+# implementations.
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+  eval 'as_fn_append ()
+  {
+    eval $1+=\$2
+  }'
+else
+  as_fn_append ()
+  {
+    eval $1=\$$1\$2
+  }
+fi # as_fn_append
+
+# as_fn_arith ARG...
+# ------------------
+# Perform arithmetic evaluation on the ARGs, and store the result in the
+# global $as_val. Take advantage of shells that can avoid forks. The arguments
+# must be portable across $(()) and expr.
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+  eval 'as_fn_arith ()
+  {
+    as_val=$(( $* ))
+  }'
+else
+  as_fn_arith ()
+  {
+    as_val=`expr "$@" || test $? -eq 1`
+  }
+fi # as_fn_arith
+
+
+# as_fn_error STATUS ERROR [LINENO LOG_FD]
+# ----------------------------------------
+# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+# script with STATUS, using 1 if that was 0.
+as_fn_error ()
+{
+  as_status=$1; test $as_status -eq 0 && as_status=1
+  if test "$4"; then
+    as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+    $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+  fi
+  $as_echo "$as_me: error: $2" >&2
+  as_fn_exit $as_status
+} # as_fn_error
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+   test "X`expr 00001 : '.*\(...\)'`" = X001; then
+  as_expr=expr
+else
+  as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+  as_basename=basename
+else
+  as_basename=false
+fi
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+  as_dirname=dirname
+else
+  as_dirname=false
+fi
+
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+	 X"$0" : 'X\(//\)$' \| \
+	 X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+    sed '/^.*\/\([^/][^/]*\)\/*$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\/\(\/\/\)$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\/\(\/\).*/{
+	    s//\1/
+	    q
+	  }
+	  s/.*/./; q'`
+
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+
+  as_lineno_1=$LINENO as_lineno_1a=$LINENO
+  as_lineno_2=$LINENO as_lineno_2a=$LINENO
+  eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" &&
+  test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || {
+  # Blame Lee E. McMahon (1931-1989) for sed's syntax.  :-)
+  sed -n '
+    p
+    /[$]LINENO/=
+  ' <$as_myself |
+    sed '
+      s/[$]LINENO.*/&-/
+      t lineno
+      b
+      :lineno
+      N
+      :loop
+      s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/
+      t loop
+      s/-\n.*//
+    ' >$as_me.lineno &&
+  chmod +x "$as_me.lineno" ||
+    { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; }
+
+  # If we had to re-execute with $CONFIG_SHELL, we're ensured to have
+  # already done that, so ensure we don't try to do so again and fall
+  # in an infinite loop.  This has already happened in practice.
+  _as_can_reexec=no; export _as_can_reexec
+  # Don't try to exec as it changes $[0], causing all sort of problems
+  # (the dirname of $[0] is not the place where we might find the
+  # original and so on.  Autoconf is especially sensitive to this).
+  . "./$as_me.lineno"
+  # Exit status is that of the last command.
+  exit
+}
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in #(((((
+-n*)
+  case `echo 'xy\c'` in
+  *c*) ECHO_T='	';;	# ECHO_T is single tab character.
+  xy)  ECHO_C='\c';;
+  *)   echo `echo ksh88 bug on AIX 6.1` > /dev/null
+       ECHO_T='	';;
+  esac;;
+*)
+  ECHO_N='-n';;
+esac
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+  rm -f conf$$.dir/conf$$.file
+else
+  rm -f conf$$.dir
+  mkdir conf$$.dir 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+  if ln -s conf$$.file conf$$ 2>/dev/null; then
+    as_ln_s='ln -s'
+    # ... but there are two gotchas:
+    # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+    # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+    # In both cases, we have to default to `cp -pR'.
+    ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+      as_ln_s='cp -pR'
+  elif ln conf$$.file conf$$ 2>/dev/null; then
+    as_ln_s=ln
+  else
+    as_ln_s='cp -pR'
+  fi
+else
+  as_ln_s='cp -pR'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+if mkdir -p . 2>/dev/null; then
+  as_mkdir_p='mkdir -p "$as_dir"'
+else
+  test -d ./-p && rmdir ./-p
+  as_mkdir_p=false
+fi
+
+as_test_x='test -x'
+as_executable_p=as_fn_executable_p
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+test -n "$DJDIR" || exec 7<&0 </dev/null
+exec 6>&1
+
+# Name of the host.
+# hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status,
+# so uname gets run too.
+ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q`
+
+#
+# Initializations.
+#
+ac_default_prefix=/usr/local
+ac_clean_files=
+ac_config_libobj_dir=.
+LIBOBJS=
+cross_compiling=no
+subdirs=
+MFLAGS=
+MAKEFLAGS=
+
+# Identity of this package.
+PACKAGE_NAME=
+PACKAGE_TARNAME=
+PACKAGE_VERSION=
+PACKAGE_STRING=
+PACKAGE_BUGREPORT=
+PACKAGE_URL=
+
+ac_unique_file="aprx.h"
+# Factoring default headers for most tests.
+ac_includes_default="\
+#include <stdio.h>
+#ifdef HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_STAT_H
+# include <sys/stat.h>
+#endif
+#ifdef STDC_HEADERS
+# include <stdlib.h>
+# include <stddef.h>
+#else
+# ifdef HAVE_STDLIB_H
+#  include <stdlib.h>
+# endif
+#endif
+#ifdef HAVE_STRING_H
+# if !defined STDC_HEADERS && defined HAVE_MEMORY_H
+#  include <memory.h>
+# endif
+# include <string.h>
+#endif
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif
+#ifdef HAVE_INTTYPES_H
+# include <inttypes.h>
+#endif
+#ifdef HAVE_STDINT_H
+# include <stdint.h>
+#endif
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif"
+
+ac_subst_vars='LTLIBOBJS
+LIBOBJS
+SVNVERSION_STRING
+VERSION_STRING
+LIBCRYPTO
+LIBSSL
+LIBRESOLV
+LIBSOCKET
+LIBGETADDRINFO
+LIBRT
+CCPTHREAD
+LIBPTHREAD
+LIBM
+CFLAGS_ARCH
+LD
+EGREP
+GREP
+CPP
+OBJEXT
+EXEEXT
+ac_ct_CC
+CPPFLAGS
+LDFLAGS
+CFLAGS
+CC
+SET_MAKE
+target_alias
+host_alias
+build_alias
+LIBS
+ECHO_T
+ECHO_N
+ECHO_C
+DEFS
+mandir
+localedir
+libdir
+psdir
+pdfdir
+dvidir
+htmldir
+infodir
+docdir
+oldincludedir
+includedir
+localstatedir
+sharedstatedir
+sysconfdir
+datadir
+datarootdir
+libexecdir
+sbindir
+bindir
+program_transform_name
+prefix
+exec_prefix
+PACKAGE_URL
+PACKAGE_BUGREPORT
+PACKAGE_STRING
+PACKAGE_VERSION
+PACKAGE_TARNAME
+PACKAGE_NAME
+PATH_SEPARATOR
+SHELL'
+ac_subst_files=''
+ac_user_opts='
+enable_option_checking
+with_embedded
+with_erlangstorage
+enable_igate
+enable_agwpe
+with_pthread
+with_pthreads
+with_openssl
+'
+      ac_precious_vars='build_alias
+host_alias
+target_alias
+CC
+CFLAGS
+LDFLAGS
+LIBS
+CPPFLAGS
+CPP'
+
+
+# Initialize some variables set by options.
+ac_init_help=
+ac_init_version=false
+ac_unrecognized_opts=
+ac_unrecognized_sep=
+# The variables have the same names as the options, with
+# dashes changed to underlines.
+cache_file=/dev/null
+exec_prefix=NONE
+no_create=
+no_recursion=
+prefix=NONE
+program_prefix=NONE
+program_suffix=NONE
+program_transform_name=s,x,x,
+silent=
+site=
+srcdir=
+verbose=
+x_includes=NONE
+x_libraries=NONE
+
+# Installation directory options.
+# These are left unexpanded so users can "make install exec_prefix=/foo"
+# and all the variables that are supposed to be based on exec_prefix
+# by default will actually change.
+# Use braces instead of parens because sh, perl, etc. also accept them.
+# (The list follows the same order as the GNU Coding Standards.)
+bindir='${exec_prefix}/bin'
+sbindir='${exec_prefix}/sbin'
+libexecdir='${exec_prefix}/libexec'
+datarootdir='${prefix}/share'
+datadir='${datarootdir}'
+sysconfdir='${prefix}/etc'
+sharedstatedir='${prefix}/com'
+localstatedir='${prefix}/var'
+includedir='${prefix}/include'
+oldincludedir='/usr/include'
+docdir='${datarootdir}/doc/${PACKAGE}'
+infodir='${datarootdir}/info'
+htmldir='${docdir}'
+dvidir='${docdir}'
+pdfdir='${docdir}'
+psdir='${docdir}'
+libdir='${exec_prefix}/lib'
+localedir='${datarootdir}/locale'
+mandir='${datarootdir}/man'
+
+ac_prev=
+ac_dashdash=
+for ac_option
+do
+  # If the previous option needs an argument, assign it.
+  if test -n "$ac_prev"; then
+    eval $ac_prev=\$ac_option
+    ac_prev=
+    continue
+  fi
+
+  case $ac_option in
+  *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;;
+  *=)   ac_optarg= ;;
+  *)    ac_optarg=yes ;;
+  esac
+
+  # Accept the important Cygnus configure options, so we can diagnose typos.
+
+  case $ac_dashdash$ac_option in
+  --)
+    ac_dashdash=yes ;;
+
+  -bindir | --bindir | --bindi | --bind | --bin | --bi)
+    ac_prev=bindir ;;
+  -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
+    bindir=$ac_optarg ;;
+
+  -build | --build | --buil | --bui | --bu)
+    ac_prev=build_alias ;;
+  -build=* | --build=* | --buil=* | --bui=* | --bu=*)
+    build_alias=$ac_optarg ;;
+
+  -cache-file | --cache-file | --cache-fil | --cache-fi \
+  | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
+    ac_prev=cache_file ;;
+  -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
+  | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
+    cache_file=$ac_optarg ;;
+
+  --config-cache | -C)
+    cache_file=config.cache ;;
+
+  -datadir | --datadir | --datadi | --datad)
+    ac_prev=datadir ;;
+  -datadir=* | --datadir=* | --datadi=* | --datad=*)
+    datadir=$ac_optarg ;;
+
+  -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \
+  | --dataroo | --dataro | --datar)
+    ac_prev=datarootdir ;;
+  -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \
+  | --dataroot=* | --dataroo=* | --dataro=* | --datar=*)
+    datarootdir=$ac_optarg ;;
+
+  -disable-* | --disable-*)
+    ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+      as_fn_error $? "invalid feature name: $ac_useropt"
+    ac_useropt_orig=$ac_useropt
+    ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+    case $ac_user_opts in
+      *"
+"enable_$ac_useropt"
+"*) ;;
+      *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig"
+	 ac_unrecognized_sep=', ';;
+    esac
+    eval enable_$ac_useropt=no ;;
+
+  -docdir | --docdir | --docdi | --doc | --do)
+    ac_prev=docdir ;;
+  -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*)
+    docdir=$ac_optarg ;;
+
+  -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv)
+    ac_prev=dvidir ;;
+  -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*)
+    dvidir=$ac_optarg ;;
+
+  -enable-* | --enable-*)
+    ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+      as_fn_error $? "invalid feature name: $ac_useropt"
+    ac_useropt_orig=$ac_useropt
+    ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+    case $ac_user_opts in
+      *"
+"enable_$ac_useropt"
+"*) ;;
+      *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig"
+	 ac_unrecognized_sep=', ';;
+    esac
+    eval enable_$ac_useropt=\$ac_optarg ;;
+
+  -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
+  | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
+  | --exec | --exe | --ex)
+    ac_prev=exec_prefix ;;
+  -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
+  | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
+  | --exec=* | --exe=* | --ex=*)
+    exec_prefix=$ac_optarg ;;
+
+  -gas | --gas | --ga | --g)
+    # Obsolete; use --with-gas.
+    with_gas=yes ;;
+
+  -help | --help | --hel | --he | -h)
+    ac_init_help=long ;;
+  -help=r* | --help=r* | --hel=r* | --he=r* | -hr*)
+    ac_init_help=recursive ;;
+  -help=s* | --help=s* | --hel=s* | --he=s* | -hs*)
+    ac_init_help=short ;;
+
+  -host | --host | --hos | --ho)
+    ac_prev=host_alias ;;
+  -host=* | --host=* | --hos=* | --ho=*)
+    host_alias=$ac_optarg ;;
+
+  -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht)
+    ac_prev=htmldir ;;
+  -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \
+  | --ht=*)
+    htmldir=$ac_optarg ;;
+
+  -includedir | --includedir | --includedi | --included | --include \
+  | --includ | --inclu | --incl | --inc)
+    ac_prev=includedir ;;
+  -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
+  | --includ=* | --inclu=* | --incl=* | --inc=*)
+    includedir=$ac_optarg ;;
+
+  -infodir | --infodir | --infodi | --infod | --info | --inf)
+    ac_prev=infodir ;;
+  -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
+    infodir=$ac_optarg ;;
+
+  -libdir | --libdir | --libdi | --libd)
+    ac_prev=libdir ;;
+  -libdir=* | --libdir=* | --libdi=* | --libd=*)
+    libdir=$ac_optarg ;;
+
+  -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
+  | --libexe | --libex | --libe)
+    ac_prev=libexecdir ;;
+  -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
+  | --libexe=* | --libex=* | --libe=*)
+    libexecdir=$ac_optarg ;;
+
+  -localedir | --localedir | --localedi | --localed | --locale)
+    ac_prev=localedir ;;
+  -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*)
+    localedir=$ac_optarg ;;
+
+  -localstatedir | --localstatedir | --localstatedi | --localstated \
+  | --localstate | --localstat | --localsta | --localst | --locals)
+    ac_prev=localstatedir ;;
+  -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
+  | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*)
+    localstatedir=$ac_optarg ;;
+
+  -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
+    ac_prev=mandir ;;
+  -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
+    mandir=$ac_optarg ;;
+
+  -nfp | --nfp | --nf)
+    # Obsolete; use --without-fp.
+    with_fp=no ;;
+
+  -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+  | --no-cr | --no-c | -n)
+    no_create=yes ;;
+
+  -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+  | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
+    no_recursion=yes ;;
+
+  -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
+  | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
+  | --oldin | --oldi | --old | --ol | --o)
+    ac_prev=oldincludedir ;;
+  -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
+  | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
+  | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
+    oldincludedir=$ac_optarg ;;
+
+  -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+    ac_prev=prefix ;;
+  -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+    prefix=$ac_optarg ;;
+
+  -program-prefix | --program-prefix | --program-prefi | --program-pref \
+  | --program-pre | --program-pr | --program-p)
+    ac_prev=program_prefix ;;
+  -program-prefix=* | --program-prefix=* | --program-prefi=* \
+  | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
+    program_prefix=$ac_optarg ;;
+
+  -program-suffix | --program-suffix | --program-suffi | --program-suff \
+  | --program-suf | --program-su | --program-s)
+    ac_prev=program_suffix ;;
+  -program-suffix=* | --program-suffix=* | --program-suffi=* \
+  | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
+    program_suffix=$ac_optarg ;;
+
+  -program-transform-name | --program-transform-name \
+  | --program-transform-nam | --program-transform-na \
+  | --program-transform-n | --program-transform- \
+  | --program-transform | --program-transfor \
+  | --program-transfo | --program-transf \
+  | --program-trans | --program-tran \
+  | --progr-tra | --program-tr | --program-t)
+    ac_prev=program_transform_name ;;
+  -program-transform-name=* | --program-transform-name=* \
+  | --program-transform-nam=* | --program-transform-na=* \
+  | --program-transform-n=* | --program-transform-=* \
+  | --program-transform=* | --program-transfor=* \
+  | --program-transfo=* | --program-transf=* \
+  | --program-trans=* | --program-tran=* \
+  | --progr-tra=* | --program-tr=* | --program-t=*)
+    program_transform_name=$ac_optarg ;;
+
+  -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd)
+    ac_prev=pdfdir ;;
+  -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*)
+    pdfdir=$ac_optarg ;;
+
+  -psdir | --psdir | --psdi | --psd | --ps)
+    ac_prev=psdir ;;
+  -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*)
+    psdir=$ac_optarg ;;
+
+  -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+  | -silent | --silent | --silen | --sile | --sil)
+    silent=yes ;;
+
+  -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
+    ac_prev=sbindir ;;
+  -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
+  | --sbi=* | --sb=*)
+    sbindir=$ac_optarg ;;
+
+  -sharedstatedir | --sharedstatedir | --sharedstatedi \
+  | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
+  | --sharedst | --shareds | --shared | --share | --shar \
+  | --sha | --sh)
+    ac_prev=sharedstatedir ;;
+  -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
+  | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
+  | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
+  | --sha=* | --sh=*)
+    sharedstatedir=$ac_optarg ;;
+
+  -site | --site | --sit)
+    ac_prev=site ;;
+  -site=* | --site=* | --sit=*)
+    site=$ac_optarg ;;
+
+  -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+    ac_prev=srcdir ;;
+  -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+    srcdir=$ac_optarg ;;
+
+  -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
+  | --syscon | --sysco | --sysc | --sys | --sy)
+    ac_prev=sysconfdir ;;
+  -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
+  | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
+    sysconfdir=$ac_optarg ;;
+
+  -target | --target | --targe | --targ | --tar | --ta | --t)
+    ac_prev=target_alias ;;
+  -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
+    target_alias=$ac_optarg ;;
+
+  -v | -verbose | --verbose | --verbos | --verbo | --verb)
+    verbose=yes ;;
+
+  -version | --version | --versio | --versi | --vers | -V)
+    ac_init_version=: ;;
+
+  -with-* | --with-*)
+    ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+      as_fn_error $? "invalid package name: $ac_useropt"
+    ac_useropt_orig=$ac_useropt
+    ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+    case $ac_user_opts in
+      *"
+"with_$ac_useropt"
+"*) ;;
+      *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig"
+	 ac_unrecognized_sep=', ';;
+    esac
+    eval with_$ac_useropt=\$ac_optarg ;;
+
+  -without-* | --without-*)
+    ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+      as_fn_error $? "invalid package name: $ac_useropt"
+    ac_useropt_orig=$ac_useropt
+    ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+    case $ac_user_opts in
+      *"
+"with_$ac_useropt"
+"*) ;;
+      *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig"
+	 ac_unrecognized_sep=', ';;
+    esac
+    eval with_$ac_useropt=no ;;
+
+  --x)
+    # Obsolete; use --with-x.
+    with_x=yes ;;
+
+  -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
+  | --x-incl | --x-inc | --x-in | --x-i)
+    ac_prev=x_includes ;;
+  -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
+  | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
+    x_includes=$ac_optarg ;;
+
+  -x-libraries | --x-libraries | --x-librarie | --x-librari \
+  | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
+    ac_prev=x_libraries ;;
+  -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
+  | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
+    x_libraries=$ac_optarg ;;
+
+  -*) as_fn_error $? "unrecognized option: \`$ac_option'
+Try \`$0 --help' for more information"
+    ;;
+
+  *=*)
+    ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='`
+    # Reject names that are not valid shell variable names.
+    case $ac_envvar in #(
+      '' | [0-9]* | *[!_$as_cr_alnum]* )
+      as_fn_error $? "invalid variable name: \`$ac_envvar'" ;;
+    esac
+    eval $ac_envvar=\$ac_optarg
+    export $ac_envvar ;;
+
+  *)
+    # FIXME: should be removed in autoconf 3.0.
+    $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2
+    expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null &&
+      $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2
+    : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}"
+    ;;
+
+  esac
+done
+
+if test -n "$ac_prev"; then
+  ac_option=--`echo $ac_prev | sed 's/_/-/g'`
+  as_fn_error $? "missing argument to $ac_option"
+fi
+
+if test -n "$ac_unrecognized_opts"; then
+  case $enable_option_checking in
+    no) ;;
+    fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;;
+    *)     $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;;
+  esac
+fi
+
+# Check all directory arguments for consistency.
+for ac_var in	exec_prefix prefix bindir sbindir libexecdir datarootdir \
+		datadir sysconfdir sharedstatedir localstatedir includedir \
+		oldincludedir docdir infodir htmldir dvidir pdfdir psdir \
+		libdir localedir mandir
+do
+  eval ac_val=\$$ac_var
+  # Remove trailing slashes.
+  case $ac_val in
+    */ )
+      ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'`
+      eval $ac_var=\$ac_val;;
+  esac
+  # Be sure to have absolute directory names.
+  case $ac_val in
+    [\\/$]* | ?:[\\/]* )  continue;;
+    NONE | '' ) case $ac_var in *prefix ) continue;; esac;;
+  esac
+  as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val"
+done
+
+# There might be people who depend on the old broken behavior: `$host'
+# used to hold the argument of --host etc.
+# FIXME: To remove some day.
+build=$build_alias
+host=$host_alias
+target=$target_alias
+
+# FIXME: To remove some day.
+if test "x$host_alias" != x; then
+  if test "x$build_alias" = x; then
+    cross_compiling=maybe
+  elif test "x$build_alias" != "x$host_alias"; then
+    cross_compiling=yes
+  fi
+fi
+
+ac_tool_prefix=
+test -n "$host_alias" && ac_tool_prefix=$host_alias-
+
+test "$silent" = yes && exec 6>/dev/null
+
+
+ac_pwd=`pwd` && test -n "$ac_pwd" &&
+ac_ls_di=`ls -di .` &&
+ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` ||
+  as_fn_error $? "working directory cannot be determined"
+test "X$ac_ls_di" = "X$ac_pwd_ls_di" ||
+  as_fn_error $? "pwd does not report name of working directory"
+
+
+# Find the source files, if location was not specified.
+if test -z "$srcdir"; then
+  ac_srcdir_defaulted=yes
+  # Try the directory containing this script, then the parent directory.
+  ac_confdir=`$as_dirname -- "$as_myself" ||
+$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+	 X"$as_myself" : 'X\(//\)[^/]' \| \
+	 X"$as_myself" : 'X\(//\)$' \| \
+	 X"$as_myself" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_myself" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)[^/].*/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\).*/{
+	    s//\1/
+	    q
+	  }
+	  s/.*/./; q'`
+  srcdir=$ac_confdir
+  if test ! -r "$srcdir/$ac_unique_file"; then
+    srcdir=..
+  fi
+else
+  ac_srcdir_defaulted=no
+fi
+if test ! -r "$srcdir/$ac_unique_file"; then
+  test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .."
+  as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir"
+fi
+ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work"
+ac_abs_confdir=`(
+	cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg"
+	pwd)`
+# When building in place, set srcdir=.
+if test "$ac_abs_confdir" = "$ac_pwd"; then
+  srcdir=.
+fi
+# Remove unnecessary trailing slashes from srcdir.
+# Double slashes in file names in object file debugging info
+# mess up M-x gdb in Emacs.
+case $srcdir in
+*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;;
+esac
+for ac_var in $ac_precious_vars; do
+  eval ac_env_${ac_var}_set=\${${ac_var}+set}
+  eval ac_env_${ac_var}_value=\$${ac_var}
+  eval ac_cv_env_${ac_var}_set=\${${ac_var}+set}
+  eval ac_cv_env_${ac_var}_value=\$${ac_var}
+done
+
+#
+# Report the --help message.
+#
+if test "$ac_init_help" = "long"; then
+  # Omit some internal or obsolete options to make the list less imposing.
+  # This message is too long to be a string in the A/UX 3.1 sh.
+  cat <<_ACEOF
+\`configure' configures this package to adapt to many kinds of systems.
+
+Usage: $0 [OPTION]... [VAR=VALUE]...
+
+To assign environment variables (e.g., CC, CFLAGS...), specify them as
+VAR=VALUE.  See below for descriptions of some of the useful variables.
+
+Defaults for the options are specified in brackets.
+
+Configuration:
+  -h, --help              display this help and exit
+      --help=short        display options specific to this package
+      --help=recursive    display the short help of all the included packages
+  -V, --version           display version information and exit
+  -q, --quiet, --silent   do not print \`checking ...' messages
+      --cache-file=FILE   cache test results in FILE [disabled]
+  -C, --config-cache      alias for \`--cache-file=config.cache'
+  -n, --no-create         do not create output files
+      --srcdir=DIR        find the sources in DIR [configure dir or \`..']
+
+Installation directories:
+  --prefix=PREFIX         install architecture-independent files in PREFIX
+                          [$ac_default_prefix]
+  --exec-prefix=EPREFIX   install architecture-dependent files in EPREFIX
+                          [PREFIX]
+
+By default, \`make install' will install all the files in
+\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc.  You can specify
+an installation prefix other than \`$ac_default_prefix' using \`--prefix',
+for instance \`--prefix=\$HOME'.
+
+For better control, use the options below.
+
+Fine tuning of the installation directories:
+  --bindir=DIR            user executables [EPREFIX/bin]
+  --sbindir=DIR           system admin executables [EPREFIX/sbin]
+  --libexecdir=DIR        program executables [EPREFIX/libexec]
+  --sysconfdir=DIR        read-only single-machine data [PREFIX/etc]
+  --sharedstatedir=DIR    modifiable architecture-independent data [PREFIX/com]
+  --localstatedir=DIR     modifiable single-machine data [PREFIX/var]
+  --libdir=DIR            object code libraries [EPREFIX/lib]
+  --includedir=DIR        C header files [PREFIX/include]
+  --oldincludedir=DIR     C header files for non-gcc [/usr/include]
+  --datarootdir=DIR       read-only arch.-independent data root [PREFIX/share]
+  --datadir=DIR           read-only architecture-independent data [DATAROOTDIR]
+  --infodir=DIR           info documentation [DATAROOTDIR/info]
+  --localedir=DIR         locale-dependent data [DATAROOTDIR/locale]
+  --mandir=DIR            man documentation [DATAROOTDIR/man]
+  --docdir=DIR            documentation root [DATAROOTDIR/doc/PACKAGE]
+  --htmldir=DIR           html documentation [DOCDIR]
+  --dvidir=DIR            dvi documentation [DOCDIR]
+  --pdfdir=DIR            pdf documentation [DOCDIR]
+  --psdir=DIR             ps documentation [DOCDIR]
+_ACEOF
+
+  cat <<\_ACEOF
+_ACEOF
+fi
+
+if test -n "$ac_init_help"; then
+
+  cat <<\_ACEOF
+
+Optional Features:
+  --disable-option-checking  ignore unrecognized --enable/--with options
+  --disable-FEATURE       do not include FEATURE (same as --enable-FEATURE=no)
+  --enable-FEATURE[=ARG]  include FEATURE [ARG=yes]
+  --disable-igate         Disable all IGate codes
+  --enable-agwpe          Enable AGWPE socket interface code.
+
+Optional Packages:
+  --with-PACKAGE[=ARG]    use PACKAGE [ARG=yes]
+  --without-PACKAGE       do not use PACKAGE (same as --with-PACKAGE=no)
+  --with-embedded  When desiring to target as embedded
+  --with-erlangstorage  When desiring a longer term backing storage on erlang datasets.  NOT compatible with EMBEDDED, REQUIRES FILESYSTEM!
+  --without-pthread   When desiring not to use pthread subsystem
+  --with-pthreads  (mistyped pthread) When desiring use pthread subsystem
+  --with-openssl=DIR    Include OpenSSL support (requires OpenSSL >= 0.9.7)
+
+Some influential environment variables:
+  CC          C compiler command
+  CFLAGS      C compiler flags
+  LDFLAGS     linker flags, e.g. -L<lib dir> if you have libraries in a
+              nonstandard directory <lib dir>
+  LIBS        libraries to pass to the linker, e.g. -l<library>
+  CPPFLAGS    (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if
+              you have headers in a nonstandard directory <include dir>
+  CPP         C preprocessor
+
+Use these variables to override the choices made by `configure' or to help
+it to find libraries and programs with nonstandard names/locations.
+
+Report bugs to the package provider.
+_ACEOF
+ac_status=$?
+fi
+
+if test "$ac_init_help" = "recursive"; then
+  # If there are subdirs, report their specific --help.
+  for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue
+    test -d "$ac_dir" ||
+      { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } ||
+      continue
+    ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+  ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+  # A ".." for each directory in $ac_dir_suffix.
+  ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+  case $ac_top_builddir_sub in
+  "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+  *)  ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+  esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+  .)  # We are building in place.
+    ac_srcdir=.
+    ac_top_srcdir=$ac_top_builddir_sub
+    ac_abs_top_srcdir=$ac_pwd ;;
+  [\\/]* | ?:[\\/]* )  # Absolute name.
+    ac_srcdir=$srcdir$ac_dir_suffix;
+    ac_top_srcdir=$srcdir
+    ac_abs_top_srcdir=$srcdir ;;
+  *) # Relative name.
+    ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+    ac_top_srcdir=$ac_top_build_prefix$srcdir
+    ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+    cd "$ac_dir" || { ac_status=$?; continue; }
+    # Check for guested configure.
+    if test -f "$ac_srcdir/configure.gnu"; then
+      echo &&
+      $SHELL "$ac_srcdir/configure.gnu" --help=recursive
+    elif test -f "$ac_srcdir/configure"; then
+      echo &&
+      $SHELL "$ac_srcdir/configure" --help=recursive
+    else
+      $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2
+    fi || ac_status=$?
+    cd "$ac_pwd" || { ac_status=$?; break; }
+  done
+fi
+
+test -n "$ac_init_help" && exit $ac_status
+if $ac_init_version; then
+  cat <<\_ACEOF
+configure
+generated by GNU Autoconf 2.69
+
+Copyright (C) 2012 Free Software Foundation, Inc.
+This configure script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it.
+_ACEOF
+  exit
+fi
+
+## ------------------------ ##
+## Autoconf initialization. ##
+## ------------------------ ##
+
+# ac_fn_c_try_compile LINENO
+# --------------------------
+# Try to compile conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_compile ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  rm -f conftest.$ac_objext
+  if { { ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_compile") 2>conftest.err
+  ac_status=$?
+  if test -s conftest.err; then
+    grep -v '^ *+' conftest.err >conftest.er1
+    cat conftest.er1 >&5
+    mv -f conftest.er1 conftest.err
+  fi
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } && {
+	 test -z "$ac_c_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then :
+  ac_retval=0
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+	ac_retval=1
+fi
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+  as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_compile
+
+# ac_fn_c_try_cpp LINENO
+# ----------------------
+# Try to preprocess conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_cpp ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  if { { ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err
+  ac_status=$?
+  if test -s conftest.err; then
+    grep -v '^ *+' conftest.err >conftest.er1
+    cat conftest.er1 >&5
+    mv -f conftest.er1 conftest.err
+  fi
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } > conftest.i && {
+	 test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+	 test ! -s conftest.err
+       }; then :
+  ac_retval=0
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+    ac_retval=1
+fi
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+  as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_cpp
+
+# ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES
+# -------------------------------------------------------
+# Tests whether HEADER exists, giving a warning if it cannot be compiled using
+# the include files in INCLUDES and setting the cache variable VAR
+# accordingly.
+ac_fn_c_check_header_mongrel ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  if eval \${$3+:} false; then :
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval \${$3+:} false; then :
+  $as_echo_n "(cached) " >&6
+fi
+eval ac_res=\$$3
+	       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+else
+  # Is the header compilable?
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5
+$as_echo_n "checking $2 usability... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+$4
+#include <$2>
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_header_compiler=yes
+else
+  ac_header_compiler=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5
+$as_echo "$ac_header_compiler" >&6; }
+
+# Is the header present?
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5
+$as_echo_n "checking $2 presence... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <$2>
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+  ac_header_preproc=yes
+else
+  ac_header_preproc=no
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5
+$as_echo "$ac_header_preproc" >&6; }
+
+# So?  What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in #((
+  yes:no: )
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5
+$as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;}
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5
+$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;}
+    ;;
+  no:yes:* )
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5
+$as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;}
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2:     check for missing prerequisite headers?" >&5
+$as_echo "$as_me: WARNING: $2:     check for missing prerequisite headers?" >&2;}
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5
+$as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;}
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2:     section \"Present But Cannot Be Compiled\"" >&5
+$as_echo "$as_me: WARNING: $2:     section \"Present But Cannot Be Compiled\"" >&2;}
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5
+$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;}
+    ;;
+esac
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval \${$3+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  eval "$3=\$ac_header_compiler"
+fi
+eval ac_res=\$$3
+	       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+fi
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+
+} # ac_fn_c_check_header_mongrel
+
+# ac_fn_c_try_run LINENO
+# ----------------------
+# Try to link conftest.$ac_ext, and return whether this succeeded. Assumes
+# that executables *can* be run.
+ac_fn_c_try_run ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  if { { ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_link") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } && { ac_try='./conftest$ac_exeext'
+  { { case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_try") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; }; then :
+  ac_retval=0
+else
+  $as_echo "$as_me: program exited with status $ac_status" >&5
+       $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_retval=$ac_status
+fi
+  rm -rf conftest.dSYM conftest_ipa8_conftest.oo
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+  as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_run
+
+# ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES
+# -------------------------------------------------------
+# Tests whether HEADER exists and can be compiled using the include files in
+# INCLUDES, setting the cache variable VAR accordingly.
+ac_fn_c_check_header_compile ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval \${$3+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+$4
+#include <$2>
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  eval "$3=yes"
+else
+  eval "$3=no"
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+eval ac_res=\$$3
+	       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+
+} # ac_fn_c_check_header_compile
+
+# ac_fn_c_try_link LINENO
+# -----------------------
+# Try to link conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_link ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  rm -f conftest.$ac_objext conftest$ac_exeext
+  if { { ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_link") 2>conftest.err
+  ac_status=$?
+  if test -s conftest.err; then
+    grep -v '^ *+' conftest.err >conftest.er1
+    cat conftest.er1 >&5
+    mv -f conftest.er1 conftest.err
+  fi
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } && {
+	 test -z "$ac_c_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest$ac_exeext && {
+	 test "$cross_compiling" = yes ||
+	 test -x conftest$ac_exeext
+       }; then :
+  ac_retval=0
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+	ac_retval=1
+fi
+  # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information
+  # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would
+  # interfere with the next link command; also delete a directory that is
+  # left behind by Apple's compiler.  We do this before executing the actions.
+  rm -rf conftest.dSYM conftest_ipa8_conftest.oo
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+  as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_link
+
+# ac_fn_c_check_func LINENO FUNC VAR
+# ----------------------------------
+# Tests whether FUNC exists, setting the cache variable VAR accordingly
+ac_fn_c_check_func ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval \${$3+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+/* Define $2 to an innocuous variant, in case <limits.h> declares $2.
+   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
+#define $2 innocuous_$2
+
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char $2 (); below.
+    Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+    <limits.h> exists even on freestanding compilers.  */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $2
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char $2 ();
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined __stub_$2 || defined __stub___$2
+choke me
+#endif
+
+int
+main ()
+{
+return $2 ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  eval "$3=yes"
+else
+  eval "$3=no"
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+fi
+eval ac_res=\$$3
+	       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+
+} # ac_fn_c_check_func
+
+# ac_fn_c_compute_int LINENO EXPR VAR INCLUDES
+# --------------------------------------------
+# Tries to find the compile-time value of EXPR in a program that includes
+# INCLUDES, setting VAR accordingly. Returns whether the value could be
+# computed
+ac_fn_c_compute_int ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  if test "$cross_compiling" = yes; then
+    # Depending upon the size, compute the lo and hi bounds.
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+$4
+int
+main ()
+{
+static int test_array [1 - 2 * !(($2) >= 0)];
+test_array [0] = 0;
+return test_array [0];
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_lo=0 ac_mid=0
+  while :; do
+    cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+$4
+int
+main ()
+{
+static int test_array [1 - 2 * !(($2) <= $ac_mid)];
+test_array [0] = 0;
+return test_array [0];
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_hi=$ac_mid; break
+else
+  as_fn_arith $ac_mid + 1 && ac_lo=$as_val
+			if test $ac_lo -le $ac_mid; then
+			  ac_lo= ac_hi=
+			  break
+			fi
+			as_fn_arith 2 '*' $ac_mid + 1 && ac_mid=$as_val
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+  done
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+$4
+int
+main ()
+{
+static int test_array [1 - 2 * !(($2) < 0)];
+test_array [0] = 0;
+return test_array [0];
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_hi=-1 ac_mid=-1
+  while :; do
+    cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+$4
+int
+main ()
+{
+static int test_array [1 - 2 * !(($2) >= $ac_mid)];
+test_array [0] = 0;
+return test_array [0];
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_lo=$ac_mid; break
+else
+  as_fn_arith '(' $ac_mid ')' - 1 && ac_hi=$as_val
+			if test $ac_mid -le $ac_hi; then
+			  ac_lo= ac_hi=
+			  break
+			fi
+			as_fn_arith 2 '*' $ac_mid && ac_mid=$as_val
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+  done
+else
+  ac_lo= ac_hi=
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+# Binary search between lo and hi bounds.
+while test "x$ac_lo" != "x$ac_hi"; do
+  as_fn_arith '(' $ac_hi - $ac_lo ')' / 2 + $ac_lo && ac_mid=$as_val
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+$4
+int
+main ()
+{
+static int test_array [1 - 2 * !(($2) <= $ac_mid)];
+test_array [0] = 0;
+return test_array [0];
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_hi=$ac_mid
+else
+  as_fn_arith '(' $ac_mid ')' + 1 && ac_lo=$as_val
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+done
+case $ac_lo in #((
+?*) eval "$3=\$ac_lo"; ac_retval=0 ;;
+'') ac_retval=1 ;;
+esac
+  else
+    cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+$4
+static long int longval () { return $2; }
+static unsigned long int ulongval () { return $2; }
+#include <stdio.h>
+#include <stdlib.h>
+int
+main ()
+{
+
+  FILE *f = fopen ("conftest.val", "w");
+  if (! f)
+    return 1;
+  if (($2) < 0)
+    {
+      long int i = longval ();
+      if (i != ($2))
+	return 1;
+      fprintf (f, "%ld", i);
+    }
+  else
+    {
+      unsigned long int i = ulongval ();
+      if (i != ($2))
+	return 1;
+      fprintf (f, "%lu", i);
+    }
+  /* Do not output a trailing newline, as this causes \r\n confusion
+     on some platforms.  */
+  return ferror (f) || fclose (f) != 0;
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+  echo >>conftest.val; read $3 <conftest.val; ac_retval=0
+else
+  ac_retval=1
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+  conftest.$ac_objext conftest.beam conftest.$ac_ext
+rm -f conftest.val
+
+  fi
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+  as_fn_set_status $ac_retval
+
+} # ac_fn_c_compute_int
+cat >config.log <<_ACEOF
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+
+It was created by $as_me, which was
+generated by GNU Autoconf 2.69.  Invocation command line was
+
+  $ $0 $@
+
+_ACEOF
+exec 5>>config.log
+{
+cat <<_ASUNAME
+## --------- ##
+## Platform. ##
+## --------- ##
+
+hostname = `(hostname || uname -n) 2>/dev/null | sed 1q`
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown`
+/bin/uname -X     = `(/bin/uname -X) 2>/dev/null     || echo unknown`
+
+/bin/arch              = `(/bin/arch) 2>/dev/null              || echo unknown`
+/usr/bin/arch -k       = `(/usr/bin/arch -k) 2>/dev/null       || echo unknown`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown`
+/usr/bin/hostinfo      = `(/usr/bin/hostinfo) 2>/dev/null      || echo unknown`
+/bin/machine           = `(/bin/machine) 2>/dev/null           || echo unknown`
+/usr/bin/oslevel       = `(/usr/bin/oslevel) 2>/dev/null       || echo unknown`
+/bin/universe          = `(/bin/universe) 2>/dev/null          || echo unknown`
+
+_ASUNAME
+
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    $as_echo "PATH: $as_dir"
+  done
+IFS=$as_save_IFS
+
+} >&5
+
+cat >&5 <<_ACEOF
+
+
+## ----------- ##
+## Core tests. ##
+## ----------- ##
+
+_ACEOF
+
+
+# Keep a trace of the command line.
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Strip out --silent because we don't want to record it for future runs.
+# Also quote any args containing shell meta-characters.
+# Make two passes to allow for proper duplicate-argument suppression.
+ac_configure_args=
+ac_configure_args0=
+ac_configure_args1=
+ac_must_keep_next=false
+for ac_pass in 1 2
+do
+  for ac_arg
+  do
+    case $ac_arg in
+    -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;;
+    -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+    | -silent | --silent | --silen | --sile | --sil)
+      continue ;;
+    *\'*)
+      ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
+    esac
+    case $ac_pass in
+    1) as_fn_append ac_configure_args0 " '$ac_arg'" ;;
+    2)
+      as_fn_append ac_configure_args1 " '$ac_arg'"
+      if test $ac_must_keep_next = true; then
+	ac_must_keep_next=false # Got value, back to normal.
+      else
+	case $ac_arg in
+	  *=* | --config-cache | -C | -disable-* | --disable-* \
+	  | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \
+	  | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \
+	  | -with-* | --with-* | -without-* | --without-* | --x)
+	    case "$ac_configure_args0 " in
+	      "$ac_configure_args1"*" '$ac_arg' "* ) continue ;;
+	    esac
+	    ;;
+	  -* ) ac_must_keep_next=true ;;
+	esac
+      fi
+      as_fn_append ac_configure_args " '$ac_arg'"
+      ;;
+    esac
+  done
+done
+{ ac_configure_args0=; unset ac_configure_args0;}
+{ ac_configure_args1=; unset ac_configure_args1;}
+
+# When interrupted or exit'd, cleanup temporary files, and complete
+# config.log.  We remove comments because anyway the quotes in there
+# would cause problems or look ugly.
+# WARNING: Use '\'' to represent an apostrophe within the trap.
+# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug.
+trap 'exit_status=$?
+  # Save into config.log some information that might help in debugging.
+  {
+    echo
+
+    $as_echo "## ---------------- ##
+## Cache variables. ##
+## ---------------- ##"
+    echo
+    # The following way of writing the cache mishandles newlines in values,
+(
+  for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do
+    eval ac_val=\$$ac_var
+    case $ac_val in #(
+    *${as_nl}*)
+      case $ac_var in #(
+      *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+      esac
+      case $ac_var in #(
+      _ | IFS | as_nl) ;; #(
+      BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
+      *) { eval $ac_var=; unset $ac_var;} ;;
+      esac ;;
+    esac
+  done
+  (set) 2>&1 |
+    case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #(
+    *${as_nl}ac_space=\ *)
+      sed -n \
+	"s/'\''/'\''\\\\'\'''\''/g;
+	  s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p"
+      ;; #(
+    *)
+      sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+      ;;
+    esac |
+    sort
+)
+    echo
+
+    $as_echo "## ----------------- ##
+## Output variables. ##
+## ----------------- ##"
+    echo
+    for ac_var in $ac_subst_vars
+    do
+      eval ac_val=\$$ac_var
+      case $ac_val in
+      *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+      esac
+      $as_echo "$ac_var='\''$ac_val'\''"
+    done | sort
+    echo
+
+    if test -n "$ac_subst_files"; then
+      $as_echo "## ------------------- ##
+## File substitutions. ##
+## ------------------- ##"
+      echo
+      for ac_var in $ac_subst_files
+      do
+	eval ac_val=\$$ac_var
+	case $ac_val in
+	*\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+	esac
+	$as_echo "$ac_var='\''$ac_val'\''"
+      done | sort
+      echo
+    fi
+
+    if test -s confdefs.h; then
+      $as_echo "## ----------- ##
+## confdefs.h. ##
+## ----------- ##"
+      echo
+      cat confdefs.h
+      echo
+    fi
+    test "$ac_signal" != 0 &&
+      $as_echo "$as_me: caught signal $ac_signal"
+    $as_echo "$as_me: exit $exit_status"
+  } >&5
+  rm -f core *.core core.conftest.* &&
+    rm -f -r conftest* confdefs* conf$$* $ac_clean_files &&
+    exit $exit_status
+' 0
+for ac_signal in 1 2 13 15; do
+  trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal
+done
+ac_signal=0
+
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -f -r conftest* confdefs.h
+
+$as_echo "/* confdefs.h */" > confdefs.h
+
+# Predefined preprocessor variables.
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_NAME "$PACKAGE_NAME"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_TARNAME "$PACKAGE_TARNAME"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_VERSION "$PACKAGE_VERSION"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_STRING "$PACKAGE_STRING"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_URL "$PACKAGE_URL"
+_ACEOF
+
+
+# Let the site file select an alternate cache file if it wants to.
+# Prefer an explicitly selected file to automatically selected ones.
+ac_site_file1=NONE
+ac_site_file2=NONE
+if test -n "$CONFIG_SITE"; then
+  # We do not want a PATH search for config.site.
+  case $CONFIG_SITE in #((
+    -*)  ac_site_file1=./$CONFIG_SITE;;
+    */*) ac_site_file1=$CONFIG_SITE;;
+    *)   ac_site_file1=./$CONFIG_SITE;;
+  esac
+elif test "x$prefix" != xNONE; then
+  ac_site_file1=$prefix/share/config.site
+  ac_site_file2=$prefix/etc/config.site
+else
+  ac_site_file1=$ac_default_prefix/share/config.site
+  ac_site_file2=$ac_default_prefix/etc/config.site
+fi
+for ac_site_file in "$ac_site_file1" "$ac_site_file2"
+do
+  test "x$ac_site_file" = xNONE && continue
+  if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5
+$as_echo "$as_me: loading site script $ac_site_file" >&6;}
+    sed 's/^/| /' "$ac_site_file" >&5
+    . "$ac_site_file" \
+      || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "failed to load site script $ac_site_file
+See \`config.log' for more details" "$LINENO" 5; }
+  fi
+done
+
+if test -r "$cache_file"; then
+  # Some versions of bash will fail to source /dev/null (special files
+  # actually), so we avoid doing that.  DJGPP emulates it as a regular file.
+  if test /dev/null != "$cache_file" && test -f "$cache_file"; then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5
+$as_echo "$as_me: loading cache $cache_file" >&6;}
+    case $cache_file in
+      [\\/]* | ?:[\\/]* ) . "$cache_file";;
+      *)                      . "./$cache_file";;
+    esac
+  fi
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5
+$as_echo "$as_me: creating cache $cache_file" >&6;}
+  >$cache_file
+fi
+
+# Check that the precious variables saved in the cache have kept the same
+# value.
+ac_cache_corrupted=false
+for ac_var in $ac_precious_vars; do
+  eval ac_old_set=\$ac_cv_env_${ac_var}_set
+  eval ac_new_set=\$ac_env_${ac_var}_set
+  eval ac_old_val=\$ac_cv_env_${ac_var}_value
+  eval ac_new_val=\$ac_env_${ac_var}_value
+  case $ac_old_set,$ac_new_set in
+    set,)
+      { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;}
+      ac_cache_corrupted=: ;;
+    ,set)
+      { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;}
+      ac_cache_corrupted=: ;;
+    ,);;
+    *)
+      if test "x$ac_old_val" != "x$ac_new_val"; then
+	# differences in whitespace do not lead to failure.
+	ac_old_val_w=`echo x $ac_old_val`
+	ac_new_val_w=`echo x $ac_new_val`
+	if test "$ac_old_val_w" != "$ac_new_val_w"; then
+	  { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5
+$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;}
+	  ac_cache_corrupted=:
+	else
+	  { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5
+$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;}
+	  eval $ac_var=\$ac_old_val
+	fi
+	{ $as_echo "$as_me:${as_lineno-$LINENO}:   former value:  \`$ac_old_val'" >&5
+$as_echo "$as_me:   former value:  \`$ac_old_val'" >&2;}
+	{ $as_echo "$as_me:${as_lineno-$LINENO}:   current value: \`$ac_new_val'" >&5
+$as_echo "$as_me:   current value: \`$ac_new_val'" >&2;}
+      fi;;
+  esac
+  # Pass precious variables to config.status.
+  if test "$ac_new_set" = set; then
+    case $ac_new_val in
+    *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;;
+    *) ac_arg=$ac_var=$ac_new_val ;;
+    esac
+    case " $ac_configure_args " in
+      *" '$ac_arg' "*) ;; # Avoid dups.  Use of quotes ensures accuracy.
+      *) as_fn_append ac_configure_args " '$ac_arg'" ;;
+    esac
+  fi
+done
+if $ac_cache_corrupted; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+  { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5
+$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;}
+  as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5
+fi
+## -------------------- ##
+## Main body of script. ##
+## -------------------- ##
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+
+
+VERSION="`cat VERSION`"
+PACKAGE=aprx
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5
+$as_echo_n "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; }
+set x ${MAKE-make}
+ac_make=`$as_echo "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'`
+if eval \${ac_cv_prog_make_${ac_make}_set+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat >conftest.make <<\_ACEOF
+SHELL = /bin/sh
+all:
+	@echo '@@@%%%=$(MAKE)=@@@%%%'
+_ACEOF
+# GNU make sometimes prints "make[1]: Entering ...", which would confuse us.
+case `${MAKE-make} -f conftest.make 2>/dev/null` in
+  *@@@%%%=?*=@@@%%%*)
+    eval ac_cv_prog_make_${ac_make}_set=yes;;
+  *)
+    eval ac_cv_prog_make_${ac_make}_set=no;;
+esac
+rm -f conftest.make
+fi
+if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+  SET_MAKE=
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+  SET_MAKE="MAKE=${MAKE-make}"
+fi
+
+
+ac_config_headers="$ac_config_headers config.h"
+
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}gcc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_CC="${ac_tool_prefix}gcc"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_CC"; then
+  ac_ct_CC=$CC
+  # Extract the first word of "gcc", so it can be a program name with args.
+set dummy gcc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_CC+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_CC"; then
+  ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_CC="gcc"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
+$as_echo "$ac_ct_CC" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_ct_CC" = x; then
+    CC=""
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    CC=$ac_ct_CC
+  fi
+else
+  CC="$ac_cv_prog_CC"
+fi
+
+if test -z "$CC"; then
+          if test -n "$ac_tool_prefix"; then
+    # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}cc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_CC="${ac_tool_prefix}cc"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+  fi
+fi
+if test -z "$CC"; then
+  # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+  ac_prog_rejected=no
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then
+       ac_prog_rejected=yes
+       continue
+     fi
+    ac_cv_prog_CC="cc"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+if test $ac_prog_rejected = yes; then
+  # We found a bogon in the path, so make sure we never use it.
+  set dummy $ac_cv_prog_CC
+  shift
+  if test $# != 0; then
+    # We chose a different compiler from the bogus one.
+    # However, it has the same basename, so the bogon will be chosen
+    # first if we set CC to just the basename; use the full file name.
+    shift
+    ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@"
+  fi
+fi
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$CC"; then
+  if test -n "$ac_tool_prefix"; then
+  for ac_prog in cl.exe
+  do
+    # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_CC="$ac_tool_prefix$ac_prog"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+    test -n "$CC" && break
+  done
+fi
+if test -z "$CC"; then
+  ac_ct_CC=$CC
+  for ac_prog in cl.exe
+do
+  # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_CC+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_CC"; then
+  ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_CC="$ac_prog"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
+$as_echo "$ac_ct_CC" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+  test -n "$ac_ct_CC" && break
+done
+
+  if test "x$ac_ct_CC" = x; then
+    CC=""
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    CC=$ac_ct_CC
+  fi
+fi
+
+fi
+
+
+test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "no acceptable C compiler found in \$PATH
+See \`config.log' for more details" "$LINENO" 5; }
+
+# Provide some information about the compiler.
+$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5
+set X $ac_compile
+ac_compiler=$2
+for ac_option in --version -v -V -qversion; do
+  { { ac_try="$ac_compiler $ac_option >&5"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_compiler $ac_option >&5") 2>conftest.err
+  ac_status=$?
+  if test -s conftest.err; then
+    sed '10a\
+... rest of stderr output deleted ...
+         10q' conftest.err >conftest.er1
+    cat conftest.er1 >&5
+  fi
+  rm -f conftest.er1 conftest.err
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }
+done
+
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out"
+# Try to create an executable without -o first, disregard a.out.
+# It will help us diagnose broken compilers, and finding out an intuition
+# of exeext.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5
+$as_echo_n "checking whether the C compiler works... " >&6; }
+ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'`
+
+# The possible output files:
+ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*"
+
+ac_rmfiles=
+for ac_file in $ac_files
+do
+  case $ac_file in
+    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;;
+    * ) ac_rmfiles="$ac_rmfiles $ac_file";;
+  esac
+done
+rm -f $ac_rmfiles
+
+if { { ac_try="$ac_link_default"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_link_default") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then :
+  # Autoconf-2.13 could set the ac_cv_exeext variable to `no'.
+# So ignore a value of `no', otherwise this would lead to `EXEEXT = no'
+# in a Makefile.  We should not override ac_cv_exeext if it was cached,
+# so that the user can short-circuit this test for compilers unknown to
+# Autoconf.
+for ac_file in $ac_files ''
+do
+  test -f "$ac_file" || continue
+  case $ac_file in
+    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj )
+	;;
+    [ab].out )
+	# We found the default executable, but exeext='' is most
+	# certainly right.
+	break;;
+    *.* )
+	if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no;
+	then :; else
+	   ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+	fi
+	# We set ac_cv_exeext here because the later test for it is not
+	# safe: cross compilers may not add the suffix if given an `-o'
+	# argument, so we may need to know it at that point already.
+	# Even if this section looks crufty: it has the advantage of
+	# actually working.
+	break;;
+    * )
+	break;;
+  esac
+done
+test "$ac_cv_exeext" = no && ac_cv_exeext=
+
+else
+  ac_file=''
+fi
+if test -z "$ac_file"; then :
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+$as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error 77 "C compiler cannot create executables
+See \`config.log' for more details" "$LINENO" 5; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5
+$as_echo_n "checking for C compiler default output file name... " >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5
+$as_echo "$ac_file" >&6; }
+ac_exeext=$ac_cv_exeext
+
+rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out
+ac_clean_files=$ac_clean_files_save
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5
+$as_echo_n "checking for suffix of executables... " >&6; }
+if { { ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_link") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then :
+  # If both `conftest.exe' and `conftest' are `present' (well, observable)
+# catch `conftest.exe'.  For instance with Cygwin, `ls conftest' will
+# work properly (i.e., refer to `conftest.exe'), while it won't with
+# `rm'.
+for ac_file in conftest.exe conftest conftest.*; do
+  test -f "$ac_file" || continue
+  case $ac_file in
+    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;;
+    *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+	  break;;
+    * ) break;;
+  esac
+done
+else
+  { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot compute suffix of executables: cannot compile and link
+See \`config.log' for more details" "$LINENO" 5; }
+fi
+rm -f conftest conftest$ac_cv_exeext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5
+$as_echo "$ac_cv_exeext" >&6; }
+
+rm -f conftest.$ac_ext
+EXEEXT=$ac_cv_exeext
+ac_exeext=$EXEEXT
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <stdio.h>
+int
+main ()
+{
+FILE *f = fopen ("conftest.out", "w");
+ return ferror (f) || fclose (f) != 0;
+
+  ;
+  return 0;
+}
+_ACEOF
+ac_clean_files="$ac_clean_files conftest.out"
+# Check that the compiler produces executables we can run.  If not, either
+# the compiler is broken, or we cross compile.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5
+$as_echo_n "checking whether we are cross compiling... " >&6; }
+if test "$cross_compiling" != yes; then
+  { { ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_link") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }
+  if { ac_try='./conftest$ac_cv_exeext'
+  { { case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_try") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; }; then
+    cross_compiling=no
+  else
+    if test "$cross_compiling" = maybe; then
+	cross_compiling=yes
+    else
+	{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot run C compiled programs.
+If you meant to cross compile, use \`--host'.
+See \`config.log' for more details" "$LINENO" 5; }
+    fi
+  fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5
+$as_echo "$cross_compiling" >&6; }
+
+rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out
+ac_clean_files=$ac_clean_files_save
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5
+$as_echo_n "checking for suffix of object files... " >&6; }
+if ${ac_cv_objext+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.o conftest.obj
+if { { ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_compile") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then :
+  for ac_file in conftest.o conftest.obj conftest.*; do
+  test -f "$ac_file" || continue;
+  case $ac_file in
+    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;;
+    *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'`
+       break;;
+  esac
+done
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot compute suffix of object files: cannot compile
+See \`config.log' for more details" "$LINENO" 5; }
+fi
+rm -f conftest.$ac_cv_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5
+$as_echo "$ac_cv_objext" >&6; }
+OBJEXT=$ac_cv_objext
+ac_objext=$OBJEXT
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5
+$as_echo_n "checking whether we are using the GNU C compiler... " >&6; }
+if ${ac_cv_c_compiler_gnu+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+#ifndef __GNUC__
+       choke me
+#endif
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_compiler_gnu=yes
+else
+  ac_compiler_gnu=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ac_cv_c_compiler_gnu=$ac_compiler_gnu
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5
+$as_echo "$ac_cv_c_compiler_gnu" >&6; }
+if test $ac_compiler_gnu = yes; then
+  GCC=yes
+else
+  GCC=
+fi
+ac_test_CFLAGS=${CFLAGS+set}
+ac_save_CFLAGS=$CFLAGS
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5
+$as_echo_n "checking whether $CC accepts -g... " >&6; }
+if ${ac_cv_prog_cc_g+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_save_c_werror_flag=$ac_c_werror_flag
+   ac_c_werror_flag=yes
+   ac_cv_prog_cc_g=no
+   CFLAGS="-g"
+   cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_prog_cc_g=yes
+else
+  CFLAGS=""
+      cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+else
+  ac_c_werror_flag=$ac_save_c_werror_flag
+	 CFLAGS="-g"
+	 cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_prog_cc_g=yes
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+   ac_c_werror_flag=$ac_save_c_werror_flag
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5
+$as_echo "$ac_cv_prog_cc_g" >&6; }
+if test "$ac_test_CFLAGS" = set; then
+  CFLAGS=$ac_save_CFLAGS
+elif test $ac_cv_prog_cc_g = yes; then
+  if test "$GCC" = yes; then
+    CFLAGS="-g -O2"
+  else
+    CFLAGS="-g"
+  fi
+else
+  if test "$GCC" = yes; then
+    CFLAGS="-O2"
+  else
+    CFLAGS=
+  fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5
+$as_echo_n "checking for $CC option to accept ISO C89... " >&6; }
+if ${ac_cv_prog_cc_c89+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_cv_prog_cc_c89=no
+ac_save_CC=$CC
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <stdarg.h>
+#include <stdio.h>
+struct stat;
+/* Most of the following tests are stolen from RCS 5.7's src/conf.sh.  */
+struct buf { int x; };
+FILE * (*rcsopen) (struct buf *, struct stat *, int);
+static char *e (p, i)
+     char **p;
+     int i;
+{
+  return p[i];
+}
+static char *f (char * (*g) (char **, int), char **p, ...)
+{
+  char *s;
+  va_list v;
+  va_start (v,p);
+  s = g (p, va_arg (v,int));
+  va_end (v);
+  return s;
+}
+
+/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default.  It has
+   function prototypes and stuff, but not '\xHH' hex character constants.
+   These don't provoke an error unfortunately, instead are silently treated
+   as 'x'.  The following induces an error, until -std is added to get
+   proper ANSI mode.  Curiously '\x00'!='x' always comes out true, for an
+   array size at least.  It's necessary to write '\x00'==0 to get something
+   that's true only with -std.  */
+int osf4_cc_array ['\x00' == 0 ? 1 : -1];
+
+/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters
+   inside strings and character constants.  */
+#define FOO(x) 'x'
+int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1];
+
+int test (int i, double x);
+struct s1 {int (*f) (int a);};
+struct s2 {int (*f) (double a);};
+int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int);
+int argc;
+char **argv;
+int
+main ()
+{
+return f (e, argv, 0) != argv[0]  ||  f (e, argv, 1) != argv[1];
+  ;
+  return 0;
+}
+_ACEOF
+for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \
+	-Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__"
+do
+  CC="$ac_save_CC $ac_arg"
+  if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_prog_cc_c89=$ac_arg
+fi
+rm -f core conftest.err conftest.$ac_objext
+  test "x$ac_cv_prog_cc_c89" != "xno" && break
+done
+rm -f conftest.$ac_ext
+CC=$ac_save_CC
+
+fi
+# AC_CACHE_VAL
+case "x$ac_cv_prog_cc_c89" in
+  x)
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5
+$as_echo "none needed" >&6; } ;;
+  xno)
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5
+$as_echo "unsupported" >&6; } ;;
+  *)
+    CC="$CC $ac_cv_prog_cc_c89"
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5
+$as_echo "$ac_cv_prog_cc_c89" >&6; } ;;
+esac
+if test "x$ac_cv_prog_cc_c89" != xno; then :
+
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5
+$as_echo_n "checking how to run the C preprocessor... " >&6; }
+# On Suns, sometimes $CPP names a directory.
+if test -n "$CPP" && test -d "$CPP"; then
+  CPP=
+fi
+if test -z "$CPP"; then
+  if ${ac_cv_prog_CPP+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+      # Double quotes because CPP needs to be expanded
+    for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp"
+    do
+      ac_preproc_ok=false
+for ac_c_preproc_warn_flag in '' yes
+do
+  # Use a header file that comes with gcc, so configuring glibc
+  # with a fresh cross-compiler works.
+  # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+  # <limits.h> exists even on freestanding compilers.
+  # On the NeXT, cc -E runs the code through the compiler's parser,
+  # not just through cpp. "Syntax error" is here to catch this case.
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+		     Syntax error
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+
+else
+  # Broken: fails on valid input.
+continue
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+  # OK, works on sane cases.  Now check whether nonexistent headers
+  # can be detected and how.
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <ac_nonexistent.h>
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+  # Broken: success on invalid input.
+continue
+else
+  # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.i conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then :
+  break
+fi
+
+    done
+    ac_cv_prog_CPP=$CPP
+
+fi
+  CPP=$ac_cv_prog_CPP
+else
+  ac_cv_prog_CPP=$CPP
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5
+$as_echo "$CPP" >&6; }
+ac_preproc_ok=false
+for ac_c_preproc_warn_flag in '' yes
+do
+  # Use a header file that comes with gcc, so configuring glibc
+  # with a fresh cross-compiler works.
+  # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+  # <limits.h> exists even on freestanding compilers.
+  # On the NeXT, cc -E runs the code through the compiler's parser,
+  # not just through cpp. "Syntax error" is here to catch this case.
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+		     Syntax error
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+
+else
+  # Broken: fails on valid input.
+continue
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+  # OK, works on sane cases.  Now check whether nonexistent headers
+  # can be detected and how.
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <ac_nonexistent.h>
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+  # Broken: success on invalid input.
+continue
+else
+  # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.i conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then :
+
+else
+  { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "C preprocessor \"$CPP\" fails sanity check
+See \`config.log' for more details" "$LINENO" 5; }
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5
+$as_echo_n "checking for grep that handles long lines and -e... " >&6; }
+if ${ac_cv_path_GREP+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -z "$GREP"; then
+  ac_path_GREP_found=false
+  # Loop through the user's path and test for each of PROGNAME-LIST
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_prog in grep ggrep; do
+    for ac_exec_ext in '' $ac_executable_extensions; do
+      ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext"
+      as_fn_executable_p "$ac_path_GREP" || continue
+# Check for GNU ac_path_GREP and select it if it is found.
+  # Check for GNU $ac_path_GREP
+case `"$ac_path_GREP" --version 2>&1` in
+*GNU*)
+  ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;;
+*)
+  ac_count=0
+  $as_echo_n 0123456789 >"conftest.in"
+  while :
+  do
+    cat "conftest.in" "conftest.in" >"conftest.tmp"
+    mv "conftest.tmp" "conftest.in"
+    cp "conftest.in" "conftest.nl"
+    $as_echo 'GREP' >> "conftest.nl"
+    "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break
+    diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+    as_fn_arith $ac_count + 1 && ac_count=$as_val
+    if test $ac_count -gt ${ac_path_GREP_max-0}; then
+      # Best one so far, save it but keep looking for a better one
+      ac_cv_path_GREP="$ac_path_GREP"
+      ac_path_GREP_max=$ac_count
+    fi
+    # 10*(2^10) chars as input seems more than enough
+    test $ac_count -gt 10 && break
+  done
+  rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+      $ac_path_GREP_found && break 3
+    done
+  done
+  done
+IFS=$as_save_IFS
+  if test -z "$ac_cv_path_GREP"; then
+    as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
+  fi
+else
+  ac_cv_path_GREP=$GREP
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5
+$as_echo "$ac_cv_path_GREP" >&6; }
+ GREP="$ac_cv_path_GREP"
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5
+$as_echo_n "checking for egrep... " >&6; }
+if ${ac_cv_path_EGREP+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if echo a | $GREP -E '(a|b)' >/dev/null 2>&1
+   then ac_cv_path_EGREP="$GREP -E"
+   else
+     if test -z "$EGREP"; then
+  ac_path_EGREP_found=false
+  # Loop through the user's path and test for each of PROGNAME-LIST
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_prog in egrep; do
+    for ac_exec_ext in '' $ac_executable_extensions; do
+      ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext"
+      as_fn_executable_p "$ac_path_EGREP" || continue
+# Check for GNU ac_path_EGREP and select it if it is found.
+  # Check for GNU $ac_path_EGREP
+case `"$ac_path_EGREP" --version 2>&1` in
+*GNU*)
+  ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;;
+*)
+  ac_count=0
+  $as_echo_n 0123456789 >"conftest.in"
+  while :
+  do
+    cat "conftest.in" "conftest.in" >"conftest.tmp"
+    mv "conftest.tmp" "conftest.in"
+    cp "conftest.in" "conftest.nl"
+    $as_echo 'EGREP' >> "conftest.nl"
+    "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break
+    diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+    as_fn_arith $ac_count + 1 && ac_count=$as_val
+    if test $ac_count -gt ${ac_path_EGREP_max-0}; then
+      # Best one so far, save it but keep looking for a better one
+      ac_cv_path_EGREP="$ac_path_EGREP"
+      ac_path_EGREP_max=$ac_count
+    fi
+    # 10*(2^10) chars as input seems more than enough
+    test $ac_count -gt 10 && break
+  done
+  rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+      $ac_path_EGREP_found && break 3
+    done
+  done
+  done
+IFS=$as_save_IFS
+  if test -z "$ac_cv_path_EGREP"; then
+    as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
+  fi
+else
+  ac_cv_path_EGREP=$EGREP
+fi
+
+   fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5
+$as_echo "$ac_cv_path_EGREP" >&6; }
+ EGREP="$ac_cv_path_EGREP"
+
+
+if test $ac_cv_c_compiler_gnu = yes; then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC needs -traditional" >&5
+$as_echo_n "checking whether $CC needs -traditional... " >&6; }
+if ${ac_cv_prog_gcc_traditional+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+    ac_pattern="Autoconf.*'x'"
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <sgtty.h>
+Autoconf TIOCGETP
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  $EGREP "$ac_pattern" >/dev/null 2>&1; then :
+  ac_cv_prog_gcc_traditional=yes
+else
+  ac_cv_prog_gcc_traditional=no
+fi
+rm -f conftest*
+
+
+  if test $ac_cv_prog_gcc_traditional = no; then
+    cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <termio.h>
+Autoconf TCGETA
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  $EGREP "$ac_pattern" >/dev/null 2>&1; then :
+  ac_cv_prog_gcc_traditional=yes
+fi
+rm -f conftest*
+
+  fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_gcc_traditional" >&5
+$as_echo "$ac_cv_prog_gcc_traditional" >&6; }
+  if test $ac_cv_prog_gcc_traditional = yes; then
+    CC="$CC -traditional"
+  fi
+fi
+
+
+if test -z "$LD" ; then
+  LD="$CC"
+fi
+LD="$LD"
+
+
+MACHINE="`uname -m`"
+if test "$MACHINE" == "i686" -o "$MACHINE" == "i386"; then
+  CFLAGS_ARCH="-march=i686"
+fi
+OS="`uname`"
+if test "$OS" == "Darwin"; then
+  CFLAGS_ARCH=""
+fi
+
+
+AX_CHECK_GNU_MAKE()
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5
+$as_echo_n "checking for ANSI C header files... " >&6; }
+if ${ac_cv_header_stdc+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <float.h>
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_header_stdc=yes
+else
+  ac_cv_header_stdc=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+if test $ac_cv_header_stdc = yes; then
+  # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <string.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  $EGREP "memchr" >/dev/null 2>&1; then :
+
+else
+  ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+  # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <stdlib.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  $EGREP "free" >/dev/null 2>&1; then :
+
+else
+  ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+  # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi.
+  if test "$cross_compiling" = yes; then :
+  :
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <ctype.h>
+#include <stdlib.h>
+#if ((' ' & 0x0FF) == 0x020)
+# define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
+# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))
+#else
+# define ISLOWER(c) \
+		   (('a' <= (c) && (c) <= 'i') \
+		     || ('j' <= (c) && (c) <= 'r') \
+		     || ('s' <= (c) && (c) <= 'z'))
+# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c))
+#endif
+
+#define XOR(e, f) (((e) && !(f)) || (!(e) && (f)))
+int
+main ()
+{
+  int i;
+  for (i = 0; i < 256; i++)
+    if (XOR (islower (i), ISLOWER (i))
+	|| toupper (i) != TOUPPER (i))
+      return 2;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+
+else
+  ac_cv_header_stdc=no
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+  conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5
+$as_echo "$ac_cv_header_stdc" >&6; }
+if test $ac_cv_header_stdc = yes; then
+
+$as_echo "#define STDC_HEADERS 1" >>confdefs.h
+
+fi
+
+# On IRIX 5.3, sys/types and inttypes.h are conflicting.
+for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \
+		  inttypes.h stdint.h unistd.h
+do :
+  as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
+ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default
+"
+if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
+  cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+for ac_header in time.h sys/time.h stdlib.h stddef.h stdint.h
+do :
+  as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
+ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default"
+if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
+  cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+for ac_header in string.h strings.h
+do :
+  as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
+ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default"
+if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
+  cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+for ac_header in pty.h
+do :
+  ac_fn_c_check_header_mongrel "$LINENO" "pty.h" "ac_cv_header_pty_h" "$ac_includes_default"
+if test "x$ac_cv_header_pty_h" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_PTY_H 1
+_ACEOF
+
+fi
+
+done
+
+for ac_header in pthread.h
+do :
+  ac_fn_c_check_header_mongrel "$LINENO" "pthread.h" "ac_cv_header_pthread_h" "$ac_includes_default"
+if test "x$ac_cv_header_pthread_h" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_PTHREAD_H 1
+_ACEOF
+
+fi
+
+done
+
+
+for ac_header in alloca.h
+do :
+  ac_fn_c_check_header_mongrel "$LINENO" "alloca.h" "ac_cv_header_alloca_h" "$ac_includes_default"
+if test "x$ac_cv_header_alloca_h" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_ALLOCA_H 1
+_ACEOF
+ $as_echo "#define HAVE_ALLOCA_H 1" >>confdefs.h
+
+fi
+
+done
+
+for ac_header in poll.h
+do :
+  ac_fn_c_check_header_mongrel "$LINENO" "poll.h" "ac_cv_header_poll_h" "$ac_includes_default"
+if test "x$ac_cv_header_poll_h" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_POLL_H 1
+_ACEOF
+ $as_echo "#define HAVE_POLL_H 1" >>confdefs.h
+
+fi
+
+done
+
+for ac_header in sys/epoll.h
+do :
+  ac_fn_c_check_header_mongrel "$LINENO" "sys/epoll.h" "ac_cv_header_sys_epoll_h" "$ac_includes_default"
+if test "x$ac_cv_header_sys_epoll_h" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_SYS_EPOLL_H 1
+_ACEOF
+ $as_echo "#define HAVE_SYS_EPOLL_H 1" >>confdefs.h
+
+fi
+
+done
+
+
+for ac_header in netinet/sctp.h
+do :
+  ac_fn_c_check_header_mongrel "$LINENO" "netinet/sctp.h" "ac_cv_header_netinet_sctp_h" "$ac_includes_default"
+if test "x$ac_cv_header_netinet_sctp_h" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_NETINET_SCTP_H 1
+_ACEOF
+ $as_echo "#define HAVE_NETINET_SCTP_H 1" >>confdefs.h
+
+fi
+
+done
+
+
+
+
+for ac_header in stdarg.h varargs.h sys/wait.h
+do :
+  as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
+ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default"
+if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
+  cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+for ac_func in vprintf
+do :
+  ac_fn_c_check_func "$LINENO" "vprintf" "ac_cv_func_vprintf"
+if test "x$ac_cv_func_vprintf" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_VPRINTF 1
+_ACEOF
+
+ac_fn_c_check_func "$LINENO" "_doprnt" "ac_cv_func__doprnt"
+if test "x$ac_cv_func__doprnt" = xyes; then :
+
+$as_echo "#define HAVE_DOPRNT 1" >>confdefs.h
+
+fi
+
+fi
+done
+
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: ** Using C compiler: $CC" >&5
+$as_echo "** Using C compiler: $CC" >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: ** Using CFLAGS:     $CFLAGS" >&5
+$as_echo "** Using CFLAGS:     $CFLAGS" >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: ** Using CPPDEP:     $CPPDEP" >&5
+$as_echo "** Using CPPDEP:     $CPPDEP" >&6; }
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether byte ordering is bigendian" >&5
+$as_echo_n "checking whether byte ordering is bigendian... " >&6; }
+if ${ac_cv_c_bigendian+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_cv_c_bigendian=unknown
+    # See if we're dealing with a universal compiler.
+    cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#ifndef __APPLE_CC__
+	       not a universal capable compiler
+	     #endif
+	     typedef int dummy;
+
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+	# Check for potential -arch flags.  It is not universal unless
+	# there are at least two -arch flags with different values.
+	ac_arch=
+	ac_prev=
+	for ac_word in $CC $CFLAGS $CPPFLAGS $LDFLAGS; do
+	 if test -n "$ac_prev"; then
+	   case $ac_word in
+	     i?86 | x86_64 | ppc | ppc64)
+	       if test -z "$ac_arch" || test "$ac_arch" = "$ac_word"; then
+		 ac_arch=$ac_word
+	       else
+		 ac_cv_c_bigendian=universal
+		 break
+	       fi
+	       ;;
+	   esac
+	   ac_prev=
+	 elif test "x$ac_word" = "x-arch"; then
+	   ac_prev=arch
+	 fi
+       done
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+    if test $ac_cv_c_bigendian = unknown; then
+      # See if sys/param.h defines the BYTE_ORDER macro.
+      cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <sys/types.h>
+	     #include <sys/param.h>
+
+int
+main ()
+{
+#if ! (defined BYTE_ORDER && defined BIG_ENDIAN \
+		     && defined LITTLE_ENDIAN && BYTE_ORDER && BIG_ENDIAN \
+		     && LITTLE_ENDIAN)
+	      bogus endian macros
+	     #endif
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  # It does; now see whether it defined to BIG_ENDIAN or not.
+	 cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <sys/types.h>
+		#include <sys/param.h>
+
+int
+main ()
+{
+#if BYTE_ORDER != BIG_ENDIAN
+		 not big endian
+		#endif
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_c_bigendian=yes
+else
+  ac_cv_c_bigendian=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+    fi
+    if test $ac_cv_c_bigendian = unknown; then
+      # See if <limits.h> defines _LITTLE_ENDIAN or _BIG_ENDIAN (e.g., Solaris).
+      cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <limits.h>
+
+int
+main ()
+{
+#if ! (defined _LITTLE_ENDIAN || defined _BIG_ENDIAN)
+	      bogus endian macros
+	     #endif
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  # It does; now see whether it defined to _BIG_ENDIAN or not.
+	 cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <limits.h>
+
+int
+main ()
+{
+#ifndef _BIG_ENDIAN
+		 not big endian
+		#endif
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_c_bigendian=yes
+else
+  ac_cv_c_bigendian=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+    fi
+    if test $ac_cv_c_bigendian = unknown; then
+      # Compile a test program.
+      if test "$cross_compiling" = yes; then :
+  # Try to guess by grepping values from an object file.
+	 cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+short int ascii_mm[] =
+		  { 0x4249, 0x4765, 0x6E44, 0x6961, 0x6E53, 0x7953, 0 };
+		short int ascii_ii[] =
+		  { 0x694C, 0x5454, 0x656C, 0x6E45, 0x6944, 0x6E61, 0 };
+		int use_ascii (int i) {
+		  return ascii_mm[i] + ascii_ii[i];
+		}
+		short int ebcdic_ii[] =
+		  { 0x89D3, 0xE3E3, 0x8593, 0x95C5, 0x89C4, 0x9581, 0 };
+		short int ebcdic_mm[] =
+		  { 0xC2C9, 0xC785, 0x95C4, 0x8981, 0x95E2, 0xA8E2, 0 };
+		int use_ebcdic (int i) {
+		  return ebcdic_mm[i] + ebcdic_ii[i];
+		}
+		extern int foo;
+
+int
+main ()
+{
+return use_ascii (foo) == use_ebcdic (foo);
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  if grep BIGenDianSyS conftest.$ac_objext >/dev/null; then
+	      ac_cv_c_bigendian=yes
+	    fi
+	    if grep LiTTleEnDian conftest.$ac_objext >/dev/null ; then
+	      if test "$ac_cv_c_bigendian" = unknown; then
+		ac_cv_c_bigendian=no
+	      else
+		# finding both strings is unlikely to happen, but who knows?
+		ac_cv_c_bigendian=unknown
+	      fi
+	    fi
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+$ac_includes_default
+int
+main ()
+{
+
+	     /* Are we little or big endian?  From Harbison&Steele.  */
+	     union
+	     {
+	       long int l;
+	       char c[sizeof (long int)];
+	     } u;
+	     u.l = 1;
+	     return u.c[sizeof (long int) - 1] == 1;
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+  ac_cv_c_bigendian=no
+else
+  ac_cv_c_bigendian=yes
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+  conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+    fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_bigendian" >&5
+$as_echo "$ac_cv_c_bigendian" >&6; }
+ case $ac_cv_c_bigendian in #(
+   yes)
+     $as_echo "#define WORDS_BIGENDIAN 1" >>confdefs.h
+;; #(
+   no)
+      ;; #(
+   universal)
+
+$as_echo "#define AC_APPLE_UNIVERSAL_BUILD 1" >>confdefs.h
+
+     ;; #(
+   *)
+     as_fn_error $? "unknown endianness
+ presetting ac_cv_c_bigendian=no (or yes) will help" "$LINENO" 5 ;;
+ esac
+
+# The cast to long int works around a bug in the HP C Compiler
+# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects
+# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'.
+# This bug is HP SR number 8606223364.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of void *" >&5
+$as_echo_n "checking size of void *... " >&6; }
+if ${ac_cv_sizeof_void_p+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (void *))" "ac_cv_sizeof_void_p"        "$ac_includes_default"; then :
+
+else
+  if test "$ac_cv_type_void_p" = yes; then
+     { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error 77 "cannot compute sizeof (void *)
+See \`config.log' for more details" "$LINENO" 5; }
+   else
+     ac_cv_sizeof_void_p=0
+   fi
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_void_p" >&5
+$as_echo "$ac_cv_sizeof_void_p" >&6; }
+
+
+
+cat >>confdefs.h <<_ACEOF
+#define SIZEOF_VOID_P $ac_cv_sizeof_void_p
+_ACEOF
+
+
+# The cast to long int works around a bug in the HP C Compiler
+# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects
+# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'.
+# This bug is HP SR number 8606223364.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of short" >&5
+$as_echo_n "checking size of short... " >&6; }
+if ${ac_cv_sizeof_short+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (short))" "ac_cv_sizeof_short"        "$ac_includes_default"; then :
+
+else
+  if test "$ac_cv_type_short" = yes; then
+     { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error 77 "cannot compute sizeof (short)
+See \`config.log' for more details" "$LINENO" 5; }
+   else
+     ac_cv_sizeof_short=0
+   fi
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_short" >&5
+$as_echo "$ac_cv_sizeof_short" >&6; }
+
+
+
+cat >>confdefs.h <<_ACEOF
+#define SIZEOF_SHORT $ac_cv_sizeof_short
+_ACEOF
+
+
+# The cast to long int works around a bug in the HP C Compiler
+# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects
+# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'.
+# This bug is HP SR number 8606223364.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of int" >&5
+$as_echo_n "checking size of int... " >&6; }
+if ${ac_cv_sizeof_int+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (int))" "ac_cv_sizeof_int"        "$ac_includes_default"; then :
+
+else
+  if test "$ac_cv_type_int" = yes; then
+     { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error 77 "cannot compute sizeof (int)
+See \`config.log' for more details" "$LINENO" 5; }
+   else
+     ac_cv_sizeof_int=0
+   fi
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_int" >&5
+$as_echo "$ac_cv_sizeof_int" >&6; }
+
+
+
+cat >>confdefs.h <<_ACEOF
+#define SIZEOF_INT $ac_cv_sizeof_int
+_ACEOF
+
+
+# The cast to long int works around a bug in the HP C Compiler
+# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects
+# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'.
+# This bug is HP SR number 8606223364.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of long" >&5
+$as_echo_n "checking size of long... " >&6; }
+if ${ac_cv_sizeof_long+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (long))" "ac_cv_sizeof_long"        "$ac_includes_default"; then :
+
+else
+  if test "$ac_cv_type_long" = yes; then
+     { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error 77 "cannot compute sizeof (long)
+See \`config.log' for more details" "$LINENO" 5; }
+   else
+     ac_cv_sizeof_long=0
+   fi
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_long" >&5
+$as_echo "$ac_cv_sizeof_long" >&6; }
+
+
+
+cat >>confdefs.h <<_ACEOF
+#define SIZEOF_LONG $ac_cv_sizeof_long
+_ACEOF
+
+
+# The cast to long int works around a bug in the HP C Compiler
+# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects
+# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'.
+# This bug is HP SR number 8606223364.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of double" >&5
+$as_echo_n "checking size of double... " >&6; }
+if ${ac_cv_sizeof_double+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (double))" "ac_cv_sizeof_double"        "$ac_includes_default"; then :
+
+else
+  if test "$ac_cv_type_double" = yes; then
+     { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error 77 "cannot compute sizeof (double)
+See \`config.log' for more details" "$LINENO" 5; }
+   else
+     ac_cv_sizeof_double=0
+   fi
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_double" >&5
+$as_echo "$ac_cv_sizeof_double" >&6; }
+
+
+
+cat >>confdefs.h <<_ACEOF
+#define SIZEOF_DOUBLE $ac_cv_sizeof_double
+_ACEOF
+
+
+
+
+cat >>confdefs.h <<_ACEOF
+#define CONFIGURE_CMD "CC='$CC' CFLAGS='$CFLAGS' $0 $ac_configure_args"
+_ACEOF
+
+
+
+
+for ac_func in atan2f
+do :
+  ac_fn_c_check_func "$LINENO" "atan2f" "ac_cv_func_atan2f"
+if test "x$ac_cv_func_atan2f" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_ATAN2F 1
+_ACEOF
+
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for atan2f in -lm" >&5
+$as_echo_n "checking for atan2f in -lm... " >&6; }
+if ${ac_cv_lib_m_atan2f+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lm  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char atan2f ();
+int
+main ()
+{
+return atan2f ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_m_atan2f=yes
+else
+  ac_cv_lib_m_atan2f=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_m_atan2f" >&5
+$as_echo "$ac_cv_lib_m_atan2f" >&6; }
+if test "x$ac_cv_lib_m_atan2f" = xyes; then :
+  LIBM="-lm"
+fi
+
+fi
+done
+
+
+for ac_func in memchr memrchr gettimeofday
+do :
+  as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
+ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
+if eval test \"x\$"$as_ac_var"\" = x"yes"; then :
+  cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+done
+
+
+for ac_func in openpty
+do :
+  ac_fn_c_check_func "$LINENO" "openpty" "ac_cv_func_openpty"
+if test "x$ac_cv_func_openpty" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_OPENPTY 1
+_ACEOF
+
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for openpty in -lutil" >&5
+$as_echo_n "checking for openpty in -lutil... " >&6; }
+if ${ac_cv_lib_util_openpty+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lutil  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char openpty ();
+int
+main ()
+{
+return openpty ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_util_openpty=yes
+else
+  ac_cv_lib_util_openpty=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_util_openpty" >&5
+$as_echo "$ac_cv_lib_util_openpty" >&6; }
+if test "x$ac_cv_lib_util_openpty" = xyes; then :
+  $as_echo "#define HAVE_OPENPTY 1" >>confdefs.h
+ LIBS="$LIBS -lutil"
+fi
+
+fi
+done
+
+
+
+
+$as_echo "#define EMBEDDED 1" >>confdefs.h
+
+
+
+# Check whether --with-embedded was given.
+if test "${with_embedded+set}" = set; then :
+  withval=$with_embedded;
+$as_echo "#define EMBEDDED 1" >>confdefs.h
+ EMBEDDED=1
+fi
+
+
+
+# Check whether --with-erlangstorage was given.
+if test "${with_erlangstorage+set}" = set; then :
+  withval=$with_erlangstorage;
+$as_echo "#define ERLANGSTORAGE 1" >>confdefs.h
+ ERLANGSTORAGE=1
+fi
+
+
+# Check whether --enable-igate was given.
+if test "${enable_igate+set}" = set; then :
+  enableval=$enable_igate; if test "${enable_igate}" = no ; then
+
+$as_echo "#define DISABLE_IGATE 1" >>confdefs.h
+
+fi
+fi
+
+
+# Check whether --enable-agwpe was given.
+if test "${enable_agwpe+set}" = set; then :
+  enableval=$enable_agwpe; if test "${enable_agwpe}" != no ; then
+
+$as_echo "#define ENABLE_AGWPE 1" >>confdefs.h
+
+fi
+fi
+
+
+
+
+# Check whether --with-pthread was given.
+if test "${with_pthread+set}" = set; then :
+  withval=$with_pthread;
+$as_echo "#define DISABLE_PTHREAD 1" >>confdefs.h
+ DISABLE_PTHREAD=1
+else
+
+$as_echo "#define ENABLE_PTHREAD 1" >>confdefs.h
+ ENABLE_PTHREAD=1
+fi
+
+
+# Check whether --with-pthreads was given.
+if test "${with_pthreads+set}" = set; then :
+  withval=$with_pthreads;
+$as_echo "#define ENABLE_PTHREAD 1" >>confdefs.h
+ ENABLE_PTHREAD=1
+fi
+
+
+
+
+if test "${ENABLE_PTHREAD}" = "1" ; then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: The --without-pthread option is not set, looking for pthread_create() function." >&5
+$as_echo "The --without-pthread option is not set, looking for pthread_create() function." >&6; }
+    have_pthread=no
+    if test $have_pthread = no; then
+       t_oldLibs="$LIBS"
+       LIBS="$LIBS -pthread"
+       t_oldCflags="$CFLAGS"
+       CFLAGS="$CFLAGS -pthread"
+    cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <pthread.h>
+int
+main ()
+{
+pthread_t pt;
+pthread_attr_t pat;
+int rc = pthread_create(&pt, &pat, NULL, NULL)
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  have_pthread=yes;{ $as_echo "$as_me:${as_lineno-$LINENO}: result: Have pthread_create()" >&5
+$as_echo "Have pthread_create()" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: Not have pthread_create()" >&5
+$as_echo "Not have pthread_create()" >&6; }
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+       if test $have_pthread = no ; then
+          { $as_echo "$as_me:${as_lineno-$LINENO}: result: Failure at HAVE_PTHREAD_CREATE" >&5
+$as_echo "Failure at HAVE_PTHREAD_CREATE" >&6; }
+       else
+
+$as_echo "#define HAVE_PTHREAD_CREATE 1" >>confdefs.h
+
+          { $as_echo "$as_me:${as_lineno-$LINENO}: result: Success at HAVE_PTHREAD_CREATE" >&5
+$as_echo "Success at HAVE_PTHREAD_CREATE" >&6; }
+          LIBPTHREAD="-pthread"
+          CCPTHREAD="-pthread"
+       fi
+       LIBS="$t_oldLibs"
+       CFLAGS="$t_oldCflags"
+    fi
+    if test $have_pthread = no; then
+       { $as_echo "$as_me:${as_lineno-$LINENO}: result: Failure at HAVE_PTHREAD_CREATE, trying second way." >&5
+$as_echo "Failure at HAVE_PTHREAD_CREATE, trying second way." >&6; }
+       t_oldLibs="$LIBS"
+       LIBS="$LIBS -lpthread"
+    cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <pthread.h>
+int
+main ()
+{
+pthread_t pt;
+pthread_attr_t pat;
+int rc = pthread_create(&pt, &pat, NULL, NULL)
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  have_pthread=yes;{ $as_echo "$as_me:${as_lineno-$LINENO}: result: Have pthread_create()" >&5
+$as_echo "Have pthread_create()" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: Not have pthread_create()" >&5
+$as_echo "Not have pthread_create()" >&6; }
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+       if test $have_pthread = no ; then
+          { $as_echo "$as_me:${as_lineno-$LINENO}: result: Failure at HAVE_PTHREAD_CREATE" >&5
+$as_echo "Failure at HAVE_PTHREAD_CREATE" >&6; }
+       else
+
+$as_echo "#define HAVE_PTHREAD_CREATE 1" >>confdefs.h
+
+          { $as_echo "$as_me:${as_lineno-$LINENO}: result: Success at HAVE_PTHREAD_CREATE" >&5
+$as_echo "Success at HAVE_PTHREAD_CREATE" >&6; }
+          LIBPTHREAD="-lpthread"
+          CCPTHREAD=""
+       fi
+       LIBS="$t_oldLibs"
+       CFLAGS="$t_oldCflags"
+    fi
+    if test $have_pthread = no; then
+       { $as_echo "$as_me:${as_lineno-$LINENO}: result: Still failure at HAVE_PTHREAD_CREATE, Run out of ways to set it up." >&5
+$as_echo "Still failure at HAVE_PTHREAD_CREATE, Run out of ways to set it up." >&6; }
+    fi
+fi
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing clock_gettime" >&5
+$as_echo_n "checking for library containing clock_gettime... " >&6; }
+if ${ac_cv_search_clock_gettime+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_func_search_save_LIBS=$LIBS
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char clock_gettime ();
+int
+main ()
+{
+return clock_gettime ();
+  ;
+  return 0;
+}
+_ACEOF
+for ac_lib in '' rt; do
+  if test -z "$ac_lib"; then
+    ac_res="none required"
+  else
+    ac_res=-l$ac_lib
+    LIBS="-l$ac_lib  $ac_func_search_save_LIBS"
+  fi
+  if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_search_clock_gettime=$ac_res
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext
+  if ${ac_cv_search_clock_gettime+:} false; then :
+  break
+fi
+done
+if ${ac_cv_search_clock_gettime+:} false; then :
+
+else
+  ac_cv_search_clock_gettime=no
+fi
+rm conftest.$ac_ext
+LIBS=$ac_func_search_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_clock_gettime" >&5
+$as_echo "$ac_cv_search_clock_gettime" >&6; }
+ac_res=$ac_cv_search_clock_gettime
+if test "$ac_res" != no; then :
+  test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
+
+
+$as_echo "#define HAVE_CLOCK_GETTIME 1" >>confdefs.h
+
+
+fi
+
+
+if test "$ac_cv_search_clock_gettime" = "-lrt"; then
+  LIBRT="-lrt"
+fi
+
+
+for ac_func in getaddrinfo
+do :
+  ac_fn_c_check_func "$LINENO" "getaddrinfo" "ac_cv_func_getaddrinfo"
+if test "x$ac_cv_func_getaddrinfo" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_GETADDRINFO 1
+_ACEOF
+
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for getaddrinfo in -lnsl" >&5
+$as_echo_n "checking for getaddrinfo in -lnsl... " >&6; }
+if ${ac_cv_lib_nsl_getaddrinfo+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lnsl  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char getaddrinfo ();
+int
+main ()
+{
+return getaddrinfo ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_nsl_getaddrinfo=yes
+else
+  ac_cv_lib_nsl_getaddrinfo=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_nsl_getaddrinfo" >&5
+$as_echo "$ac_cv_lib_nsl_getaddrinfo" >&6; }
+if test "x$ac_cv_lib_nsl_getaddrinfo" = xyes; then :
+  LIBGETADDRINFO="-lnsl"
+fi
+
+fi
+done
+
+
+
+#
+#  We check for various libraries
+#  - SysVr4 style of "-lsocket" at first (unless in libc)
+#    The hallmark is  connect()  routine (we presume)
+#
+ac_cv_libsocket_both=1
+ac_fn_c_check_func "$LINENO" "connect" "ac_cv_func_connect"
+if test "x$ac_cv_func_connect" = xyes; then :
+  ac_cv_libsocket_both=0
+fi
+
+ac_fn_c_check_func "$LINENO" "gethostbyname" "ac_cv_func_gethostbyname"
+if test "x$ac_cv_func_gethostbyname" = xyes; then :
+  ac_cv_libsocket_both=0
+fi
+
+if test "$ac_cv_libsocket_both" = 1 ; then
+  # Check cache
+  if test "$ac_cv_func_socket_lxnet" = yes ; then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: need -lxnet library (cached)" >&5
+$as_echo "need -lxnet library (cached)" >&6; }
+    LIBSOCKET="-lnsl -lsocket -lxnet"
+  else
+  if test "$ac_cv_func_socket_lsocket" = yes ; then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: need -lsocket library (cached)" >&5
+$as_echo "need -lsocket library (cached)" >&6; }
+    LIBSOCKET="-lsocket"
+    if test "$ac_cv_func_gethostbyname_lnsl" = yes ; then
+        LIBSOCKET="-lnsl -lsocket"
+    fi
+  else
+    # Well, will this work ?  SysVR4, but not Sun Solaris ?
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for connect in -lxnet" >&5
+$as_echo_n "checking for connect in -lxnet... " >&6; }
+if ${ac_cv_lib_xnet_connect+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lxnet  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char connect ();
+int
+main ()
+{
+return connect ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_xnet_connect=yes
+else
+  ac_cv_lib_xnet_connect=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_xnet_connect" >&5
+$as_echo "$ac_cv_lib_xnet_connect" >&6; }
+if test "x$ac_cv_lib_xnet_connect" = xyes; then :
+  LIBSOCKET="-lnsl -lsocket -lxnet"
+                                 ac_cv_func_socket_lsocket=no
+                                 ac_cv_func_socket_lxnet=yes
+else
+
+      { $as_echo "$as_me:${as_lineno-$LINENO}: checking for connect in -lsocket" >&5
+$as_echo_n "checking for connect in -lsocket... " >&6; }
+if ${ac_cv_lib_socket_connect+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lsocket  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char connect ();
+int
+main ()
+{
+return connect ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_socket_connect=yes
+else
+  ac_cv_lib_socket_connect=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_socket_connect" >&5
+$as_echo "$ac_cv_lib_socket_connect" >&6; }
+if test "x$ac_cv_lib_socket_connect" = xyes; then :
+  LIBSOCKET="-lsocket"
+                                     ac_cv_func_socket_lsocket=yes
+else
+  ac_cv_func_socket_lsocket=no
+fi
+
+      if test "$ac_cv_func_socket_lsocket" = yes ; then
+        t_oldLibs="$LIBS"
+        LIBS="$LIBS -lsocket $LIBRESOLV"
+        cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+gethostbyname();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+else
+
+          LIBS="$LIBS -lnsl" # Add this Solaris library..
+          cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+gethostbyname();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+                        LIBSOCKET="-lsocket -lnsl"
+                        ac_cv_func_gethostbyname_lnsl=yes
+
+else
+
+                   as_fn_error $? "Weird, '$LIBS' not enough to find  gethostnyname() ?!" "$LINENO" 5
+
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+        LIBS="$t_oldLibs"
+      fi
+
+fi
+
+  fi
+  fi
+fi
+
+if test "x$LIBRESOLV" = "x"; then
+  # Ok, No  -lresolv,  is this enough for the  _res  to appear ?
+  t_oldLibs="$LIBS"
+  LIBS="$LIBS $LIBSOCKET"
+  ac_cv_var__res_options=no
+  # This following is for IRIX6.4, and I sincerely hope it
+  # will not fail on other systems...  It did! It did!
+  # Many systems don't have idemponent headers, they need specific
+  # includes before latter ones, or the latter ones won't be successful...
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <resolv.h>
+int
+main ()
+{
+_res.options = RES_INIT;
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_var__res_options=yes
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext;
+  if test "$ac_cv_var__res_options" != "yes"; then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: Can't do without  -lresolv  to link resolver's  _res.options" >&5
+$as_echo "Can't do without  -lresolv  to link resolver's  _res.options" >&6; }
+    LIBS="$LIBS -lresolv"
+  fi
+  LIBS="$t_oldLibs"
+fi
+
+# See about the routines that possibly exist at the libraries..
+LIBS="$t_oldLibs $LIBSOCKET"
+for ac_func in socket socketpair
+do :
+  as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
+ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
+if eval test \"x\$"$as_ac_var"\" = x"yes"; then :
+  cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+done
+
+LIBS="$t_oldLibs"
+
+if test "$ac_cv_func_socket" = no -a "$LIBSOCKET" != ""; then
+  LIBS="$LIBS $LIBSOCKET"
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+socket();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_func_socket=yes
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+  if test $ac_cv_func_socket = yes; then
+    $as_echo "#define HAVE_SOCKET 1" >>confdefs.h
+
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: Has  socket()  when using  $LIBSOCKET" >&5
+$as_echo "Has  socket()  when using  $LIBSOCKET" >&6; }
+  fi
+  LIBS="$t_oldLibs"
+fi
+if test "$ac_cv_func_socketpair" = no -a "$LIBSOCKET" != ""; then
+  LIBS="$LIBS $LIBSOCKET"
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+socketpair();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_func_socketpair=yes
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+  if test $ac_cv_func_socketpair = yes; then
+    $as_echo "#define HAVE_SOCKETPAIR 1" >>confdefs.h
+
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: Has  socketpair()  when using  $LIBSOCKET" >&5
+$as_echo "Has  socketpair()  when using  $LIBSOCKET" >&6; }
+  fi
+  LIBS="$t_oldLibs"
+fi
+
+
+# Check whether --with-openssl was given.
+if test "${with_openssl+set}" = set; then :
+  withval=$with_openssl; with_openssl=$withval
+else
+  with_openssl=no
+fi
+
+
+
+if test "$with_openssl" != "no" ; then
+  for ac_header in openssl/ssl.h
+do :
+  ac_fn_c_check_header_mongrel "$LINENO" "openssl/ssl.h" "ac_cv_header_openssl_ssl_h" "$ac_includes_default"
+if test "x$ac_cv_header_openssl_ssl_h" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_OPENSSL_SSL_H 1
+_ACEOF
+
+fi
+
+done
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing TLSv1_server_method" >&5
+$as_echo_n "checking for library containing TLSv1_server_method... " >&6; }
+if ${ac_cv_search_TLSv1_server_method+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_func_search_save_LIBS=$LIBS
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char TLSv1_server_method ();
+int
+main ()
+{
+return TLSv1_server_method ();
+  ;
+  return 0;
+}
+_ACEOF
+for ac_lib in '' ssl; do
+  if test -z "$ac_lib"; then
+    ac_res="none required"
+  else
+    ac_res=-l$ac_lib
+    LIBS="-l$ac_lib  $ac_func_search_save_LIBS"
+  fi
+  if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_search_TLSv1_server_method=$ac_res
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext
+  if ${ac_cv_search_TLSv1_server_method+:} false; then :
+  break
+fi
+done
+if ${ac_cv_search_TLSv1_server_method+:} false; then :
+
+else
+  ac_cv_search_TLSv1_server_method=no
+fi
+rm conftest.$ac_ext
+LIBS=$ac_func_search_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_TLSv1_server_method" >&5
+$as_echo "$ac_cv_search_TLSv1_server_method" >&6; }
+ac_res=$ac_cv_search_TLSv1_server_method
+if test "$ac_res" != no; then :
+  test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
+
+$as_echo "#define HAVE_TLSV1_SERVER_METHOD 1" >>confdefs.h
+
+fi
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing X509_free" >&5
+$as_echo_n "checking for library containing X509_free... " >&6; }
+if ${ac_cv_search_X509_free+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_func_search_save_LIBS=$LIBS
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char X509_free ();
+int
+main ()
+{
+return X509_free ();
+  ;
+  return 0;
+}
+_ACEOF
+for ac_lib in '' crypto; do
+  if test -z "$ac_lib"; then
+    ac_res="none required"
+  else
+    ac_res=-l$ac_lib
+    LIBS="-l$ac_lib  $ac_func_search_save_LIBS"
+  fi
+  if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_search_X509_free=$ac_res
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext
+  if ${ac_cv_search_X509_free+:} false; then :
+  break
+fi
+done
+if ${ac_cv_search_X509_free+:} false; then :
+
+else
+  ac_cv_search_X509_free=no
+fi
+rm conftest.$ac_ext
+LIBS=$ac_func_search_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_X509_free" >&5
+$as_echo "$ac_cv_search_X509_free" >&6; }
+ac_res=$ac_cv_search_X509_free
+if test "$ac_res" != no; then :
+  test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
+
+$as_echo "#define HAVE_X509_FREE 1" >>confdefs.h
+
+fi
+
+
+  if test "$ac_cv_search_TLSv1_server_method" = "-lssl"; then
+    LIBSSL="-lssl"
+  fi
+  if test "$ac_cv_search_X509_free" = "-lcrypto"; then
+    LIBCRYPTO="-lcrypto"
+  fi
+fi
+
+t_vers="`cat VERSION`"
+VERSION_STRING="`cat VERSION`"
+
+t_vers="`cat SVNVERSION`"
+SVNVERSION_STRING="$t_vers"
+
+
+ac_config_files="$ac_config_files Makefile"
+
+cat >confcache <<\_ACEOF
+# This file is a shell script that caches the results of configure
+# tests run on this system so they can be shared between configure
+# scripts and configure runs, see configure's option --config-cache.
+# It is not useful on other systems.  If it contains results you don't
+# want to keep, you may remove or edit it.
+#
+# config.status only pays attention to the cache file if you give it
+# the --recheck option to rerun configure.
+#
+# `ac_cv_env_foo' variables (set or unset) will be overridden when
+# loading this file, other *unset* `ac_cv_foo' will be assigned the
+# following values.
+
+_ACEOF
+
+# The following way of writing the cache mishandles newlines in values,
+# but we know of no workaround that is simple, portable, and efficient.
+# So, we kill variables containing newlines.
+# Ultrix sh set writes to stderr and can't be redirected directly,
+# and sets the high bit in the cache file unless we assign to the vars.
+(
+  for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do
+    eval ac_val=\$$ac_var
+    case $ac_val in #(
+    *${as_nl}*)
+      case $ac_var in #(
+      *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+      esac
+      case $ac_var in #(
+      _ | IFS | as_nl) ;; #(
+      BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
+      *) { eval $ac_var=; unset $ac_var;} ;;
+      esac ;;
+    esac
+  done
+
+  (set) 2>&1 |
+    case $as_nl`(ac_space=' '; set) 2>&1` in #(
+    *${as_nl}ac_space=\ *)
+      # `set' does not quote correctly, so add quotes: double-quote
+      # substitution turns \\\\ into \\, and sed turns \\ into \.
+      sed -n \
+	"s/'/'\\\\''/g;
+	  s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p"
+      ;; #(
+    *)
+      # `set' quotes correctly as required by POSIX, so do not add quotes.
+      sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+      ;;
+    esac |
+    sort
+) |
+  sed '
+     /^ac_cv_env_/b end
+     t clear
+     :clear
+     s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/
+     t end
+     s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/
+     :end' >>confcache
+if diff "$cache_file" confcache >/dev/null 2>&1; then :; else
+  if test -w "$cache_file"; then
+    if test "x$cache_file" != "x/dev/null"; then
+      { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5
+$as_echo "$as_me: updating cache $cache_file" >&6;}
+      if test ! -f "$cache_file" || test -h "$cache_file"; then
+	cat confcache >"$cache_file"
+      else
+        case $cache_file in #(
+        */* | ?:*)
+	  mv -f confcache "$cache_file"$$ &&
+	  mv -f "$cache_file"$$ "$cache_file" ;; #(
+        *)
+	  mv -f confcache "$cache_file" ;;
+	esac
+      fi
+    fi
+  else
+    { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5
+$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;}
+  fi
+fi
+rm -f confcache
+
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+# Let make expand exec_prefix.
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
+DEFS=-DHAVE_CONFIG_H
+
+ac_libobjs=
+ac_ltlibobjs=
+U=
+for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue
+  # 1. Remove the extension, and $U if already installed.
+  ac_script='s/\$U\././;s/\.o$//;s/\.obj$//'
+  ac_i=`$as_echo "$ac_i" | sed "$ac_script"`
+  # 2. Prepend LIBOBJDIR.  When used with automake>=1.10 LIBOBJDIR
+  #    will be set to the directory where LIBOBJS objects are built.
+  as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext"
+  as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo'
+done
+LIBOBJS=$ac_libobjs
+
+LTLIBOBJS=$ac_ltlibobjs
+
+
+
+
+: "${CONFIG_STATUS=./config.status}"
+ac_write_fail=0
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files $CONFIG_STATUS"
+{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5
+$as_echo "$as_me: creating $CONFIG_STATUS" >&6;}
+as_write_fail=0
+cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1
+#! $SHELL
+# Generated by $as_me.
+# Run this file to recreate the current configuration.
+# Compiler output produced by configure, useful for debugging
+# configure, is in config.log if it exists.
+
+debug=false
+ac_cs_recheck=false
+ac_cs_silent=false
+
+SHELL=\${CONFIG_SHELL-$SHELL}
+export SHELL
+_ASEOF
+cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1
+## -------------------- ##
+## M4sh Initialization. ##
+## -------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+  emulate sh
+  NULLCMD=:
+  # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+  # is contrary to our usage.  Disable this feature.
+  alias -g '${1+"$@"}'='"$@"'
+  setopt NO_GLOB_SUBST
+else
+  case `(set -o) 2>/dev/null` in #(
+  *posix*) :
+    set -o posix ;; #(
+  *) :
+     ;;
+esac
+fi
+
+
+as_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+# Prefer a ksh shell builtin over an external printf program on Solaris,
+# but without wasting forks for bash or zsh.
+if test -z "$BASH_VERSION$ZSH_VERSION" \
+    && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
+  as_echo='print -r --'
+  as_echo_n='print -rn --'
+elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+  as_echo='printf %s\n'
+  as_echo_n='printf %s'
+else
+  if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+    as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+    as_echo_n='/usr/ucb/echo -n'
+  else
+    as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+    as_echo_n_body='eval
+      arg=$1;
+      case $arg in #(
+      *"$as_nl"*)
+	expr "X$arg" : "X\\(.*\\)$as_nl";
+	arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+      esac;
+      expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+    '
+    export as_echo_n_body
+    as_echo_n='sh -c $as_echo_n_body as_echo'
+  fi
+  export as_echo_body
+  as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+  PATH_SEPARATOR=:
+  (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+    (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+      PATH_SEPARATOR=';'
+  }
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order.  Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+IFS=" ""	$as_nl"
+
+# Find who we are.  Look in the path if we contain no directory separator.
+as_myself=
+case $0 in #((
+  *[\\/]* ) as_myself=$0 ;;
+  *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+  done
+IFS=$as_save_IFS
+
+     ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+  as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+  $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+  exit 1
+fi
+
+# Unset variables that we do not need and which cause bugs (e.g. in
+# pre-3.0 UWIN ksh).  But do not cause bugs in bash 2.01; the "|| exit 1"
+# suppresses any "Segmentation fault" message there.  '((' could
+# trigger a bug in pdksh 5.2.14.
+for as_var in BASH_ENV ENV MAIL MAILPATH
+do eval test x\${$as_var+set} = xset \
+  && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+
+# as_fn_error STATUS ERROR [LINENO LOG_FD]
+# ----------------------------------------
+# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+# script with STATUS, using 1 if that was 0.
+as_fn_error ()
+{
+  as_status=$1; test $as_status -eq 0 && as_status=1
+  if test "$4"; then
+    as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+    $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+  fi
+  $as_echo "$as_me: error: $2" >&2
+  as_fn_exit $as_status
+} # as_fn_error
+
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+  return $1
+} # as_fn_set_status
+
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+  set +e
+  as_fn_set_status $1
+  exit $1
+} # as_fn_exit
+
+# as_fn_unset VAR
+# ---------------
+# Portably unset VAR.
+as_fn_unset ()
+{
+  { eval $1=; unset $1;}
+}
+as_unset=as_fn_unset
+# as_fn_append VAR VALUE
+# ----------------------
+# Append the text in VALUE to the end of the definition contained in VAR. Take
+# advantage of any shell optimizations that allow amortized linear growth over
+# repeated appends, instead of the typical quadratic growth present in naive
+# implementations.
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+  eval 'as_fn_append ()
+  {
+    eval $1+=\$2
+  }'
+else
+  as_fn_append ()
+  {
+    eval $1=\$$1\$2
+  }
+fi # as_fn_append
+
+# as_fn_arith ARG...
+# ------------------
+# Perform arithmetic evaluation on the ARGs, and store the result in the
+# global $as_val. Take advantage of shells that can avoid forks. The arguments
+# must be portable across $(()) and expr.
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+  eval 'as_fn_arith ()
+  {
+    as_val=$(( $* ))
+  }'
+else
+  as_fn_arith ()
+  {
+    as_val=`expr "$@" || test $? -eq 1`
+  }
+fi # as_fn_arith
+
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+   test "X`expr 00001 : '.*\(...\)'`" = X001; then
+  as_expr=expr
+else
+  as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+  as_basename=basename
+else
+  as_basename=false
+fi
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+  as_dirname=dirname
+else
+  as_dirname=false
+fi
+
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+	 X"$0" : 'X\(//\)$' \| \
+	 X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+    sed '/^.*\/\([^/][^/]*\)\/*$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\/\(\/\/\)$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\/\(\/\).*/{
+	    s//\1/
+	    q
+	  }
+	  s/.*/./; q'`
+
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in #(((((
+-n*)
+  case `echo 'xy\c'` in
+  *c*) ECHO_T='	';;	# ECHO_T is single tab character.
+  xy)  ECHO_C='\c';;
+  *)   echo `echo ksh88 bug on AIX 6.1` > /dev/null
+       ECHO_T='	';;
+  esac;;
+*)
+  ECHO_N='-n';;
+esac
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+  rm -f conf$$.dir/conf$$.file
+else
+  rm -f conf$$.dir
+  mkdir conf$$.dir 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+  if ln -s conf$$.file conf$$ 2>/dev/null; then
+    as_ln_s='ln -s'
+    # ... but there are two gotchas:
+    # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+    # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+    # In both cases, we have to default to `cp -pR'.
+    ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+      as_ln_s='cp -pR'
+  elif ln conf$$.file conf$$ 2>/dev/null; then
+    as_ln_s=ln
+  else
+    as_ln_s='cp -pR'
+  fi
+else
+  as_ln_s='cp -pR'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+
+# as_fn_mkdir_p
+# -------------
+# Create "$as_dir" as a directory, including parents if necessary.
+as_fn_mkdir_p ()
+{
+
+  case $as_dir in #(
+  -*) as_dir=./$as_dir;;
+  esac
+  test -d "$as_dir" || eval $as_mkdir_p || {
+    as_dirs=
+    while :; do
+      case $as_dir in #(
+      *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+      *) as_qdir=$as_dir;;
+      esac
+      as_dirs="'$as_qdir' $as_dirs"
+      as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+	 X"$as_dir" : 'X\(//\)[^/]' \| \
+	 X"$as_dir" : 'X\(//\)$' \| \
+	 X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_dir" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)[^/].*/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\).*/{
+	    s//\1/
+	    q
+	  }
+	  s/.*/./; q'`
+      test -d "$as_dir" && break
+    done
+    test -z "$as_dirs" || eval "mkdir $as_dirs"
+  } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
+
+
+} # as_fn_mkdir_p
+if mkdir -p . 2>/dev/null; then
+  as_mkdir_p='mkdir -p "$as_dir"'
+else
+  test -d ./-p && rmdir ./-p
+  as_mkdir_p=false
+fi
+
+
+# as_fn_executable_p FILE
+# -----------------------
+# Test if FILE is an executable regular file.
+as_fn_executable_p ()
+{
+  test -f "$1" && test -x "$1"
+} # as_fn_executable_p
+as_test_x='test -x'
+as_executable_p=as_fn_executable_p
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+exec 6>&1
+## ----------------------------------- ##
+## Main body of $CONFIG_STATUS script. ##
+## ----------------------------------- ##
+_ASEOF
+test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# Save the log message, to keep $0 and so on meaningful, and to
+# report actual input values of CONFIG_FILES etc. instead of their
+# values after options handling.
+ac_log="
+This file was extended by $as_me, which was
+generated by GNU Autoconf 2.69.  Invocation command line was
+
+  CONFIG_FILES    = $CONFIG_FILES
+  CONFIG_HEADERS  = $CONFIG_HEADERS
+  CONFIG_LINKS    = $CONFIG_LINKS
+  CONFIG_COMMANDS = $CONFIG_COMMANDS
+  $ $0 $@
+
+on `(hostname || uname -n) 2>/dev/null | sed 1q`
+"
+
+_ACEOF
+
+case $ac_config_files in *"
+"*) set x $ac_config_files; shift; ac_config_files=$*;;
+esac
+
+case $ac_config_headers in *"
+"*) set x $ac_config_headers; shift; ac_config_headers=$*;;
+esac
+
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+# Files that config.status was made for.
+config_files="$ac_config_files"
+config_headers="$ac_config_headers"
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+ac_cs_usage="\
+\`$as_me' instantiates files and other configuration actions
+from templates according to the current configuration.  Unless the files
+and actions are specified as TAGs, all are instantiated by default.
+
+Usage: $0 [OPTION]... [TAG]...
+
+  -h, --help       print this help, then exit
+  -V, --version    print version number and configuration settings, then exit
+      --config     print configuration, then exit
+  -q, --quiet, --silent
+                   do not print progress messages
+  -d, --debug      don't remove temporary files
+      --recheck    update $as_me by reconfiguring in the same conditions
+      --file=FILE[:TEMPLATE]
+                   instantiate the configuration file FILE
+      --header=FILE[:TEMPLATE]
+                   instantiate the configuration header FILE
+
+Configuration files:
+$config_files
+
+Configuration headers:
+$config_headers
+
+Report bugs to the package provider."
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
+ac_cs_version="\\
+config.status
+configured by $0, generated by GNU Autoconf 2.69,
+  with options \\"\$ac_cs_config\\"
+
+Copyright (C) 2012 Free Software Foundation, Inc.
+This config.status script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it."
+
+ac_pwd='$ac_pwd'
+srcdir='$srcdir'
+test -n "\$AWK" || AWK=awk
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# The default lists apply if the user does not specify any file.
+ac_need_defaults=:
+while test $# != 0
+do
+  case $1 in
+  --*=?*)
+    ac_option=`expr "X$1" : 'X\([^=]*\)='`
+    ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'`
+    ac_shift=:
+    ;;
+  --*=)
+    ac_option=`expr "X$1" : 'X\([^=]*\)='`
+    ac_optarg=
+    ac_shift=:
+    ;;
+  *)
+    ac_option=$1
+    ac_optarg=$2
+    ac_shift=shift
+    ;;
+  esac
+
+  case $ac_option in
+  # Handling of the options.
+  -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+    ac_cs_recheck=: ;;
+  --version | --versio | --versi | --vers | --ver | --ve | --v | -V )
+    $as_echo "$ac_cs_version"; exit ;;
+  --config | --confi | --conf | --con | --co | --c )
+    $as_echo "$ac_cs_config"; exit ;;
+  --debug | --debu | --deb | --de | --d | -d )
+    debug=: ;;
+  --file | --fil | --fi | --f )
+    $ac_shift
+    case $ac_optarg in
+    *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+    '') as_fn_error $? "missing file argument" ;;
+    esac
+    as_fn_append CONFIG_FILES " '$ac_optarg'"
+    ac_need_defaults=false;;
+  --header | --heade | --head | --hea )
+    $ac_shift
+    case $ac_optarg in
+    *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+    esac
+    as_fn_append CONFIG_HEADERS " '$ac_optarg'"
+    ac_need_defaults=false;;
+  --he | --h)
+    # Conflict between --help and --header
+    as_fn_error $? "ambiguous option: \`$1'
+Try \`$0 --help' for more information.";;
+  --help | --hel | -h )
+    $as_echo "$ac_cs_usage"; exit ;;
+  -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+  | -silent | --silent | --silen | --sile | --sil | --si | --s)
+    ac_cs_silent=: ;;
+
+  # This is an error.
+  -*) as_fn_error $? "unrecognized option: \`$1'
+Try \`$0 --help' for more information." ;;
+
+  *) as_fn_append ac_config_targets " $1"
+     ac_need_defaults=false ;;
+
+  esac
+  shift
+done
+
+ac_configure_extra_args=
+
+if $ac_cs_silent; then
+  exec 6>/dev/null
+  ac_configure_extra_args="$ac_configure_extra_args --silent"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+if \$ac_cs_recheck; then
+  set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
+  shift
+  \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6
+  CONFIG_SHELL='$SHELL'
+  export CONFIG_SHELL
+  exec "\$@"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+exec 5>>config.log
+{
+  echo
+  sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX
+## Running $as_me. ##
+_ASBOX
+  $as_echo "$ac_log"
+} >&5
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+
+# Handling of arguments.
+for ac_config_target in $ac_config_targets
+do
+  case $ac_config_target in
+    "config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;;
+    "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;;
+
+  *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;;
+  esac
+done
+
+
+# If the user did not use the arguments to specify the items to instantiate,
+# then the envvar interface is used.  Set only those that are not.
+# We use the long form for the default assignment because of an extremely
+# bizarre bug on SunOS 4.1.3.
+if $ac_need_defaults; then
+  test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files
+  test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers
+fi
+
+# Have a temporary directory for convenience.  Make it in the build tree
+# simply because there is no reason against having it here, and in addition,
+# creating and moving files from /tmp can sometimes cause problems.
+# Hook for its removal unless debugging.
+# Note that there is a small window in which the directory will not be cleaned:
+# after its creation but before its name has been assigned to `$tmp'.
+$debug ||
+{
+  tmp= ac_tmp=
+  trap 'exit_status=$?
+  : "${ac_tmp:=$tmp}"
+  { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status
+' 0
+  trap 'as_fn_exit 1' 1 2 13 15
+}
+# Create a (secure) tmp directory for tmp files.
+
+{
+  tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` &&
+  test -d "$tmp"
+}  ||
+{
+  tmp=./conf$$-$RANDOM
+  (umask 077 && mkdir "$tmp")
+} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5
+ac_tmp=$tmp
+
+# Set up the scripts for CONFIG_FILES section.
+# No need to generate them if there are no CONFIG_FILES.
+# This happens for instance with `./config.status config.h'.
+if test -n "$CONFIG_FILES"; then
+
+
+ac_cr=`echo X | tr X '\015'`
+# On cygwin, bash can eat \r inside `` if the user requested igncr.
+# But we know of no other shell where ac_cr would be empty at this
+# point, so we can use a bashism as a fallback.
+if test "x$ac_cr" = x; then
+  eval ac_cr=\$\'\\r\'
+fi
+ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' </dev/null 2>/dev/null`
+if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then
+  ac_cs_awk_cr='\\r'
+else
+  ac_cs_awk_cr=$ac_cr
+fi
+
+echo 'BEGIN {' >"$ac_tmp/subs1.awk" &&
+_ACEOF
+
+
+{
+  echo "cat >conf$$subs.awk <<_ACEOF" &&
+  echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' &&
+  echo "_ACEOF"
+} >conf$$subs.sh ||
+  as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'`
+ac_delim='%!_!# '
+for ac_last_try in false false false false false :; do
+  . ./conf$$subs.sh ||
+    as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+
+  ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X`
+  if test $ac_delim_n = $ac_delim_num; then
+    break
+  elif $ac_last_try; then
+    as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+  else
+    ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
+  fi
+done
+rm -f conf$$subs.sh
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK &&
+_ACEOF
+sed -n '
+h
+s/^/S["/; s/!.*/"]=/
+p
+g
+s/^[^!]*!//
+:repl
+t repl
+s/'"$ac_delim"'$//
+t delim
+:nl
+h
+s/\(.\{148\}\)..*/\1/
+t more1
+s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/
+p
+n
+b repl
+:more1
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t nl
+:delim
+h
+s/\(.\{148\}\)..*/\1/
+t more2
+s/["\\]/\\&/g; s/^/"/; s/$/"/
+p
+b
+:more2
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t delim
+' <conf$$subs.awk | sed '
+/^[^""]/{
+  N
+  s/\n//
+}
+' >>$CONFIG_STATUS || ac_write_fail=1
+rm -f conf$$subs.awk
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACAWK
+cat >>"\$ac_tmp/subs1.awk" <<_ACAWK &&
+  for (key in S) S_is_set[key] = 1
+  FS = ""
+
+}
+{
+  line = $ 0
+  nfields = split(line, field, "@")
+  substed = 0
+  len = length(field[1])
+  for (i = 2; i < nfields; i++) {
+    key = field[i]
+    keylen = length(key)
+    if (S_is_set[key]) {
+      value = S[key]
+      line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3)
+      len += length(value) + length(field[++i])
+      substed = 1
+    } else
+      len += 1 + keylen
+  }
+
+  print line
+}
+
+_ACAWK
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then
+  sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g"
+else
+  cat
+fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \
+  || as_fn_error $? "could not setup config files machinery" "$LINENO" 5
+_ACEOF
+
+# VPATH may cause trouble with some makes, so we remove sole $(srcdir),
+# ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and
+# trailing colons and then remove the whole line if VPATH becomes empty
+# (actually we leave an empty line to preserve line numbers).
+if test "x$srcdir" = x.; then
+  ac_vpsub='/^[	 ]*VPATH[	 ]*=[	 ]*/{
+h
+s///
+s/^/:/
+s/[	 ]*$/:/
+s/:\$(srcdir):/:/g
+s/:\${srcdir}:/:/g
+s/:@srcdir@:/:/g
+s/^:*//
+s/:*$//
+x
+s/\(=[	 ]*\).*/\1/
+G
+s/\n//
+s/^[^=]*=[	 ]*$//
+}'
+fi
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+fi # test -n "$CONFIG_FILES"
+
+# Set up the scripts for CONFIG_HEADERS section.
+# No need to generate them if there are no CONFIG_HEADERS.
+# This happens for instance with `./config.status Makefile'.
+if test -n "$CONFIG_HEADERS"; then
+cat >"$ac_tmp/defines.awk" <<\_ACAWK ||
+BEGIN {
+_ACEOF
+
+# Transform confdefs.h into an awk script `defines.awk', embedded as
+# here-document in config.status, that substitutes the proper values into
+# config.h.in to produce config.h.
+
+# Create a delimiter string that does not exist in confdefs.h, to ease
+# handling of long lines.
+ac_delim='%!_!# '
+for ac_last_try in false false :; do
+  ac_tt=`sed -n "/$ac_delim/p" confdefs.h`
+  if test -z "$ac_tt"; then
+    break
+  elif $ac_last_try; then
+    as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5
+  else
+    ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
+  fi
+done
+
+# For the awk script, D is an array of macro values keyed by name,
+# likewise P contains macro parameters if any.  Preserve backslash
+# newline sequences.
+
+ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]*
+sed -n '
+s/.\{148\}/&'"$ac_delim"'/g
+t rset
+:rset
+s/^[	 ]*#[	 ]*define[	 ][	 ]*/ /
+t def
+d
+:def
+s/\\$//
+t bsnl
+s/["\\]/\\&/g
+s/^ \('"$ac_word_re"'\)\(([^()]*)\)[	 ]*\(.*\)/P["\1"]="\2"\
+D["\1"]=" \3"/p
+s/^ \('"$ac_word_re"'\)[	 ]*\(.*\)/D["\1"]=" \2"/p
+d
+:bsnl
+s/["\\]/\\&/g
+s/^ \('"$ac_word_re"'\)\(([^()]*)\)[	 ]*\(.*\)/P["\1"]="\2"\
+D["\1"]=" \3\\\\\\n"\\/p
+t cont
+s/^ \('"$ac_word_re"'\)[	 ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p
+t cont
+d
+:cont
+n
+s/.\{148\}/&'"$ac_delim"'/g
+t clear
+:clear
+s/\\$//
+t bsnlc
+s/["\\]/\\&/g; s/^/"/; s/$/"/p
+d
+:bsnlc
+s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p
+b cont
+' <confdefs.h | sed '
+s/'"$ac_delim"'/"\\\
+"/g' >>$CONFIG_STATUS || ac_write_fail=1
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+  for (key in D) D_is_set[key] = 1
+  FS = ""
+}
+/^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ {
+  line = \$ 0
+  split(line, arg, " ")
+  if (arg[1] == "#") {
+    defundef = arg[2]
+    mac1 = arg[3]
+  } else {
+    defundef = substr(arg[1], 2)
+    mac1 = arg[2]
+  }
+  split(mac1, mac2, "(") #)
+  macro = mac2[1]
+  prefix = substr(line, 1, index(line, defundef) - 1)
+  if (D_is_set[macro]) {
+    # Preserve the white space surrounding the "#".
+    print prefix "define", macro P[macro] D[macro]
+    next
+  } else {
+    # Replace #undef with comments.  This is necessary, for example,
+    # in the case of _POSIX_SOURCE, which is predefined and required
+    # on some systems where configure will not decide to define it.
+    if (defundef == "undef") {
+      print "/*", prefix defundef, macro, "*/"
+      next
+    }
+  }
+}
+{ print }
+_ACAWK
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+  as_fn_error $? "could not setup config headers machinery" "$LINENO" 5
+fi # test -n "$CONFIG_HEADERS"
+
+
+eval set X "  :F $CONFIG_FILES  :H $CONFIG_HEADERS    "
+shift
+for ac_tag
+do
+  case $ac_tag in
+  :[FHLC]) ac_mode=$ac_tag; continue;;
+  esac
+  case $ac_mode$ac_tag in
+  :[FHL]*:*);;
+  :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;;
+  :[FH]-) ac_tag=-:-;;
+  :[FH]*) ac_tag=$ac_tag:$ac_tag.in;;
+  esac
+  ac_save_IFS=$IFS
+  IFS=:
+  set x $ac_tag
+  IFS=$ac_save_IFS
+  shift
+  ac_file=$1
+  shift
+
+  case $ac_mode in
+  :L) ac_source=$1;;
+  :[FH])
+    ac_file_inputs=
+    for ac_f
+    do
+      case $ac_f in
+      -) ac_f="$ac_tmp/stdin";;
+      *) # Look for the file first in the build tree, then in the source tree
+	 # (if the path is not absolute).  The absolute path cannot be DOS-style,
+	 # because $ac_f cannot contain `:'.
+	 test -f "$ac_f" ||
+	   case $ac_f in
+	   [\\/$]*) false;;
+	   *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";;
+	   esac ||
+	   as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;;
+      esac
+      case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac
+      as_fn_append ac_file_inputs " '$ac_f'"
+    done
+
+    # Let's still pretend it is `configure' which instantiates (i.e., don't
+    # use $as_me), people would be surprised to read:
+    #    /* config.h.  Generated by config.status.  */
+    configure_input='Generated from '`
+	  $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g'
+	`' by configure.'
+    if test x"$ac_file" != x-; then
+      configure_input="$ac_file.  $configure_input"
+      { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5
+$as_echo "$as_me: creating $ac_file" >&6;}
+    fi
+    # Neutralize special characters interpreted by sed in replacement strings.
+    case $configure_input in #(
+    *\&* | *\|* | *\\* )
+       ac_sed_conf_input=`$as_echo "$configure_input" |
+       sed 's/[\\\\&|]/\\\\&/g'`;; #(
+    *) ac_sed_conf_input=$configure_input;;
+    esac
+
+    case $ac_tag in
+    *:-:* | *:-) cat >"$ac_tmp/stdin" \
+      || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;;
+    esac
+    ;;
+  esac
+
+  ac_dir=`$as_dirname -- "$ac_file" ||
+$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+	 X"$ac_file" : 'X\(//\)[^/]' \| \
+	 X"$ac_file" : 'X\(//\)$' \| \
+	 X"$ac_file" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$ac_file" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)[^/].*/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\).*/{
+	    s//\1/
+	    q
+	  }
+	  s/.*/./; q'`
+  as_dir="$ac_dir"; as_fn_mkdir_p
+  ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+  ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+  # A ".." for each directory in $ac_dir_suffix.
+  ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+  case $ac_top_builddir_sub in
+  "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+  *)  ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+  esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+  .)  # We are building in place.
+    ac_srcdir=.
+    ac_top_srcdir=$ac_top_builddir_sub
+    ac_abs_top_srcdir=$ac_pwd ;;
+  [\\/]* | ?:[\\/]* )  # Absolute name.
+    ac_srcdir=$srcdir$ac_dir_suffix;
+    ac_top_srcdir=$srcdir
+    ac_abs_top_srcdir=$srcdir ;;
+  *) # Relative name.
+    ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+    ac_top_srcdir=$ac_top_build_prefix$srcdir
+    ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+
+  case $ac_mode in
+  :F)
+  #
+  # CONFIG_FILE
+  #
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# If the template does not know about datarootdir, expand it.
+# FIXME: This hack should be removed a few years after 2.60.
+ac_datarootdir_hack=; ac_datarootdir_seen=
+ac_sed_dataroot='
+/datarootdir/ {
+  p
+  q
+}
+/@datadir@/p
+/@docdir@/p
+/@infodir@/p
+/@localedir@/p
+/@mandir@/p'
+case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in
+*datarootdir*) ac_datarootdir_seen=yes;;
+*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*)
+  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5
+$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;}
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+  ac_datarootdir_hack='
+  s&@datadir@&$datadir&g
+  s&@docdir@&$docdir&g
+  s&@infodir@&$infodir&g
+  s&@localedir@&$localedir&g
+  s&@mandir@&$mandir&g
+  s&\\\${datarootdir}&$datarootdir&g' ;;
+esac
+_ACEOF
+
+# Neutralize VPATH when `$srcdir' = `.'.
+# Shell code in configure.ac might set extrasub.
+# FIXME: do we really want to maintain this feature?
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_sed_extra="$ac_vpsub
+$extrasub
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+:t
+/@[a-zA-Z_][a-zA-Z_0-9]*@/!b
+s|@configure_input@|$ac_sed_conf_input|;t t
+s&@top_builddir@&$ac_top_builddir_sub&;t t
+s&@top_build_prefix@&$ac_top_build_prefix&;t t
+s&@srcdir@&$ac_srcdir&;t t
+s&@abs_srcdir@&$ac_abs_srcdir&;t t
+s&@top_srcdir@&$ac_top_srcdir&;t t
+s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t
+s&@builddir@&$ac_builddir&;t t
+s&@abs_builddir@&$ac_abs_builddir&;t t
+s&@abs_top_builddir@&$ac_abs_top_builddir&;t t
+$ac_datarootdir_hack
+"
+eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \
+  >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+
+test -z "$ac_datarootdir_hack$ac_datarootdir_seen" &&
+  { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } &&
+  { ac_out=`sed -n '/^[	 ]*datarootdir[	 ]*:*=/p' \
+      "$ac_tmp/out"`; test -z "$ac_out"; } &&
+  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined.  Please make sure it is defined" >&5
+$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined.  Please make sure it is defined" >&2;}
+
+  rm -f "$ac_tmp/stdin"
+  case $ac_file in
+  -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";;
+  *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";;
+  esac \
+  || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+ ;;
+  :H)
+  #
+  # CONFIG_HEADER
+  #
+  if test x"$ac_file" != x-; then
+    {
+      $as_echo "/* $configure_input  */" \
+      && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs"
+    } >"$ac_tmp/config.h" \
+      || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+    if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then
+      { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5
+$as_echo "$as_me: $ac_file is unchanged" >&6;}
+    else
+      rm -f "$ac_file"
+      mv "$ac_tmp/config.h" "$ac_file" \
+	|| as_fn_error $? "could not create $ac_file" "$LINENO" 5
+    fi
+  else
+    $as_echo "/* $configure_input  */" \
+      && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \
+      || as_fn_error $? "could not create -" "$LINENO" 5
+  fi
+ ;;
+
+
+  esac
+
+done # for ac_tag
+
+
+as_fn_exit 0
+_ACEOF
+ac_clean_files=$ac_clean_files_save
+
+test $ac_write_fail = 0 ||
+  as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5
+
+
+# configure is writing to config.log, and then calls config.status.
+# config.status does its own redirection, appending to config.log.
+# Unfortunately, on DOS this fails, as config.log is still kept open
+# by configure, so config.status won't be able to write to it; its
+# output is simply discarded.  So we exec the FD to /dev/null,
+# effectively closing config.log, so it can be properly (re)opened and
+# appended to by config.status.  When coming back to configure, we
+# need to make the FD available again.
+if test "$no_create" != yes; then
+  ac_cs_success=:
+  ac_config_status_args=
+  test "$silent" = yes &&
+    ac_config_status_args="$ac_config_status_args --quiet"
+  exec 5>/dev/null
+  $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false
+  exec 5>>config.log
+  # Use ||, not &&, to avoid exiting from the if with $? = 1, which
+  # would make configure fail if this is the last instruction.
+  $ac_cs_success || as_fn_exit 1
+fi
+if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5
+$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;}
+fi
+
diff --git a/configure-stamp b/configure-stamp
new file mode 100644
index 0000000..e69de29
diff --git a/configure.in b/configure.in
new file mode 100644
index 0000000..8442293
--- /dev/null
+++ b/configure.in
@@ -0,0 +1,318 @@
+dnl Process this file with autoconf to produce a configure script.
+AC_INIT
+AC_CONFIG_SRCDIR([aprx.h])
+
+dnl For automake
+VERSION="`cat VERSION`"
+PACKAGE=aprx
+dnl AM_INIT_AUTOMAKE($PACKAGE, $VERSION)
+
+AC_PROG_MAKE_SET
+
+AC_CONFIG_HEADERS([config.h])
+
+dnl Checks for programs.
+AC_PROG_CC
+AC_PROG_GCC_TRADITIONAL
+
+dnl AC_PATH_PROG(LD, ld, ld)dnl
+if test -z "$LD" ; then
+  LD="$CC"
+fi
+AC_SUBST(LD,"$LD")
+
+dnl If on i686, we'll need -march=i686 to get the atomic instructions
+dnl On FreeBSD, the architecture is i386.
+MACHINE="`uname -m`"
+if test "$MACHINE" == "i686" -o "$MACHINE" == "i386"; then
+  CFLAGS_ARCH="-march=i686"
+fi
+OS="`uname`"
+if test "$OS" == "Darwin"; then
+  CFLAGS_ARCH=""
+fi
+AC_SUBST(CFLAGS_ARCH)
+
+dnl Check for GNU make
+AX_CHECK_GNU_MAKE()
+
+
+dnl Check for headers.
+AC_CHECK_HEADERS(time.h sys/time.h stdlib.h stddef.h stdint.h)
+AC_CHECK_HEADERS(string.h strings.h)
+AC_CHECK_HEADERS(pty.h)
+AC_CHECK_HEADERS(pthread.h)
+
+dnl Checks for system headers
+AC_CHECK_HEADERS([alloca.h],    AC_DEFINE([HAVE_ALLOCA_H]))
+AC_CHECK_HEADERS([poll.h],      AC_DEFINE([HAVE_POLL_H]))
+dnl AC_CHECK_FUNC(ppoll,,[Probably have ppoll of Linux])
+AC_CHECK_HEADERS([sys/epoll.h], AC_DEFINE([HAVE_SYS_EPOLL_H]))
+
+dnl SCTP checks
+AC_CHECK_HEADERS([netinet/sctp.h], AC_DEFINE([HAVE_NETINET_SCTP_H]))
+
+
+
+dnl Check for varargs
+AC_CHECK_HEADERS(stdarg.h varargs.h sys/wait.h)
+AC_FUNC_VPRINTF
+
+
+dnl This group must be after header tests
+
+
+AC_MSG_RESULT([** Using C compiler: $CC])
+AC_MSG_RESULT([** Using CFLAGS:     $CFLAGS])
+AC_MSG_RESULT([** Using CPPDEP:     $CPPDEP])
+
+AC_C_BIGENDIAN
+dnl AC_INLINE
+AC_CHECK_SIZEOF(void *)
+AC_CHECK_SIZEOF(short)
+AC_CHECK_SIZEOF(int)
+AC_CHECK_SIZEOF(long)
+AC_CHECK_SIZEOF(double)
+
+dnl AC_DEFINE_UNQUOTED(CONFIGURE_CMD,"$0 $ac_configure_args")
+AC_DEFINE_UNQUOTED(CONFIGURE_CMD,
+                   "CC='$CC' CFLAGS='$CFLAGS' $0 $ac_configure_args",
+		   [Configuration command line])
+
+
+dnl Checks for libraries.
+AC_SUBST(LIBM)
+AC_CHECK_FUNCS(atan2f,,
+	       AC_CHECK_LIB(m, atan2f,
+			    [LIBM="-lm"]))
+
+AC_CHECK_FUNCS(memchr memrchr gettimeofday)
+
+dnl Checks for library functions.
+AC_CHECK_FUNCS(openpty,,
+	       AC_CHECK_LIB(util, openpty,
+			    [AC_DEFINE(HAVE_OPENPTY,1,[])] [LIBS="$LIBS -lutil"]))
+
+dnl Check for user options
+
+dnl The "EMBEDDED" is now always on, replaced with --with-erlangstorage
+AC_DEFINE(EMBEDDED,1,[Define for an embedded target])
+
+AC_ARG_WITH(embedded, [  --with-embedded  When desiring to target as embedded],
+		      [AC_DEFINE(EMBEDDED,1,[Define for an embedded target]) EMBEDDED=1])
+
+AC_ARG_WITH(erlangstorage, [  --with-erlangstorage  When desiring a longer term backing storage on erlang datasets.  NOT compatible with EMBEDDED, REQUIRES FILESYSTEM!],
+		      [AC_DEFINE(ERLANGSTORAGE,1,[Define for a non-embedded system with filesystem based Erlang history storage]) ERLANGSTORAGE=1])
+
+AC_ARG_ENABLE(igate,    [  --disable-igate         Disable all IGate codes],
+[if test "${enable_igate}" = no ; then
+    AC_DEFINE(DISABLE_IGATE,1,[Define to 1 if you want to disable all IGATE codes.])
+fi])
+
+AC_ARG_ENABLE(agwpe,    [  --enable-agwpe          Enable AGWPE socket interface code.],
+[if test "${enable_agwpe}" != no ; then
+    AC_DEFINE(ENABLE_AGWPE,1,[Define to 1 if you want to enable AGWPE socket interface.])
+fi])
+
+
+AC_ARG_WITH(pthread,  [  --without-pthread   When desiring not to use pthread subsystem],
+                      [AC_DEFINE(DISABLE_PTHREAD,1,[Define for pthread(3p) disabling]) DISABLE_PTHREAD=1],
+		      [AC_DEFINE(ENABLE_PTHREAD,1,[Define for pthread(3p) enabling]) ENABLE_PTHREAD=1])
+AC_ARG_WITH(pthreads, [  --with-pthreads  (mistyped pthread) When desiring use pthread subsystem],
+		      [AC_DEFINE(ENABLE_PTHREAD,1,[Define for pthread(3p) enabling]) ENABLE_PTHREAD=1])
+
+dnl search for pthread libs and compilation option
+AC_SUBST(LIBPTHREAD)
+AC_SUBST(CCPTHREAD)
+if test "${ENABLE_PTHREAD}" = "1" ; then
+    AC_MSG_RESULT([The --without-pthread option is not set, looking for pthread_create() function.])
+    have_pthread=no
+    if test $have_pthread = no; then
+       t_oldLibs="$LIBS"
+       LIBS="$LIBS -pthread"
+       t_oldCflags="$CFLAGS"
+       CFLAGS="$CFLAGS -pthread"
+    AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <pthread.h>]],[[pthread_t pt;
+pthread_attr_t pat;
+int rc = pthread_create(&pt, &pat, NULL, NULL)]])],
+                      [have_pthread=yes;AC_MSG_RESULT([Have pthread_create()])],
+                      [AC_MSG_RESULT([Not have pthread_create()])])
+
+       if test $have_pthread = no ; then
+          AC_MSG_RESULT([Failure at HAVE_PTHREAD_CREATE])
+       else
+          AC_DEFINE(HAVE_PTHREAD_CREATE,1,[Have pthread_create() function])
+          AC_MSG_RESULT([Success at HAVE_PTHREAD_CREATE])
+          LIBPTHREAD="-pthread"
+          CCPTHREAD="-pthread"
+       fi
+       LIBS="$t_oldLibs"
+       CFLAGS="$t_oldCflags"
+    fi
+    if test $have_pthread = no; then
+       AC_MSG_RESULT([Failure at HAVE_PTHREAD_CREATE, trying second way.])
+       t_oldLibs="$LIBS"
+       LIBS="$LIBS -lpthread"
+    AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <pthread.h>]],[[pthread_t pt;
+pthread_attr_t pat;
+int rc = pthread_create(&pt, &pat, NULL, NULL)]])],
+                      [have_pthread=yes;AC_MSG_RESULT([Have pthread_create()])],
+                      [AC_MSG_RESULT([Not have pthread_create()])])
+
+       if test $have_pthread = no ; then
+          AC_MSG_RESULT([Failure at HAVE_PTHREAD_CREATE])
+       else
+          AC_DEFINE(HAVE_PTHREAD_CREATE,1,[Have pthread_create() function])
+          AC_MSG_RESULT([Success at HAVE_PTHREAD_CREATE])
+          LIBPTHREAD="-lpthread"
+          CCPTHREAD=""
+       fi
+       LIBS="$t_oldLibs"
+       CFLAGS="$t_oldCflags"
+    fi
+    if test $have_pthread = no; then
+       AC_MSG_RESULT([Still failure at HAVE_PTHREAD_CREATE, Run out of ways to set it up.])
+    fi
+fi
+
+
+
+dnl Check for clock_gettime, and a library to have it
+AC_SUBST(LIBRT)
+AC_SEARCH_LIBS([clock_gettime], [rt], [
+  AC_DEFINE(HAVE_CLOCK_GETTIME, 1,[Have clock_gettime])
+])
+
+if test "$ac_cv_search_clock_gettime" = "-lrt"; then
+  LIBRT="-lrt"
+fi
+
+dnl Solaris resolver solution:
+AC_SUBST(LIBGETADDRINFO)
+AC_CHECK_FUNCS(getaddrinfo,,
+	       AC_CHECK_LIB(nsl, getaddrinfo,
+			    [LIBGETADDRINFO="-lnsl"]))
+
+AC_SUBST(LIBSOCKET)dnl
+AC_SUBST(LIBRESOLV)dnl
+
+#
+#  We check for various libraries
+#  - SysVr4 style of "-lsocket" at first (unless in libc)
+#    The hallmark is  connect()  routine (we presume)
+#
+ac_cv_libsocket_both=1
+AC_CHECK_FUNC(connect, ac_cv_libsocket_both=0)
+AC_CHECK_FUNC(gethostbyname, ac_cv_libsocket_both=0)
+if test "$ac_cv_libsocket_both" = 1 ; then
+  # Check cache
+  if test "$ac_cv_func_socket_lxnet" = yes ; then
+    AC_MSG_RESULT([need -lxnet library (cached)])
+    LIBSOCKET="-lnsl -lsocket -lxnet"
+  else
+  if test "$ac_cv_func_socket_lsocket" = yes ; then
+    AC_MSG_RESULT([need -lsocket library (cached)])
+    LIBSOCKET="-lsocket"
+    if test "$ac_cv_func_gethostbyname_lnsl" = yes ; then
+        LIBSOCKET="-lnsl -lsocket"
+    fi
+  else
+    # Well, will this work ?  SysVR4, but not Sun Solaris ?
+    AC_CHECK_LIB(xnet, connect, [LIBSOCKET="-lnsl -lsocket -lxnet"
+                                 ac_cv_func_socket_lsocket=no
+                                 ac_cv_func_socket_lxnet=yes],[
+      AC_CHECK_LIB(socket, connect, [LIBSOCKET="-lsocket"
+                                     ac_cv_func_socket_lsocket=yes],
+                                     ac_cv_func_socket_lsocket=no)
+      if test "$ac_cv_func_socket_lsocket" = yes ; then
+        t_oldLibs="$LIBS"
+        LIBS="$LIBS -lsocket $LIBRESOLV"
+        AC_TRY_LINK([],[gethostbyname();], ,[
+          LIBS="$LIBS -lnsl" # Add this Solaris library..
+          AC_TRY_LINK([],[gethostbyname();],[
+                        LIBSOCKET="-lsocket -lnsl"
+                        ac_cv_func_gethostbyname_lnsl=yes
+                ], [
+                   AC_MSG_ERROR([Weird, '$LIBS' not enough to find  gethostnyname() ?!])
+                ])
+          ])
+        LIBS="$t_oldLibs"
+      fi
+    ])
+  fi
+  fi
+fi
+
+if test "x$LIBRESOLV" = "x"; then
+  # Ok, No  -lresolv,  is this enough for the  _res  to appear ?
+  t_oldLibs="$LIBS"
+  LIBS="$LIBS $LIBSOCKET"
+  ac_cv_var__res_options=no
+  # This following is for IRIX6.4, and I sincerely hope it
+  # will not fail on other systems...  It did! It did!
+  # Many systems don't have idemponent headers, they need specific
+  # includes before latter ones, or the latter ones won't be successful...
+  AC_TRY_LINK([#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <resolv.h>],
+              [_res.options = RES_INIT;],
+                ac_cv_var__res_options=yes);
+  if test "$ac_cv_var__res_options" != "yes"; then
+    AC_MSG_RESULT([Can't do without  -lresolv  to link resolver's  _res.options])
+    LIBS="$LIBS -lresolv"
+  fi
+  LIBS="$t_oldLibs"
+fi
+
+# See about the routines that possibly exist at the libraries..
+LIBS="$t_oldLibs $LIBSOCKET"
+AC_CHECK_FUNCS(socket socketpair)
+LIBS="$t_oldLibs"
+
+if test "$ac_cv_func_socket" = no -a "$LIBSOCKET" != ""; then
+  LIBS="$LIBS $LIBSOCKET"
+  AC_TRY_LINK([],[socket();], ac_cv_func_socket=yes)
+  if test $ac_cv_func_socket = yes; then
+    AC_DEFINE(HAVE_SOCKET)
+    AC_MSG_RESULT([Has  socket()  when using  $LIBSOCKET])
+  fi
+  LIBS="$t_oldLibs"
+fi
+if test "$ac_cv_func_socketpair" = no -a "$LIBSOCKET" != ""; then
+  LIBS="$LIBS $LIBSOCKET"
+  AC_TRY_LINK([],[socketpair();], ac_cv_func_socketpair=yes)
+  if test $ac_cv_func_socketpair = yes; then
+    AC_DEFINE(HAVE_SOCKETPAIR)
+    AC_MSG_RESULT([Has  socketpair()  when using  $LIBSOCKET])
+  fi
+  LIBS="$t_oldLibs"
+fi
+
+dnl Check for openssl
+AC_ARG_WITH(openssl, [  --with-openssl[=DIR]    Include OpenSSL support (requires OpenSSL >= 0.9.7)], [with_openssl=$withval], [with_openssl=no])
+AC_SUBST(LIBSSL)
+AC_SUBST(LIBCRYPTO)
+if test "$with_openssl" != "no" ; then
+  AC_CHECK_HEADERS([openssl/ssl.h])
+  AC_SEARCH_LIBS(TLSv1_server_method, ssl, AC_DEFINE(HAVE_TLSV1_SERVER_METHOD, 1, [OpenSSL 0.9.7 or later]))
+  AC_SEARCH_LIBS(X509_free, crypto, AC_DEFINE(HAVE_X509_FREE, 1, [OpenSSL 0.9.7 or later]))
+  
+  if test "$ac_cv_search_TLSv1_server_method" = "-lssl"; then
+    LIBSSL="-lssl"
+  fi
+  if test "$ac_cv_search_X509_free" = "-lcrypto"; then
+    LIBCRYPTO="-lcrypto"
+  fi
+fi
+
+dnl Define compilation variables supplying version information
+t_vers="`cat VERSION`"
+AC_SUBST(VERSION_STRING, "`cat VERSION`")
+t_vers="`cat SVNVERSION`"
+AC_SUBST(SVNVERSION_STRING, "$t_vers")
+
+dnl Output files
+AC_CONFIG_FILES([Makefile])
+AC_OUTPUT
diff --git a/coverity-build-submit.sh b/coverity-build-submit.sh
new file mode 100644
index 0000000..a9e9cad
--- /dev/null
+++ b/coverity-build-submit.sh
@@ -0,0 +1,27 @@
+#!/bin/bash
+
+set -e
+
+export PATH=$PATH:~/src/cov-analysis-linux64-6.5.1/bin
+
+make clean
+./configure
+rm -rf cov-int
+cov-build --dir cov-int make
+tar cvfz aprx-coverity.tgz cov-int
+rm -rf cov-int
+
+VERSION="`cat VERSION`"
+PROJECT="Aprx"
+PASSWORD="`cat ~/.covpw`"
+
+echo "Uploading Aprx version $VERSION to Coverity..."
+
+curl --form file=@aprx-coverity.tgz --form project="$PROJECT" \
+	--form password="$PASSWORD" \
+	--form email=oh2mqk at sral.fi \
+	--form version="$VERSION" \
+	--form description="" \
+	http://scan5.coverity.com/cgi-bin/upload.py
+
+rm -f aprx-coverity.tgz
diff --git a/crc.c b/crc.c
new file mode 100644
index 0000000..77cfa51
--- /dev/null
+++ b/crc.c
@@ -0,0 +1,286 @@
+/* **************************************************************** *
+ *                                                                  *
+ *  APRX -- 2nd generation receive-only APRS-i-gate with            *
+ *          minimal requirement of esoteric facilities or           *
+ *          libraries of any kind beyond UNIX system libc.          *
+ *                                                                  *
+ * (c) Matti Aarnio - OH2MQK,  2007-2014                            *
+ *                                                                  *
+ * **************************************************************** */
+
+#include "aprx.h"
+
+
+/*
+	3 different CRC algorithms:
+	    1)  CRC-16
+	    2)  CRC-CCITT
+	    3)  CRC-FLEXNET
+
+   - - - - - - - - -
+
+   SYMEK et al. have defined a way to run CRC inside KISS frames to
+   verify that the KISS-frame itself is correct:
+
+   http://www.symek.com/g/smack.html
+   http://www.ir3ip.net/iw3fqg/doc/smak.htm
+
+   SMACK variation recycles the top-most bit of the TNC-id nibble, and
+   thus permits up to 8 TNC ports on line.  Top-most bit is always one
+   on SMACK frames.
+
+   SMACK runs CRC16 over whole KISS frame buffer, including the CMD byte.
+   The CRC-code is thus _different_ from what will be sent out on radio,
+   the latter being CRC-CCITT (see further below):
+
+      Following CRC16-polynome is used:
+
+         X^16 + X^15 + X^2 + 1
+
+      The CRC-generator is preset to zero.
+
+   Chosen initialize to zero does mean that after a correct packet with a
+   correct checksum is ran thru this CRC, the output checksum will be zero.
+
+   - - - - - - - - -
+
+
+--  ITU-T V.42 / 1993:
+
+   8.1.1.6.1	16-bit frame check sequence
+
+	The FCS field shall be the sixteen-bit sequence preceding the closing
+	flag. The 16-bit FCS shall be the ones complement of the sum (modulo 2)
+	of
+           a)	the remainder of x^k (x^15 + x^14 + x^13 + x^12 +
+	        x^11 + x^10 + x^9 + x^8 + x^7 + x^6 + x^5 + x^4 +
+		x^3 + x^2 + x^1 + 1) divided (modulo 2) by the generator
+		polynomial x^16 + x^12 + x^5 + 1, where k is the number
+		of bits in the frame existing between, but not including,
+		the final bit of the opening flag and the first bit of the
+		FCS, excluding bits inserted for transparency; and
+	   b)	the remainder of the division (modulo 2) by the generator
+	        polynomial x^16 + x^12 + x^5 + 1, of the product of x^16
+		by the content of the frame existing between, but not
+		including, the final bit of the opening flag and the first
+		bit of the FCS, excluding bits inserted for transparency.
+
+	As a typical implementation at the transmitter, the initial content
+	of the register of the device computing the remainder of the division
+	is preset to all 1s and is then modified by division by the generator
+	polynomial (as described above) of the address, control and information
+	fields; the ones complement of the resulting remainder is transmitted
+	as the sixteen-bit FCS.
+
+	As a typical implementation at the receiver, the initial content of
+	the register of the device computing the remainder is preset to all 1s.
+	The final remainder, after multiplication by x^16 and then division
+	(modulo 2) by the generator polynomial x^16 + x^12 + x^5 + 1 of the
+	serial incoming protected bits and the FCS, will be
+	“0001 1101 0000 1111” (x^15 through x^0, respectively) in the absence
+	of transmission errors.
+
+
+  Same wording is also on ITU-T X.25 specification.
+
+   - - - - - - - - -
+
+	Where is FLEXNET CRC specification?
+	
+
+*/
+
+
+// Polynome 0xA001
+// referred from kiss.c !
+const uint16_t crc16_table[] = {
+	0x0000, 0xc0c1, 0xc181, 0x0140, 0xc301, 0x03c0, 0x0280,	0xc241,
+	0xc601, 0x06c0, 0x0780, 0xc741,	0x0500, 0xc5c1, 0xc481,	0x0440,
+	0xcc01, 0x0cc0, 0x0d80, 0xcd41,	0x0f00, 0xcfc1, 0xce81,	0x0e40,
+	0x0a00, 0xcac1, 0xcb81, 0x0b40,	0xc901, 0x09c0, 0x0880,	0xc841,
+
+	0xd801, 0x18c0, 0x1980, 0xd941,	0x1b00, 0xdbc1, 0xda81,	0x1a40,
+	0x1e00, 0xdec1, 0xdf81, 0x1f40,	0xdd01, 0x1dc0, 0x1c80,	0xdc41,
+	0x1400, 0xd4c1, 0xd581, 0x1540,	0xd701, 0x17c0, 0x1680,	0xd641,
+	0xd201, 0x12c0, 0x1380, 0xd341,	0x1100, 0xd1c1, 0xd081,	0x1040,
+
+
+	0xf001, 0x30c0, 0x3180, 0xf141,	0x3300, 0xf3c1, 0xf281,	0x3240,
+	0x3600, 0xf6c1, 0xf781, 0x3740,	0xf501, 0x35c0, 0x3480,	0xf441,
+	0x3c00, 0xfcc1, 0xfd81, 0x3d40,	0xff01, 0x3fc0, 0x3e80,	0xfe41,
+	0xfa01, 0x3ac0, 0x3b80, 0xfb41,	0x3900, 0xf9c1, 0xf881,	0x3840,
+
+	0x2800, 0xe8c1, 0xe981, 0x2940,	0xeb01, 0x2bc0, 0x2a80,	0xea41,
+	0xee01, 0x2ec0, 0x2f80, 0xef41,	0x2d00, 0xedc1, 0xec81,	0x2c40,
+	0xe401, 0x24c0, 0x2580, 0xe541,	0x2700, 0xe7c1, 0xe681,	0x2640,
+	0x2200, 0xe2c1, 0xe381, 0x2340,	0xe101, 0x21c0, 0x2080,	0xe041,
+
+
+	0xa001, 0x60c0, 0x6180, 0xa141,	0x6300, 0xa3c1, 0xa281,	0x6240,
+	0x6600, 0xa6c1, 0xa781, 0x6740,	0xa501, 0x65c0, 0x6480,	0xa441,
+	0x6c00, 0xacc1, 0xad81, 0x6d40,	0xaf01, 0x6fc0, 0x6e80,	0xae41,
+	0xaa01, 0x6ac0, 0x6b80, 0xab41,	0x6900, 0xa9c1, 0xa881,	0x6840,
+
+	0x7800, 0xb8c1, 0xb981, 0x7940,	0xbb01, 0x7bc0, 0x7a80,	0xba41,
+	0xbe01, 0x7ec0, 0x7f80, 0xbf41,	0x7d00, 0xbdc1, 0xbc81,	0x7c40,
+	0xb401, 0x74c0, 0x7580, 0xb541,	0x7700, 0xb7c1, 0xb681,	0x7640,
+	0x7200, 0xb2c1, 0xb381, 0x7340,	0xb101, 0x71c0, 0x7080,	0xb041,
+
+
+	0x5000, 0x90c1, 0x9181, 0x5140,	0x9301, 0x53c0, 0x5280,	0x9241,
+	0x9601, 0x56c0, 0x5780, 0x9741,	0x5500, 0x95c1, 0x9481,	0x5440,
+	0x9c01, 0x5cc0, 0x5d80, 0x9d41,	0x5f00, 0x9fc1, 0x9e81,	0x5e40,
+	0x5a00, 0x9ac1, 0x9b81, 0x5b40,	0x9901, 0x59c0, 0x5880,	0x9841,
+
+	0x8801, 0x48c0, 0x4980, 0x8941,	0x4b00, 0x8bc1, 0x8a81,	0x4a40,
+	0x4e00, 0x8ec1, 0x8f81, 0x4f40,	0x8d01, 0x4dc0, 0x4c80,	0x8c41,
+	0x4400, 0x84c1, 0x8581, 0x4540, 0x8701, 0x47c0, 0x4680,	0x8641,
+	0x8201, 0x42c0, 0x4380, 0x8341,	0x4100, 0x81c1, 0x8081,	0x4040
+};
+
+uint16_t calc_crc_16(const uint8_t *buf, int n)
+{
+	uint16_t crc = 0;
+
+	while (--n >= 0) {
+		crc = (((crc >> 8) & 0xff) ^
+		       crc16_table[(crc ^ *buf++) & 0xFF]);
+	}
+	return crc;
+}
+
+// Return 0 for correct result, anything else for incorrect one
+int check_crc_16(const uint8_t *buf, int n)
+{
+	uint16_t crc = calc_crc_16(buf, n);
+	return (crc != 0); // Correct result is when crc == 0
+}
+
+
+// Polynome 0x8408
+const uint16_t crc_ccitt_table[256] = {
+        0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
+        0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
+        0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
+        0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
+        0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
+        0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
+        0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
+        0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
+        0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
+        0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
+        0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
+        0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
+        0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
+        0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
+        0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
+        0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
+        0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
+        0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
+        0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
+        0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
+        0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
+        0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
+        0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
+        0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
+        0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
+        0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
+        0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
+        0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
+        0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
+        0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
+        0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
+        0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
+};
+
+uint16_t calc_crc_ccitt(uint16_t crc, const uint8_t *buffer, int len)
+{
+        while (len--) {
+		uint8_t c = *buffer++;
+                crc = (crc >> 8) ^ crc_ccitt_table[(crc ^ c) & 0xff];
+	}
+        return crc;
+}
+
+#if 0 // not used!
+// From start of packet to end of packet _including_ 16 bits of FCS
+// Return 0 for OK, other values for errors
+int check_crc_ccitt(const uint8_t *buf, int n) {
+	uint16_t crc = calc_crc_ccitt(0xFFFF, buf, n);
+
+	return (crc != 0xF0B8);
+}
+#endif
+
+
+const uint16_t crc_flex_table[] = {
+	0x0f87, 0x1e0e, 0x2c95, 0x3d1c, 0x49a3, 0x582a, 0x6ab1, 0x7b38,
+	0x83cf, 0x9246, 0xa0dd, 0xb154, 0xc5eb, 0xd462, 0xe6f9, 0xf770,
+	0x1f06, 0x0e8f, 0x3c14, 0x2d9d, 0x5922, 0x48ab, 0x7a30, 0x6bb9,
+	0x934e, 0x82c7, 0xb05c, 0xa1d5, 0xd56a, 0xc4e3, 0xf678, 0xe7f1,
+
+	0x2e85, 0x3f0c, 0x0d97, 0x1c1e, 0x68a1, 0x7928, 0x4bb3, 0x5a3a,
+	0xa2cd, 0xb344, 0x81df, 0x9056, 0xe4e9, 0xf560, 0xc7fb, 0xd672,
+	0x3e04, 0x2f8d, 0x1d16, 0x0c9f, 0x7820, 0x69a9, 0x5b32, 0x4abb,
+	0xb24c, 0xa3c5, 0x915e, 0x80d7, 0xf468, 0xe5e1, 0xd77a, 0xc6f3,
+
+
+	0x4d83, 0x5c0a, 0x6e91, 0x7f18, 0x0ba7, 0x1a2e, 0x28b5, 0x393c,
+	0xc1cb, 0xd042, 0xe2d9, 0xf350, 0x87ef, 0x9666, 0xa4fd, 0xb574,
+	0x5d02, 0x4c8b, 0x7e10, 0x6f99, 0x1b26, 0x0aaf, 0x3834, 0x29bd,
+	0xd14a, 0xc0c3, 0xf258, 0xe3d1, 0x976e, 0x86e7, 0xb47c, 0xa5f5,
+
+	0x6c81, 0x7d08, 0x4f93, 0x5e1a, 0x2aa5, 0x3b2c, 0x09b7, 0x183e,
+	0xe0c9, 0xf140, 0xc3db, 0xd252, 0xa6ed, 0xb764, 0x85ff, 0x9476,
+	0x7c00, 0x6d89, 0x5f12, 0x4e9b, 0x3a24, 0x2bad, 0x1936, 0x08bf,
+	0xf048, 0xe1c1, 0xd35a, 0xc2d3, 0xb66c, 0xa7e5, 0x957e, 0x84f7,
+
+
+	0x8b8f, 0x9a06, 0xa89d, 0xb914, 0xcdab, 0xdc22, 0xeeb9, 0xff30,
+	0x07c7, 0x164e, 0x24d5, 0x355c, 0x41e3, 0x506a, 0x62f1, 0x7378,
+	0x9b0e, 0x8a87, 0xb81c, 0xa995, 0xdd2a, 0xcca3, 0xfe38, 0xefb1,
+	0x1746, 0x06cf, 0x3454, 0x25dd, 0x5162, 0x40eb, 0x7270, 0x63f9,
+
+	0xaa8d, 0xbb04, 0x899f, 0x9816, 0xeca9, 0xfd20, 0xcfbb, 0xde32,
+	0x26c5, 0x374c, 0x05d7, 0x145e, 0x60e1, 0x7168, 0x43f3, 0x527a,
+	0xba0c, 0xab85, 0x991e, 0x8897, 0xfc28, 0xeda1, 0xdf3a, 0xceb3,
+	0x3644, 0x27cd, 0x1556, 0x04df, 0x7060, 0x61e9, 0x5372, 0x42fb,
+
+
+	0xc98b, 0xd802, 0xea99, 0xfb10, 0x8faf, 0x9e26, 0xacbd, 0xbd34,
+	0x45c3, 0x544a, 0x66d1, 0x7758, 0x03e7, 0x126e, 0x20f5, 0x317c,
+	0xd90a, 0xc883, 0xfa18, 0xeb91, 0x9f2e, 0x8ea7, 0xbc3c, 0xadb5,
+	0x5542, 0x44cb, 0x7650, 0x67d9, 0x1366, 0x02ef, 0x3074, 0x21fd,
+
+	0xe889, 0xf900, 0xcb9b, 0xda12, 0xaead, 0xbf24, 0x8dbf, 0x9c36,
+	0x64c1, 0x7548, 0x47d3, 0x565a, 0x22e5, 0x336c, 0x01f7, 0x107e,
+	0xf808, 0xe981, 0xdb1a, 0xca93, 0xbe2c, 0xafa5, 0x9d3e, 0x8cb7,
+	0x7440, 0x65c9, 0x5752, 0x46db, 0x3264, 0x23ed, 0x1176, 0x00ff
+};
+
+uint16_t calc_crc_flex(const uint8_t *cp, int size)
+{
+	uint16_t crc = 0xffff;
+
+	while (size--) {
+	  uint8_t c = *cp++;
+	  crc = (crc << 8) ^ crc_flex_table[((crc >> 8) ^ c) & 0xff];
+	}
+
+	return crc;
+}
+
+#if 0 // not used!
+int check_crc_flex(const uint8_t *cp, int size)
+{
+	uint16_t crc = calc_crc_flex(cp, size);
+
+	if (size < 3)
+		return -1;
+
+	if (crc != 0x7070)
+		return -1;
+
+	return 0;
+}
+#endif
diff --git a/debian/aprx.default b/debian/aprx.default
new file mode 100644
index 0000000..8fe2c08
--- /dev/null
+++ b/debian/aprx.default
@@ -0,0 +1,10 @@
+#
+# STARTAPRX: start aprx on boot. Should be set to "yes" once you have
+#            configured aprx.
+#
+STARTAPRX="no"
+
+#
+# Additional options that are passed to the Daemon.
+#
+DAEMON_OPTS=""
diff --git a/debian/aprx.init b/debian/aprx.init
new file mode 100644
index 0000000..0043822
--- /dev/null
+++ b/debian/aprx.init
@@ -0,0 +1,155 @@
+#! /bin/sh
+### BEGIN INIT INFO
+# Provides:          aprx
+# Required-Start:    $syslog $local_fs
+# Required-Stop:     $syslog $local_fs
+# Should-Start:      ax25ifs
+# Default-Start:     2 3 4 5
+# Default-Stop:      0 1 6
+# Short-Description: start and stop aprx
+# Description:       Monitor and gateway radio amateur APRS radio network datagrams
+### END INIT INFO
+
+# Do NOT "set -e"
+
+# PATH should only include /usr/* if it runs after the mountnfs.sh script
+PATH=/sbin:/usr/sbin:/bin:/usr/bin
+DESC="aprx igate"
+NAME=aprx
+DAEMON=/usr/sbin/$NAME
+DAEMON_ARGS=""
+PIDFILE=/var/run/$NAME.pid
+SCRIPTNAME=/etc/init.d/$NAME
+
+# Exit if the package is not installed
+[ -x "$DAEMON" ] || exit 0
+
+# Read configuration variable file if it is present
+[ -r /etc/default/$NAME ] && . /etc/default/$NAME
+
+# Load the VERBOSE setting and other rcS variables
+. /lib/init/vars.sh
+
+# Define LSB log_* functions.
+# Depend on lsb-base (>= 3.2-14) to ensure that this file is present
+# and status_of_proc is working.
+. /lib/lsb/init-functions
+
+#
+# Function that starts the daemon/service
+#
+do_start()
+{
+        # Return
+        #   0 if daemon has been started
+        #   1 if daemon was already running
+        #   2 if daemon could not be started
+        start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON --test > /dev/null \
+                || return 1
+        start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON -- \
+                $DAEMON_ARGS \
+                || return 2
+        # Add code here, if necessary, that waits for the process to be ready
+        # to handle requests from services started subsequently which depend
+        # on this one.  As a last resort, sleep for some time.
+}
+
+#
+# Function that stops the daemon/service
+#
+do_stop()
+{
+        # Return
+        #   0 if daemon has been stopped
+        #   1 if daemon was already stopped
+        #   2 if daemon could not be stopped
+        #   other if a failure occurred
+        start-stop-daemon --stop --quiet --retry=TERM/30/KILL/5 --pidfile $PIDFILE --name $NAME
+        RETVAL="$?"
+        [ "$RETVAL" = 2 ] && return 2
+        # Wait for children to finish too if this is a daemon that forks
+        # and if the daemon is only ever run from this initscript.
+        # If the above conditions are not satisfied then add some other code
+        # that waits for the process to drop all resources that could be
+        # needed by services started subsequently.  A last resort is to
+        # sleep for some time.
+        start-stop-daemon --stop --quiet --oknodo --retry=0/30/KILL/5 --exec $DAEMON
+        [ "$?" = 2 ] && return 2
+        # Many daemons don't delete their pidfiles when they exit.
+        rm -f $PIDFILE
+        return "$RETVAL"
+}
+
+
+#
+# Function that sends a SIGHUP to the daemon/service
+#
+do_reload() {
+        #
+        # If the daemon can reload its configuration without
+        # restarting (for example, when it is sent a SIGHUP),
+        # then implement that here.
+        #
+        start-stop-daemon --stop --signal 1 --quiet --pidfile $PIDFILE --name $NAME
+        return 0
+}
+
+case "$1" in
+  start)
+        [ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC" "$NAME"
+        do_start
+        case "$?" in
+                0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
+                2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
+        esac
+        ;;
+  stop)
+        [ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME"
+        do_stop
+        case "$?" in
+                0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
+                2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
+        esac
+        ;;
+  status)
+       status_of_proc "$DAEMON" "$NAME" && exit 0 || exit $?
+       ;;
+  #reload|force-reload)
+        #
+        # If do_reload() is not implemented then leave this commented out
+        # and leave 'force-reload' as an alias for 'restart'.
+        #
+        #log_daemon_msg "Reloading $DESC" "$NAME"
+        #do_reload
+        #log_end_msg $?
+        #;;
+  restart|force-reload)
+        #
+        # If the "reload" option is implemented then remove the
+        # 'force-reload' alias
+        #
+        log_daemon_msg "Restarting $DESC" "$NAME"
+        do_stop
+        case "$?" in
+          0|1)
+                do_start
+                case "$?" in
+                        0) log_end_msg 0 ;;
+                        1) log_end_msg 1 ;; # Old process is still running
+                        *) log_end_msg 1 ;; # Failed to start
+                esac
+                ;;
+          *)
+                # Failed to stop
+                log_end_msg 1
+                ;;
+        esac
+        ;;
+  *)
+        #echo "Usage: $SCRIPTNAME {start|stop|restart|reload|force-reload}" >&2
+        echo "Usage: $SCRIPTNAME {start|stop|status|restart|force-reload}" >&2
+        exit 3
+        ;;
+esac
+
+:
diff --git a/debian/aprx.postinst.debhelper b/debian/aprx.postinst.debhelper
new file mode 100644
index 0000000..d9381e4
--- /dev/null
+++ b/debian/aprx.postinst.debhelper
@@ -0,0 +1,15 @@
+# Automatically added by dh_installinit
+if [ -x "/etc/init.d/aprx" ]; then
+	update-rc.d aprx defaults >/dev/null
+	if [ -n "$2" ]; then
+		_dh_action=restart
+	else
+		_dh_action=start
+	fi
+	if [ -x "`which invoke-rc.d 2>/dev/null`" ]; then
+		invoke-rc.d aprx $_dh_action || exit $?
+	else
+		/etc/init.d/aprx $_dh_action || exit $?
+	fi
+fi
+# End automatically added section
diff --git a/debian/aprx.postrm.debhelper b/debian/aprx.postrm.debhelper
new file mode 100644
index 0000000..bc814dd
--- /dev/null
+++ b/debian/aprx.postrm.debhelper
@@ -0,0 +1,5 @@
+# Automatically added by dh_installinit
+if [ "$1" = "purge" ] ; then
+	update-rc.d aprx remove >/dev/null || exit $?
+fi
+# End automatically added section
diff --git a/debian/aprx.prerm.debhelper b/debian/aprx.prerm.debhelper
new file mode 100644
index 0000000..0e93bb5
--- /dev/null
+++ b/debian/aprx.prerm.debhelper
@@ -0,0 +1,9 @@
+# Automatically added by dh_installinit
+if [ -x "/etc/init.d/aprx" ] && [ "$1" = remove ]; then
+	if [ -x "`which invoke-rc.d 2>/dev/null`" ]; then
+		invoke-rc.d aprx stop || exit $?
+	else
+		/etc/init.d/aprx stop || exit $?
+	fi
+fi
+# End automatically added section
diff --git a/debian/aprx.substvars b/debian/aprx.substvars
new file mode 100644
index 0000000..36e5a58
--- /dev/null
+++ b/debian/aprx.substvars
@@ -0,0 +1 @@
+shlibs:Depends=libc6 (>= 2.7-1)
diff --git a/debian/aprx/DEBIAN/conffiles b/debian/aprx/DEBIAN/conffiles
new file mode 100644
index 0000000..4c1c3ce
--- /dev/null
+++ b/debian/aprx/DEBIAN/conffiles
@@ -0,0 +1,5 @@
+/etc/apparmor.d/sbin.aprx
+/etc/aprx.conf
+/etc/logrotate.d/aprx
+/etc/default/aprx
+/etc/init.d/aprx
diff --git a/debian/aprx/DEBIAN/control b/debian/aprx/DEBIAN/control
new file mode 100644
index 0000000..b739b92
--- /dev/null
+++ b/debian/aprx/DEBIAN/control
@@ -0,0 +1,19 @@
+Package: aprx
+Version: 2.08.580-1
+Architecture: i386
+Maintainer: HAM APRX release  maintenance <aprx at ham>
+Installed-Size: 1048
+Depends: libc6 (>= 2.7-1), openssl
+Section: hamradio
+Priority: extra
+Description: APRS Digipeater and iGate
+ Aprx is an APRS specific Digipeater and iGate.
+ It supports multiple KISS-TNCs on serial ports  and listening
+ to any kernel AX.25 network interfaces.
+ .
+ Additional features include a built-in "erlang-monitor" to analyze
+ activity level of radio channels.
+ .
+ This software requires a valid (and unique) ham radio callsign to
+ operate fully and is therefore useful mainly for licensed radio
+ amateurs.
diff --git a/debian/aprx/DEBIAN/md5sums b/debian/aprx/DEBIAN/md5sums
new file mode 100644
index 0000000..282a406
--- /dev/null
+++ b/debian/aprx/DEBIAN/md5sums
@@ -0,0 +1,13 @@
+7c2a0786fee7fee92b86115088853a62  usr/sbin/aprx
+d6a98f1bbd799491f9559fc43e8bf7f6  usr/sbin/aprx-stat
+a9d04507f86642315745ba8f0e76df32  usr/share/man/man8/aprx.8.gz
+9cf04acfcca16e1c5791bcd395052b27  usr/share/man/man8/aprx-stat.8.gz
+673c8ba180344e2d5c22bb75f99809ae  usr/share/doc/aprx/README
+09890d56e7d42c48f4bafcff6366b304  usr/share/doc/aprx/LICENSE
+6a4c523ff4e1adba1aaf0b8d3325fb08  usr/share/doc/aprx/ROADMAP
+c994b2fce146b8ef5cda6678ca45b6f2  usr/share/doc/aprx/copyright
+261f41ba62cd3667fa45400cb41c92f9  usr/share/doc/aprx/TODO.gz
+70e5e4e805429add4c0fd5958722e6b3  usr/share/doc/aprx/PROTOCOLS.gz
+5105fa38a3b4f732baea02a62b5c6eb9  usr/share/doc/aprx/aprx.conf.gz
+02cd7c464362015dd31ea4c5e0d8fe2b  usr/share/doc/aprx/aprx-complex.conf.gz
+4823ba66d187982a7570635cbed33a79  usr/share/doc/aprx/aprx-manual.pdf.gz
diff --git a/debian/aprx/DEBIAN/postinst b/debian/aprx/DEBIAN/postinst
new file mode 100755
index 0000000..d0406f7
--- /dev/null
+++ b/debian/aprx/DEBIAN/postinst
@@ -0,0 +1,17 @@
+#!/bin/sh
+set -e
+# Automatically added by dh_installinit
+if [ -x "/etc/init.d/aprx" ]; then
+	update-rc.d aprx defaults >/dev/null
+	if [ -n "$2" ]; then
+		_dh_action=restart
+	else
+		_dh_action=start
+	fi
+	if [ -x "`which invoke-rc.d 2>/dev/null`" ]; then
+		invoke-rc.d aprx $_dh_action || exit $?
+	else
+		/etc/init.d/aprx $_dh_action || exit $?
+	fi
+fi
+# End automatically added section
diff --git a/debian/aprx/DEBIAN/postrm b/debian/aprx/DEBIAN/postrm
new file mode 100755
index 0000000..4dd5333
--- /dev/null
+++ b/debian/aprx/DEBIAN/postrm
@@ -0,0 +1,7 @@
+#!/bin/sh
+set -e
+# Automatically added by dh_installinit
+if [ "$1" = "purge" ] ; then
+	update-rc.d aprx remove >/dev/null || exit $?
+fi
+# End automatically added section
diff --git a/debian/aprx/DEBIAN/prerm b/debian/aprx/DEBIAN/prerm
new file mode 100755
index 0000000..f96d6f9
--- /dev/null
+++ b/debian/aprx/DEBIAN/prerm
@@ -0,0 +1,11 @@
+#!/bin/sh
+set -e
+# Automatically added by dh_installinit
+if [ -x "/etc/init.d/aprx" ] && [ "$1" = remove ]; then
+	if [ -x "`which invoke-rc.d 2>/dev/null`" ]; then
+		invoke-rc.d aprx stop || exit $?
+	else
+		/etc/init.d/aprx stop || exit $?
+	fi
+fi
+# End automatically added section
diff --git a/debian/aprx/etc/apparmor.d/sbin.aprx b/debian/aprx/etc/apparmor.d/sbin.aprx
new file mode 100644
index 0000000..00b878f
--- /dev/null
+++ b/debian/aprx/etc/apparmor.d/sbin.aprx
@@ -0,0 +1,17 @@
+#include <tunables/global>
+
+/sbin/aprx {
+  #include <abstractions/base>
+  #include <abstractions/nameservice>
+
+
+  capability setgid,
+  capability setuid,
+  capability sys_chroot,
+
+
+  /etc/aprx.conf r,
+  owner /var/run/aprx.pid rwk,
+  owner /var/run/aprx.state rwk,
+  owner /var/log/aprx/* rwk,
+}
diff --git a/debian/aprx/etc/default/aprx b/debian/aprx/etc/default/aprx
new file mode 100644
index 0000000..8fe2c08
--- /dev/null
+++ b/debian/aprx/etc/default/aprx
@@ -0,0 +1,10 @@
+#
+# STARTAPRX: start aprx on boot. Should be set to "yes" once you have
+#            configured aprx.
+#
+STARTAPRX="no"
+
+#
+# Additional options that are passed to the Daemon.
+#
+DAEMON_OPTS=""
diff --git a/debian/aprx/etc/init.d/aprx b/debian/aprx/etc/init.d/aprx
new file mode 100755
index 0000000..0043822
--- /dev/null
+++ b/debian/aprx/etc/init.d/aprx
@@ -0,0 +1,155 @@
+#! /bin/sh
+### BEGIN INIT INFO
+# Provides:          aprx
+# Required-Start:    $syslog $local_fs
+# Required-Stop:     $syslog $local_fs
+# Should-Start:      ax25ifs
+# Default-Start:     2 3 4 5
+# Default-Stop:      0 1 6
+# Short-Description: start and stop aprx
+# Description:       Monitor and gateway radio amateur APRS radio network datagrams
+### END INIT INFO
+
+# Do NOT "set -e"
+
+# PATH should only include /usr/* if it runs after the mountnfs.sh script
+PATH=/sbin:/usr/sbin:/bin:/usr/bin
+DESC="aprx igate"
+NAME=aprx
+DAEMON=/usr/sbin/$NAME
+DAEMON_ARGS=""
+PIDFILE=/var/run/$NAME.pid
+SCRIPTNAME=/etc/init.d/$NAME
+
+# Exit if the package is not installed
+[ -x "$DAEMON" ] || exit 0
+
+# Read configuration variable file if it is present
+[ -r /etc/default/$NAME ] && . /etc/default/$NAME
+
+# Load the VERBOSE setting and other rcS variables
+. /lib/init/vars.sh
+
+# Define LSB log_* functions.
+# Depend on lsb-base (>= 3.2-14) to ensure that this file is present
+# and status_of_proc is working.
+. /lib/lsb/init-functions
+
+#
+# Function that starts the daemon/service
+#
+do_start()
+{
+        # Return
+        #   0 if daemon has been started
+        #   1 if daemon was already running
+        #   2 if daemon could not be started
+        start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON --test > /dev/null \
+                || return 1
+        start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON -- \
+                $DAEMON_ARGS \
+                || return 2
+        # Add code here, if necessary, that waits for the process to be ready
+        # to handle requests from services started subsequently which depend
+        # on this one.  As a last resort, sleep for some time.
+}
+
+#
+# Function that stops the daemon/service
+#
+do_stop()
+{
+        # Return
+        #   0 if daemon has been stopped
+        #   1 if daemon was already stopped
+        #   2 if daemon could not be stopped
+        #   other if a failure occurred
+        start-stop-daemon --stop --quiet --retry=TERM/30/KILL/5 --pidfile $PIDFILE --name $NAME
+        RETVAL="$?"
+        [ "$RETVAL" = 2 ] && return 2
+        # Wait for children to finish too if this is a daemon that forks
+        # and if the daemon is only ever run from this initscript.
+        # If the above conditions are not satisfied then add some other code
+        # that waits for the process to drop all resources that could be
+        # needed by services started subsequently.  A last resort is to
+        # sleep for some time.
+        start-stop-daemon --stop --quiet --oknodo --retry=0/30/KILL/5 --exec $DAEMON
+        [ "$?" = 2 ] && return 2
+        # Many daemons don't delete their pidfiles when they exit.
+        rm -f $PIDFILE
+        return "$RETVAL"
+}
+
+
+#
+# Function that sends a SIGHUP to the daemon/service
+#
+do_reload() {
+        #
+        # If the daemon can reload its configuration without
+        # restarting (for example, when it is sent a SIGHUP),
+        # then implement that here.
+        #
+        start-stop-daemon --stop --signal 1 --quiet --pidfile $PIDFILE --name $NAME
+        return 0
+}
+
+case "$1" in
+  start)
+        [ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC" "$NAME"
+        do_start
+        case "$?" in
+                0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
+                2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
+        esac
+        ;;
+  stop)
+        [ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME"
+        do_stop
+        case "$?" in
+                0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
+                2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
+        esac
+        ;;
+  status)
+       status_of_proc "$DAEMON" "$NAME" && exit 0 || exit $?
+       ;;
+  #reload|force-reload)
+        #
+        # If do_reload() is not implemented then leave this commented out
+        # and leave 'force-reload' as an alias for 'restart'.
+        #
+        #log_daemon_msg "Reloading $DESC" "$NAME"
+        #do_reload
+        #log_end_msg $?
+        #;;
+  restart|force-reload)
+        #
+        # If the "reload" option is implemented then remove the
+        # 'force-reload' alias
+        #
+        log_daemon_msg "Restarting $DESC" "$NAME"
+        do_stop
+        case "$?" in
+          0|1)
+                do_start
+                case "$?" in
+                        0) log_end_msg 0 ;;
+                        1) log_end_msg 1 ;; # Old process is still running
+                        *) log_end_msg 1 ;; # Failed to start
+                esac
+                ;;
+          *)
+                # Failed to stop
+                log_end_msg 1
+                ;;
+        esac
+        ;;
+  *)
+        #echo "Usage: $SCRIPTNAME {start|stop|restart|reload|force-reload}" >&2
+        echo "Usage: $SCRIPTNAME {start|stop|status|restart|force-reload}" >&2
+        exit 3
+        ;;
+esac
+
+:
diff --git a/debian/aprx/etc/logrotate.d/aprx b/debian/aprx/etc/logrotate.d/aprx
new file mode 100644
index 0000000..3665ba2
--- /dev/null
+++ b/debian/aprx/etc/logrotate.d/aprx
@@ -0,0 +1,8 @@
+/var/log/aprx/aprx-rf.log /var/log/aprx/aprx.log  /var/log/aprx/dprs.log  /var/log/aprx/erlang.log {
+	weekly
+	rotate 4
+	compress
+	missingok
+	notifempty
+	create 644 root adm
+}
diff --git a/debian/aprx/usr/sbin/aprx b/debian/aprx/usr/sbin/aprx
new file mode 100755
index 0000000..b078b09
Binary files /dev/null and b/debian/aprx/usr/sbin/aprx differ
diff --git a/debian/aprx/usr/sbin/aprx-stat b/debian/aprx/usr/sbin/aprx-stat
new file mode 100755
index 0000000..bd8f3bb
Binary files /dev/null and b/debian/aprx/usr/sbin/aprx-stat differ
diff --git a/debian/aprx/usr/share/doc/aprx/LICENSE b/debian/aprx/usr/share/doc/aprx/LICENSE
new file mode 100644
index 0000000..db21adc
--- /dev/null
+++ b/debian/aprx/usr/share/doc/aprx/LICENSE
@@ -0,0 +1,27 @@
+Copyright (c) 2007-2014, Matti Aarnio
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of  Matti Aarnio  nor the names of its contributors
+      may be used to endorse or promote products derived from this software
+      without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/debian/aprx/usr/share/doc/aprx/PROTOCOLS.gz b/debian/aprx/usr/share/doc/aprx/PROTOCOLS.gz
new file mode 100644
index 0000000..a623c2d
Binary files /dev/null and b/debian/aprx/usr/share/doc/aprx/PROTOCOLS.gz differ
diff --git a/debian/aprx/usr/share/doc/aprx/README b/debian/aprx/usr/share/doc/aprx/README
new file mode 100644
index 0000000..8c130bc
--- /dev/null
+++ b/debian/aprx/usr/share/doc/aprx/README
@@ -0,0 +1,86 @@
+
+		APRX    v2.08
+
+A multitalented APRS / DPRS / APRSIS "i-gate" with following properties:
+
+   Config file (-f option) default is:  /etc/aprx.conf
+   Other runtime options are: -v,  -d,  -h/-?  (verbout, debug and help)
+
+   - Rx-IGate functionality works correctly
+   - Tx-IGate functionality works correctly
+
+   - Can do APRS New-N and generic AX.25 node digipeater functionality
+     with transmitters
+
+   - Has same-channel Viscous Digipeater functionality to not to digipeat
+     at all, if during initial wait period the packet is heard again.
+
+   - Has cross-interface Viscous Digipeater functionality to not to digipeat,
+     if during the initial wait period the packet is heard on destination
+     interface at least once, and at least once from other sources.
+
+   - Can receive data from multiple receivers/modems on local machine
+     serial ports, both classical and USB.
+
+   - Can receive data from remote TCP stream connectable serial ports
+     over the internet.
+
+   - Understands on serial ports (local and remote TCP ones):
+       - several KISS protocol variants, checksummed variants preferred
+       - TNC2 debug style text (Rx-iGate receive only.)
+       - D-STAR data side-channel "D-PRS"
+
+   - Connects with one  callsign-ssid  pair to APRS-IS core for all
+     received radio ports (the "mycall" parameter), but reports
+     receiving radio port at each Rx-iGated packet
+
+   - Knows that messages with following tokens in VIA fields of the
+     path are not to be relayed into network:
+              RFONLY, NOGATE, TCPIP, TCPXX
+
+   - Knows that following source address prefixes are bogus and thus
+     to be junked at Rx-iGate:
+              WIDE, RELAY, TRACE, TCPIP, TCPXX, NOCALL, N0CALL
+     (Actually these are string prefixes, so any WIDE*-* will block, etc.)
+
+   - Has integrated D-PRS -> APRS/APRSIS Rx-iGate.
+     Can even do D-PRS -> APRS RF conversion.
+     This is experimental quality for "GPS" packets, the "GPS-A" is OK.
+
+   - Does not require machine to have AX.25 protocol support internally!
+
+   - On Linux machine with kernel internal AX.25 protocol support, does
+     listen on internal AX.25 network in promiscuous form, and requires
+     to be running as root to do that.   Does not fail to start in case
+     the port fails to open (running as non-root.)
+
+   - Built-in "erlang-monitor" actually counts bytes per time interval
+     (1 min, 10 min, and 20 min)  on each receiving interface, including
+     all that feed internal AX.25 network.
+
+   - Telemetry reported erlang data is sent out every 20 minutes, and
+     contains summarized data from 10 minute round-robin memory arrays.
+     These are _not_ sent at exact 10 minutes of wall-clock, but exact
+     20 minutes from previous telemetry reporting, and first one is sent
+     20 minutes after program start.
+
+   - Telemetry reported erlang data can be sent also over APRS radio
+     port, but only for ports with valid AX.25 callsigns. See aprx-manual.pdf
+
+   - The netbeacons are distributed timewise more evenly around the interval,
+     and even the interval length is varied at random in between 20 and 30
+     minutes.  Number of netbeacons are unlimited, but their minimum transmit
+     interval is 3 seconds making the amount of beacons sendable in 20 minutes
+     to be: 20*60/3 = 400.  All will be sent, but the cycle will just take
+     longer.
+
+   - Source code is at SVN repository:   http://repo.ham.fi/svn/aprx
+   - A Wiki page of this package:        http://wiki.ham.fi/Aprx.en
+   - A google-group for Aprx:   http://groups.google.com/group/aprx-software
+
+   - This program is also compilable as "EMBEDDED" target without
+     any statistics buffer required at the system disk (or RAM-disk).
+     See the INSTALL file.
+
+
+by Matti Aarnio - OH2MQK - oh2mqk-at-sral-fi - 2007-2014
diff --git a/debian/aprx/usr/share/doc/aprx/ROADMAP b/debian/aprx/usr/share/doc/aprx/ROADMAP
new file mode 100644
index 0000000..95f70c4
--- /dev/null
+++ b/debian/aprx/usr/share/doc/aprx/ROADMAP
@@ -0,0 +1,26 @@
+		Aprx Roadmap and Future Directions
+
+
+Version 1
+    - APRS Rx-only iGate				- Complete, working
+    - channel activity monitoring and telemetry		- Complete, working
+
+
+Version 2
+    - Digipeater					- Working
+      - Analyze and detect station distance             - Working
+    - Radio beacons					- Working
+    - Bidirection (Rx/Tx) APRS iGate			- Working
+    - DPRS->APRS GW	       				- Working
+
+Version 2+
+
+    - Port to ucLinux	       				- Planned (pthread OK)
+
+    - Port to Windows
+
+    - Automated coverage statistics analyzer, and
+      reporting it via digi node identity beacons.
+            "ALOHA circles"
+
+    - Automated coverage plotting
diff --git a/debian/aprx/usr/share/doc/aprx/TODO.gz b/debian/aprx/usr/share/doc/aprx/TODO.gz
new file mode 100644
index 0000000..848a682
Binary files /dev/null and b/debian/aprx/usr/share/doc/aprx/TODO.gz differ
diff --git a/debian/aprx/usr/share/doc/aprx/aprx-complex.conf.gz b/debian/aprx/usr/share/doc/aprx/aprx-complex.conf.gz
new file mode 100644
index 0000000..331afe6
Binary files /dev/null and b/debian/aprx/usr/share/doc/aprx/aprx-complex.conf.gz differ
diff --git a/debian/aprx/usr/share/doc/aprx/aprx-manual.pdf.gz b/debian/aprx/usr/share/doc/aprx/aprx-manual.pdf.gz
new file mode 100644
index 0000000..238586e
Binary files /dev/null and b/debian/aprx/usr/share/doc/aprx/aprx-manual.pdf.gz differ
diff --git a/debian/aprx/usr/share/doc/aprx/aprx.conf.gz b/debian/aprx/usr/share/doc/aprx/aprx.conf.gz
new file mode 100644
index 0000000..3a2c225
Binary files /dev/null and b/debian/aprx/usr/share/doc/aprx/aprx.conf.gz differ
diff --git a/debian/aprx/usr/share/doc/aprx/copyright b/debian/aprx/usr/share/doc/aprx/copyright
new file mode 100644
index 0000000..322cb19
--- /dev/null
+++ b/debian/aprx/usr/share/doc/aprx/copyright
@@ -0,0 +1 @@
+See LICENSE.
diff --git a/debian/aprx/usr/share/man/man8/aprx-stat.8.gz b/debian/aprx/usr/share/man/man8/aprx-stat.8.gz
new file mode 100644
index 0000000..0bf6968
Binary files /dev/null and b/debian/aprx/usr/share/man/man8/aprx-stat.8.gz differ
diff --git a/debian/aprx/usr/share/man/man8/aprx.8.gz b/debian/aprx/usr/share/man/man8/aprx.8.gz
new file mode 100644
index 0000000..4d3b82c
Binary files /dev/null and b/debian/aprx/usr/share/man/man8/aprx.8.gz differ
diff --git a/debian/changelog b/debian/changelog
new file mode 100644
index 0000000..3b6a4a0
--- /dev/null
+++ b/debian/changelog
@@ -0,0 +1,12 @@
+aprx (2.08.593-1) unstable; urgency=low
+
+  * See main ChangeLog.
+
+ -- aprx maintainer <arpx at ham>  Sun, 06 Apr 2014 02:06:07 +0300
+
+aprx (0.0.0-1) unstable; urgency=low
+
+  * Initial debianization.
+
+ -- Kimmo Jukarainen <oh3gnu at ham>  Thu,  3 Jan 2008 20:35:29 +0200
+
diff --git a/debian/compat b/debian/compat
new file mode 100644
index 0000000..7ed6ff8
--- /dev/null
+++ b/debian/compat
@@ -0,0 +1 @@
+5
diff --git a/debian/control b/debian/control
new file mode 100644
index 0000000..139e156
--- /dev/null
+++ b/debian/control
@@ -0,0 +1,22 @@
+Source: aprx
+Section: hamradio
+Priority: extra
+Maintainer: HAM APRX release  maintenance <aprx at ham>
+Build-Depends: debhelper (>= 4), libssl-dev
+Standards-Version: 3.7.2
+
+Package: aprx
+Architecture: any
+Depends: ${shlibs:Depends}, openssl
+Description: APRS Digipeater and iGate
+ Aprx is an APRS specific Digipeater and iGate.
+ It supports multiple KISS-TNCs on serial ports  and listening 
+ to any kernel AX.25 network interfaces.
+ .
+ Additional features include a built-in "erlang-monitor" to analyze
+ activity level of radio channels.
+ .
+ This software requires a valid (and unique) ham radio callsign to
+ operate fully and is therefore useful mainly for licensed radio
+ amateurs.
+
diff --git a/debian/copyright b/debian/copyright
new file mode 100644
index 0000000..322cb19
--- /dev/null
+++ b/debian/copyright
@@ -0,0 +1 @@
+See LICENSE.
diff --git a/debian/dirs b/debian/dirs
new file mode 100644
index 0000000..0ded9b9
--- /dev/null
+++ b/debian/dirs
@@ -0,0 +1,6 @@
+etc/
+etc/apparmor.d
+usr/sbin
+usr/share/man/man8
+var/log/aprx
+var/run
diff --git a/debian/docs b/debian/docs
new file mode 100644
index 0000000..1a08e42
--- /dev/null
+++ b/debian/docs
@@ -0,0 +1,8 @@
+README
+TODO
+PROTOCOLS
+LICENSE
+ROADMAP
+aprx.conf
+aprx-complex.conf
+doc/aprx-manual.pdf
diff --git a/debian/files b/debian/files
new file mode 100644
index 0000000..0d9a581
--- /dev/null
+++ b/debian/files
@@ -0,0 +1 @@
+aprx_2.08.580-1_i386.deb hamradio extra
diff --git a/debian/postinst.off b/debian/postinst.off
new file mode 100644
index 0000000..2c75b45
--- /dev/null
+++ b/debian/postinst.off
@@ -0,0 +1,49 @@
+#!/bin/sh -e
+
+action="$1"
+oldversion="$2"
+
+. /usr/share/debconf/confmodule
+db_version 2.0
+
+umask 022
+
+if [ "$action" != configure ] ; then
+	exit 0
+fi
+
+# functions
+
+setup_aprx_user() {
+        if ! getent passwd aprsc >/dev/null; then
+        	echo "Creating user account: 'aprsc'"
+                adduser --quiet --system --no-create-home --home /var/run/aprx --shell /usr/sbin/nologin --group aprx
+        fi
+}
+
+fix_permissions() {
+        :
+	# chown aprx:aprx /opt/aprsc/logs /opt/aprsc/data
+}
+
+apparmor_config() {
+	# Reload AppArmor profile
+	APP_PROFILE="/etc/apparmor.d/sbin.aprx"
+	if [ -f "$APP_PROFILE" ] && aa-status --enabled 2>/dev/null; then
+		echo "Installing apparmor profile..."
+		apparmor_parser -r -T -W "$APP_PROFILE" || true
+	fi
+}
+
+# main
+
+# setup_aprx_user
+# fix_permissions
+apparmor_config
+
+# dh_installdeb will replace this with shell code automatically
+# generated by other debhelper scripts.
+
+#DEBHELPER#
+
+exit 0
diff --git a/debian/rules b/debian/rules
new file mode 100755
index 0000000..8ce7c56
--- /dev/null
+++ b/debian/rules
@@ -0,0 +1,96 @@
+#!/usr/bin/make -f
+
+# Uncomment this to turn on verbose mode.
+#export DH_VERBOSE=1
+
+CFLAGS = -Wall -g
+
+ifneq (,$(findstring noopt,$(DEB_BUILD_OPTIONS)))
+	CFLAGS += -O0
+else
+	CFLAGS += -O2
+endif
+
+configure: configure-stamp
+configure-stamp:
+	dh_testdir
+	# Add here commands to configure the package.
+	./configure --with-pthread --sbindir=/usr/sbin --sysconfdir=/etc \
+		--localstatedir=/var --mandir=/usr/share/man \
+		CC="gcc" \
+		CFLAGS="${CFLAGS}" \
+		AFLAGS="${CFLAGS} --noexecstack" \
+		LDFLAGS="${CFLAGS} -z noexecstack"
+	touch configure-stamp
+
+
+build: build-stamp
+
+build-stamp: configure-stamp 
+	dh_testdir
+
+	# Add here commands to compile the package.
+	$(MAKE)
+	#docbook-to-man debian/aprx.sgml > aprx.1
+
+	touch $@
+
+clean:
+	dh_testdir
+	dh_testroot
+	rm -f build-stamp configure-stamp
+
+	# Add here commands to clean up after the build process.
+	-$(MAKE) clean
+	rm -f debian/aprx.logrotate
+
+	dh_clean 
+
+install: build
+	dh_testdir
+	dh_testroot
+	dh_clean -k 
+	dh_installdirs
+
+	# Add here commands to install the package into debian/aprx.
+	$(MAKE) DESTDIR=$(CURDIR)/debian/aprx logrotate.aprx install
+	cp logrotate.aprx debian/aprx.logrotate
+	install -m 644 apparmor.aprx $(CURDIR)/debian/aprx/etc/apparmor.d/sbin.aprx
+
+# Build architecture-independent files here.
+binary-indep: build install
+# We have nothing to do by default.
+
+# Build architecture-dependent files here.
+binary-arch: build install
+	dh_testdir
+	dh_testroot
+#	dh_installchangelogs ChangeLog
+	dh_installdocs
+	dh_installexamples
+#	dh_install
+#	dh_installmenu
+#	dh_installdebconf	
+	dh_installlogrotate
+#	dh_installemacsen
+#	dh_installpam
+#	dh_installmime
+#	dh_python
+	dh_installinit --restart-after-upgrade
+#	dh_installcron
+#	dh_installinfo
+	dh_installman
+	dh_link
+#	dh_strip
+	dh_compress
+	dh_fixperms
+#	dh_perl
+#	dh_makeshlibs
+	dh_installdeb
+	dh_shlibdeps
+	dh_gencontrol
+	dh_md5sums
+	dh_builddeb
+
+binary: binary-indep binary-arch
+.PHONY: build clean binary-indep binary-arch binary install configure
diff --git a/digipeater.c b/digipeater.c
new file mode 100644
index 0000000..329169a
--- /dev/null
+++ b/digipeater.c
@@ -0,0 +1,1867 @@
+/* **************************************************************** *
+ *                                                                  *
+ *  APRX -- 2nd generation receive-only APRS-i-gate with            *
+ *          minimal requirement of esoteric facilities or           *
+ *          libraries of any kind beyond UNIX system libc.          *
+ *                                                                  *
+ * (c) Matti Aarnio - OH2MQK,  2007-2014                            *
+ *                                                                  *
+ * **************************************************************** */
+
+#include "aprx.h"
+
+static int digi_count;
+static struct digipeater **digis;
+
+#define TOKENBUCKET_INTERVAL 5  // 5 seconds per refill.
+                                // 60/5 part of "ratelimit" to be max
+                                // that token bucket can be filled to.
+
+static struct timeval tokenbucket_timer;
+
+struct viastate {
+        int hopsreq;
+        int hopsdone;
+        int tracereq;
+        int tracedone;
+        int digireq;
+        int digidone;
+
+        int fixthis;
+        int fixall;
+        int probably_heard_direct;
+};
+
+struct digistate {
+        struct viastate v;
+
+        int     ax25addrlen;
+        uint8_t ax25addr[90]; // 70 for address, a bit more for "body"
+};
+
+
+#define AX25ADDRMAXLEN 70  // SRC + DEST + 8*VIA (7 bytes each)
+#define AX25ADDRLEN  7
+#define AX25HBIT  0x80
+#define AX25ATERM 0x01
+
+static char * tracewords[] = { "WIDE","TRACE","RELAY" };
+static int tracewordlens[] = { 4, 5, 5 };
+static const struct tracewide default_trace_param = {
+        4, 4, 1,
+        3,
+        tracewords,
+        tracewordlens
+};
+static char * widewords[] = { "WIDE","RELAY" };
+static int widewordlens[] = { 4,5 };
+static const struct tracewide default_wide_param = {
+        4, 4, 0,
+        2,
+        widewords,
+        widewordlens
+};
+
+static int  run_tokenbucket_timers(void);
+
+
+float ratelimitmax     = 9999999.9;
+float rateincrementmax = 9999999.9;
+
+
+/*
+ * regex_filter_add() -- adds configured regular expressions
+ *                       into forbidden patterns list.
+ * 
+ * These are actually processed on TNC2 format text line, and not
+ * AX.25 datastream per se.
+ */
+static int regex_filter_add(struct configfile *cf,
+                            struct digipeater_source *src,
+                            char *param1,
+                            char *str)
+{
+        int rc;
+        int groupcode = -1;
+        regex_t re, *rep;
+        char errbuf[2000];
+
+        if (strcmp(param1, "source") == 0) {
+                groupcode = 0;
+        } else if (strcmp(param1, "destination") == 0) {
+                groupcode = 1;
+        } else if (strcmp(param1, "via") == 0) {
+                groupcode = 2;
+        } else if (strcmp(param1, "data") == 0) {
+                groupcode = 3;
+        } else {
+                printf("%s:%d ERROR: Bad RE target: '%s'  must be one of: source, destination, via\n",
+                       cf->name, cf->linenum, param1);
+                return 1;
+        }
+
+        if (!*str) {
+                printf("%s:%d ERROR: Expected RE pattern missing or a NUL string.\n",
+                       cf->name, cf->linenum);
+                return 1;               /* Bad input.. */
+        }
+
+        param1 = str;
+        str = config_SKIPTEXT(str, NULL); // Handle quoted string
+        str = config_SKIPSPACE(str);
+
+        memset(&re, 0, sizeof(re));
+        rc = regcomp(&re, param1, REG_EXTENDED | REG_NOSUB);
+
+        if (rc != 0) {          /* Something is bad.. */
+                *errbuf = 0;
+                regerror(rc, &re, errbuf, sizeof(errbuf));
+                printf("%s:%d ERROR: Bad POSIX RE input, error: %s\n",
+                       cf->name, cf->linenum, errbuf);
+                return 1;
+        }
+
+        /* param1 and str were processed successfully ... */
+
+        rep = calloc(1,sizeof(*rep));
+        *rep = re;
+
+        switch (groupcode) {
+        case 0:
+                src->sourceregscount += 1;
+                src->sourceregs =
+                        realloc(src->sourceregs,
+                                src->sourceregscount * sizeof(void *));
+                src->sourceregs[src->sourceregscount - 1] = rep;
+                break;
+        case 1:
+                src->destinationregscount += 1;
+                src->destinationregs =
+                        realloc(src->destinationregs,
+                                src->destinationregscount * sizeof(void *));
+                src->destinationregs[src->destinationregscount - 1] = rep;
+                break;
+        case 2:
+                src->viaregscount += 1;
+                src->viaregs = realloc(src->viaregs,
+                                       src->viaregscount * sizeof(void *));
+                src->viaregs[src->viaregscount - 1] = rep;
+                break;
+        case 3:
+                src->dataregscount += 1;
+                src->dataregs =
+                        realloc(src->dataregs,
+                                src->dataregscount * sizeof(void *));
+                src->dataregs[src->dataregscount - 1] = rep;
+                break;
+        }
+        return 0; // OK state
+}
+
+
+static int match_tracewide(const char *via, const struct tracewide *twp)
+{
+        int i;
+        if (twp == NULL) return 0;
+
+        for (i = 0; i < twp->nkeys; ++i) {
+                // if (debug>2) printf(" match:'%s'",twp->keys[i]);
+                if (memcmp(via, twp->keys[i], twp->keylens[i]) == 0) {
+                        return twp->keylens[i];
+                }
+        }
+        return 0;
+}
+
+static int match_aliases(const char *via, struct aprx_interface *txif)
+{
+        int i;
+        for (i = 0; i < txif->aliascount; ++i) {
+                if (strcmp(via, txif->aliases[i]) == 0)
+                        return 1;
+        }
+        return 0;
+}
+
+static int count_single_tnc2_tracewide(struct viastate *state, const char *viafield, const int istrace, const int matchlen, const int viaindex)
+{
+        const char *p = viafield + matchlen;
+        const char reqc = p[0];
+        const char c    = p[1];
+        const char remc = p[2];
+        int req, done;
+
+        int hasHflag = (strchr(viafield,'*') != NULL);
+
+        // Non-matched case, may have H-bit flag
+        if (matchlen == 0) {
+          /*
+                state->hopsreq  += 0;
+                state->hopsdone += 0;
+                state->tracereq  += 0;
+                state->tracedone += 0;
+          */
+                state->digireq  += 1;
+                state->digidone += hasHflag;
+                if (viaindex == 2 && !hasHflag)
+                  state->probably_heard_direct = 1;
+                // if (debug>1) printf(" a[req=%d,done=%d,trace=%d]",0,0,hasHflag);
+                return 0;
+        }
+
+        // Is the character following matched part one of: [1-7]
+        if (!('1' <= reqc && reqc <= '7')) {
+                // Not a digit, this is single matcher..
+                state->hopsreq  += 1;
+                state->hopsdone += hasHflag;
+                if (istrace) {
+                  state->tracereq  += 1;
+                  state->tracedone += hasHflag;
+                }
+                if (viaindex == 2 && !hasHflag)
+                  state->probably_heard_direct = 1;
+                // if (debug>1) printf(" d[req=%d,done=%d]",1,hasHflag);
+                return 0;
+        }
+
+        req = reqc - '0';
+
+        if (c == '*' && remc == 0) { // WIDE1*
+                state->hopsreq  += req;
+                state->hopsdone += req;
+                if (istrace) {
+                  state->tracereq  += req;
+                  state->tracedone += req;
+                }
+                // if (debug>1) printf(" e[req=%d,done=%d]",req,req);
+                return 0;
+        }
+        if (c == 0) { // Bogus WIDE1 - uidigi puts these out.
+                state->fixthis = 1;
+                state->hopsreq  += req;
+                state->hopsdone += req;
+                if (istrace) {
+                  state->tracereq  += req;
+                  state->tracedone += req;
+                }
+                // if (debug>1) printf(" E[req=%d,done=%d]",req,req);
+                return 0;
+        }
+        // Not WIDE1-
+        if (c != '-') {
+                state->hopsreq  += 1;
+                state->hopsdone += hasHflag;
+                if (istrace) {
+                  state->tracereq  += 1;
+                  state->tracedone += hasHflag;
+                }
+                // if (debug>1) printf(" f[req=%d,done=%d]",1,hasHflag);
+                return 0;
+        }
+
+        // OK, it is "WIDEn-" plus "N"
+        if ('0' <= remc  && remc <= '7' && p[3] == 0) {
+          state->hopsreq  += req;
+          done = req - (remc - '0');
+          state->hopsdone += done;
+          if (done < 0) {
+            // Something like "WIDE3-7", which is definitely bogus!
+            state->fixall = 1;
+            if (viaindex == 2 && !hasHflag)
+              state->probably_heard_direct = 1;
+            return 0;
+          }
+          if (istrace) {
+            state->tracereq  += req;
+            state->tracedone += done;
+          }
+          if (viaindex == 2) {
+            if (memcmp("TRACE",viafield,5)==0) // A real "TRACE" in first slot?
+              state->probably_heard_direct = 1;
+
+            else if (!hasHflag && done == 0) // WIDE3-3 on first slot
+              state->probably_heard_direct = 1;
+          }
+          // if (debug>1) printf(" g[req=%d,done=%d%s]",req,done,hasHflag ? ",Hflag!":"");
+          return 0;
+
+        } else if (('8' <= remc && remc <= '9' && p[3] == 0) ||
+                   (remc == '1' && '0' <= p[3] && p[3] <= '5' && p[4] == 0)) {
+          // The request has SSID value in range of 8 to 15
+          state->fixall = 1;
+          if (viaindex == 2 && !hasHflag)
+            state->probably_heard_direct = 1;
+          return 0;
+
+        } else {
+          // Yuck, impossible/syntactically invalid
+          state->hopsreq  += 1;
+          state->hopsdone += hasHflag;
+          if (istrace) {
+            state->tracereq  += 1;
+            state->tracedone += hasHflag;
+          }
+          if (viaindex == 2 && !hasHflag)
+            state->probably_heard_direct = 1;
+          // if (debug>1) printf(" h[req=%d,done=%d]",1,hasHflag);
+          return 1;
+        }
+}
+
+static int match_transmitter(const char *viafield, const struct digipeater_source *src, const int lastviachar)
+{
+        struct aprx_interface *aif = src->parent->transmitter;
+        int tlen = strlen(aif->callsign);
+
+        if (memcmp(viafield, aif->callsign, tlen) == 0) {
+          if (viafield[tlen] == lastviachar)
+            return 1;
+        }
+
+        return 0;
+}
+
+static int try_reject_filters(const int  fieldtype,
+                              const char *field,
+                              struct digipeater_source *src)
+{
+        int i;
+        int stat = 0;
+        switch (fieldtype) {
+        case 0: // Source
+                for (i = 0; i < src->sourceregscount; ++i) {
+                        stat = regexec(src->sourceregs[i],
+                                       field, 0, NULL, 0);
+                        if (stat == 0)
+                                return 1;       /* MATCH! */
+                }
+                if (memcmp("MYCALL",field,6)==0) return 1;
+                if (memcmp("N0CALL",field,6)==0) return 1;
+                if (memcmp("NOCALL",field,6)==0) return 1;
+                break;
+        case 1: // Destination
+
+                for (i = 0; i < src->destinationregscount; ++i) {
+                        int stat = regexec(src->destinationregs[i],
+                                           field, 0, NULL, 0);
+                        if (stat == 0)
+                                return 1;       /* MATCH! */
+                }
+                if (memcmp("MYCALL",field,6)==0) return 1;
+                if (memcmp("N0CALL",field,6)==0) return 1;
+                if (memcmp("NOCALL",field,6)==0) return 1;
+                break;
+        case 2: // Via
+
+                for (i = 0; i < src->viaregscount; ++i) {
+                        int stat = regexec(src->viaregs[i],
+                                           field, 0, NULL, 0);
+                        if (stat == 0)
+                                return 1;       /* MATCH! */
+                }
+                if (memcmp("MYCALL",field,6)==0) return 1;
+                if (memcmp("N0CALL",field,6)==0) return 1;
+                if (memcmp("NOCALL",field,6)==0) return 1;
+                break;
+        case 3: // Data
+
+                for (i = 0; i < src->dataregscount; ++i) {
+                        int stat = regexec(src->dataregs[i],
+                                           field, 0, NULL, 0);
+                        if (stat == 0)
+                                return 1;       /* MATCH! */
+                }
+                break;
+        default:
+                if (debug)
+                  printf("try_reject_filters(fieldtype=%d) - CODE BUG\n",
+                         fieldtype);
+                return 1;
+        }
+        if (stat != 0 && stat != REG_NOMATCH) {
+                // Some odd reason for an error?
+                
+        }
+        return 0;
+}
+
+/* Parse executed and requested WIDEn-N/TRACEn-N info */
+static int parse_tnc2_hops(struct digistate *state, struct digipeater_source *src, struct pbuf_t *pb)
+{
+        const char *p = pb->dstcall_end+1;
+        const char *s;
+        const struct digipeater *digi = src->parent;
+        const char *lastviastar;
+        char viafield[15]; // temp buffer for many uses
+        int have_fault = 0;
+        int viaindex = 1; // First via index will be 2..
+        int activeviacount = 0;
+        int len;
+        int digiok;
+
+        if (debug>1) printf(" hops count of buffer: %s\n",p);
+
+        if (src->src_relaytype == DIGIRELAY_THIRDPARTY) {
+          state->v.hopsreq = 1; // Bonus for tx-igated 3rd-party frames
+          state->v.tracereq = 1; // Bonus for tx-igated 3rd-party frames
+          state->v.hopsdone = 0;
+          state->v.tracedone = 0;
+          state->v.probably_heard_direct = 1;
+          return 0;
+        }
+
+        // Copy the SRCCALL part of  SRCALL>DSTCALL  to viafield[] buffer
+        len = pb->srccall_end - pb->data;
+        if (len >= sizeof(viafield)) len = sizeof(viafield)-1;
+        memcpy(viafield, pb->data, len);
+        viafield[len] = 0;
+        // if (debug>2)printf(" srccall='%s'",viafield);
+        if (try_reject_filters(0, viafield, src)) {
+          if (debug>1) printf(" - Src filters reject\n");
+          return 1; // Src reject filters
+        }
+
+        // Copy the DSTCALL part of  SRCALL>DSTCALL  to viafield[] buffer
+        len = pb->dstcall_end - pb->srccall_end -1;
+        if (len >= sizeof(viafield)) len = sizeof(viafield)-1;
+        memcpy(viafield, pb->srccall_end+1, len);
+        viafield[len] = 0;
+        // if (debug>2)printf(" destcall='%s'",viafield);
+        if (try_reject_filters(1, viafield, src)) {
+          if (debug>1) printf(" - Dest filters reject\n");
+          return 1; // Dest reject filters
+        }
+
+        // Where is the last via-field with a start on it?
+        len = pb->info_start - p; if (len < 0) len=0;
+        lastviastar = memrchr(p, len, '*');
+
+        // Loop over VIA fields to see if we need to digipeat anything.
+        while (p < pb->info_start && !have_fault) {
+          len = 0;
+
+          if (*p == ':') {
+            // A round may stop at ':' found at the end of the processed field,
+            // then next round finds it at the start of the field.
+            break;
+          }
+
+          // Scan for a VIA field ...
+          for (s = p; s < pb->info_start; ++s) {
+            if (*s == ',' || *s == ':') {
+              // ... until comma or double-colon.
+              break;
+            }
+          }
+          // [p..s) is now one VIA field.
+          if (s == p && *p != ':') {  // BAD!
+            have_fault = 1;
+            if (debug>1) printf(" S==P ");
+            break;
+          }
+          if (*p == 'q') break; // APRSIS q-constructs..
+          ++viaindex;
+
+          // Pick-up a viafield to separate buffer for processing
+          len = s-p;
+          if (len >= sizeof(viafield)) len = sizeof(viafield)-2;
+          memcpy(viafield, p, len);
+          viafield[len] = 0;
+          if (*s == ',') ++s;
+          p = s;
+
+          // Only last via field with H-bit is indicated at TNC2 format,
+          // but this digi code logic needs it at every VIA field where
+          // it is set.  Therefore this crooked way to add it to picked
+          // up fields.
+          if (strchr(viafield,'*') == NULL) {
+            // If it exists somewhere, and we are not yet at it..
+            if (lastviastar != NULL && p < lastviastar)
+              strcat(viafield,"*"); // we do know that there is space for this.
+          }
+
+          if (debug>1) printf(" - ViaField[%d]: '%s'\n", viaindex, viafield);
+
+          // VIA-field picked up, now analyze it..
+
+          if (try_reject_filters(2, viafield, src)) {
+            if (debug>1) printf(" - Via filters reject\n");
+            return 1; // via reject filters
+          }
+
+          // Transmitter callsign match with H-flag set.
+          if (match_transmitter(viafield, src, '*')) {
+            if (debug>1) printf(" - Tx match reject\n");
+            // Oops, LOOP!  I have transmit this in past
+            // (according to my transmitter callsign present
+            // in a VIA field!)
+            return 1;
+          }
+
+          // If there is no '*' meaning this has not been
+          // processed, then this is active field..
+          if (strchr(viafield, '*') == NULL)
+            ++activeviacount;
+
+          digiok = 0;
+
+          // If first active field (without '*') matches
+          // transmitter or alias, then this digi is accepted
+          // regardless if it is APRS or some other protocol.
+          if (activeviacount == 1 &&
+              (match_transmitter(viafield, src, 0) ||
+               match_aliases(viafield, digi->transmitter))) {
+            if (debug>1) printf(" - Tx match accept!\n");
+            state->v.hopsreq  += 1;
+            state->v.tracereq += 1;
+            digiok = 1;
+          }
+
+          // .. otherwise following rules are applied only to APRS packets.
+          if (pb->is_aprs) {
+            if ((len = match_tracewide(viafield, src->src_trace))) {
+              have_fault = count_single_tnc2_tracewide(&state->v, viafield, 1, len, viaindex);
+              if (!have_fault)
+                digiok = 1;
+            } else if ((len = match_tracewide(viafield, digi->trace))) {
+              have_fault = count_single_tnc2_tracewide(&state->v, viafield, 1, len, viaindex);
+              if (!have_fault)
+                digiok = 1;
+            } else if ((len = match_tracewide(viafield, src->src_wide))) {
+              have_fault = count_single_tnc2_tracewide(&state->v, viafield, 0, len, viaindex);
+              if (!have_fault)
+                digiok = 1;
+            } else if ((len = match_tracewide(viafield, digi->wide))) {
+              have_fault = count_single_tnc2_tracewide(&state->v, viafield, 0, len, viaindex);
+              if (!have_fault)
+                digiok = 1;
+            } else {
+              // No match on trace or wide, but if there was earlier
+              // match on interface or alias, then it set "digiok" for us.
+            }
+          }
+          if (state->v.fixthis || state->v.fixall) {
+            // Argh..  bogus WIDEn seen, which is what UIDIGIs put out..
+            // Also some other broken requests are "fixed": like WIDE3-7
+            // Fixing it: We set the missing H-bit, and continue processing.
+            // (That fixing is done in incoming AX25 address field, which
+            //  we generally do not touch - with this exception.)
+            pb->ax25addr[ AX25ADDRLEN*viaindex + AX25ADDRLEN-1 ] |= AX25HBIT;
+            state->v.fixthis = 0;
+          }
+          if (!digiok) {
+            if (debug>1) printf(" this via field is not matching with a TRACE, WIDE, ALIAS or INTERFACE.\n");
+            break;
+          }
+        }
+        if (debug>1) printf(" req=%d,done=%d [%s,%s,%s]\n",
+                            state->v.hopsreq,state->v.hopsdone,
+                            have_fault ? "FAULT":"OK",
+                            (state->v.hopsreq > state->v.hopsdone) ? "DIGIPEAT":"DROP",
+                            (state->v.tracereq > state->v.tracedone) ? "TRACE":"WIDE");
+        return have_fault;
+}
+
+
+static void free_tracewide(struct tracewide *twp)
+{
+        int i;
+
+        if (twp == NULL) return;
+        if (twp->keys) {
+          for (i = 0; i < twp->nkeys; ++i)
+            free((void*)(twp->keys[i]));
+          free(twp->keys);
+        }
+        if (twp->keylens)
+          free((void*)(twp->keylens));
+
+        free(twp);
+}
+static void free_source(struct digipeater_source *src)
+{
+        if (src == NULL) return;
+        free(src);
+}
+
+static struct tracewide *digipeater_config_tracewide(struct configfile *cf, int is_trace)
+{
+        char  *name, *param1;
+        char  *str       = cf->buf;
+        int    has_fault = 0;
+        int    nkeys     = 0;
+        char **keywords  = NULL;
+        int   *keylens   = NULL;
+        int    maxreq    = 4;
+        int    maxdone   = 4;
+        struct tracewide *tw;
+
+        while (readconfigline(cf) != NULL) {
+                if (configline_is_comment(cf))
+                        continue;       /* Comment line, or empty line */
+
+                // It can be severely indented...
+                str = config_SKIPSPACE(cf->buf);
+
+                name = str;
+                str = config_SKIPTEXT(str, NULL);
+                str = config_SKIPSPACE(str);
+                config_STRLOWER(name);
+
+                param1 = str;
+                str = config_SKIPTEXT(str, NULL);
+                str = config_SKIPSPACE(str);
+
+                if (is_trace) {
+                  if (strcmp(name, "</trace>") == 0) {
+                    break;
+                  }
+                } else {
+                  if (strcmp(name, "</wide>") == 0) {
+                    break;
+                  }
+                }
+
+                // ... actual parameters
+                if (strcmp(name,"maxreq") == 0) {
+                  maxreq = atoi(param1);
+                  // if (debug) printf(" maxreq %d\n",maxreq);
+
+                } else if (strcmp(name,"maxdone") == 0) {
+                  maxdone = atoi(param1);
+                  // if (debug) printf(" maxdone %d\n",maxdone);
+
+                } else if (strcmp(name,"keys") == 0) {
+                  char *k = strtok(param1, ",");
+                  for (; k ; k = strtok(NULL,",")) {
+                    ++nkeys;
+                    // if (debug) printf(" n=%d key='%s'\n",nkeys,k);
+                    keywords = realloc(keywords, sizeof(char*) * nkeys);
+                    keywords[nkeys-1] = strdup(k);
+
+                    keylens  = realloc(keylens,  sizeof(int) * nkeys);
+                    keylens[nkeys-1] = strlen(k);
+                  }
+
+                } else {
+                  has_fault = 1;
+                  printf("%s:%d ERROR: Unknown keyword inside %s subblock: '%s'\n",
+                         cf->name, cf->linenum, is_trace ? "<trace>":"<wide>", name);
+                }
+        }
+
+        if (has_fault) {
+          int i;
+          for (i = 0; i < nkeys; ++i)
+            free(keywords[i]);
+          if (keywords != NULL)
+            free(keywords);
+          if (keylens != NULL)
+            free(keylens);
+          return NULL;
+        }
+
+        tw = calloc(1,sizeof(*tw));
+
+        tw->maxreq   = maxreq;
+        tw->maxdone  = maxdone;
+        tw->is_trace = is_trace;
+        tw->nkeys    = nkeys;
+        tw->keys     = keywords;
+        tw->keylens  = keylens;
+
+        return tw;
+}
+
+static struct digipeater_source *digipeater_config_source(struct configfile *cf)
+{
+        char *name, *param1;
+        char *str = cf->buf;
+        int has_fault = 0;
+        int viscous_delay = 0;
+        float ratelimit = 120;
+        float rateincrement = 60;
+
+        struct aprx_interface *source_aif = NULL;
+        struct digipeater_source  *source = NULL;
+        digi_relaytype          relaytype = DIGIRELAY_DIGIPEAT;
+        struct filter_t          *filters = NULL;
+        struct tracewide    *source_trace = NULL;
+        struct tracewide     *source_wide = NULL;
+        struct digipeater_source regexsrc;
+#ifndef DISABLE_IGATE
+        char                    *via_path = NULL;
+        char                    *msg_path = NULL;
+        uint8_t               ax25viapath[AX25ADDRLEN];
+        uint8_t                msgviapath[AX25ADDRLEN];
+#endif
+
+        memset(&regexsrc, 0, sizeof(regexsrc));
+#ifndef DISABLE_IGATE
+        memset(ax25viapath, 0, sizeof(ax25viapath));
+        memset(msgviapath,  0, sizeof(msgviapath));
+#endif
+
+        while (readconfigline(cf) != NULL) {
+                if (configline_is_comment(cf))
+                        continue;       /* Comment line, or empty line */
+
+                // It can be severely indented...
+                str = config_SKIPSPACE(cf->buf);
+
+                name = str;
+                str = config_SKIPTEXT(str, NULL);
+                str = config_SKIPSPACE(str);
+                config_STRLOWER(name);
+
+                param1 = str;
+                str = config_SKIPTEXT(str, NULL);
+                str = config_SKIPSPACE(str);
+
+                if (strcmp(name, "</source>") == 0) {
+                        break;
+
+                        // ... actual parameters
+                } else if (strcmp(name,"source") == 0) {
+                        if (debug)
+                          printf("%s:%d <source> source = '%s'\n",
+                                 cf->name, cf->linenum, param1);
+
+                        if (strcasecmp(param1,"$mycall") == 0)
+                                param1 = (char*)mycall;
+
+                        source_aif = find_interface_by_callsign(param1);
+                        if (source_aif == NULL) {
+                                has_fault = 1;
+                                printf("%s:%d ERROR: Digipeater source '%s' not found\n",
+                                       cf->name, cf->linenum, param1);
+                        }
+                        if (debug>1)
+                          printf(" .. source_aif = %p\n", source_aif);
+
+                } else if (strcmp(name, "viscous-delay") == 0) {
+                        viscous_delay = atoi(param1);
+                        if (debug) printf(" viscous-delay = %d\n",viscous_delay);
+                        if (viscous_delay < 0) {
+                          printf("%s:%d ERROR: Bad value for viscous-delay: '%s'\n",
+                                 cf->name, cf->linenum, param1);
+                          viscous_delay = 0;
+                          has_fault = 1;
+                        }
+                        if (viscous_delay > 9) {
+                          printf("%s:%d ERROR: Too large value for viscous-delay: '%s'\n",
+                                 cf->name, cf->linenum, param1);
+                          viscous_delay = 9;
+                          has_fault = 1;
+                        }
+
+                } else if (strcmp(name, "ratelimit") == 0) {
+                        char *param2 = str;
+                        str = config_SKIPTEXT(str, NULL);
+                        str = config_SKIPSPACE(str);
+
+                        rateincrement = (float)atof(param1);
+                        ratelimit     = (float)atof(param2);
+                        if (rateincrement < 0.01 || rateincrement > rateincrementmax)
+                                rateincrement = 60;
+                        if (ratelimit < 0.01 || ratelimit > ratelimitmax)
+                                ratelimit = 120;
+                        if (ratelimit < rateincrement)
+                          rateincrement = ratelimit;
+                        if (debug)
+                          printf("  .. ratelimit %f %f\n",
+                                 rateincrement, ratelimit);
+
+                } else if (strcmp(name,"regex-filter") == 0) {
+                        if (regex_filter_add(cf, &regexsrc, param1, str)) {
+                          // prints errors internally
+                          has_fault = 1;
+                        }
+
+#ifndef DISABLE_IGATE
+                } else if (strcmp(name, "via-path") == 0) {
+
+                        // Validate that source callsign is "APRSIS"
+                        // or "DPRS" for this parameter
+
+                        if (source_aif == NULL ||
+                            (strcmp(source_aif->callsign,"APRSIS") != 0 &&
+                             strcmp(source_aif->callsign,"DPRS") != 0)) {
+                          printf("%s:%d ERROR: via-path parameter is available only on 'source APRSIS' and 'source DPRS' cases.\n",
+                                 cf->name, cf->linenum);
+                          has_fault = 1;
+                          continue;
+                        }
+
+                        via_path  = strdup(param1);
+                        config_STRUPPER(via_path);
+
+                        if (parse_ax25addr(ax25viapath, via_path, 0x00)) {
+                          has_fault = 1;
+                          printf("%s:%d ERROR: via-path parameter is not valid AX.25 callsign: '%s'\n",
+                                 cf->name, cf->linenum, via_path);
+                          free(via_path);
+                          via_path = NULL;
+                          continue;
+                        }
+
+                        if (debug)
+                                printf("via-path '%s'\n", via_path);
+
+                } else if (strcmp(name, "msg-path") == 0) {
+
+                        // Validate that source callsign is "APRSIS"
+                        // or "DPRS" for this parameter
+
+                        if (source_aif == NULL ||
+                            (strcmp(source_aif->callsign,"APRSIS") != 0 &&
+                             strcmp(source_aif->callsign,"DPRS") != 0)) {
+                          printf("%s:%d ERROR: msg-path parameter is available only on 'source APRSIS' and 'source DPRS' cases.\n",
+                                 cf->name, cf->linenum);
+                          has_fault = 1;
+                          continue;
+                        }
+
+                        msg_path  = strdup(param1);
+                        config_STRUPPER(msg_path);
+
+                        if (parse_ax25addr(msgviapath, msg_path, 0x00)) {
+                          has_fault = 1;
+                          printf("%s:%d ERROR: msg-path parameter is not valid AX.25 callsign: '%s'\n",
+                                 cf->name, cf->linenum, msg_path);
+                          free(msg_path);
+                          msg_path = NULL;
+                          continue;
+                        }
+
+                        if (debug)
+                                printf("msg-path '%s'\n", msg_path);
+#endif
+                } else if (strcmp(name,"<trace>") == 0) {
+                        if (source_trace == NULL) {
+                          source_trace = digipeater_config_tracewide(cf, 1);
+                          // prints errors internally
+                        } else {
+                          has_fault = 1;
+                          printf("%s:%d ERROR: double definition of <trace> block.\n",
+                                 cf->name, cf->linenum);
+                        }
+
+                } else if (strcmp(name,"<wide>") == 0) {
+                        if (source_wide == NULL) {
+                          source_wide  = digipeater_config_tracewide(cf, 0);
+                          // prints errors internally
+                        } else {
+                          has_fault = 1;
+                          printf("%s:%d ERROR: double definition of <wide> block.\n",
+                                 cf->name, cf->linenum);
+                        }
+
+                } else if (strcmp(name,"filter") == 0) {
+                        if (filter_parse(&filters, param1)) {
+                          // prints errors internally
+                          
+                          has_fault = 1;
+                          printf("%s:%d ERROR: Error at filter parser.\n",
+                                 cf->name, cf->linenum);
+                        } else {
+                          if (debug)
+                            printf(" .. OK filter %s\n", param1);
+                        }
+
+                } else if (strcmp(name,"relay-type") == 0 ||   // documented name
+                           strcmp(name,"relay-format") == 0 || // an alias
+                           strcmp(name,"digi-mode") == 0) {    // very old alias
+                        config_STRLOWER(param1);
+                        if (strcmp(param1,"digipeat") == 0) {
+                          relaytype = DIGIRELAY_DIGIPEAT;
+                        } else if (strcmp(param1,"digipeated") == 0) {
+                          relaytype = DIGIRELAY_DIGIPEAT;
+                        } else if (strcmp(param1,"digipeater") == 0) {
+                          relaytype = DIGIRELAY_DIGIPEAT;
+                        } else if (strcmp(param1,"directonly") == 0) {
+                          relaytype = DIGIRELAY_DIGIPEAT_DIRECTONLY;
+                        } else if (strcmp(param1,"third-party") == 0) {
+                          relaytype = DIGIRELAY_THIRDPARTY;
+                        } else if (strcmp(param1,"3rd-party") == 0) {
+                          relaytype = DIGIRELAY_THIRDPARTY;
+                        } else {
+                          printf("%s:%d ERROR: Digipeater <source>'s %s did not recognize: '%s' \n", cf->name, cf->linenum, name, param1);
+                          has_fault = 1;
+                        }
+                } else {
+                        printf("%s:%d ERROR: Digipeater <source>'s %s did not recognize: '%s' \n", cf->name, cf->linenum, name, param1);
+                        has_fault = 1;
+                }
+        }
+
+        if (source_aif == NULL) {
+                has_fault = 1;
+                printf("%s:%d ERROR: Missing or bad 'source =' definition at this <source> group.\n",
+                       cf->name, cf->linenum);
+        }
+
+        if (!has_fault && (source_aif != NULL)) {
+                source = calloc(1,sizeof(*source));
+                
+                source->src_if        = source_aif;
+                source->src_relaytype = relaytype;
+                source->src_filters   = filters;
+                source->src_trace     = source_trace;
+                source->src_wide      = source_wide;
+#ifndef DISABLE_IGATE
+                source->via_path      = via_path;
+                source->msg_path      = msg_path;
+                memcpy(source->ax25viapath, ax25viapath, sizeof(ax25viapath));
+                memcpy(source->msgviapath,  msgviapath,  sizeof(msgviapath));
+                if (msg_path == NULL) { // default value of via-path !
+                  source->msg_path    = via_path;
+                  memcpy(source->msgviapath,  ax25viapath,  sizeof(ax25viapath));
+                }
+#endif
+
+                source->viscous_delay = viscous_delay;
+
+                source->tbf_limit     = (ratelimit * TOKENBUCKET_INTERVAL)/60;
+                source->tbf_increment = (rateincrement * TOKENBUCKET_INTERVAL)/60;
+                source->tokenbucket   = source->tbf_limit;
+                
+                // RE pattern reject filters
+                source->sourceregscount      = regexsrc.sourceregscount;
+                source->sourceregs           = regexsrc.sourceregs;
+                source->destinationregscount = regexsrc.destinationregscount;
+                source->destinationregs      = regexsrc.destinationregs;
+                source->viaregscount         = regexsrc.viaregscount;
+                source->viaregs              = regexsrc.viaregs;
+                source->dataregscount        = regexsrc.dataregscount;
+                source->dataregs             = regexsrc.dataregs;
+
+        } else {
+                // Errors detected
+                free_tracewide(source_trace);
+                free_tracewide(source_wide);
+                // filters_free(filters);
+                // free regexsrc's allocations
+                if (debug)
+                  printf("Seen errors at <digipeater><source> definition.\n");
+        }
+
+        if (debug>1)printf(" .. <source> definition returning %p\n",source);
+        return source;
+}
+
+int digipeater_config(struct configfile *cf)
+{
+        char *name, *param1;
+        char *str = cf->buf;
+        int has_fault = 0;
+        int i;
+        const int line0 = cf->linenum;
+
+        struct aprx_interface *aif = NULL;
+        float ratelimit = 60;
+        float rateincrement = 60;
+        float srcratelimit = 60;
+        float srcrateincrement = 60;
+        int sourcecount = 0;
+        int dupestoretime = 30; // FIXME: parametrize! 30 is minimum..
+        struct digipeater_source **sources = NULL;
+        struct digipeater *digi = NULL;
+        struct tracewide *traceparam = NULL;
+        struct tracewide *wideparam  = NULL;
+
+        while (readconfigline(cf) != NULL) {
+                if (configline_is_comment(cf))
+                        continue;       /* Comment line, or empty line */
+
+                // It can be severely indented...
+                str = config_SKIPSPACE(cf->buf);
+
+                name = str;
+                str = config_SKIPTEXT(str, NULL);
+                str = config_SKIPSPACE(str);
+                config_STRLOWER(name);
+
+                param1 = str;
+                str = config_SKIPTEXT(str, NULL);
+                str = config_SKIPSPACE(str);
+
+                if (strcmp(name, "</digipeater>") == 0) {
+                        break;
+                }
+                if (strcmp(name, "transmit") == 0 ||
+                    strcmp(name, "transmitter") == 0) {
+                        if (strcasecmp(param1,"$mycall") == 0)
+                                param1 = (char*)mycall;
+
+                        aif = find_interface_by_callsign(param1);
+                        if (aif != NULL && (!aif->tx_ok)) {
+                          aif = NULL; // Not 
+                          printf("%s:%d ERROR: This transmit interface has no TX-OK TRUE setting: '%s'\n",
+                                 cf->name, cf->linenum, param1);
+                          has_fault = 1;
+                        } else if (aif != NULL && aif->txrefcount > 0) {
+                          aif = NULL;
+                          printf("%s:%d ERROR: This transmit interface is being used on multiple <digipeater>s as transmitter: '%s'\n",
+                                 cf->name, cf->linenum, param1);
+                          has_fault = 1;
+                        } else if (aif == NULL) {
+                          printf("%s:%d ERROR: Unknown interface: '%s'\n",
+                                 cf->name, cf->linenum, param1);
+                          has_fault = 1;
+                        }
+
+                } else if (strcmp(name, "ratelimit") == 0) {
+                        char *param2 = str;
+                        str = config_SKIPTEXT(str, NULL);
+                        str = config_SKIPSPACE(str);
+
+                        rateincrement = (float)atof(param1);
+                        ratelimit     = (float)atof(param2);
+                        if (rateincrement < 0.01 || rateincrement > rateincrementmax)
+                                rateincrement = 60;
+                        if (ratelimit < 0.01 || ratelimit > ratelimitmax)
+                                ratelimit = 60;
+                        if (ratelimit < rateincrement)
+                                rateincrement = ratelimit;
+                        if (debug)
+                                printf("  .. ratelimit %f %f\n",
+                                       rateincrement, ratelimit);
+
+                } else if (strcmp(name, "srcratelimit") == 0) {
+                        char *param2 = str;
+                        str = config_SKIPTEXT(str, NULL);
+                        str = config_SKIPSPACE(str);
+
+                        srcrateincrement = (float)atof(param1);
+                        srcratelimit     = (float)atof(param2);
+                        if (srcrateincrement < 0.01 || srcrateincrement > rateincrementmax)
+                                srcrateincrement = 60;
+                        if (srcratelimit < 0.01 || srcratelimit > ratelimitmax)
+                                srcratelimit = 60;
+                        if (srcratelimit < srcrateincrement)
+                                srcrateincrement = srcratelimit;
+                        if (debug)
+                                printf("  .. srcratelimit %f %f\n",
+                                       srcrateincrement, srcratelimit);
+
+                } else if (strcmp(name, "<trace>") == 0) {
+                        if (traceparam == NULL) {
+                          traceparam = digipeater_config_tracewide(cf, 1);
+                          if (traceparam == NULL) {
+                            printf("%s:%d ERROR: <trace> definition failed!\n",
+                                 cf->name, cf->linenum);
+                            has_fault = 1;
+                          }
+                        } else {
+                          printf("%s:%d ERROR: Double definition of <trace> !\n",
+                                 cf->name, cf->linenum);
+                          has_fault = 1;
+                        }
+
+                } else if (strcmp(name, "<wide>") == 0) {
+                        if (wideparam == NULL) {
+                          wideparam = digipeater_config_tracewide(cf, 0);
+                          if (wideparam == NULL) {
+                            printf("%s:%d ERROR: <wide> definition failed!\n",
+                                 cf->name, cf->linenum);
+                            has_fault = 1;
+                          }
+                        } else {
+                          printf("%s:%d ERROR: Double definition of <wide> !\n",
+                                 cf->name, cf->linenum);
+                          has_fault = 1;
+                        }
+
+                } else if (strcmp(name, "<source>") == 0) {
+                        struct digipeater_source *src =
+                                digipeater_config_source(cf);
+                        if (src != NULL) {
+                                // Found a source, link it!
+                                sources = realloc(sources, sizeof(void*) * (sourcecount+1));
+                                sources[sourcecount] = src;
+                                ++sourcecount;
+                        } else {
+                                has_fault = 1;
+                                printf("%s:%d ERROR: <source> definition failed\n",
+                                       cf->name, cf->linenum);
+                        }
+
+                } else {
+                  printf("%s:%d ERROR: Unknown <digipeater> config keyword: '%s'\n",
+                         cf->name, cf->linenum, name);
+                  has_fault = 1;
+                  continue;
+                }
+        }
+
+        if (aif == NULL && !has_fault) {
+                printf("%s:%d ERROR: Digipeater defined without transmit interface.\n",
+                       cf->name, cf->linenum);
+                has_fault = 1;
+        }
+        if (sourcecount == 0 && !has_fault) {
+                printf("%s:%d ERROR: Digipeater defined without <source>:s.\n",
+                       cf->name, cf->linenum);
+                has_fault = 1;
+        }
+        // Check that source definitions are unique
+        for ( i = 0; i < sourcecount; ++i ) {
+                int j;
+                for (j = i+1; j < sourcecount; ++j) {
+                        if (sources[i]->src_if == sources[j]->src_if) {
+                                has_fault = 1;
+                                printf("%s:%d Two <source>s on this <digipeater> definition use same <interface>: '%s'\n",
+                                       cf->name, line0, sources[i]->src_if->callsign);
+                        }
+                }
+        }
+
+        if (has_fault) {
+                // Free allocated resources and link pointers, if any
+                for ( i = 0; i < sourcecount; ++i ) {
+                        free_source(sources[i]);
+                }
+                if (sources != NULL)
+                        free(sources);
+
+                free_tracewide(traceparam);
+                free_tracewide(wideparam);
+
+                printf("ERROR: Config fault observed on <digipeater> definitions! \n");
+        } else {
+                // Construct the digipeater
+
+                digi = calloc(1,sizeof(*digi));
+
+                if (debug>1)printf("<digipeater> sourcecount=%d\n",sourcecount);
+
+                // up-link all interfaces used as sources
+                for ( i = 0; i < sourcecount; ++i ) {
+                        struct digipeater_source *src = sources[i];
+                        src->parent = digi; // Set parent link
+
+                        src->src_if->digisources = realloc( src->src_if->digisources,
+                                                            (src->src_if->digisourcecount +1) * (sizeof(void*)));
+                        src->src_if->digisources[src->src_if->digisourcecount] = src;
+                        src->src_if->digisourcecount += 1;
+                }
+
+                aif->txrefcount += 1; // Increment Tx usage Reference count.
+                                      // We permit only one <digipeater> to
+                                      // use any given Tx-interface. (Rx:es
+                                      // permit multiple uses.)
+                digi->transmitter   = aif;
+                digi->tbf_limit     = (ratelimit * TOKENBUCKET_INTERVAL)/60;
+                digi->tbf_increment = (rateincrement * TOKENBUCKET_INTERVAL)/60;
+                digi->src_tbf_limit = (srcratelimit * TOKENBUCKET_INTERVAL)/60;
+                digi->src_tbf_increment = (srcrateincrement * TOKENBUCKET_INTERVAL)/60;
+                digi->tokenbucket   = digi->tbf_limit;
+
+                digi->dupechecker   = dupecheck_new(dupestoretime);  // Dupecheck is per transmitter
+#ifndef DISABLE_IGATE
+                digi->historydb     = historydb_new();  // HistoryDB is per transmitter
+#endif
+
+                digi->trace         = (traceparam != NULL) ? traceparam : & default_trace_param;
+                digi->wide          = (wideparam  != NULL) ? wideparam  : & default_wide_param;
+
+                digi->sourcecount   = sourcecount;
+                digi->sources       = sources;
+
+                digis = realloc( digis, sizeof(void*) * (digi_count+1));
+                digis[digi_count] = digi;
+                ++digi_count;
+        }
+        return has_fault;
+}
+
+
+static int decrement_ssid(uint8_t *ax25addr)
+{
+        // bit-field manipulation
+        int ssid = (ax25addr[AX25ADDRLEN-1] >> 1) & 0x0F;
+        if (ssid > 0)
+          --ssid;
+        ax25addr[AX25ADDRLEN-1] = (ax25addr[AX25ADDRLEN-1] & 0xE1) | (ssid << 1);
+        return ssid;
+}
+
+
+/* 0 == accept, otherwise reject */
+/*
+int digipeater_receive_filter(struct digipeater_source *src, struct pbuf_t *pb)
+{
+        
+        if (src->src_filters == NULL) {
+          if (debug>1)
+            printf("No source filters, accepted the packet from %s.\n", src->src_if->callsign);
+          return 0;
+        }
+        int rc = filter_process(pb, src->src_filters, src->parent->historydb);
+        if (rc != 1) {
+          if (debug>1)
+            printf("Source filtering rejected the packet from %s.\n", src->src_if->callsign);
+          return 1;
+        }
+        if (debug>1)
+          printf("Source filtering accepted the packet from %s.\n", src->src_if->callsign);
+        return 0;
+}
+*/
+
+static void digipeater_receive_backend(struct digipeater_source *src, struct pbuf_t *pb)
+{
+        int len, viaindex;
+        struct digistate state;
+        struct viastate  viastate;
+        struct digipeater *digi = src->parent;
+        char viafield[14]; // room for text format
+        uint8_t *axaddr, *e;
+
+        memset(&state,    0, sizeof(state));
+        memset(&viastate, 0, sizeof(viastate));
+
+        //  2) Verify that none of our interface callsigns does match any
+        //     of already DIGIPEATED via fields! (fields that have H-bit set)
+        //   ( present implementation: this digi's transmitter callsign is
+        //     verified)
+
+        // Parse executed and requested WIDEn-N/TRACEn-N info
+        if (parse_tnc2_hops(&state, src, pb)) {
+                // A fault was observed! -- tests include "not this transmitter"
+                if (debug>1)
+                  printf("Parse_tnc2_hops rejected this.");
+                return;
+        }
+
+        if (pb->is_aprs) {
+
+          if (state.v.probably_heard_direct) {
+            // Collect a decaying average of distances to stations?
+            //  .. could auto-beacon an aloha-circle - maybe
+            //  .. note: this does not get packets that have no VIA fields.
+            // Score of direct DX:es?
+            //  .. note: this does not get packets that have no VIA fields.
+          } else {
+            if (src->src_relaytype == DIGIRELAY_DIGIPEAT_DIRECTONLY) {
+              // Source relaytype is DIRECTONLY, and this was not
+              // likely directly heard...
+              if (debug>1) printf("DIRECTONLY -mode, and packet is probably not direct heard.");
+              return;
+            }
+          }
+          // Keep score of all DX packets?
+
+          if (try_reject_filters(3, pb->info_start, src)) {
+            if (debug>1)
+              printf(" - Data body regexp filters reject\n");
+            return; // data body regexp reject filters
+          }
+
+          // FIXME: 3) aprsc style filters checking in service area of the packet..
+
+        }
+
+        // 4) Hop-count filtering:
+
+        // APRSIS sourced packets have different rules than DIGIPEAT
+        // packets...
+        if (state.v.hopsreq <= state.v.hopsdone) {
+          if (debug>1) printf(" No remaining hops to execute.\n");
+          return;
+        }
+        if (state.v.hopsreq   > digi->trace->maxreq  ||
+            state.v.hopsreq   > digi->wide->maxreq   ||
+            state.v.tracereq  > digi->trace->maxreq  ||
+            state.v.hopsdone  > digi->trace->maxdone ||
+            state.v.hopsdone  > digi->wide->maxdone  ||
+            state.v.tracedone > digi->trace->maxdone) {
+          if (debug) printf(" Packet exceeds digipeat limits\n");
+          if (!state.v.probably_heard_direct) {
+            if (debug) printf(".. discard.\n");
+            return;
+          } else {
+            state.v.fixall = 1;
+          }
+        }
+
+        // if (debug) printf(" Packet accepted to digipeat!\n");
+
+        state.ax25addrlen = pb->ax25addrlen;
+        memcpy(state.ax25addr, pb->ax25addr, pb->ax25addrlen);
+        axaddr = state.ax25addr + 2*AX25ADDRLEN;
+        e      = state.ax25addr + state.ax25addrlen;
+
+        if (state.v.fixall) {
+          // Okay, insert my transmitter callsign on the first
+          // VIA field, and mark the rest with H-bit
+          // (in search loop below)
+          int taillen = e - axaddr;
+          if (state.ax25addrlen >= AX25ADDRMAXLEN) {
+            if (debug) printf(" FIXALL TRACE overgrows the VIA fields! Dropping last of incoming ones.\n");
+            // Drop the last via field to make room for insert below.
+            state.ax25addrlen -= AX25ADDRLEN;
+            taillen           -= AX25ADDRLEN;
+          }
+          // If we have a tail, move it up (there is always room for it)
+          if (taillen > 0)
+            memmove(axaddr+AX25ADDRLEN, axaddr, taillen);
+          state.ax25addrlen += AX25ADDRLEN;
+          e = state.ax25addr + state.ax25addrlen; // recalculate!
+
+          // Put the transmitter callsign in
+          memcpy(axaddr, digi->transmitter->ax25call, AX25ADDRLEN);
+
+          // Set Address Termination bit at the last VIA field
+          // (possibly ours, or maybe the previous one was truncated..)
+          axaddr[state.ax25addrlen-1] |= AX25ATERM;
+        }
+
+        // Search for first AX.25 VIA field that does not have H-bit set:
+        viaindex = 1; // First via field is number 2
+        *viafield = 0; // clear that buffer for starters
+        for (; axaddr < e; axaddr += AX25ADDRLEN, ++viaindex) {
+          ax25_to_tnc2_fmtaddress(viafield, axaddr, 0);
+          // if (debug>1) {
+          //   printf(" via: %s", viafield);
+          // }
+
+          // Initial parsing said that things are seriously wrong..
+          // .. and we will digipeat the packet with all H-bits set.
+          if (state.v.fixall) axaddr[AX25ADDRLEN-1] |= AX25HBIT;
+
+          if (!(axaddr[AX25ADDRLEN-1] & AX25HBIT)) // No "Has Been Digipeated" bit set
+            break; // this doesn't happen in "fixall" mode
+        }
+
+        switch (src->src_relaytype) {
+        case DIGIRELAY_THIRDPARTY:
+                // Effectively disable the digipeat modifying of address
+                axaddr = e;
+                break;
+        case DIGIRELAY_DIGIPEAT:
+                // Normal functionality
+                break;
+        default: ;
+        }
+
+        // Unprocessed VIA field found (not in FIXALL mode)
+        if (axaddr < e) {       // VIA-field of interest has been found
+
+// FIXME: 5) / 6) Cross-frequency/cross-band digipeat may add a special
+//                label telling that the message originated on other band
+
+          // 7) WIDEn-N treatment (as well as transmitter matching digi)
+          if (pb->digi_like_aprs) {
+            if (strcmp(viafield,digi->transmitter->callsign) == 0 ||
+                // Match on the transmitter callsign without the star...
+                match_aliases(viafield, digi->transmitter)) {
+                // .. or match transmitter interface alias.
+
+              // Treat it as a TRACE request.
+
+              int aterm = axaddr[AX25ADDRLEN-1] & AX25ATERM; // save old address termination bit
+              // Put the transmitter callsign in, and set the H-bit.
+              memcpy(axaddr, digi->transmitter->ax25call, AX25ADDRLEN);
+              axaddr[AX25ADDRLEN-1] |= (AX25HBIT | aterm); // Set H-bit
+              
+            } else if ((len = match_tracewide(viafield, src->src_trace))) {
+              count_single_tnc2_tracewide(&viastate, viafield, 1, len, viaindex);
+            } else if ((len = match_tracewide(viafield, digi->trace))) {
+              count_single_tnc2_tracewide(&viastate, viafield, 1, len, viaindex);
+            } else if ((len = match_tracewide(viafield, src->src_wide))) {
+              count_single_tnc2_tracewide(&viastate, viafield, 0, len, viaindex);
+            } else if ((len = match_tracewide(viafield, digi->wide))) {
+              count_single_tnc2_tracewide(&viastate, viafield, 0, len, viaindex);
+            }
+
+          } else { // Not "digi_as_aprs" rules
+
+            if (strcmp(viafield,digi->transmitter->callsign) == 0) {
+              // Match on the transmitter callsign without the star.
+              // Treat it as a TRACE request.
+              int aterm = axaddr[AX25ADDRLEN-1] & AX25ATERM; // save old address termination bit
+              // Put the transmitter callsign in, and set the H-bit.
+              memcpy(axaddr, digi->transmitter->ax25call, AX25ADDRLEN);
+              axaddr[AX25ADDRLEN-1] |= (AX25HBIT | aterm); // Set H-bit
+              
+            } else if (match_aliases(viafield, digi->transmitter)) {
+              // Match on the aliases.
+              // Treat it as a TRACE request.
+              int aterm = axaddr[AX25ADDRLEN-1] & AX25ATERM; // save old address termination bit
+              // Put the transmitter callsign in, and set the H-bit.
+              memcpy(axaddr, digi->transmitter->ax25call, AX25ADDRLEN);
+              axaddr[AX25ADDRLEN-1] |= (AX25HBIT | aterm); // Set H-bit
+            }
+          }
+
+          if (viastate.tracereq > viastate.tracedone) {
+            // if (debug) printf(" TRACE on %s!\n",viafield);
+            // Must move it up in memory to be able to put
+            // transmitter callsign in
+            int taillen = e - axaddr;
+            int newssid;
+            if (state.ax25addrlen >= AX25ADDRMAXLEN) {
+              if (debug) printf(" TRACE overgrows the VIA fields! Discard.\n");
+              return;
+            }
+            memmove(axaddr+AX25ADDRLEN, axaddr, taillen);
+            state.ax25addrlen += AX25ADDRLEN;
+
+            newssid = decrement_ssid(axaddr+AX25ADDRLEN);
+            if (newssid <= 0)
+              axaddr[2*AX25ADDRLEN-1] |= AX25HBIT; // Set H-bit
+            // Put the transmitter callsign in, and set the H-bit.
+            memcpy(axaddr, digi->transmitter->ax25call, AX25ADDRLEN);
+            axaddr[AX25ADDRLEN-1] |= AX25HBIT; // Set H-bit
+
+          } else if (viastate.hopsreq > viastate.hopsdone) {
+            // If configuration didn't process "WIDE" et.al. as
+            // a TRACE, then here we process them without trace..
+            int newssid;
+            if (debug) printf(" VIA on %s!\n",viafield);
+            newssid = decrement_ssid(axaddr);
+            if (newssid <= 0)
+              axaddr[AX25ADDRLEN-1] |= AX25HBIT; // Set H-bit
+          }
+        }
+        {
+          history_cell_t *hcell;
+          char tbuf[2800];
+          int is_ui = 0, ui_pid = -1, frameaddrlen = 0, tnc2addrlen = 0, t2l;
+          // uint8_t *u = state.ax25addr + state.ax25addrlen;
+          // *u++ = 0;
+          // *u++ = 0;
+          // *u++ = 0;
+          t2l = ax25_format_to_tnc( state.ax25addr,
+                                    state.ax25addrlen+AX25ADDRLEN-1,
+                                    tbuf, sizeof(tbuf),
+                                    & frameaddrlen, &tnc2addrlen,
+                                    & is_ui, &ui_pid );
+          tbuf[t2l] = 0;
+          if (debug) {
+            printf(" out-hdr: '%s' data='",tbuf);
+            (void)fwrite(pb->ax25data+2, pb->ax25datalen-2,  // without Control+PID
+                         1, stdout);
+            printf("'\n");
+          }
+
+#ifndef DISABLE_IGATE
+          // Insert into history database - track every packet
+          hcell = historydb_insert_( digi->historydb, pb, 1 );
+
+          if (hcell != NULL) {
+            if (hcell->tokenbucket < 1.0) {
+              if (debug) printf("TRANSMITTER SOURCE CALLSIGN RATELIMIT DISCARD.\n");
+              return;
+            }
+            hcell->tokenbucket -= 1.0;
+          }
+#endif
+
+          // Now we do token bucket filtering -- rate limiting
+          if (digi->tokenbucket < 1.0) {
+            if (debug) printf("TRANSMITTER RATELIMIT DISCARD.\n");
+            return;
+          }
+          digi->tokenbucket -= 1.0;
+
+          if (pb->is_aprs && rflogfile) {
+            int t2l2;
+            // Essentially Debug logging.. to file
+
+            if (sizeof(tbuf) - pb->ax25datalen > t2l && t2l > 0) {
+              // Have space for body too, skip leading Ctrl+PID bytes
+              memcpy(tbuf+t2l, pb->ax25data+2, pb->ax25datalen-2); // Ctrl+PID skiped
+              t2l2 = t2l + pb->ax25datalen-2; // tbuf size sans Ctrl+PID
+
+              rflog( digi->transmitter->callsign, 'T', 0, tbuf, t2l2 );
+              tbuf[t2l]=0;
+            }
+          }
+
+        // Feed to dupe-filter (transmitter specific)
+        // this means we have already seen it, and when 
+        // it comes back from somewhere, we do not digipeat
+        // it ourselves.
+
+        // This recording is needed at output side of digipeater
+        // for APRSIS and DPRS transmit gates.
+
+        if (t2l>0) {
+          dupecheck_aprs( digi->dupechecker,
+                          (const char *)tbuf,
+                          t2l,
+                          (const char *)pb->ax25data+2,
+                          pb->ax25datalen-2 );  // ignore Ctrl+PID
+        } else {
+          dupecheck_aprs( digi->dupechecker,
+                          (const char *)state.ax25addr,
+                          state.ax25addrlen,
+                          (const char *)pb->ax25data+2,
+                          pb->ax25datalen-2 );  // ignore Ctrl+PID
+        }
+        }
+
+        // Feed to interface_transmit_ax25() with new header and body
+        interface_transmit_ax25( digi->transmitter,
+                                 state.ax25addr, state.ax25addrlen,
+                                 (const char*)pb->ax25data, pb->ax25datalen );
+        if (debug>1) printf("Done.\n");
+}
+
+
+void digipeater_receive( struct digipeater_source *src,
+                         struct pbuf_t *pb )
+{
+        // Below numbers like "4)" refer to Requirement Specification
+        // paper chapter 2.6: Digipeater Rules
+
+        //  The dupe-filter exists for APRS frames, possibly for some
+        // selected UI frame types, and definitely not for CONS frames.
+
+        if (debug)
+          printf("digipeater_receive() from %s, is_aprs=%d viscous_delay=%d\n",
+                 src->src_if->callsign, pb->is_aprs, src->viscous_delay);
+
+        if (src->tokenbucket < 1.0) {
+          if (debug) printf("SOURCE RATELIMIT DISCARD\n");
+          return;
+        }
+        src->tokenbucket -= 1.0;
+
+
+        if (pb->is_aprs) {
+
+                const int source_is_transmitter = (src->src_if ==
+                                                   src->parent->transmitter);
+
+                // 1) Feed to dupe-filter (transmitter specific)
+                //    If the dupe detector on this packet has reached
+                //    count > 1, drop it.
+
+                int jittery = src->viscous_delay > 0 ? random() % 3 + src->viscous_delay : 0;
+                dupe_record_t *dupe = dupecheck_pbuf( src->parent->dupechecker,
+                                                      pb, jittery);
+                if (dupe == NULL) {  // Oops.. allocation error!
+                  if (debug)
+                    printf("digipeater_receive() - dupecheck_pbuf() allocation error, packet discarded\n");
+                  return;
+                }
+
+                // 1.1) optional viscous delay!
+
+                if (src->viscous_delay == 0) { // No delay, direct cases
+
+                        // First packet on direct source arrives here
+                        // with  seen = 1
+
+                        // 1.x) Analyze dupe checking
+
+                        if (debug>1)
+                          printf("Seen this packet %d times (delayed=%d)\n",
+                                 dupe->delayed_seen + dupe->seen,
+                                 dupe->delayed_seen);
+
+                        if (dupe->seen > 1) {
+                          // N:th direct packet, duplicate.
+                          // Drop this direct packet.
+                          if (debug>1) printf(".. discarded\n");
+                          return;
+                        }
+
+                        if (dupe->seen == 1 && dupe->delayed_seen > 0 &&
+                            dupe->pbuf == NULL) {
+                          // First direct, but dupe record does not have
+                          // pbuf anymore indicating that a delayed 
+                          // handling did process it sometime in past.
+                          // Drop this direct packet.
+                          if (debug>1) printf(".. discarded\n");
+                          return;
+                        }
+
+                        if (dupe->seen == 1 && dupe->delayed_seen >= 0 &&
+                            dupe->pbuf != NULL) {
+
+                          // First direct, and pbuf exists in dupe record.
+                          // It was added first to viscous queue, and
+                          // a bit latter came this direct one.
+                          // Remove one from viscous queue, and proceed
+                          // with direct processing.
+
+                          if (debug>1) printf(" .. discard dupe record, process immediately");
+
+                          pbuf_put(dupe->pbuf);
+                          dupe->pbuf = NULL;
+                          dupe = NULL; // Do not do  dupecheck_put() here!
+                        }
+
+                } else {  // src->viscous_delay > 0
+
+                        // First packet on viscous source arrives here
+                        // with   dupe->delayed_seen = 1
+
+                        // Has this been seen on direct channel?
+                        if (dupe->seen > 0) {
+                          // Already processed thru direct processing,
+                          // no point in adding this to viscous delay queue
+                          if (debug>1)
+                            printf("Seen this packet %d times. Discarding it.\n",
+                                   dupe->delayed_seen + dupe->seen);
+                          return;
+                        }
+
+                        // Depending on source definition, the transmitter is
+                        // either non-viscous or viscous.  We care about it
+                        // only when the source is viscous:
+                        if (source_is_transmitter)
+                                dupe->seen_on_transmitter += 1;
+
+                        if (dupe->delayed_seen > 1) {
+                          // 2nd or more of same packet from delayed source
+                          if (debug>1)
+                            printf("Seen this packet %d times.\n",
+                                   dupe->delayed_seen + dupe->seen);
+
+                          // If any of them is transmitter interface, then
+                          // drop the queued packet, and drop current one.
+                          if (dupe->seen_on_transmitter > 0) {
+
+                            // If pbuf is on delayed queue, drop it.
+                            if (dupe->pbuf != NULL) {
+                              pbuf_put(dupe->pbuf);
+                              dupe->pbuf = NULL;
+                              dupe = NULL; // Do not do  dupecheck_put() here!
+                            }
+
+                          }
+                          if (debug>1) printf(".. discarded\n");
+                          return;
+                        }
+
+                        // First time that we have seen this packet at all.
+                        // Put the pbuf_t on viscous delay queue.. (Put
+                        // this dupe_record_t there, and the pbuf_t pointer
+                        // is already in that dupe_record_t.)
+                        src->viscous_queue_size += 1;
+                        if (src->viscous_queue_size > src->viscous_queue_space) {
+                          src->viscous_queue_space += 16;
+                          src->viscous_queue = realloc( src->viscous_queue,
+                                                        sizeof(void*) *
+                                                        src->viscous_queue_space );
+                        }
+                        src->viscous_queue[ src->viscous_queue_size -1 ]
+                                = dupecheck_get(dupe);
+                        
+                        if (debug) printf("%ld ENTER VISCOUS QUEUE: len=%d pbuf=%p\n",
+                                          tick.tv_sec, src->viscous_queue_size, pb);
+                        return; // Put on viscous queue
+
+                } 
+        }
+        // Send directly to backend
+        if (debug>1) printf(".. direct to processing\n");
+        digipeater_receive_backend(src, pb);
+}
+
+dupecheck_t *digipeater_find_dupecheck(const struct aprx_interface *aif)
+{
+        int i;
+        for (i = 0; i < digi_count; ++i) {
+          if (aif == digis[i]->transmitter)
+            return digis[i]->dupechecker;
+        }
+        return NULL;
+}
+
+static void digipeater_resettime(void *arg)
+{
+        struct timeval *tv = (struct timeval *)arg;
+        *tv = tick;
+}
+
+
+// Viscous queue processing needs poll digis <source>s for delayed actions
+int  digipeater_prepoll(struct aprxpolls *app)
+{
+        int d, s;
+
+        if (tokenbucket_timer.tv_sec == 0) {
+                tokenbucket_timer = tick; // init this..
+        }
+
+        // If the time(2) has jumped around a lot,
+        // and we didn't get around to do our work, reset the timer.
+
+        if (time_reset) {
+                digipeater_resettime(&tokenbucket_timer);
+        }
+        
+        if (tv_timercmp( &tokenbucket_timer, &tick ) <= 0) {
+          // Run the digipeater timer handling now
+          // Will also advance the timer!
+          if (debug>2) printf("digipeater_prepoll() run tokenbucket_timers\n");
+          tv_timeradd_seconds( &tokenbucket_timer, &tokenbucket_timer, TOKENBUCKET_INTERVAL);
+          run_tokenbucket_timers();
+        }
+
+        if (tv_timercmp( &tokenbucket_timer, &app->next_timeout ) <= 0) {
+          app->next_timeout = tokenbucket_timer;
+        }
+
+        // if (debug>2) printf("digipeater_prepoll - 1 - timeout millis=%d\n",aprxpolls_millis(app));
+
+        // Over all digipeaters..
+        for (d = 0; d < digi_count; ++d) {
+          struct digipeater *digi = digis[d];
+          // Over all sources in those digipeaters
+          for (s = 0; s < digi->sourcecount; ++s) {
+            struct timeval tv;
+            struct digipeater_source * src = digi->sources[s];
+            // If viscous delay is zero, there is no work...
+            // if (src->viscous_delay == 0)
+            //   continue;
+            // Delay is non-zero, perhaps there is work?
+            if (src->viscous_queue_size == 0) // Empty queue
+              continue;
+            // First entry expires first
+            tv.tv_sec = src->viscous_queue[0]->t + src->viscous_delay;
+            tv.tv_usec = 0;
+            if (tv_timercmp(&app->next_timeout, &tv) > 0) {
+              app->next_timeout = tv;
+              // if (debug>2) printf("digipeater_prepoll - 2 - timeout millis=%d\n",aprxpolls_millis(app));
+            }
+          }
+        }
+
+        return 0;
+}
+
+static void sourcecalltick(struct digipeater *digi);
+
+int  digipeater_postpoll(struct aprxpolls *app)
+{
+        int d, s, i, donecount;
+
+        if (tv_timercmp(&tokenbucket_timer, &tick) < 0) {
+          tv_timeradd_seconds( &tokenbucket_timer, &tokenbucket_timer, TOKENBUCKET_INTERVAL);
+          run_tokenbucket_timers();
+        }
+
+        // Over all digipeaters..
+        for (d = 0; d < digi_count; ++d) {
+          struct digipeater *digi = digis[d];
+
+          // Over all sources in those digipeaters
+          for (s = 0; s < digi->sourcecount; ++s) {
+            struct digipeater_source * src = digi->sources[s];
+
+            // If viscous delay is zero, there is no work...
+            // if (src->viscous_delay == 0)
+            //   continue;
+            // Delay is non-zero, perhaps there is work?
+            if (src->viscous_queue_size == 0) // Empty queue
+              continue;
+            // Feed backend from viscous queue
+            donecount = 0;
+            for (i = 0; i < src->viscous_queue_size; ++i) {
+              struct dupe_record_t *dupe = src->viscous_queue[i];
+              time_t t = dupe->t + src->viscous_delay;
+              if ((t - tick.tv_sec) <= 0) {
+                if (debug)printf("%ld LEAVE VISCOUS QUEUE: dupe=%p pbuf=%p\n",
+                                 tick.tv_sec, dupe, dupe->pbuf);
+                if (dupe->pbuf != NULL) {
+                  // We send the pbuf from viscous queue, if it still is
+                  // present in the dupe record.  (For example direct sourced
+                  // packets remove a packet from queued dupe record.)
+                  digipeater_receive_backend(src, dupe->pbuf);
+
+                  // Remove the delayed pbuf from this dupe record.
+                  pbuf_put(dupe->pbuf);
+                  dupe->pbuf = NULL;
+                }
+                dupecheck_put(dupe);
+                ++donecount;
+              } else {
+                break; // found a case we are not yet interested in.
+              }
+            }
+            if (donecount > 0) {
+              if (donecount >= src->viscous_queue_size) {
+                // All cleared
+                src->viscous_queue_size = 0;
+              } else {
+                // Compact the queue left after this processing round
+                i = src->viscous_queue_size - donecount;
+                memcpy(&src->viscous_queue[0],
+                       &src->viscous_queue[donecount],
+                       sizeof(void*) * i);
+                src->viscous_queue_size = i;
+              }
+            }
+          }
+        }
+
+        return 0;
+}
+
+static int  run_tokenbucket_timers()
+{
+        int d, s;
+        // Over all digipeaters..
+        for (d = 0; d < digi_count; ++d) {
+          struct digipeater *digi = digis[d];
+
+          digi->tokenbucket += digi->tbf_increment;
+          if (digi->tokenbucket > digi->tbf_limit)
+            digi->tokenbucket = digi->tbf_limit;
+
+#ifndef DISABLE_IGATE
+          sourcecalltick(digi);
+#endif
+
+          // Over all sources in those digipeaters
+          for (s = 0; s < digi->sourcecount; ++s) {
+            struct digipeater_source * src = digi->sources[s];
+
+            src->tokenbucket += src->tbf_increment;
+            if (src->tokenbucket > src->tbf_limit)
+              src->tokenbucket = src->tbf_limit;
+
+          }
+        }
+
+        return 0;
+}
+
+#ifndef DISABLE_IGATE
+static void sourcecalltick(struct digipeater *digi)
+{
+        int i;
+        historydb_t *db = digi->historydb;
+        if (db == NULL) return; // Should never happen..
+
+        for (i = 0; i < HISTORYDB_HASH_MODULO; ++i) {
+          history_cell_t *c = db->hash[i];
+          for ( ; c != NULL; c = c->next ) {
+            c->tokenbucket += digi->src_tbf_increment;
+            if (c->tokenbucket > digi->src_tbf_limit)
+              c->tokenbucket = digi->src_tbf_limit;
+          }
+        }
+}
+#endif
+
+// An utility function that exists at GNU Libc..
+
+#if !defined(HAVE_MEMRCHR) && !defined(_FOR_VALGRIND_)
+void   *memrchr(const void *s, int c, size_t n) {
+  const unsigned char *p = s;
+  c &= 0xFF;
+  for (p = s+n; n > 0; --n, --p) {
+    if (*p == c) return (void*)p;
+  }
+  return NULL;
+}
+#endif
diff --git a/doc/aprx-manual-pics.odp b/doc/aprx-manual-pics.odp
new file mode 100644
index 0000000..6412ea4
Binary files /dev/null and b/doc/aprx-manual-pics.odp differ
diff --git a/doc/aprx-manual.odt b/doc/aprx-manual.odt
new file mode 100644
index 0000000..d8cea5d
Binary files /dev/null and b/doc/aprx-manual.odt differ
diff --git a/doc/aprx-manual.pdf b/doc/aprx-manual.pdf
new file mode 100644
index 0000000..d8dcd6e
Binary files /dev/null and b/doc/aprx-manual.pdf differ
diff --git a/doc/aprx-requirement-specification.odt b/doc/aprx-requirement-specification.odt
new file mode 100644
index 0000000..4dbf8a5
Binary files /dev/null and b/doc/aprx-requirement-specification.odt differ
diff --git a/doc/aprx-requirement-specification.pdf b/doc/aprx-requirement-specification.pdf
new file mode 100644
index 0000000..bc3af9e
Binary files /dev/null and b/doc/aprx-requirement-specification.pdf differ
diff --git a/dprsgw.c b/dprsgw.c
new file mode 100644
index 0000000..4c42523
--- /dev/null
+++ b/dprsgw.c
@@ -0,0 +1,1094 @@
+/* **************************************************************** *
+ *                                                                  *
+ *  APRX -- 2nd generation receive-only APRS-i-gate with            *
+ *          minimal requirement of esoteric facilities or           *
+ *          libraries of any kind beyond UNIX system libc.          *
+ *                                                                  *
+ * (c) Matti Aarnio - OH2MQK,  2007-2014                            *
+ *                                                                  *
+ * **************************************************************** */
+
+#include "aprx.h"
+
+#ifndef DISABLE_IGATE
+
+/*
+ *  The DPRS RX Gateway
+ *
+ *  Receive data from DPRS.
+ *  Convert to 3rd-party frame.
+ *  Send out to APRSIS and Digipeaters.
+ *
+ *      http://www.aprs-is.net/DPRS.aspx
+ *
+ *
+ *
+ *  GPSxyz -> APRS symbols mapping:
+ *
+ *      http://www.aprs.org/symbols/symbolsX.txt
+ */
+
+typedef struct dprsgw_history {
+	time_t gated;
+	char   callsign[10];
+} dprsgw_history_t;
+
+// Up to 30 history entries to not to send same callsign too often
+#define HISTORYSIZE 30
+
+typedef struct dprs_gw {
+	char *ggaline;
+	char *rmcline;
+	int ggaspace;
+	int rmcspace;
+
+	int              historylimit;  // Time limit in seconds
+	dprsgw_history_t history[HISTORYSIZE];
+} dprsgw_t;
+
+
+// The dprslog() logs ONLY when '-d' mode is running.
+// .. and it will be removed soon.
+
+const char *dprslogfile;
+
+void dprslog( const time_t stamp, const uint8_t *buf ) {
+  if (dprslogfile == NULL) return; // Nothing to do
+
+  FILE *fp = fopen(dprslogfile,"a");
+  if (fp != NULL) {
+    fprintf(fp, "%ld\t%s\n", stamp, (const char *)buf);
+    fclose(fp);
+  }
+}
+
+
+static void dprsgw_flush(dprsgw_t *dp) {
+	if (dp->ggaline == NULL) {
+	  dp->ggaspace = 200;
+	  dp->ggaline = malloc(200);
+	}
+	if (dp->rmcline == NULL) {
+	  dp->rmcspace = 200;
+	  dp->rmcline = malloc(200);
+	}
+	dp->ggaline[0] = 0;
+	dp->rmcline[0] = 0;
+}
+
+static void *dprsgw_new(int historylimit) {
+	dprsgw_t *dp = calloc(1, sizeof(*dp));
+        dp->historylimit = historylimit;
+	dprsgw_flush(dp); // init buffers
+	return dp;
+}
+
+// Ratelimit returns 0 for "can send", 1 for "too soon"
+static int dprsgw_ratelimit( dprsgw_t *dp, const void *tnc2buf ) {
+	int i, n;
+	char callsign[10];
+	time_t expiry = tick.tv_sec - dp->historylimit;
+
+	memcpy(callsign, tnc2buf, sizeof(callsign));
+	callsign[sizeof(callsign)-1] = 0;
+	for (i = 0; i < sizeof(callsign); ++i) {
+	  char c = callsign[i];
+	  if (c == '>') {
+	    callsign[i] = 0;
+	    break;
+	  }
+	}
+	n = -1;
+	for (i = 0; i < HISTORYSIZE; ++i) {
+
+          // Is there an entry?
+          if (dp->history[i].callsign[0] == 0)
+            continue; 
+
+          if ((dp->history[i].gated - tick.tv_sec) >  0) {
+            // system time has jumped backwards, expire it.
+            dp->history[i].gated = expiry;
+          }
+	  if ((dp->history[i].gated - expiry) > 0) {
+	    // Fresh enough to be interesting!
+	    if (strcmp(dp->history[i].callsign, callsign) == 0) {
+	      // This callsign!
+	      return 1;
+	    }
+	  } else {
+	    dp->history[i].callsign[0] = 0; // discard it..
+	    if (n < 0) 
+	      n = i; // save first free slot's index
+	  }
+	}
+	if (n >= 0) {
+	  memcpy(dp->history[n].callsign, callsign, sizeof(callsign));
+	  dp->history[n].gated = tick.tv_sec;
+	}
+	return 0;
+}
+
+typedef struct gps2apr_syms {
+	const char gps[3];
+	const char aprs[3];
+	int  flags;
+} gps2aprs_syms_t;
+
+// FIXME: Some symbols have 3 characters,
+//        others take 3rd as overlay...
+//        Add control flags below!
+
+static const gps2aprs_syms_t gps2aprsSyms[] = {
+  { "A0", "\\0", 0 },
+  { "A1", "\\1", 0 },
+  { "A2", "\\2", 0 },
+  { "A3", "\\3", 0 },
+  { "A4", "\\4", 0 },
+  { "A5", "\\5", 0 },
+  { "A6", "\\6", 0 },
+  { "A7", "\\7", 0 },
+  { "A8", "\\8", 0 },
+  { "A9", "\\9", 0 },
+  { "AA", "\\A", 0 },
+  { "AB", "\\B", 0 },
+  { "AC", "\\C", 0 },
+  { "AD", "\\D", 0 },
+  { "AE", "\\E", 0 },
+  { "AF", "\\F", 0 },
+  { "AG", "\\G", 0 },
+  { "AH", "\\H", 0 },
+  { "AI", "\\I", 0 },
+  { "AJ", "\\J", 0 },
+  { "AK", "\\K", 0 },
+  { "AL", "\\L", 0 },
+  { "AM", "\\M", 0 },
+  { "AN", "\\N", 0 },
+  { "AO", "\\O", 0 },
+  { "AP", "\\P", 0 },
+  { "AQ", "\\Q", 0 },
+  { "AR", "\\R", 0 },
+  { "AS", "\\S", 0 },
+  { "AT", "\\T", 0 },
+  { "AU", "\\U", 0 },
+  { "AV", "\\V", 0 },
+  { "AW", "\\W", 0 },
+  { "AX", "\\X", 0 },
+  { "AY", "\\Y", 0 },
+  { "AZ", "\\Z", 0 },
+  { "BB", "/!",  0 },
+  { "BC", "/\"", 0 },
+  { "BD", "/#", 0 },
+  { "BE", "/$", 0 },
+  { "BF", "/%", 0 },
+  { "BG", "/&", 0 },
+  { "BH", "/'", 0 },
+  { "BI", "/(", 0 },
+  { "BJ", "/)", 0 },
+  { "BK", "/*", 0 },
+  { "BL", "/+", 0 },
+  { "BM", "/,", 0 },
+  { "BN", "/-", 0 },
+  { "BO", "/.", 0 },
+  { "BP", "//", 0 },
+  { "DS", "\\[", 0 },
+  { "DT", "\\\\", 0 },
+  { "DU", "\\]", 0 },
+  { "DV", "\\^", 0 },
+  { "DW", "\\_", 0 },
+  { "DX", "\\`", 0 },
+  { "HS", "/[", 0 },
+  { "HT", "/\\", 0 },
+  { "HU", "/]", 0 },
+  { "HV", "/^", 0 },
+  { "HW", "/_", 0 },
+  { "HX", "/`", 0 },
+  { "J1", "/{", 0 },
+  { "J2", "/|", 0 },
+  { "J3", "/}", 0 },
+  { "J4", "/~", 0 },
+  { "LA", "/a", 0 },
+  { "LB", "/b", 0 },
+  { "LC", "/c", 0 },
+  { "LD", "/d", 0 },
+  { "LE", "/e", 0 },
+  { "LF", "/f", 0 },
+  { "LG", "/g", 0 },
+  { "LH", "/h", 0 },
+  { "LI", "/i", 0 },
+  { "LJ", "/j", 0 },
+  { "LK", "/k", 0 },
+  { "LL", "/l", 0 },
+  { "LM", "/m", 0 },
+  { "LN", "/n", 0 },
+  { "LO", "/o", 0 },
+  { "LP", "/p", 0 },
+  { "LQ", "/q", 0 },
+  { "LR", "/r", 0 },
+  { "LS", "/s", 0 },
+  { "LT", "/t", 0 },
+  { "LU", "/u", 0 },
+  { "LV", "/v", 0 },
+  { "LW", "/w", 0 },
+  { "LX", "/x", 0 },
+  { "LY", "/y", 0 },
+  { "LZ", "/z", 0 },
+  { "MR", "/:", 0 },
+  { "MS", "/;", 0 },
+  { "MT", "/<", 0 },
+  { "MU", "/=", 0 },
+  { "MV", "/>", 0 },
+  { "MW", "/?", 0 },
+  { "MX", "/@", 0 },
+  { "NR", "\\:", 0 },
+  { "NS", "\\;", 0 },
+  { "NT", "\\<", 0 },
+  { "NU", "\\=", 0 },
+  { "NV", "\\>", 0 },
+  { "NW", "\\?", 0 },
+  { "NX", "\\@", 0 },
+  { "OB", "\\!", 0 },
+  { "OC", "\\\"", 0 },
+  { "OD", "\\#", 0 },
+  { "OE", "\\$", 0 },
+  { "OF", "\\%", 0 },
+  { "OG", "\\&", 0 },
+  { "OH", "\\'", 0 },
+  { "OI", "\\(", 0 },
+  { "OJ", "\\)", 0 },
+  { "OK", "\\*", 0 },
+  { "OL", "\\+", 0 },
+  { "OM", "\\,", 0 },
+  { "ON", "\\-", 0 },
+  { "OO", "\\.", 0 },
+  { "OP", "\\/", 0 },
+  { "P0", "/0", 0 },
+  { "P1", "/1", 0 },
+  { "P2", "/2", 0 },
+  { "P3", "/3", 0 },
+  { "P4", "/4", 0 },
+  { "P5", "/5", 0 },
+  { "P6", "/6", 0 },
+  { "P7", "/7", 0 },
+  { "P8", "/8", 0 },
+  { "P9", "/9", 0 },
+  { "PA", "/A", 0 },
+  { "PB", "/B", 0 },
+  { "PC", "/C", 0 },
+  { "PD", "/D", 0 },
+  { "PE", "/E", 0 },
+  { "PF", "/F", 0 },
+  { "PG", "/G", 0 },
+  { "PH", "/H", 0 },
+  { "PI", "/I", 0 },
+  { "PJ", "/J", 0 },
+  { "PK", "/K", 0 },
+  { "PL", "/L", 0 },
+  { "PM", "/M", 0 },
+  { "PN", "/N", 0 },
+  { "PO", "/O", 0 },
+  { "PP", "/P", 0 },
+  { "PQ", "/Q", 0 },
+  { "PR", "/R", 0 },
+  { "PS", "/S", 0 },
+  { "PT", "/T", 0 },
+  { "PU", "/U", 0 },
+  { "PV", "/V", 0 },
+  { "PW", "/W", 0 },
+  { "PX", "/X", 0 },
+  { "PY", "/Y", 0 },
+  { "PZ", "/Z", 0 },
+  { "Q1", "\\{", 0 },
+  { "Q2", "\\|", 0 },
+  { "Q3", "\\}", 0 },
+  { "Q4", "\\~", 0 },
+  { "SA", "\\a", 0 },
+  { "SB", "\\b", 0 },
+  { "SC", "\\c", 0 },
+  { "SD", "\\d", 0 },
+  { "SE", "\\e", 0 },
+  { "SF", "\\f", 0 },
+  { "SG", "\\g", 0 },
+  { "SH", "\\h", 0 },
+  { "SI", "\\i", 0 },
+  { "SJ", "\\j", 0 },
+  { "SK", "\\k", 0 },
+  { "SL", "\\l", 0 },
+  { "SM", "\\m", 0 },
+  { "SN", "\\n", 0 },
+  { "SO", "\\o", 0 },
+  { "SP", "\\p", 0 },
+  { "SQ", "\\q", 0 },
+  { "SR", "\\r", 0 },
+  { "SS", "\\s", 0 },
+  { "ST", "\\t", 0 },
+  { "SU", "\\u", 0 },
+  { "SV", "\\v", 0 },
+  { "SW", "\\w", 0 },
+  { "SX", "\\x", 0 },
+  { "SY", "\\y", 0 },
+  { "SZ", "\\z", 0 },
+};
+
+static int gps2aprs_syms_count = sizeof(gps2aprsSyms) / sizeof(gps2aprsSyms[0]);
+
+static int parse_gps2aprs_symbol(const char *gpsxxx, char *aprssymbol) {
+	int i, mid, high, low;
+	char gps[3];
+	gps[0] = gpsxxx[0];
+	gps[1] = gpsxxx[1];
+	gps[2] = 0;
+	low = 0;
+	high = gps2aprs_syms_count-1;
+	while (low < high) {
+	  mid = (low + high) >> 1; // divide by 2
+	  i = strcmp(gps, gps2aprsSyms[mid].gps);
+	  // if (debug) printf("GPS2APRS: '%s' '%s', low=%d mid=%d high=%d\n",gps, gps2aprsSyms[mid].gps, low, mid, high);
+	  if (i == 0) {
+	    // Exact match
+	    char c3 = gpsxxx[2];
+	    strcpy(aprssymbol, gps2aprsSyms[mid].aprs);
+	    if (c3 != 0 && c3 != ' ' && aprssymbol[0] != '/') {
+	      // FIXME: overlay ???
+	      aprssymbol[0] = c3;
+	    }
+	    return 0;
+	  }
+	  if (i > 0) {
+	    low = mid+1;
+	  } else {
+	    high = mid-1;
+	  }
+	}
+	return i;
+}
+
+
+// The "Specification" says to use this checksum method..
+// It uses right-left inverted version of the polynome
+// of CCITT-CRC-16 but in the end it INVERTS the result!
+// Thus the result is NOT CCITT-CRC-16, but something
+// uniquely ICOM D-STAR..
+/*
+static int dprsgw_crccheck( const uint8_t *s, int len )
+{
+	int icomcrc = 0xffff;
+	for ( ; len > 0; ++s, --len) {
+	  uint8_t ch = *s;
+	  int i;
+	  for (i = 0; i < 8; i++) {
+	    int xorflag = (icomcrc ^ ch) & 0x01;
+	    icomcrc >>= 1;
+	    if (xorflag)
+	      icomcrc ^= 0x8408;
+	    ch >>= 1;
+	  }
+	}
+	return (~icomcrc) & 0xffff;
+}
+*/
+
+static int dprsgw_isvalid( struct serialport *S )
+{
+	int i;
+
+	if (S->rdlinelen < 20) {
+	  if (debug) printf("Too short a line for DPRS");
+	  return 0; // definitely not!
+	}
+
+	if (memcmp("$$CRC", S->rdline, 5) == 0 && S->rdline[9] == ',') {
+	  // Maybe a $$CRCB727,OH3BK-D>APRATS,DSTAR*:@165340h6128.23N/02353.52E-D-RATS (GPS-A) /A=000377
+	  int crc;
+	  int csum = -1;
+	  int crc16;
+
+	  S->rdline[S->rdlinelen] = '\r';
+	  crc16 = calc_crc_ccitt(0xFFFF, S->rdline+10, S->rdlinelen+1-10); // INCLUDE the CR on CRC calculation!
+	  crc = (crc16 ^ 0xFFFF); // Output is INVERTED
+
+	  S->rdline[S->rdlinelen] = 0;
+	  i = sscanf((const char*)(S->rdline), "$$CRC%04x,", &csum);
+	  if (i != 1 || csum != crc) {
+	    if (debug) printf("Bad DPRS APRS CRC: l=%d, i=%d, %04x/%04x vs. %s\n", S->rdlinelen, i, crc, csum, S->rdline);
+	    // return 0;
+	  } else {
+	    if (debug>1) printf("$$CRC  DSTAR=%04x CCITT-X25-FCS=%04x\n", csum, crc16);
+
+	    if (debug) printf("Good DPRS APRS CRC: l=%d, i=%d, %04x/%04x vs. %s\n", S->rdlinelen, i, crc, csum, S->rdline);
+	    return 1;
+	  }
+	  return 0;
+
+	} else if (memcmp("$GP", S->rdline, 3) == 0) {
+	  // Maybe  $GPRMC,170130.02,A,6131.6583,N,02339.1552,E,0.00,154.8,290510,6.5,E,A*02  ?
+	  int xor = 0;
+	  int csum = -1;
+	  char c;
+	  // if (debug) printf("NMEA: '%s'\n", S->rdline);
+	  for (i = 1; i < S->rdlinelen; ++i) {
+	    c = S->rdline[i];
+	    if (c == '*' && (i >= S->rdlinelen - 3)) {
+	      break;
+	    }
+	    xor ^= c;
+	  }
+	  xor &= 0xFF;
+	  if (i != S->rdlinelen -3 || S->rdline[i] != '*')
+	    return 0; // Wrong place to stop
+	  if (sscanf((const char *)(S->rdline+i), "*%02x%c", &csum, &c) != 1) {
+	    return 0; // Too little or too much
+	  }
+	  if (xor != csum) {
+	    if (debug) printf("Bad DPRS $GP... checksum: %02x vs. %02x\n", csum, xor);
+	    return 0;
+	  }
+	  return 1;
+	} else {
+	  int xor = 0;
+	  int csum = -1;
+	  char c;
+	  // .. uh?  maybe?  Precisely 29 characters:
+	  // "OH3KGR M,                    "
+	  if (S->rdlinelen != 29 || S->rdline[8] != ',') {
+	    if (debug) printf("Bad DPRS identification(?) packet - length(%d) != 29 || line[8] != ',': %s\n",
+			      S->rdlinelen, S->rdline);
+	    return 0;
+	  }
+	  if (debug) printf("DPRS NMEA: '%s'\n", S->rdline);
+	  for (i = 0; i < S->rdlinelen; ++i) {
+	    c = S->rdline[i];
+	    if (c == '*') {
+	      break;
+	    }
+	    xor ^= c;
+	  }
+	  xor &= 0xFF;
+	  if (sscanf((const char *)(S->rdline+i), "*%x%c", &csum, &c) < 1) {
+	    if (memcmp(S->rdline+8, ",                    ", 21) == 0) {
+	      if (debug) printf("DPRS IDENT LINE OK: '%s'\n", S->rdline);
+	      return 1;
+	    }
+	    // if (debug) printf("csum bad NMEA: '%s'\n", S->rdline);
+	    return 0; // Too little or too much
+	  }
+	  if (xor != csum) {
+	    if (debug) printf("Bad DPRS IDENT LINE checksum: %02x vs. %02x\n", csum, xor);
+	    return 0;
+	  }
+	  if (debug) printf("DPRS IDENT LINE OK: '%s'\n", S->rdline);
+	  // if (debug) printf("csum valid NMEA: '%s'\n", S->rdline);
+	  return 1; // Maybe valid?
+	}
+}
+
+
+// Split NMEA text line at ',' characters
+static int dprsgw_nmea_split(char *nmea, char *fields[], int n) {
+	int i = 0;
+	--n;
+	fields[i] = nmea;
+	for ( ; *nmea; ++nmea ) {
+	  for ( ; *nmea != 0 && *nmea != ','; ++nmea )
+	    ;
+	  if (*nmea == 0) break; // THE END!
+	  if (*nmea == ',')
+	    *nmea++ = 0; // COMMA terminates a field, change to SPACE
+	  if (i < n) ++i;  // Prep next field index
+	  fields[i] = nmea; // save field pointer
+	}
+	fields[i] = NULL;
+	return i;
+}
+
+static void dprsgw_nmea_igate( const struct aprx_interface *aif,
+			       const uint8_t *ident, dprsgw_t *dp ) {
+	int i;
+	char *gga[20];
+	char *rmc[20];
+	char tnc2buf[2000];
+	int  tnc2addrlen;
+	int  tnc2buflen;
+	char *p, *p2;
+	const char *p0;
+	const char *s;
+	int  alt_feet = -9999999;
+	char aprssym[3];
+
+	if (debug) {
+	  printf(" DPRS: ident='%s', GGA='%s', RMC='%s'\n", ident, dp->ggaline, dp->rmcline);
+	}
+
+	strcpy(aprssym, "/>"); // Default..
+	parse_gps2aprs_symbol((const char *)ident+9, aprssym);
+
+	memset(gga, 0, sizeof(gga));
+	memset(rmc, 0, sizeof(rmc));
+
+	// $GPGGA,hhmmss.dd,xxmm.dddd,<N|S>,yyymm.dddd,<E|W>,v,
+	//        ss,d.d,h.h,M,g.g,M,a.a,xxxx*hh<CR><LF>
+
+	// $GPRMC,hhmmss.dd,S,xxmm.dddd,<N|S>,yyymm.dddd,<E|W>,
+	//        s.s,h.h,ddmmyy,d.d, <E|W>,M*hh<CR><LF>
+	//    ,S, = Status:  'A' = Valid, 'V' = Invalid
+
+	if (dp->ggaline[0] != 0)
+	  dprsgw_nmea_split(dp->ggaline, gga, 20);
+	if (dp->rmcline[0] != 0)
+	  dprsgw_nmea_split(dp->rmcline, rmc, 20);
+
+	if (rmc[2] != NULL && strcmp(rmc[2],"A") != 0) {
+	  if (debug) printf("Invalid DPRS $GPRMC packet (validity='%s')\n",
+			    rmc[2]);
+	  return;
+	}
+	if (gga[6] != NULL && strcmp(gga[6],"1") != 0) {
+	  if (debug) printf("Invalid DPRS $GPGGA packet (validity='%s')\n",
+			    gga[6]);
+	  return;
+	}
+	if (dp->ggaline[0] == 0 && dp->rmcline[0] == 0) {
+	  if (debug) printf("No DPRS $GPRMC nor $GPGGA packets available.\n");
+	  return;
+	}
+
+	p = tnc2buf;
+	for (i = 0; i < 8; ++i) {
+	  if (ident[i] == ' ') {
+	    *p++ = '-';
+	    for ( ; ident[i+1] == ' ' && i < 8; ++i );
+	    continue;
+	  }
+	  *p++ = ident[i];
+	}
+
+        if (p > tnc2buf && p[-1] == '-') --p;
+
+	p += sprintf(p, ">APDPRS,DSTAR*");
+
+
+	tnc2addrlen = p - tnc2buf;
+	*p++ = ':';
+	*p++ = '!'; // Std position w/o messaging
+	p2 = p;
+	if (gga[2] != NULL) {
+	  s = gga[2];
+	} else if (rmc[3] != NULL) {
+	  s = rmc[3];
+	} else {
+	  // No coordinate!
+	  if (debug) printf("dprsgw: neither GGA nor RMC coordinates available, discarding!\n");
+	  return;
+	}
+	p0 = strchr(s, '.');
+	if (!p0) {
+	  if (debug) printf("dprsgw: invalid format NMEA North coordinate: '%s'\n", s);
+	  return;
+	}
+	while (p0 - s < 4) {
+	  *p++ = '0';
+	  ++p0; // move virtually
+	}
+	p += sprintf(p, "%s", s);
+	if (p2+7 < p) { // Too long!
+	  p = p2+7;
+	}
+	while (p2+7 > p) { // Too short!
+	  *p++ = ' '; // unprecise position
+	}
+	if (gga[2] != NULL) {
+	  s = gga[3]; // <N|S>
+	} else if (rmc[3] != NULL) {
+	  s = rmc[4]; // <N|S>
+	}
+	p += sprintf(p, "%s", s);
+
+	*p++ = aprssym[0];
+	p2 = p;
+	if (gga[2] != NULL) {
+	  s = gga[4]; // yyymm.dddd
+	} else if (rmc[3] != NULL) {
+	  s = rmc[5]; // yyymm.dddd
+	}
+	p0 = strchr(s, '.');
+	if (!p0) {
+	  if (debug) printf("dprsgw: invalid format NMEA East coordinate: '%s'\n", s);
+	  return;
+	}
+	while (p0 - s < 5) {
+	  *p++ = '0';
+	  ++p0; // move virtually
+	}
+
+	p += sprintf(p, "%s", s);
+	if (p2+8 < p) { // Too long!
+	  p = p2+8;
+	}
+	while (p2+8 > p) { // Too short!
+	  *p++ = ' '; // unprecise position
+	}
+	if (gga[2] != NULL) {
+	  p += sprintf(p, "%s", gga[5]); // <E|W>
+	} else if (rmc[3] != NULL) {
+	  p += sprintf(p, "%s", rmc[6]); // <E|W>
+	}
+
+	*p++ = aprssym[1];
+
+	//  DPRS: ident='OH3BK  D,BN  *59             ', GGA='$GPGGA,204805,6128.230,N,2353.520,E,1,3,0,115,M,0,M,,*6d', RMC=''
+	//  DPRSGW GPS data: OH3BK-D>APDPRS,DSTAR*:!6128.23N/02353.52E>
+
+	if (gga[2] != NULL) {
+	  if (gga[9] != NULL && gga[9][0] != 0)
+	    alt_feet = strtol(gga[9], NULL, 10);
+	  if (strcmp(gga[10],"M") == 0) {
+	    // Meters!  Convert to feet..
+	    alt_feet = (10000 * alt_feet) / 3048;
+	  } else {
+	    // Already feet - presumably
+	  }
+	}
+
+	// FIXME: more data!
+	// RMC HEADING/SPEED
+
+	p0 = (const char *)ident + 29;
+	s  = (const char *)ident + 9+4;
+	p2 = p;
+
+	for ( ; s < p0; ++s ) {
+	  if (*s != ' ')
+	    break;
+	}
+	if (s < p0)
+	  *p++ = ' ';
+	for ( ; s < p0; ++s ) {
+	  if (*s == '*')
+	    break;
+	  *p++ = *s;
+	}
+	if (p > p2)
+	  *p++ = ' ';
+
+	if (alt_feet > -9999999) {
+	  p += sprintf(p, "/A=%06d", alt_feet);
+	}
+
+	*p = 0;
+	tnc2buflen = p - tnc2buf;
+
+	if (debug) printf("DPRSGW GPS data: %s\n", tnc2buf);
+
+	if (!dprsgw_ratelimit( dp, tnc2buf )) {
+
+	  char *fromcall, *origtocall;
+	  char *b;
+
+          if (aif != NULL) {
+            igate_to_aprsis( aif->callsign, 0, (const char *)tnc2buf, tnc2addrlen, tnc2buflen, 0, 0);
+          // Bytes have been counted previously, now count meaningful packet
+            erlang_add(aif->callsign, ERLANG_RX, 0, 1);
+          }
+
+	  fromcall = tnc2buf;
+	  p = fromcall;
+	  origtocall = NULL;
+	  while (*p != '>' && *p != 0) ++p;
+	  if (*p == '>') {
+	    *p++ = 0;
+	    origtocall = p;
+	  } else
+	    return; // BAD :-(
+	  p = origtocall;
+	  while (p != NULL && *p != ':' &&  *p != 0 && *p != ',') ++p;
+	  if (p != NULL && (*p == ':' || *p == ',')) {
+	    *p++ = 0;
+	  }
+	  b = tnc2buf + tnc2addrlen +1;
+	  interface_receive_3rdparty( aif,
+				      fromcall, origtocall, "DSTAR*",
+				      b, tnc2buflen - (b-tnc2buf) );
+	}
+}
+
+static void dprsgw_rxigate( struct serialport *S )
+{
+	const struct aprx_interface *aif = S->interface[0];
+	uint8_t *tnc2addr    = S->rdline;
+	int      tnc2addrlen = S->rdlinelen;
+	uint8_t *tnc2body    = S->rdline;
+	int      tnc2bodylen = S->rdlinelen;
+
+#ifndef DPRSGW_DEBUG_MAIN
+	if (aif == NULL) {
+	  if (debug) printf("OOPS! NO <interface> ON DPRS SERIAL PORT! BUG!\n");
+	  return;
+	}
+#endif
+
+	if (memcmp("$$CRC", tnc2addr, 5) == 0 && tnc2addrlen > 20) {
+	  tnc2addr += 10;
+	  tnc2addrlen -= 10;
+	  tnc2bodylen -= 10; // header + body together
+	  tnc2body = memchr( tnc2addr, ':', tnc2addrlen);
+	  if (tnc2body != NULL) {
+	    char *fromcall, *origtocall;
+	    char *s;
+
+	    tnc2addrlen = tnc2body - tnc2addr;
+	    ++tnc2body;
+
+	    if (dprsgw_ratelimit(S->dprsgw, tnc2addr)) {
+	      // Rate-limit ordered rejection
+	      return;
+	    }
+
+	    // Acceptable packet, Rx-iGate it!
+	    igate_to_aprsis( aif->callsign, 0, (const char *)tnc2addr, tnc2addrlen, tnc2bodylen, 0, 0);
+          // Bytes have been counted previously, now count meaningful packet
+            erlang_add( aif->callsign, ERLANG_RX, 0, 1 );
+
+	    fromcall = (char*)tnc2addr;
+	    s = fromcall;
+	    origtocall = NULL;
+	    while (*s != '>' && *s != 0) ++s;
+	    if (*s == '>') {
+	      *s++ = 0;
+	      origtocall = s;
+	    } else
+	      return; // BAD :-(
+	    s = origtocall;
+	    while (s != NULL && *s != ':' &&  *s != 0 && *s != ',') ++s;
+	    if (s != NULL && (*s == ':' || *s == ',')) {
+	      *s++ = 0;
+	    }
+
+	    interface_receive_3rdparty( aif,
+					fromcall, origtocall, "DSTAR*",
+					(const char*)tnc2body, tnc2bodylen - (tnc2body-tnc2addr) );
+	    return;
+	    
+	  } else {
+	    // Bad packet!
+	    if (debug) printf("Bad DPRS packet! %s\n", S->rdline);
+	    return;
+	  }
+
+	} else if (memcmp("$GPGGA,", tnc2addr, 7) == 0) {
+	  dprsgw_t *dp = S->dprsgw;
+	  
+	  if (dp->ggaspace <= S->rdlinelen) {
+	    dp->ggaline  = realloc(dp->ggaline, S->rdlinelen+1);
+	    dp->ggaspace = S->rdlinelen;
+	  }
+	  memcpy(dp->ggaline, tnc2addr, tnc2bodylen);
+	  dp->ggaline[tnc2bodylen] = 0;
+	  if (debug) printf("DPRS GGA: %s\n", dp->ggaline);
+
+	} else if (memcmp("$GPRMC,", tnc2addr, 7) == 0) {
+	  dprsgw_t *dp = S->dprsgw;
+	  
+	  if (dp->rmcspace <= S->rdlinelen) {
+	    dp->rmcline  = realloc(dp->rmcline, S->rdlinelen+1);
+	    dp->rmcspace = S->rdlinelen;
+	  }
+	  memcpy(dp->rmcline, tnc2addr, tnc2bodylen);
+	  dp->rmcline[tnc2bodylen] = 0;
+	  if (debug) printf("DPRS RMC: %s\n", dp->rmcline);
+
+	} else if (tnc2addr[8] == ',' && tnc2bodylen == 29) {
+	  // Acceptable DPRS "ident" line
+	  dprsgw_t *dp = S->dprsgw;
+	  tnc2addr[tnc2bodylen] = 0; // zero-terminate just in case
+	  dprsgw_nmea_igate(aif, tnc2addr, dp);
+
+	} else {
+	  // this should never be called...
+	  if (debug) printf("Unrecognized DPRS packet: %s\n", S->rdline);
+	  return;
+	}
+}
+
+/*
+ *  Receive one text line from serial port
+ *  It will end with 0x00 byte, and not contain \r nor \n.
+ *
+ *  It MAY have junk at the start.
+ *
+ *
+ */
+
+static void dprsgw_receive( struct serialport *S )
+{
+	int i;
+	uint8_t *p;
+
+	if (debug) dprslog(S->rdline_time, S->rdline);
+
+	do {
+	  if (dprsgw_isvalid(S)) {
+	    // Feed it to DPRS-APRS-GATE
+	    dprsgw_rxigate( S );
+	    return; // Done!
+	  } else {
+	    // Not a good packet! See if there is a good packet inside?
+	    dprsgw_flush(S->dprsgw);  // bad input -> discard accumulated data
+
+	    p = memchr(S->rdline+1, '$', S->rdlinelen-1);
+	    if (p == NULL)
+	      break; // No '$' to start something
+	    i = S->rdlinelen - (p - S->rdline);
+	    if (i <= 0)
+	      break; // exhausted!
+	    S->rdlinelen = i;
+	    memcpy(S->rdline, p, S->rdlinelen);
+	    S->rdline[i] = 0;
+	    continue;
+	  }
+	} while(1);
+}
+
+
+/*
+ *  Receive more data from DPRS type serial port
+ *  This handles correct data accumulation and sync hunting
+ */
+int dprsgw_pulldprs( struct serialport *S )
+{
+	const time_t rdtime = S->rdline_time;
+	const struct aprx_interface *aif = S->interface[0];
+	int c;
+	int i;
+
+        // Account all received bytes, this may or may not be a packet
+        erlang_add(aif->callsign, ERLANG_RX, S->rdlinelen, 0);
+
+
+	if (S->dprsgw == NULL)
+	  S->dprsgw = dprsgw_new(30);   // FIXME: hard-coded 30 second delay for DPRS repeats
+
+	if ((rdtime+2 - tick.tv_sec) < 0) {
+		// A timeout has happen? (2 seconds!) Either data is added constantly,
+		// or nothing was received from DPRS datastream!
+
+		if (S->rdlinelen > 0)
+		  if (debug)printf("dprsgw: previous data is %d sec old, discarding its state: %s\n",((int)(tick.tv_sec-rdtime)), S->rdline);
+
+		S->rdline[S->rdlinelen] = 0;
+		if (S->rdlinelen > 0 && debug) dprslog(rdtime, S->rdline);
+		S->rdlinelen = 0;
+
+		dprsgw_flush(S->dprsgw);  // timeout -> discard accumulated data
+	}
+	S->rdline_time = tick.tv_sec;
+
+	for (i=0 ; ; ++i) {
+
+		c = ttyreader_getc(S);
+		if (c < 0) {
+		  // if (debug) printf("dprsgw_pulldprs: read %d chars\n", i);
+			return c;	/* Out of input.. */
+		}
+		if (debug>2) printf("DPRS %ld %3d %02X '%c'\n", tick.tv_sec, S->rdlinelen, c, c);
+
+		/* S->dprsstate != 0: read data into S->rdline,
+		   == 0: discard data until CR|LF.
+		   Zero-size read line is discarded as well
+		   (only CR|LF on input frame)  */
+
+		/* Looking for CR or LF.. */
+		if (c == '\n' || c == '\r') {
+		  /* End of line seen! */
+		  if (S->rdlinelen > 0) {
+		  
+		    /* Non-zero-size string, put terminating 0 byte on it. */
+		    S->rdline[S->rdlinelen] = 0;
+		  
+		    dprsgw_receive(S);
+		  }
+		  S->rdlinelen = 0;
+		  continue;
+		}
+		// A '$' starts possible data..
+		if (c == '$' && S->rdlinelen == 0) {
+		  S->rdline[S->rdlinelen++] = c;
+		  continue;
+		}
+		// More fits in?
+		if (S->rdlinelen >= sizeof(S->rdline)-3) {
+		  // Too long a line...
+		  do {
+		    int len;
+		    uint8_t *p;
+		    dprsgw_flush(S->dprsgw);
+		    
+		    // Look for first '$' in buffer _after_ first char
+		    p = memchr(S->rdline+1, '$', S->rdlinelen-1);
+		    if (!p) {
+		      S->rdlinelen = 0;
+		      break; // Not found
+		    }
+		    len = S->rdlinelen - (p - S->rdline);
+		    if (len <= 0) {
+		      S->rdlinelen = 0;
+		      break; // exhausted
+		    }
+		    memcpy(S->rdline, p, len);
+		    S->rdline[len] = 0;
+		    S->rdlinelen = len;
+		    if (len >= 3) {
+		      if (memcmp("$$C", S->rdline, 3) != 0 &&
+			  memcmp("$GP", S->rdline, 3) != 0) {
+			// Not acceptable 3-char prefix
+			// Eat away the collected prefixes..
+			continue;
+		      }
+		    }
+		    break;
+		  } while(1);
+		}
+		S->rdline[S->rdlinelen++] = c;
+
+/*
+		// Too short to say anything?
+		if (S->rdlinelen < 3) {
+		  continue;
+		}
+		if (S->rdlinelen == 3 &&
+		    (memcmp("$$C", S->rdline, 3) != 0 &&
+		     memcmp("$GP", S->rdline, 3) != 0)) {
+		  // No correct start, discard...
+		  dprsgw_flush(S->dprsgw);
+		  S->rdlinelen = 2;
+		  memcpy(S->rdline, S->rdline+1, 2);
+		  S->rdline[S->rdlinelen] = 0;
+		  if (S->rdline[0] != '$') {
+		    // Didn't start with a '$'
+		    S->rdlinelen = 0;
+		  }
+		  continue;
+		}
+*/
+	}			/* .. input loop */
+
+	return 0;		/* not reached */
+}
+
+
+int  dprsgw_prepoll(struct aprxpolls *app)
+{
+	return 0; // returns number of sockets filled (ignored at caller)
+}
+
+int  dprsgw_postpoll(struct aprxpolls *app)
+{
+	return 0; // returns number of sockets filled (ignored at caller)
+}
+
+
+
+#ifdef DPRSGW_DEBUG_MAIN
+
+int freadln(FILE *fp, char *p, int buflen) // DPRSGW_DEBUG_MAIN
+{
+  int n = 0;
+  while (!feof(fp)) {
+    int c = fgetc(fp);
+    if (c == EOF) break;
+    if (n >= buflen) break;
+    *p++ = c;
+    ++n;
+    if (c == '\n') break;
+    if (c == '\r') break;
+  }
+  return n;
+}
+
+int ttyreader_getc(struct serialport *S)  // DPRSGW_DEBUG_MAIN
+{
+	if (S->rdcursor >= S->rdlen) {	/* Out of data ? */
+		if (S->rdcursor)
+			S->rdcursor = S->rdlen = 0;
+		/* printf("-\n"); */
+		return -1;
+	}
+
+	/* printf(" %02X", 0xFF & S->rdbuf[S->rdcursor++]); */
+
+	return (0xFF & S->rdbuf[S->rdcursor++]);
+}
+void igate_to_aprsis(const char *portname, const int tncid, const char *tnc2buf, int tnc2addrlen, int tnc2len, const int discard, const int strictax25_) // DPRSGW_DEBUG_MAIN
+{
+  printf("DPRS RX-IGATE: %s\n", tnc2buf);
+}
+
+void interface_receive_3rdparty(const struct aprx_interface *aif, const char *fromcall, const char *origtocall, const char *gwtype, const char *tnc2data, const int tnc2datalen) // DPRSGW_DEBUG_MAIN
+{
+  printf("DPRS 3RDPARTY RX: ....:}%s>%s,%s,GWCALLSIGN*:%s\n",
+	 fromcall, origtocall, gwtype, tnc2data);
+}
+
+int debug = 3;
+struct timeval tick;
+int main(int argc, char *argv[]) {
+  struct serialport S;
+  memset(&S, 0, sizeof(S));
+
+#if 0
+  // A test where string has initially some incomplete data, then finally a real data
+  printf("\nFIRST TEST\n");
+  strcpy((void*)S.rdline, "x$x4$GPPP$$$GP  $$CRCB727,OH3BK-D>$$CRCB727,OH3BK-D>APRATS,DSTAR*:@165340h6128.23N/02353.52E-D-RATS (GPS-A) /A=000377");
+  S.rdlinelen = strlen((void*)S.rdline);
+  dprsgw_receive(&S);
+
+  printf("\nSECOND TEST\n");
+  strcpy((void*)S.rdline, "\304\3559\202\333$$CRCC3F5,OH3KGR-M>API282,DSTAR*:/123035h6131.29N/02340.45E>/IC-E2820");
+  S.rdlinelen = strlen((void*)S.rdline);
+  dprsgw_receive(&S);
+
+  printf("\nTHIRD TEST\n");
+  strcpy((void*)S.rdline, "[SOB]\"=@=@=@=>7\310=@\010!~~~~~~~!~~~~~~~\001\001\001\001\001\001\001\001[EOB]$$CRCBFB7,OH3BK>APRATS,DSTAR*:@124202h6128.23N/02353.52E-D-RATS (GPS-A) /A=000377");
+  S.rdlinelen = strlen((void*)S.rdline);
+  dprsgw_receive(&S);
+
+  printf("\nTEST 4.\n");
+  strcpy((void*)S.rdline, "$GPGGA,164829.02,6131.6572,N,02339.1567,E,1,08,1.1,111.3,M,19.0,M,,*61");
+  S.rdlinelen = strlen((void*)S.rdline);
+  dprsgw_receive(&S);
+
+  printf("\nTEST 5.\n");
+  strcpy((void*)S.rdline, "$GPRMC,170130.02,A,6131.6583,N,02339.1552,E,0.00,154.8,290510,6.5,E,A*02");
+  // strcpy((void*)S.rdline, "$GPRMC,164830.02,A,6131.6572,N,02339.1567,E,0.00,182.2,290510,6.5,E,A*07");
+  S.rdlinelen = strlen((void*)S.rdline);
+  dprsgw_receive(&S);
+
+  printf("\nTEST 6.\n");
+  strcpy((void*)S.rdline, "OH3BK  D,BN  *59             ");
+  S.rdlinelen = strlen((void*)S.rdline);
+  dprsgw_receive(&S);
+#endif
+
+  S.ttyname = "testfile";
+  S.ttycallsign[0] = "OH2MQK-DR";
+  FILE *fp = fopen("tt.log", "r");
+  for (;;) {
+    char buf1[3000];
+    int n = freadln(fp, buf1, sizeof(buf1));
+    if (n == 0) break;
+    char *ep;
+    tick.tv_sec = strtol(buf1, &ep, 10); // test code time init
+    if (*ep == '\t') ++ep;
+    int len = n - (ep - buf1);
+    if (len > 0) {
+      memcpy(S.rdbuf+S.rdlen, ep, len);
+      S.rdlen += len;
+    }
+    if (S.rdlen > 0)
+      dprsgw_pulldprs(&S);
+
+  }
+  fclose(fp);
+
+  return 0;
+}
+#endif
+#endif
diff --git a/dupecheck.c b/dupecheck.c
new file mode 100644
index 0000000..d14c543
--- /dev/null
+++ b/dupecheck.c
@@ -0,0 +1,484 @@
+/* **************************************************************** *
+ *                                                                  *
+ *  APRX -- 2nd generation receive-only APRS-i-gate with            *
+ *          minimal requirement of esoteric facilities or           *
+ *          libraries of any kind beyond UNIX system libc.          *
+ *                                                                  *
+ * (c) Matti Aarnio - OH2MQK,  2007-2014                            *
+ *                                                                  *
+ * **************************************************************** */
+
+#include "aprx.h"
+
+/*
+ *	Some parts of this code are copied from:
+ */
+/*
+ *	aprsc
+ *
+ *	(c) Heikki Hannikainen, OH7LZB <hessu at hes.iki.fi>
+ *
+ *	This program is licensed under the BSD license, which can be found
+ *	in the file LICENSE.
+ *	
+ */
+
+/*
+ *	dupecheck.c: the dupe-checkers
+ */
+
+static int           dupecheck_cellgauge;
+static int           dupecheckers_count;
+static dupecheck_t **dupecheckers;
+
+
+#ifndef _FOR_VALGRIND_
+cellarena_t *dupecheck_cells;
+#endif
+
+const int duperecord_size  = sizeof(struct dupe_record_t);
+const int duperecord_align = __alignof__(struct dupe_record_t);
+
+/*
+ *	The cellmalloc does not need internal MUTEX, it is being used in single thread..
+ */
+
+void dupecheck_init(void)
+{
+#ifndef _FOR_VALGRIND_
+	dupecheck_cells = cellinit( "dupecheck",
+				    duperecord_size,
+				    duperecord_align,
+				    CELLMALLOC_POLICY_LIFO | CELLMALLOC_POLICY_NOMUTEX,
+				    4 /* 4 kB at the time */,
+				    0 /* minfree */);
+#endif
+}
+
+/*
+ * dupecheck_new() creates a new instance of dupechecker
+ *
+ */
+dupecheck_t *dupecheck_new(const int storetime) {
+	dupecheck_t *dp = calloc(1, sizeof(dupecheck_t));
+
+	++dupecheckers_count;
+	dupecheckers = realloc(dupecheckers,
+			       sizeof(dupecheck_t *) * dupecheckers_count);
+	dupecheckers[ dupecheckers_count -1 ] = dp;
+
+        dp->storetime = storetime;
+
+	return dp;
+}
+
+
+static dupe_record_t *dupecheck_db_alloc(int alen, int pktlen)
+{
+	dupe_record_t *dp;
+#ifndef _FOR_VALGRIND_
+//	if (debug) printf("DUPECHECK db alloc(alen=%d,dlen=%d) %s",
+//			  alen,pktlen, dupecheck_free ? "FreeChain":"CellMalloc");
+
+	dp = cellmalloc(dupecheck_cells);
+//	if (debug) printf(" dp=%p\n",dp);
+	if (dp == NULL)
+		return NULL;
+	// cellmalloc() block may need separate pktbuf
+	memset(dp, 0, sizeof(*dp));
+	dp->packet = dp->packetbuf;
+	if (pktlen > sizeof(dp->packetbuf))
+		dp->packet = malloc(pktlen+1);
+#else
+	// directly malloced block is fine as is
+	dp = calloc(1, pktlen + sizeof(*dp));
+	dp->packet = dp->packetbuf; // always suitable size
+#endif
+	dp->alen = alen;
+	dp->plen = pktlen;
+
+	++dupecheck_cellgauge;
+
+	dupecheck_get(dp); // increment refcount
+
+	// if(debug)printf("DUPECHECK db alloc() returning dp=%p\n",dp);
+	return dp;
+}
+
+static void dupecheck_db_free(dupe_record_t *dp)
+{
+	if (dp->pbuf != NULL) { // If a pbuf is referred, release it
+		pbuf_put(dp->pbuf); // decrements refcount - and frees at zero.
+		dp->pbuf = NULL;
+	}
+#ifndef _FOR_VALGRIND_
+	if (dp->packet != dp->packetbuf)
+		free(dp->packet);
+	cellfree(dupecheck_cells, dp);
+#else
+	free(dp);
+#endif
+	--dupecheck_cellgauge;
+}
+
+// Increment refcount
+dupe_record_t *dupecheck_get(dupe_record_t *dp)
+{
+	dp->refcount += 1;
+	return dp;
+}
+
+// Decrement refcount, when zero, call free
+void dupecheck_put(dupe_record_t *dp)
+{
+	dp->refcount -= 1;
+	if (dp->refcount <= 0) {
+		dupecheck_db_free(dp);
+	}
+}
+
+/*	The  dupecheck_cleanup() is for regular database cleanups,
+ *	Call this about once a minute.
+ *
+ *	Note: entry validity is possibly shorter time than the cleanup
+ *	invocation interval!
+ */
+static void dupecheck_cleanup(void)
+{
+	dupe_record_t *dp, **dpp;
+	int cleancount = 0, i, d;
+
+	// All dupecheckers..
+	for (d = 0; d < dupecheckers_count; ++d) {
+
+	  // Within this dupechecker...
+	  struct dupecheck_t *dpc = dupecheckers[d];
+	  for (i = 0; i < DUPECHECK_DB_SIZE; ++i) {
+	    dpp = & (dpc->dupecheck_db[i]);
+	    while (( dp = *dpp )) {
+	      if ((dp->t_exp - tick.tv_sec) < 0) {
+		/* Old..  discard. */
+		*dpp = dp->next;
+		dp->next = NULL;
+		dupecheck_put(dp);
+		++cleancount;
+		continue;
+	      }
+	      /* No expiry, just advance the pointer */
+	      dpp = &dp->next;
+	    }
+	  }
+	}
+	// hlog( LOG_DEBUG, "dupecheck_cleanup() removed %d entries, count now %ld",
+	//       cleancount, dupecheck_cellgauge );
+}
+
+/*
+ *	Check a single packet for duplicates in APRS sense
+ *	The addr/alen must be in TNC2 monitor format, data/dlen
+ *      are expected to be APRS payload as well.
+ */
+
+dupe_record_t *dupecheck_aprs(dupecheck_t *dpc,
+			      const char *addr, const int alen,
+			      const char *data, const int dlen)
+{
+	/* check a single packet */
+	// pb->flags |= F_DUPE; /* this is a duplicate! */
+
+	int i;
+	int addrlen;  // length of the address part
+	int datalen;  // length of the payload
+	uint32_t hash, idx;
+	dupe_record_t **dpp, *dp;
+
+	// 1) collect canonic rep of the address (SRC,DEST, no VIAs)
+	i = 1;
+	for (addrlen = 0; addrlen < alen; ++ addrlen) {
+		const char c = addr[addrlen];
+		if (c == 0 || c == ',' || c == ':') {
+			break;
+		}
+		if (c == '-' && i) {
+			i = 0;
+		}
+	}
+
+        // code to prevent segmentation fault
+        if (addrlen > 18) {
+          if (debug>1) printf("  addrlen=\"%d\" > 18, discard packet\n",addrlen);
+          return NULL;
+        }
+
+	// Canonic tail has no SPACEs in data portion!
+	// TODO: how to treat 0 bytes ???
+	datalen = dlen;
+	while (datalen > 0 && data[datalen-1] == ' ')
+		--datalen;
+
+	// there are no 3rd-party frames in APRS-IS ...
+
+	// 2) calculate checksum (from disjoint memory areas)
+
+	hash = keyhash(addr, addrlen, 0);
+	hash = keyhash(data, datalen, hash);
+	idx  = hash;
+
+	// 3) lookup if same checksum is in some hash bucket chain
+	//  3b) compare packet...
+	//    3b1) flag as F_DUPE if so
+	// DUPECHECK_DB_SIZE == 16 -> 4 bits index
+	idx ^= (idx >> 16); /* fold the hash bits.. */
+	idx ^= (idx >>  8); /* fold the hash bits.. */
+	idx ^= (idx >>  4); /* fold the hash bits.. */
+	i = idx % DUPECHECK_DB_SIZE;
+	dpp = &(dpc->dupecheck_db[i]);
+	while (*dpp) {
+		dp = *dpp;
+		if ((dp->t_exp - tick.tv_sec) < 0) {
+			// Old ones are discarded when seen
+			*dpp = dp->next;
+			dp->next = NULL;
+			dupecheck_put(dp);
+			continue;
+		}
+		if (dp->hash == hash) {
+			// HASH match!  And not too old!
+			if (dp->alen == addrlen &&
+			    dp->plen == datalen &&
+			    memcmp(addr, dp->addresses, addrlen) == 0 &&
+			    memcmp(data, dp->packet,    datalen) == 0) {
+				// PACKET MATCH!
+				dp->seen += 1;
+				return dp;
+			}
+			// no packet match.. check next
+		}
+		dpp = &dp->next;
+	}
+	// dpp points to pointer at the tail of the chain
+
+	// 4) Add comparison copy of non-dupe into dupe-db
+
+	dp = dupecheck_db_alloc(addrlen, datalen);
+	if (dp == NULL) return NULL; // alloc error!
+	*dpp = dp; // Put it on tail of existing chain
+
+
+	memcpy(dp->addresses, addr, addrlen);
+	memcpy(dp->packet,    data, datalen);
+
+	dp->seen  = 1;  // First observation gets number 1
+	dp->hash  = hash;
+	dp->t     = tick.tv_sec;
+	dp->t_exp = tick.tv_sec + dpc->storetime;
+	return NULL;
+}
+
+
+/*
+ *  dupecheck_pbuf() returns pointer to dupe record, if pbuf is
+ *  a duplicate.  Otherwise it return a NULL.
+ */
+dupe_record_t *dupecheck_pbuf(dupecheck_t *dpc, struct pbuf_t *pb, const int viscous_delay)
+{
+	int i;
+	uint32_t hash, idx;
+	dupe_record_t **dpp, *dp;
+	const char *addr = pb->data;
+	int   alen = pb->dstcall_end - addr;
+
+	const char *dataend = pb->data + pb->packet_len;
+	const char *data    = pb->info_start;
+	int   dlen = dataend - data;
+
+	int addrlen = alen;
+	int datalen = dlen;
+	char *p;
+
+	/* if (debug && pb->is_aprs) {
+	  printf("dupecheck[1] addr='");
+	  fwrite(addr, alen, 1, stdout);
+	  printf("' data='");
+	  fwrite(data, dlen, 1, stdout);
+	  printf("'\n");
+	} */
+
+
+	// Canonic tail has no SPACEs in data portion!
+	// TODO: how to treat 0 bytes ???
+	
+	if (!pb->is_aprs) {
+		// data and dlen are raw AX.25 section pointers
+		data    = (const char*) pb->ax25data;
+		datalen = pb->ax25datalen;
+
+	} else {  // Do with APRS rules
+	    for (;;) {
+
+		// 1) collect canonic rep of the address
+		i = 1;
+		for (addrlen = 0; addrlen < alen; ++ addrlen) {
+			const char c = addr[addrlen];
+			if (c == 0 || c == ',' || c == ':') {
+				break;
+			}
+			if (c == '-' && i) {
+				i = 0;
+			}
+		}
+		while (datalen > 0 && data[datalen-1] == ' ')
+			--datalen;
+
+		if (data[0] == '}') {
+			// 3rd party frame!
+			addr = data+1;
+			p = memchr(addr,':',datalen-1);
+			if (p == NULL)
+				break; // Invalid 3rd party frame, no ":" in it
+			alen = p - addr;
+			data = p+1;
+			datalen = dataend - data;
+
+			/* if (debug && pb->is_aprs) {
+			  printf("dupecheck[2] 3rd-party: addr='");
+			  fwrite(addr, alen, 1, stdout);
+			  printf("' data='");
+			  fwrite(data, datalen, 1, stdout);
+			  printf("'\n");
+			} */
+
+			continue;  // repeat the processing!
+		}
+		break; // No repeat necessary in general case
+	    }
+	}
+
+	// 2) calculate checksum (from disjoint memory areas)
+
+	/* if (debug && pb->is_aprs) {
+	  printf("dupecheck[3] addr='");
+	  fwrite(addr, addrlen, 1, stdout);
+	  printf("' data='");
+	  fwrite(data, datalen, 1, stdout);
+	  printf("'\n");
+	} */
+
+	hash = keyhash(addr, addrlen, 0);
+	hash = keyhash(data, datalen, hash);
+	idx  = hash;
+
+	/* if (debug>1) {
+	     printf("DUPECHECK: Addr='");
+	     fwrite(addr, 1, addrlen, stdout);
+	     printf("' Data='");
+	     fwrite(data, 1, datalen, stdout);
+	     printf("'  hash=%x\n", hash);
+	   }
+	*/
+
+	// 3) lookup if same checksum is in some hash bucket chain
+	//  3b) compare packet...
+	//    3b1) flag as F_DUPE if so
+	// DUPECHECK_DB_SIZE == 16 -> 4 bits index
+	idx ^= (idx >> 16); /* fold the hash bits.. */
+	idx ^= (idx >>  8); /* fold the hash bits.. */
+	idx ^= (idx >>  4); /* fold the hash bits.. */
+	i = idx % DUPECHECK_DB_SIZE;
+	dpp = &(dpc->dupecheck_db[i]);
+	while (*dpp) {
+		dp = *dpp;
+		if ((dp->t_exp - tick.tv_sec) < 0) {
+			// Old ones are discarded when seen
+			*dpp = dp->next;
+			dp->next = NULL;
+			dupecheck_put(dp);
+			continue;
+		}
+		if (dp->hash == hash) {
+			// HASH match!  And not too old!
+			if (dp->alen == addrlen &&
+			    dp->plen == datalen &&
+			    memcmp(addr, dp->addresses, addrlen) == 0 &&
+			    memcmp(data, dp->packet,    datalen) == 0) {
+				// PACKET MATCH!
+				if (viscous_delay > 0)
+				  dp->delayed_seen += 1;
+				else
+				  dp->seen += 1;
+				return dp;
+			}
+			// no packet match.. check next
+		}
+		dpp = &dp->next;
+	}
+	// dpp points to pointer at the tail of the chain
+
+	// 4) Add comparison copy of non-dupe into dupe-db
+
+	dp = dupecheck_db_alloc(addrlen, datalen);
+	if (dp == NULL) {
+	  if (debug) printf("DUPECHECK ALLOC ERROR!\n");
+	  return NULL; // alloc error!
+	}
+	*dpp = dp; // Put it on tail of existing chain
+
+	memcpy(dp->addresses, addr, addrlen);
+	memcpy(dp->packet,    data, datalen);
+
+	dp->pbuf  = pbuf_get(pb); // increments refcount
+	if (viscous_delay > 0) {  // First observation gets number 1
+	  dp->seen         = 0;
+	  dp->delayed_seen = 1;
+	  dp->pbuf         = pb;
+	} else {
+	  dp->seen         = 1;
+	  dp->delayed_seen = 0;
+	}
+
+	dp->hash  = hash;
+	dp->t     = tick.tv_sec;
+	dp->t_exp = tick.tv_sec + dpc->storetime;
+
+	return dp;
+}
+
+/*
+ * dupechecker aprx poll integration, timed tasks control
+ *
+ */
+
+static struct timeval dupecheck_cleanup_nexttime;
+
+static void dupecheck_resettime(void *arg)
+{
+	struct timeval *tv = (struct timeval *)arg;
+        *tv = tick;
+}
+
+int dupecheck_prepoll(struct aprxpolls *app)
+{
+	if (time_reset) {
+        	dupecheck_resettime(&dupecheck_cleanup_nexttime);
+        }
+
+	if (dupecheck_cleanup_nexttime.tv_sec == 0) dupecheck_cleanup_nexttime = tick;
+
+	if (tv_timercmp(&dupecheck_cleanup_nexttime, &app->next_timeout) > 0)
+		app->next_timeout = dupecheck_cleanup_nexttime;
+
+	return 0;		/* No poll descriptors, only time.. */
+}
+
+
+int dupecheck_postpoll(struct aprxpolls *app)
+{
+        if (tv_timercmp(&dupecheck_cleanup_nexttime, &tick) > 0)
+		return 0;	/* Too early.. */
+
+        tv_timeradd_seconds( &dupecheck_cleanup_nexttime, &tick, 30 ); // tick every 30 second or so
+
+	dupecheck_cleanup();
+
+	return 0;
+}
diff --git a/erlang.c b/erlang.c
new file mode 100644
index 0000000..11f07bc
--- /dev/null
+++ b/erlang.c
@@ -0,0 +1,703 @@
+/* **************************************************************** *
+ *                                                                  *
+ *  APRX -- 2nd generation receive-only APRS-i-gate with            *
+ *          minimal requirement of esoteric facilities or           *
+ *          libraries of any kind beyond UNIX system libc.          *
+ *                                                                  *
+ * (c) Matti Aarnio - OH2MQK,  2007-2014                            *
+ *                                                                  *
+ * **************************************************************** */
+
+
+#include "aprx.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+
+
+/* The erlang module accounts data reception per 1m/10m/60m
+   intervals, and reports them on verbout.. */
+
+
+/* #define USE_ONE_MINUTE_INTERVAL 1 */
+
+
+static struct timeval erlang_time_end_1min;
+static float erlang_time_ival_1min = 1.0;
+
+static struct timeval erlang_time_end_10min;
+static float erlang_time_ival_10min = 1.0;
+
+#ifdef ERLANGSTORAGE
+static struct timeval erlang_time_end_60min;
+static float erlang_time_ival_60min = 1.0;
+#endif
+
+#ifdef ERLANGSTORAGE
+static const char *erlangtitle = "APRX SNMP + Erlang dataset\n";
+#endif
+
+int erlangsyslog;		/* if set, will log via syslog(3)  */
+int erlanglog1min;		/* if set, will log also "ERLANG1" interval  */
+
+const char *erlanglogfile;
+const char *erlang_backingstore = VARRUN "/aprx.state";
+
+#ifdef ERLANGSTORAGE
+static int erlang_file_fd = -1;
+static int erlang_mmap_size;
+#endif
+
+static void *erlang_mmap;
+
+struct erlanghead *ErlangHead;
+struct erlangline **ErlangLines;
+int ErlangLinesCount;
+int erlang_data_is_nonshared;	/* In embedded target.. */
+
+struct erlang_file {
+	struct erlanghead head;
+	struct erlangline lines[1];
+};
+
+static void erlang_backingstore_startops(void)
+{
+	ErlangHead->server_pid = getpid();
+	ErlangHead->start_time = time(NULL);
+
+	if (!mycall)
+		strncpy(ErlangHead->mycall, "N0CALL",
+			sizeof(ErlangHead->mycall));
+	else
+		strncpy(ErlangHead->mycall, mycall,
+			sizeof(ErlangHead->mycall));
+	ErlangHead->mycall[sizeof(ErlangHead->mycall) - 1] = 0;	/* NUL terminate */
+}
+
+static int erlang_backingstore_grow(int do_create, int add_count)
+{
+	struct erlang_file *EF;
+	int i;
+#ifdef ERLANGSTORAGE
+	struct stat st;
+	char buf[256];
+	int new_size, pagesize = sysconf(_SC_PAGE_SIZE);
+	int doing_init = 0;
+
+	if (erlang_data_is_nonshared)
+		goto embedded_only;
+
+	if (erlang_file_fd < 0) {
+		goto embedded_only;
+	}
+
+	fstat(erlang_file_fd, &st);
+	lseek(erlang_file_fd, 0, SEEK_END);
+
+	new_size = st.st_size;
+
+	if (new_size % pagesize) {
+		new_size /= pagesize;
+		++new_size;
+		new_size *= pagesize;
+	}
+	if (new_size == 0) {
+		new_size = pagesize;
+		doing_init = 1;
+	}
+	/* new_size expanded to be exact page size multiple.  */
+
+	/* If the new size is larger than the file size..
+	   .. and at least one page size (e.g. 4 kB) .. */
+
+	if (new_size > st.st_size) {
+		/* .. then we fill in the file to given size.  */
+		int i, rc, l;
+		i = st.st_size;
+		memset(buf, 0, sizeof(buf));
+		lseek(erlang_file_fd, 0, SEEK_END);
+		while (i < new_size) {
+			l = sizeof(buf);
+			if (new_size - i < l)
+				l = new_size - i;
+			rc = write(erlang_file_fd, buf, l);
+			if (rc < 0 && errno == EINTR)
+				continue;
+			if (rc != l)
+				break;
+			i += rc;
+		}
+	}
+
+      redo_open:;
+
+	if (erlang_mmap) {
+		msync(erlang_mmap, erlang_mmap_size, MS_SYNC);
+		munmap(erlang_mmap, erlang_mmap_size);
+		erlang_mmap = NULL;
+		erlang_mmap_size = 0;
+		ErlangHead = NULL;
+	}
+
+	/* Some (early Linux) systems mmap() offset on IO pointer... */
+	lseek(erlang_file_fd, 0, SEEK_SET);
+	fstat(erlang_file_fd, &st);
+
+	erlang_mmap_size = st.st_size;
+	erlang_mmap =
+		mmap(NULL, erlang_mmap_size,
+		     PROT_READ | (do_create ? PROT_WRITE : 0), MAP_SHARED,
+		     erlang_file_fd, 0);
+	if (erlang_mmap == MAP_FAILED) {
+		erlang_mmap = NULL;
+		syslog(LOG_ERR,
+		       "Erlang-file mmap() failed, fd=%d, errno=%d: %s",
+		       erlang_file_fd, errno, strerror(errno));
+	}
+	if (erlang_mmap) {
+
+		int rc, l;
+		EF = erlang_mmap;
+
+		ErlangHead = &EF->head;
+
+		if (EF->head.version != ERLANGLINE_STRUCT_VERSION ||
+		    EF->head.last_update == 0) {
+			if (doing_init) {
+				/* Not initialized ? */
+				memset(erlang_mmap, 0, erlang_mmap_size);
+
+				strcpy(EF->head.title, erlangtitle);
+				EF->head.version =
+					ERLANGLINE_STRUCT_VERSION;
+				EF->head.linecount = 0;
+				EF->head.last_update = tick.tv_sec;
+				ErlangLinesCount = 0;
+			} else {
+				/* Wrong head magic, and not doing block init..  */
+				munmap(erlang_mmap, erlang_mmap_size);
+				erlang_mmap = NULL;
+				erlang_mmap_size = 0;
+				syslog(LOG_ERR,
+				       "Erlang-file has bad magic in it, not opening! Not modifying!");
+				close(erlang_file_fd);
+				erlang_file_fd = -1;
+
+				goto embedded_only;	/* BAD BAD ! */
+			}
+		}
+
+		if (EF->head.linecount != ErlangLinesCount
+		    || add_count > 0) {
+			/* must resize.. */
+			int new_count = EF->head.linecount + add_count;
+			new_size =
+				sizeof(struct erlang_file) +
+				sizeof(struct erlangline) * (new_count -
+							     1);
+
+			if (new_size % pagesize) {
+				new_size /= pagesize;
+				++new_size;
+				new_size *= pagesize;
+			}
+
+			i = st.st_size;
+			memset(buf, 0, sizeof(buf));
+			lseek(erlang_file_fd, 0, SEEK_END);	/* append on the file.. */
+			while (i < new_size) {
+				l = sizeof(buf);
+				if (new_size - i < l)
+					l = new_size - i;
+				rc = write(erlang_file_fd, buf, l);
+				if (rc < 0 && errno == EINTR)
+					continue;
+				if (rc != l)
+					break;
+				i += rc;
+			}
+
+			if (i < new_size) {
+				munmap(erlang_mmap, erlang_mmap_size);
+				erlang_mmap = NULL;
+
+				goto embedded_only;	/* BAD BAD ! */
+			}
+
+			add_count = 0;
+			if (do_create)
+				EF->head.linecount = new_count;
+			ErlangLinesCount = new_count;
+
+			goto redo_open;	/* redo mapping */
+		}
+
+		/* Ok, successfull open, correct linecount */
+		ErlangLines =
+			(void *) realloc((void *) ErlangLines,
+					 (ErlangLinesCount +
+					  1) * sizeof(void *));
+
+		for (i = 0; i < ErlangLinesCount; ++i) {
+			ErlangLines[i] = &EF->lines[i];
+		}
+
+
+
+		return 0;	/* OK ! */
+	}
+
+      embedded_only:;
+#endif				/* ... ERLANGSTORAGE ... */
+
+	erlang_data_is_nonshared = 1;
+
+	if (add_count > 0 || !erlang_mmap) {
+		ErlangLinesCount += add_count;
+		erlang_mmap = realloc(erlang_mmap, sizeof(*EF) +
+				      (ErlangLinesCount +
+				       1) * sizeof(struct erlangline));
+	}
+
+	EF = erlang_mmap;
+	ErlangHead = &EF->head;
+
+	/* Ok, successfull open, correct linecount */
+	ErlangLines =
+		(void *) realloc((void *) ErlangLines,
+				 (ErlangLinesCount + 1) * sizeof(void *));
+
+	for (i = 0; i < ErlangLinesCount; ++i) {
+		ErlangLines[i] = &EF->lines[i];
+	}
+
+	return 0;
+}
+
+static int erlang_backingstore_open(int do_create)
+{
+#ifdef ERLANGSTORAGE
+	if (!erlang_backingstore) {
+		syslog(LOG_ERR, "erlang_backingstore not defined!");
+		erlang_data_is_nonshared = 1;
+	}
+	if (erlang_file_fd < 0 && erlang_backingstore) {
+		erlang_file_fd = open(erlang_backingstore, do_create ? O_RDWR : O_RDONLY, 0644);	/* Presume: it exists! */
+		if ((erlang_file_fd < 0) && do_create && (errno == ENOENT)) {
+			erlang_file_fd =
+				open(erlang_backingstore,
+				     O_RDWR | O_CREAT | O_EXCL, 0644);
+		}
+	}
+	if (erlang_file_fd < 0) {
+		syslog(LOG_ERR,
+		       "Open of '%s' for erlang_backingstore file failed!  errno=%d: %s",
+		       erlang_backingstore, errno, strerror(errno));
+		erlang_data_is_nonshared = 1;
+	}
+#endif
+	return erlang_backingstore_grow(do_create, 0);	/* Just open */
+}
+
+
+static struct erlangline *erlang_findline(const char *portname,
+					  int bytes_per_minute)
+{
+	int i;
+	struct erlangline *E;
+	if (portname == NULL) return NULL;
+
+	if (bytes_per_minute == 0)
+	  bytes_per_minute = (int) ((1200.0 * 60) / 8.2); // Default of 1200 bps
+
+	/* Allocate a new ErlangLines[] entry for this object,
+	   if no existing one is found.. */
+
+	E = NULL;
+	if (ErlangLines) {
+		for (i = 0; i < ErlangLinesCount; ++i) {
+			if (strcmp(portname, ErlangLines[i]->name) == 0) {
+				/* HOO-RAY!  It is this one! */
+				E = ErlangLines[i];
+				break;
+			}
+		}
+	}
+	/* If found -- err... why we are SETing it AGAIN ? */
+
+
+	if (!E) {
+
+		/* Allocate a new one */
+		erlang_backingstore_grow(1, 1);
+		if (!ErlangLines)
+			return NULL;	/* D'uh! */
+
+		E = ErlangLines[ErlangLinesCount - 1];	/* Last one is the lattest.. */
+
+		memset(E, 0, sizeof(*E));
+		strncpy(E->name, portname, sizeof(E->name) - 1);
+		E->name[sizeof(E->name) - 1] = 0;
+
+		E->erlang_capa = bytes_per_minute;
+		E->index = ErlangLinesCount - 1;
+
+#ifdef ERLANGSTORAGE
+		E->e1_cursor = 0;
+		E->e1_max  = APRXERL_1M_COUNT;
+		E->e10_cursor = 0;
+		E->e10_max = APRXERL_10M_COUNT;
+		E->e60_cursor = 0;
+		E->e60_max = APRXERL_60M_COUNT;
+#else
+#if (USE_ONE_MINUTE_DATA == 1)
+		E->e1_cursor = 0;
+		E->e1_max  = APRXERL_1M_COUNT;
+#else
+		E->e10_cursor = 0;
+		E->e10_max = APRXERL_10M_COUNT;
+#endif
+#endif
+	}
+	return E;
+}
+
+
+static void erlang_timer_init(void *dummy)
+{
+
+	/* Time intervals will end at next even
+	   1 minute/10 minutes/60 minutes,
+	   although said interval will be shorter than full. */
+
+	erlang_time_end_1min.tv_sec = tick.tv_sec + 60 - (tick.tv_sec % 60);
+        erlang_time_end_1min.tv_usec = 0;
+	erlang_time_ival_1min = (float) (60 - tick.tv_sec % 60) / 60.0;
+
+	erlang_time_end_10min.tv_sec = tick.tv_sec + 600 - (tick.tv_sec % 600);
+	erlang_time_end_10min.tv_usec = 0;
+	erlang_time_ival_10min = (float) (600 - tick.tv_sec % 600) / 600.0;
+
+#ifdef ERLANGSTORAGE
+	erlang_time_end_60min.tv_sec = tick.tv_sec + 3600 - (tick.tv_sec % 3600);
+	erlang_time_end_60min.tv_usec = 0;
+	erlang_time_ival_60min = (float) (3600 - tick.tv_sec % 3600) / 3600.0;
+#endif
+}
+
+
+/*
+ *  erlang_set()
+ */
+void erlang_set(const char *portname, int bytes_per_minute)
+{
+	erlang_findline(portname, bytes_per_minute);
+}
+
+/*
+ *  erlang_add()
+ */
+void erlang_add(const char *portname, ErlangMode erl, int bytes, int packets)
+{
+	struct erlangline *E;
+	if (!portname) return;
+
+	E = erlang_findline(portname, (int) ((1200.0 * 60) / 8.2));
+
+	if (debug > 1)
+	  printf("erlang_add(%s, %s, %d, %d)\n", portname,
+		 (erl == ERLANG_RX ? "RX":(erl == ERLANG_TX ? "TX": "DROP")),
+		 bytes, packets);
+
+	if (!E)
+		return;
+
+	if (erl == ERLANG_RX) {
+		E->SNMP.bytes_rx += bytes;
+		E->SNMP.packets_rx += packets;
+		E->SNMP.update = tick.tv_sec;
+		E->last_update = tick.tv_sec;
+
+#ifdef ERLANGSTORAGE
+		E->erl1m.bytes_rx += bytes;
+		E->erl1m.packets_rx += packets;
+		E->erl1m.update = tick.tv_sec;
+
+		E->erl10m.bytes_rx += bytes;
+		E->erl10m.packets_rx += packets;
+		E->erl10m.update = tick.tv_sec;
+
+		E->erl60m.bytes_rx += bytes;
+		E->erl60m.packets_rx += packets;
+		E->erl60m.update = tick.tv_sec;
+#else
+#if (USE_ONE_MINUTE_STORAGE == 1)
+		E->erl1m.bytes_rx += bytes;
+		E->erl1m.packets_rx += packets;
+		E->erl1m.update = tick.tv_sec;
+#else
+		E->erl10m.bytes_rx += bytes;
+		E->erl10m.packets_rx += packets;
+		E->erl10m.update = tick.tv_sec;
+#endif
+#endif
+	}
+	if (erl == ERLANG_TX) {
+		E->SNMP.bytes_tx += bytes;
+		E->SNMP.packets_tx += packets;
+		E->SNMP.update = tick.tv_sec;
+		E->last_update = tick.tv_sec;
+
+#ifdef ERLANGSTORAGE
+		E->erl1m.bytes_tx += bytes;
+		E->erl1m.packets_tx += packets;
+		E->erl1m.update = tick.tv_sec;
+
+		E->erl10m.bytes_tx += bytes;
+		E->erl10m.packets_tx += packets;
+		E->erl10m.update = tick.tv_sec;
+
+		E->erl60m.bytes_tx += bytes;
+		E->erl60m.packets_tx += packets;
+		E->erl60m.update = tick.tv_sec;
+#else
+#if (USE_ONE_MINUTE_STORAGE == 1)
+		E->erl1m.bytes_tx += bytes;
+		E->erl1m.packets_tx += packets;
+		E->erl1m.update = tick.tv_sec;
+#else
+		E->erl10m.bytes_tx += bytes;
+		E->erl10m.packets_tx += packets;
+		E->erl10m.update = tick.tv_sec;
+#endif
+#endif
+	}
+	if (erl == ERLANG_DROP) {
+		E->SNMP.bytes_rxdrop += bytes;
+		E->SNMP.packets_rxdrop += packets;
+		E->SNMP.update = tick.tv_sec;
+		E->last_update = tick.tv_sec;
+
+#ifdef ERLANGSTORAGE
+		E->erl1m.bytes_rxdrop += bytes;
+		E->erl1m.packets_rxdrop += packets;
+		E->erl1m.update = tick.tv_sec;
+
+		E->erl10m.bytes_rxdrop += bytes;
+		E->erl10m.packets_rxdrop += packets;
+		E->erl10m.update = tick.tv_sec;
+
+		E->erl60m.bytes_rxdrop += bytes;
+		E->erl60m.packets_rxdrop += packets;
+		E->erl60m.update = tick.tv_sec;
+#else
+#if (USE_ONE_MINUTE_STORAGE == 1)
+		E->erl1m.bytes_rxdrop += bytes;
+		E->erl1m.packets_rxdrop += packets;
+		E->erl1m.update = tick.tv_sec;
+#else
+		E->erl10m.bytes_rxdrop += bytes;
+		E->erl10m.packets_rxdrop += packets;
+		E->erl10m.update = tick.tv_sec;
+#endif
+#endif
+	}
+}
+
+
+/*
+ *  erlang_time_end() - process erlang measurement interval time end event
+ */
+static void erlang_time_end(void)
+{
+	int i;
+	char msgbuf[500];
+	char logtime[40];
+	FILE *fp = NULL;
+
+	if (erlanglogfile) {
+		/* actually we want it to the erlanglogfile... */
+		fp = fopen(erlanglogfile, "a");
+	}
+
+	printtime(logtime, sizeof(logtime));
+
+	if (tv_timercmp(&tick, &erlang_time_end_1min) >= 0) {
+		erlang_time_end_1min.tv_sec += 60;
+#if (defined(ERLANGSTORAGE) || (USE_ONE_MINUTE_STORAGE == 1))
+		for (i = 0; i < ErlangLinesCount; ++i) {
+			struct erlangline *E = ErlangLines[i];
+			E->last_update = tick.tv_sec;
+
+			if (erlanglog1min) {
+				sprintf(msgbuf,
+					"ERLANG%-2d %s Rx %6ld %3ld Dp %6ld %3ld Tx %6ld %3ld : %5.3f %5.3f %5.3f",
+					1, E->name, 
+					E->erl1m.bytes_rx,
+					E->erl1m.packets_rx,
+					E->erl1m.bytes_rxdrop,
+					E->erl1m.packets_rxdrop,
+					E->erl1m.bytes_tx, E->erl1m.packets_tx,
+					((float) E->erl1m.bytes_rx /
+					 (float) E->erlang_capa *
+					 erlang_time_ival_1min),
+					((float) E->erl1m.bytes_rxdrop /
+					 (float) E->erlang_capa *
+					 erlang_time_ival_1min),
+					((float)E->erl1m.bytes_tx /
+					 (float)E->erlang_capa *
+					 erlang_time_ival_1min)
+					);
+				if (fp)
+					fprintf(fp, "%s %s\n", logtime,
+						msgbuf);
+				else if (erlangout)
+					printf("%ld\t%s\n", tick.tv_sec, msgbuf);
+				if (erlangsyslog)
+					syslog(LOG_INFO, "%ld %s", tick.tv_sec,
+					       msgbuf);
+			}
+
+			E->erl1m.update = tick.tv_sec;
+			E->e1[E->e1_cursor] = E->erl1m;
+			++E->e1_cursor;
+			if (E->e1_cursor >= E->e1_max)
+				E->e1_cursor = 0;
+
+			memset(&E->erl1m, 0, sizeof(E->erl1m));
+			E->erl1m.update = tick.tv_sec;
+		}
+		erlang_time_ival_1min = 1.0;
+#endif
+	}
+	if (tv_timercmp(&tick, &erlang_time_end_10min) >= 0) {
+		erlang_time_end_10min.tv_sec += 600;
+#if (defined(ERLANGSTORAGE) || (USE_ONE_MINUTE_STORAGE == 0))
+		for (i = 0; i < ErlangLinesCount; ++i) {
+			struct erlangline *E = ErlangLines[i];
+			E->last_update = tick.tv_sec;
+			sprintf(msgbuf,
+				"ERLANG%-2d %s Rx %6ld %3ld Dp %6ld %3ld Tx %6ld %3ld : %5.3f %5.3f %5.3f",
+				10, E->name, 
+				E->erl10m.bytes_rx, E->erl10m.packets_rx,
+				E->erl10m.bytes_rxdrop,
+				E->erl10m.packets_rxdrop,
+				E->erl10m.bytes_tx, E->erl10m.packets_tx,
+				((float) E->erl10m.bytes_rx /
+				 ((float) E->erlang_capa * 10.0 *
+				  erlang_time_ival_10min)),
+				((float) E->erl10m.bytes_rxdrop /
+				 ((float) E->erlang_capa * 10.0 *
+				  erlang_time_ival_10min)),
+				((float)E->erl10m.bytes_tx /
+				 ((float)E->erlang_capa * 10.0 *
+				  erlang_time_ival_10min))
+				);
+			if (fp)
+				fprintf(fp, "%s %s\n", logtime, msgbuf);
+			else if (erlangout)
+				printf("%ld\t%s\n", tick.tv_sec, msgbuf);
+			if (erlangsyslog)
+				syslog(LOG_INFO, "%ld %s", tick.tv_sec, msgbuf);
+
+			E->erl10m.update = tick.tv_sec;
+			E->e10[E->e10_cursor] = E->erl10m;
+			++E->e10_cursor;
+			if (E->e10_cursor >= E->e10_max)
+				E->e10_cursor = 0;
+			memset(&E->erl10m, 0, sizeof(E->erl10m));
+			E->erl10m.update = tick.tv_sec;
+		}
+		erlang_time_ival_10min = 1.0;
+#endif
+	}
+#ifdef ERLANGSTORAGE
+	if (tv_timercmp(&tick, &erlang_time_end_60min) >= 0) {
+		erlang_time_end_60min.tv_sec += 3600;
+		for (i = 0; i < ErlangLinesCount; ++i) {
+			struct erlangline *E = ErlangLines[i];
+			/* E->last_update = now.tv_sec; -- the 10 minute step does also this */
+			sprintf(msgbuf,
+				"ERLANG%-2d %s Rx %6ld %3ld Dp %6ld %3ld Tx %6ld %3ld : %5.3f %5.3f %5.3f",
+				60, E->name, 
+				E->erl60m.bytes_rx, E->erl60m.packets_rx,
+				E->erl60m.bytes_rxdrop,
+				E->erl60m.packets_rxdrop,
+				E->erl60m.bytes_tx,  E->erl60m.packets_tx,
+				((float) E->erl60m.bytes_rx /
+				 ((float) E->erlang_capa * 60.0 *
+				  erlang_time_ival_60min)),
+				((float) E->erl60m.bytes_rxdrop /
+				 ((float) E->erlang_capa * 60.0 *
+				  erlang_time_ival_60min)),
+				((float)E->erl60m.bytes_tx /
+				 ((float)E->erlang_capa * 60.0 *
+				  erlang_time_ival_60min))
+				);
+			if (fp)
+				fprintf(fp, "%s %s\n", logtime, msgbuf);
+			else if (erlangout)
+				printf("%ld\t%s\n", tick.tv_sec, msgbuf);
+			if (erlangsyslog)
+				syslog(LOG_INFO, "%ld %s", tick.tv_sec, msgbuf);
+
+			E->erl60m.update = tick.tv_sec;
+			E->e60[E->e60_cursor] = E->erl60m;
+			++E->e60_cursor;
+			if (E->e60_cursor >= E->e60_max)
+				E->e60_cursor = 0;
+
+			memset(&E->erl60m, 0, sizeof(E->erl60m));
+			E->erl60m.update = tick.tv_sec;
+		}
+		erlang_time_ival_60min = 1.0;
+	}
+#endif
+	if (fp)
+		fclose(fp);
+}
+
+int erlang_prepoll(struct aprxpolls *app)
+{
+        if (time_reset) {
+        	if (debug) printf("erlang_timer_init() to be called\n");
+        	erlang_timer_init(NULL);
+        }
+
+	if (tv_timercmp(&app->next_timeout, &erlang_time_end_1min) > 0)
+		app->next_timeout = erlang_time_end_1min;
+	if (tv_timercmp(&app->next_timeout, &erlang_time_end_10min) > 0)
+		app->next_timeout = erlang_time_end_10min;
+#ifdef ERLANGSTORAGE
+	if (tv_timercmp(&app->next_timeout, &erlang_time_end_60min) > 0)
+		app->next_timeout = erlang_time_end_60min;
+#endif
+	return 0;
+}
+
+int erlang_postpoll(struct aprxpolls *app)
+{
+	if (tv_timercmp(&tick, &erlang_time_end_1min) >= 0 ||
+	    tv_timercmp(&tick, &erlang_time_end_10min) >= 0
+#ifdef ERLANGSTORAGE
+	    || tv_timercmp(&tick, &erlang_time_end_60min) >= 0
+#endif
+	    )
+		erlang_time_end();
+
+	return 0;
+}
+
+
+void erlang_init(const char *syslog_facility_name)
+{
+        erlang_timer_init(NULL);
+}
+
+void erlang_start(int do_create)
+{
+	erlang_backingstore_open(do_create);
+	if (do_create > 1)
+		erlang_backingstore_startops();
+}
diff --git a/filter.c b/filter.c
new file mode 100644
index 0000000..df21556
--- /dev/null
+++ b/filter.c
@@ -0,0 +1,2331 @@
+/********************************************************************
+ *  APRX -- 2nd generation APRS-i-gate with                         *
+ *          minimal requirement of esoteric facilities or           *
+ *          libraries of any kind beyond UNIX system libc.          *
+ *                                                                  *
+ * (c) Matti Aarnio - OH2MQK,  2007-2014                            *
+ *                                                                  *
+ ********************************************************************/
+/*
+ *	aprsc
+ *
+ *	(c) Matti Aarnio, OH2MQK, <oh2mqk at sral.fi>
+ *
+ *	This program is licensed under the BSD license, which can be found
+ *	in the file LICENSE.
+ *	
+ */
+
+#include "aprx.h"
+
+#include "cellmalloc.h"
+#include "historydb.h"
+#include "keyhash.h"
+
+/*
+  See:  http://www.aprs-is.net/javaprssrvr/javaprsfilter.htm
+
+  a/latN/lonW/latS/lonE Area filter
+  b/call1/call2...  	Budlist filter (*)
+  d/digi1/digi2...  	Digipeater filter (*)
+  e/call1/call1/...  	Entry station filter (*)
+  f/call/dist  		Friend Range filter
+  g/call1/call2..       Group Messaging filter (*)
+  m/dist  		My Range filter
+  o/obj1/obj2...  	Object filter (*)
+  p/aa/bb/cc...  	Prefix filter
+  q/con/ana 	 	q Contruct filter
+  r/lat/lon/dist  	Range filter
+  s/pri/alt/over  	Symbol filter
+  t/poimntqsu3*c	Type filter
+  t/poimntqsu3*c/call/km Type filter
+  u/unproto1/unproto2/.. Unproto filter (*)
+
+  Sample usage frequencies (out of entire APRS-IS):
+
+   23.7  a/  <-- Optimize!
+    9.2  b/  <-- Optimize?
+    1.4  d/
+    0.2  e/
+    2.2  f/
+   20.9  m/  <-- Optimize!
+    0.2  o/
+   14.4  p/  <-- Optimize!
+    0.0  pk
+    0.0  pm
+    0.4  q/
+   19.0  r/  <-- Optimize!
+    0.1  s_
+    1.6  s/
+    6.6  t/
+    0.1  u/
+
+
+  (*) = wild-card supported
+
+  Undocumented at above web-page, but apparent behaviour is:
+
+  - Everything not explicitely stated to be case sensitive is
+    case INSENSITIVE
+
+  - Minus-prefixes on filters behave as is there are two sets of
+    filters:
+
+       - filters without minus-prefixes add on approved set, and all
+         those without are evaluated at first
+       - filters with minus-prefixes are evaluated afterwards to drop
+         selections after the additive filter has been evaluated
+
+
+  - Our current behaviour is: "evaluate everything in entry order,
+    stop at first match",  which enables filters like:
+               p/OH2R -p/OH2 p/OH
+    while javAPRSSrvr filter adjunct behaves like the request is:
+               -p/OH2  p/OH
+    that is, OH2R** stations are not passed thru.
+
+*/
+
+
+/* FIXME:  What exactly is the meaning of negation on the pattern ?
+**         Match as a failure to match, and stop searching ?
+**         Something filter dependent ?
+**
+** javAPRSSrvr Filter Adjunct  manual tells:
+
+ #14 Exclusion filter
+
+All the above filters also support exclusion. Be prefixing the above filters with a
+dash the result will be the opposite. Any packet that match the exclusion filter will
+NOT pass. The exclusion filters will be processed first so if there is a match for an
+exclusion then the packet is not passed no matter any other filter definitions.
+
+*/
+
+#define WildCard      0x80  /* it is wild-carded prefix string  */
+#define NegationFlag  0x40  /*                                  */
+#define LengthMask    0x0F  /* only low 4 bits encode length    */
+
+/* values above are chosen for 4 byte alignment.. */
+
+struct filter_refcallsign_t {
+	char	callsign[CALLSIGNLEN_MAX+1]; /* size: 10.. */
+	int8_t	reflen; /* length and flags */
+};
+struct filter_head_t {
+	struct filter_t *next;
+	const char *text; /* filter text as is		*/
+	float   f_latN, f_lonE;
+	union {
+	  float   f_latS;   /* for A filter */
+	  float   f_coslat; /* for R filter */
+	} u1;
+	union {
+	  float   f_lonW; /* for A filter */
+	  float   f_dist; /* for R filter */
+	} u2;
+	time_t  hist_age;
+
+	char	type;	  /* 1 char			*/
+	int16_t	negation; /* boolean flag		*/
+	union {
+	  int16_t numnames; /* used as named, and as cache validity flag */
+	  int16_t len1s;    /*  or len1 of s-filter */
+	} u3;
+	union {
+	  int16_t bitflags; /* used as bit-set on T_*** enumerations */
+	  int16_t len1;     /*  or as len2 of s-filter */
+	} u4;
+	union {
+                struct { int16_t len2s, len2, len3s, len3; } lens; /* of s-filter */
+		/* for cases where there is only one.. */
+		struct filter_refcallsign_t  refcallsign;
+		/*  malloc()ed array, alignment important! */
+		struct filter_refcallsign_t *refcallsigns;
+	} u5;
+};
+
+struct filter_t {
+	struct filter_head_t h;
+#define FILT_TEXTBUFSIZE (508-sizeof(struct filter_head_t))
+	char textbuf[FILT_TEXTBUFSIZE];
+};
+
+#define QC_C	0x001 /* Q-filter flag bits */
+#define QC_X	0x002
+#define QC_U	0x004
+#define QC_o	0x008
+#define QC_O	0x010
+#define QC_S	0x020
+#define QC_r	0x040
+#define QC_R	0x080
+#define QC_Z	0x100
+#define QC_I	0x200
+
+#define QC_AnalyticsI	0x800
+
+/*
+// For q-filter analytics: entrycall igate filter database
+struct filter_entrycall_t {
+	struct filter_entrycall_t *next;
+	time_t expirytime;
+	uint32_t hash;
+	int	len;
+	char	callsign[CALLSIGNLEN_MAX+1];
+};
+*/
+/*
+struct filter_wx_t {
+	struct filter_wx_t *next;
+	time_t expirytime;
+	uint32_t hash;
+	int	len;
+	char	callsign[CALLSIGNLEN_MAX+1];
+};
+*/
+
+typedef enum {
+	MatchExact,
+	MatchPrefix,
+	MatchWild
+} MatchEnum;
+
+/*
+#define FILTER_ENTRYCALL_HASHSIZE 2048	// Around 500-600 in db,  this looks
+					//  for collision free result..
+int filter_entrycall_maxage = 60*60;	// 1 hour, default.  Validity on
+					// lookups: 5 minutes less..
+int filter_entrycall_cellgauge;
+
+struct filter_entrycall_t *filter_entrycall_hash[FILTER_ENTRYCALL_HASHSIZE];
+*/
+
+/*
+#define FILTER_WX_HASHSIZE 1024		// Around 300-400 in db,  this looks
+					//  for collision free result..
+int filter_wx_maxage = 60*60;		// 1 hour, default.  Validity on
+					// lookups: 5 minutes less..
+int filter_wx_cellgauge;
+
+struct filter_wx_t *filter_wx_hash[FILTER_WX_HASHSIZE];
+*/
+
+#ifndef _FOR_VALGRIND_
+cellarena_t *filter_cells;
+//cellarena_t *filter_entrycall_cells;
+//cellarena_t *filter_wx_cells;
+#endif
+
+
+int hist_lookup_interval = 20; /* FIXME: Configurable: Cache historydb
+				  position lookups this much seconds on
+				  each filter entry referring to some
+				  fixed callsign (f,m,t) */
+
+float filter_lat2rad(float lat)
+{
+	return (lat * (M_PI / 180.0));
+}
+
+float filter_lon2rad(float lon)
+{
+	return (lon * (M_PI / 180.0));
+}
+
+
+const int filter_cellsize  = sizeof(struct filter_t);
+const int filter_cellalign = __alignof__(struct filter_t);
+
+void filter_init(void)
+{
+#ifndef _FOR_VALGRIND_
+	/* A _few_... */
+
+	filter_cells = cellinit( "filter",
+				 filter_cellsize,
+				 filter_cellalign,
+				 CELLMALLOC_POLICY_LIFO,
+				 4 /* 4 kB at the time,
+				      should be enough in all cases.. */,
+				 0 /* minfree */ );
+
+	/* printf("filter: sizeof=%d alignof=%d\n",
+	   sizeof(struct filter_t),__alignof__(struct filter_t)); */
+
+/*
+	// Couple thousand
+	filter_entrycall_cells = cellinit( "entrycall",
+					   sizeof(struct filter_entrycall_t),
+					   __alignof__(struct filter_entrycall_t),
+					   CELLMALLOC_POLICY_FIFO,
+					   32, // 32 kB at the time,
+					   0 // minfree
+					  );
+*/
+/*
+	// Under 1 thousand..
+	filter_wx_cells = cellinit( "wxcalls",
+				    sizeof(struct filter_wx_t),
+				    __alignof__(struct filter_wx_t),
+				    CELLMALLOC_POLICY_FIFO,
+				    32, // 32 kB at the time
+				    0 // minfree
+				   );
+*/
+#endif
+}
+
+#if 0
+static void filter_entrycall_free(struct filter_entrycall_t *f)
+{
+#ifndef _FOR_VALGRIND_
+	cellfree( filter_entrycall_cells, f );
+#else
+	free(f);
+#endif
+	-- filter_entrycall_cellgauge;
+}
+
+/*
+ *	filter_entrycall_insert() is for support of  q//i  filters.
+ *	That is, "pass on any message that has traversed thru entry 
+ *	igate which has identified itself with qAr or qAR.  Not all
+ *	messages traversed thru such gate will have those same q-cons
+ *	values, thus this database keeps info about entry igate that
+ *	have shown such capability in recent past.
+ *
+ *	This must be called by the incoming_parse() in every case
+ *	(or at least when qcons is either 'r' or 'R'.)
+ *
+ *	The key has no guaranteed alignment, no way to play tricks
+ *	with gcc builtin optimizers.
+ */
+
+int filter_entrycall_insert(struct pbuf_t *pb)
+{
+	struct filter_entrycall_t *f, **fp, *f2;
+	/* OK, pre-parsing produced accepted result */
+	uint32_t hash;
+	int idx, keylen;
+	const char qcons = pb->qconst_start[2];
+	const char *key = pb->qconst_start+4;
+        char uckey[CALLSIGNLEN_MAX+1];
+
+	for (keylen = 0; keylen < CALLSIGNLEN_MAX; ++keylen) {
+		int c = key[keylen];
+		if (c == ',' || c == ':')
+			break;
+                if ('a' <= c && c <= 'z')
+                	c -= ('a' - 'A');
+                uckey[keylen] = c;
+                uckey[keylen+1] = 0;
+	}
+	if ((key[keylen] != ',' && key[keylen] != ':') || keylen < CALLSIGNLEN_MIN)
+		return 0; /* Bad entry-station callsign */
+
+        pb->entrycall_len = keylen; // FIXME: should be in incoming parser...
+
+	/* We insert only those that have Q-Constructs of qAR or qAr */
+	if (qcons != 'r' && qcons != 'R') return 0;
+
+	hash = keyhash(uckey, keylen, 0);
+	idx = (hash ^ (hash >> 11) ^ (hash >> 22) ) % FILTER_ENTRYCALL_HASHSIZE; /* Fold the hashbits.. */
+
+
+	fp = &filter_entrycall_hash[idx];
+	f2 = NULL;
+	while (( f = *fp )) {
+		if ( f->hash == hash ) {
+			if (f->len == keylen) {
+				int cmp = strncasecmp(f->callsign, uckey, keylen);
+				if (cmp == 0) { /* Have key match */
+					f->expirytime = tick.tv_sec + filter_entrycall_maxage;
+					f2 = f;
+					break;
+				}
+			}
+		}
+		/* No match at all, advance the pointer.. */
+		fp = &(f -> next);
+	}
+	if (!f2) {
+
+		/* Allocate and insert into hash table */
+
+		fp = &filter_entrycall_hash[idx];
+
+#ifndef _FOR_VALGRIND_
+		f = cellmalloc(filter_entrycall_cells);
+#else
+		f = calloc(1, sizeof(*f));
+#endif
+		if (f) {
+			f->next  = *fp;
+			f->expirytime = tick.tv_sec + filter_entrycall_maxage;
+			f->hash  = hash;
+			f->len   = keylen;
+			memcpy(f->callsign, uckey, keylen);
+			memset(f->callsign+keylen, 0, sizeof(f->callsign)-keylen);
+
+			*fp = f2 = f;
+
+			++ filter_entrycall_cellgauge;
+		}
+	}
+
+	return (f2 != NULL);
+}
+
+/*
+ *	filter_entrycall_lookup() is for support of  q//i  filters.
+ *	That is, "pass on any message that has traversed thru entry 
+ *	igate which has identified itself with qAr or qAR.  Not all
+ *	messages traversed thru such gate will have those same q-cons
+ *	values, thus this keeps database about entry servers that have
+ *	shown such capability in recent past.
+ *
+ *	The key has no guaranteed alignment, no way to play tricks
+ *	with gcc builtin optimizers.
+ */
+
+static int filter_entrycall_lookup(const struct pbuf_t *pb)
+{
+	struct filter_entrycall_t *f, **fp, *f2;
+	const char *key  = pb->qconst_start+4;
+	const int keylen = pb->entrycall_len;
+
+	uint32_t  hash   = keyhashuc(key, keylen, 0);
+	int idx = ( hash ^ (hash >> 11) ^ (hash >> 22) ) % FILTER_ENTRYCALL_HASHSIZE;   /* fold the hashbits.. */
+
+	f2 = NULL;
+
+	fp = &filter_entrycall_hash[idx];
+	while (( f = *fp )) {
+		if ( f->hash == hash ) {
+			if (f->len == keylen) {
+				int rc =  strncasecmp(f->callsign, key, keylen);
+				if (rc == 0) { /* Have key match, see if it is
+						  still valid entry ? */
+                                	if ((f->expirytime - (tick.tv_sec - 60)) < 0) {
+						f2 = f;
+						break;
+					}
+				}
+			}
+		}
+		/* No match at all, advance the pointer.. */
+		fp = &(f -> next);
+	}
+
+	return (f2 != NULL);
+}
+
+/* 
+ *	The  filter_entrycall_cleanup()  does purge old entries
+ *	out of the database.  Run about once a minute.
+ */
+void filter_entrycall_cleanup(void)
+{
+	int k, cleancount = 0;
+	struct filter_entrycall_t *f, **fp;
+
+	for (k = 0; k < FILTER_ENTRYCALL_HASHSIZE; ++k) {
+		fp = & filter_entrycall_hash[k];
+		while (( f = *fp )) {
+			/* Did it expire ? */
+                  if ((f->expirytime - tick.tv_sec) <= 0) {
+				*fp = f->next;
+				f->next = NULL;
+				filter_entrycall_free(f);
+				++cleancount;
+				continue;
+			}
+			/* No purge, advance the pointer.. */
+			fp = &(f -> next);
+		}
+	}
+
+	// hlog( LOG_DEBUG, "filter_entrycall_cleanup() removed %d entries, count now: %ld",
+	//       cleancount, filter_entrycall_cellgauge );
+}
+
+/* 
+ *	The  filter_entrycall_atend()  does purge all entries
+ *	out of the database.  Run at the exit of the program.
+ *	This exists primarily to make valgrind happy...
+ */
+void filter_entrycall_atend(void)
+{
+	int k;
+	struct filter_entrycall_t *f, **fp;
+
+	for (k = 0; k < FILTER_ENTRYCALL_HASHSIZE; ++k) {
+		fp = & filter_entrycall_hash[k];
+		while (( f = *fp )) {
+			*fp = f->next;
+			f->next = NULL;
+			filter_entrycall_free(f);
+		}
+	}
+}
+
+
+void filter_entrycall_dump(FILE *fp)
+{
+	int k;
+	struct filter_entrycall_t *f;
+
+	for (k = 0; k < FILTER_ENTRYCALL_HASHSIZE; ++k) {
+		f = filter_entrycall_hash[k];
+
+		for ( ; f; f = f->next ) {
+			fprintf( fp, "%ld\t%s\n",
+				 (long)f->expirytime, f->callsign );
+		}
+	}
+}
+#endif
+
+/* ================================================================ */
+
+
+#if 0
+static void filter_wx_free(struct filter_wx_t *f)
+{
+#ifndef _FOR_VALGRIND_
+	cellfree( filter_wx_cells, f );
+#else
+	free(f);
+#endif
+	--filter_wx_cellgauge;
+}
+
+/*
+ *	The  filter_wx_insert()  does lookup key storage for problem of:
+ *
+ *	Positionless T_WX packets want also position packets on output filters.
+ */
+
+int filter_wx_insert(struct pbuf_t *pb)
+{
+	struct filter_wx_t *f, **fp, *f2;
+	/* OK, pre-parsing produced accepted result */
+	const char *key  = pb->data;
+	const int keylen = pb->srccall_end - key;
+	uint32_t hash;
+	int idx;
+        char uckey[CALLSIGNLEN_MAX+1];
+
+	/* If it is not a WX packet without position, we are not intrerested */
+	if (!((pb->packettype & T_WX) && !(pb->flags & F_HASPOS)))
+		return 0;
+
+	for (idx = 0; idx <= keylen && idx < CALLSIGNLEN_MAX; ++idx) {
+		int c = key[idx];
+		if (c == ',' || c == ':')
+			break;
+                if ('a' <= c && c <= 'z')
+                  c -= ('a' - 'A');
+                uckey[idx] = c;
+                uckey[idx+1] = 0;
+	}
+
+	hash = keyhash(uckey, keylen, 0);
+	idx = ( hash ^ (hash >> 10) ^ (hash >> 20) ) % FILTER_WX_HASHSIZE; /* fold the hashbits.. */
+
+	fp = &filter_wx_hash[idx];
+	f2 = NULL;
+	while (( f = *fp )) {
+		if ( f->hash == hash ) {
+			if (f->len == keylen) {
+				int cmp = memcmp(f->callsign, uckey, keylen);
+				if (cmp == 0) { /* Have key match */
+					f->expirytime = tick.tv_sec + filter_wx_maxage;
+					f2 = f;
+					break;
+				}
+			}
+		}
+		/* No match at all, advance the pointer.. */
+		fp = &(f -> next);
+	}
+	if (!f2) {
+
+		/* Allocate and insert into hash table */
+
+		fp = &filter_wx_hash[idx];
+
+#ifndef _FOR_VALGRIND_
+		f = cellmalloc(filter_wx_cells);
+#else
+		f = calloc(1, sizeof(*f));
+#endif
+		++filter_wx_cellgauge;
+		if (f) {
+			f->next  = *fp;
+			f->expirytime = tick.tv_sec + filter_wx_maxage;
+			f->hash  = hash;
+			f->len   = keylen;
+			memcpy(f->callsign, key, keylen);
+			memset(f->callsign+keylen, 0, sizeof(f->callsign)-keylen);
+
+			*fp = f2 = f;
+		}
+	}
+
+	return 0;
+}
+
+static int filter_wx_lookup(const struct pbuf_t *pb)
+{
+	struct filter_wx_t *f, **fp, *f2;
+	const char *key  = pb->data;
+	const int keylen = pb->srccall_end - key;
+
+	uint32_t  hash   = keyhashuc(key, keylen, 0);
+	int idx = ( hash ^ (hash >> 10) ^ (hash >> 20) ) % FILTER_WX_HASHSIZE; /* fold the hashbits.. */
+
+	f2 = NULL;
+
+	fp = &filter_wx_hash[idx];
+	while (( f = *fp )) {
+		if ( f->hash == hash ) {
+			if (f->len == keylen) {
+				int rc = strncasecmp(f->callsign, key, keylen);
+				if (rc == 0) { /* Have key match, see if it is
+						  still valid entry ? */
+                                  if ((f->expirytime - (tick.tv_sec - 60)) < 0) {
+						f2 = f;
+						break;
+					}
+				}
+			}
+		}
+		/* No match at all, advance the pointer.. */
+		fp = &(f -> next);
+	}
+
+	return (f2 != NULL);
+}
+
+
+/* 
+ *	The  filter_wx_cleanup()  does purge old entries
+ *	out of the database.  Run about once a minute.
+ */
+void filter_wx_cleanup(void)
+{
+	int k, cleancount = 0;
+	struct filter_wx_t *f, **fp;
+
+	for (k = 0; k < FILTER_WX_HASHSIZE; ++k) {
+		fp = & filter_wx_hash[k];
+		while (( f = *fp )) {
+			/* Did it expire ? */
+                	if ((f->expirytime - tick.tv_sec) <= 0) {
+				*fp = f->next;
+				f->next = NULL;
+				filter_wx_free(f);
+				++cleancount;
+				continue;
+			}
+			/* No purge, advance the pointer.. */
+			fp = &(f -> next);
+		}
+	}
+
+	// hlog( LOG_DEBUG, "filter_wx_cleanup() removed %d entries, count now: %ld",
+	//       cleancount, filter_wx_cellgauge );
+}
+
+/* 
+ *	The  filter_wx_atend()  does purge all entries
+ *	out of the database.  Run at the exit of the program.
+ *	This exists primarily to make valgrind happy...
+ */
+void filter_wx_atend(void)
+{
+	int k;
+	struct filter_wx_t *f, **fp;
+
+	for (k = 0; k < FILTER_WX_HASHSIZE; ++k) {
+		fp = & filter_wx_hash[k];
+		while (( f = *fp )) {
+			*fp = f->next;
+			f->next = NULL;
+			filter_wx_free(f);
+		}
+	}
+}
+
+
+void filter_wx_dump(FILE *fp)
+{
+	int k;
+	struct filter_wx_t *f;
+
+	for (k = 0; k < FILTER_WX_HASHSIZE; ++k) {
+		f = filter_wx_hash[k];
+
+		for ( ; f; f = f->next ) {
+			fprintf( fp, "%ld\t%s\n",
+				 (long)f->expirytime, f->callsign );
+		}
+	}
+}
+#endif
+
+/* ================================================================ */
+
+
+void filter_preprocess_dupefilter(struct pbuf_t *pbuf)
+{
+#if 0
+	filter_entrycall_insert(pbuf);
+	filter_wx_insert(pbuf);
+#endif
+}
+
+void filter_postprocess_dupefilter(struct pbuf_t *pbuf, historydb_t *historydb)
+{
+	/*
+	 *    If there is no position at this packet from earlier
+	 *    processing, try now to find one by the callsign of
+	 *    the packet sender.
+	 *    
+	 */
+#ifndef DISABLE_IGATE
+	if (!(pbuf->flags & F_HASPOS)) {
+		history_cell_t *hist;
+		hist = historydb_lookup(historydb, pbuf->srcname, pbuf->srcname_len);
+		// hlog( LOG_DEBUG, "postprocess_dupefilter: no pos, looking up '%.*s', rc=%d",
+		//       pbuf->srcname_len, pbuf->srcname, rc );
+		if (hist != NULL) {
+			pbuf->lat     = hist->lat;
+			pbuf->lng     = hist->lon;
+			pbuf->cos_lat = hist->coslat;
+
+			pbuf->flags  |= F_HASPOS;
+		}
+	}
+#endif
+}
+
+
+/* ================================================================ */
+
+/*
+ *	filter_match_on_callsignset()  matches prefixes, or exact keys
+ *	on filters of types:  b, d, e, o, p, u
+ *	('p' and 'b' need OPTIMIZATION - others get it for free)
+ *
+ */
+
+static int filter_match_on_callsignset(struct filter_refcallsign_t *ref, int keylen, struct filter_t *f, const MatchEnum wildok)
+{
+	int i;
+	struct filter_refcallsign_t *r  = f->h.u5.refcallsigns;
+	const char                  *r1 = (const void*)ref->callsign;
+
+	if (debug) printf(" filter_match_on_callsignset(ref='%s', keylen=%d, filter='%s')\n", ref->callsign, keylen, f->h.text);
+
+	for (i = 0; i < f->h.u3.numnames; ++i) {
+		const int reflen = r[i].reflen;
+		const int len    = reflen & LengthMask;
+		const char   *r2 = (const void*)r[i].callsign;
+
+		if (debug)printf(" .. reflen=0x%02x r2='%s'\n", reflen & 0xFF, r2);
+
+
+		switch (wildok) {
+		case MatchExact:
+			if (len != keylen)
+				continue; /* no match */
+			/* length OK, compare content */
+			if (strncasecmp( r1, r2, len ) != 0) continue;
+			/* So it was an exact match
+			** Precisely speaking..  we should check that there is
+			** no WildCard flag, or such.  But then this match
+			** method should not be used if parser finds any such.
+			*/
+			return ( reflen & NegationFlag ? 2 : 1 );
+			break;
+		case MatchPrefix:
+			if (len > keylen || !len) {
+				/* reference string length is longer than our key */
+				continue;
+			}
+			if (strncasecmp( r1, r2, len ) != 0) continue;
+
+			return ( reflen & NegationFlag ? 2 : 1 );
+			break;
+		case MatchWild:
+			if (len > keylen || !len) {
+				/* reference string length is longer than our key */
+				continue;
+			}
+
+			if (strncasecmp( r1, r2, len ) != 0) continue;
+
+			if (reflen & WildCard)
+				return ( reflen & NegationFlag ? 2 : 1 );
+
+			if (len == keylen)
+				return ( reflen & NegationFlag ? 2 : 1 );
+			break;
+		default:
+			break;
+		}
+	}
+	return 0; /* no match */
+}
+
+/*
+ *	filter_parse_one_callsignset()  collects multiple callsigns
+ *	on filters of types:  b, d, e, o, p, u
+ *
+ *	If previous filter was of same type as this one, that one's refbuf is extended.
+ */
+
+static int filter_parse_one_callsignset(struct filter_t **ffp, struct filter_t *f0, const char *filt0, MatchEnum wildok)
+{
+	char prefixbuf[CALLSIGNLEN_MAX+1];
+	char *k;
+	const char *p;
+	int i, refcount, wildcard;
+	int refmax = 0, extend = 0;
+	struct filter_refcallsign_t *refbuf;
+	struct filter_t *ff = *ffp;
+	
+	p = filt0;
+	if (*p == '-') ++p;
+        // Skip the first '/'
+	while (*p && *p != '/') ++p;
+	if (*p == '/') ++p;
+	/* count the number of prefixes in there.. */
+	while (*p) {
+		if (*p) ++refmax;
+		while (*p && *p != '/') ++p;
+		if (*p == '/') ++p;
+	}
+	if (refmax == 0) {
+          printf("Filter definition of '%s' has no prefixes defined.\n", filt0);
+          return -1; /* No prefixes ?? */
+        }
+
+	if (ff && ff->h.type == f0->h.type) { /* SAME TYPE,
+						 extend previous record! */
+		extend = 1;
+		refcount = ff->h.u3.numnames + refmax;
+		refbuf   = realloc(ff->h.u5.refcallsigns, sizeof(*refbuf) * refcount);
+		ff->h.u5.refcallsigns = refbuf;
+		refcount = ff->h.u3.numnames;
+	} else {
+		refbuf = calloc(1, sizeof(*refbuf)*refmax);
+		refcount = 0;
+		f0->h.u5.refcallsigns = refbuf;
+		f0->h.u3.numnames  = 0;
+	}
+
+	p = filt0;
+	if (*p == '-') ++p;
+        // Skip the first '/'
+	while (*p && *p != '/') ++p;
+	if (*p == '/') ++p;
+
+	/* hlog(LOG_DEBUG, "p-filter: '%s' vs. '%s'", p, keybuf); */
+	while (*p)  {
+		k = prefixbuf;
+		memset(prefixbuf, 0, sizeof(prefixbuf));
+		i = 0;
+		wildcard = 0;
+		while (*p != 0 && *p != '/') {
+                 	int c = *p++;
+			if (c == '*') {
+                          wildcard = 1;
+                          if (wildok != MatchWild) {
+                            printf("Wild-card matching not permitted, yet filter definition says: '%s'\n", filt0);
+                            return -1;
+                          }
+                          continue;
+			}
+                        if (i < CALLSIGNLEN_MAX) {
+                          *k++ = c;
+                          ++i;
+                        } else {
+                          printf("Too long callsign string: '%s' input: '%s'\n", prefixbuf, filt0);
+                          return -1; // invalid input
+                        }
+		}
+		*k = 0;
+		/* OK, we have one prefix part collected, scan source until next '/' */
+		if (*p != 0 && *p != '/') ++p;
+		if (*p == '/') ++p;
+		/* If there is more of patterns, the loop continues.. */
+
+		/* Store the refprefix */
+		memset(&refbuf[refcount], 0, sizeof(refbuf[refcount]));
+		memcpy(refbuf[refcount].callsign, prefixbuf, sizeof(refbuf[refcount].callsign));
+		refbuf[refcount].reflen = strlen(prefixbuf);
+		if (wildcard)
+			refbuf[refcount].reflen |= WildCard;
+		if (f0->h.negation)
+			refbuf[refcount].reflen |= NegationFlag;
+		++refcount;
+	}
+
+	f0->h.u3.numnames = refcount;
+	if (extend) {
+		char *s;
+		ff->h.u3.numnames = refcount;
+		i = strlen(ff->h.text) + strlen(filt0)+2;
+		if (i <= FILT_TEXTBUFSIZE) {
+			/* Fits in our built-in buffer block - like previous..
+			** Append on existing buffer
+			*/
+			s = ff->textbuf + strlen(ff->textbuf);
+			sprintf(s, " %s", filt0);
+		} else {
+			/* It does not fit anymore.. */
+			s = malloc(i); /* alloc a new one */
+			sprintf(s, "%s %s", p, filt0); /* .. and catenate. */
+			p = ff->h.text;
+			if (ff->h.text != ff->textbuf) /* possibly free old */
+				free((void*)p);
+			ff->h.text = s;     /* store new */
+		}
+	}
+	/* If not extending existing filter item, let main parser do the finalizations */
+
+	return extend;
+}
+
+int filter_parse_one_s(struct filter_t *f0, struct filter_t **ffp, const char *filt0)
+{
+	/* s/pri/alt/over  	Symbol filter
+
+	   pri = symbols in primary table
+	   alt = symbols in alternate table
+	   over = overlay character (case sensitive)
+
+	   For example:
+	   s/->   This will pass all House and Car symbols (primary table)
+	   s//#   This will pass all Digi with or without overlay
+	   s//#/T This will pass all Digi with overlay of capital T
+
+	   About 10-15 s-filters in entire APRS-IS core at any given time.
+	   Up to 520 invocations per second at peak.
+	*/
+	const char *s = filt0;
+	// struct filter_t *ff = *ffp;
+	int len1, len2, len3, len4, len5, len6;
+
+	if (*s == '-')
+		++s;
+	if (*s == 's' || *s == 'S')
+		++s;
+	if (*s != '/')
+		return -1; 
+	++s;
+
+	len1 = len2 = len3 = len4 = len5 = len6 = 0;
+
+	while (1) {
+
+		len1 = s - filt0;
+		while (*s && *s != '/') ++s;
+		len2 = s - filt0;
+
+		f0->h.u3.len1s = len1;
+		f0->h.u4.len1  = len2 - len1;
+		f0->h.u5.lens.len2s = f0->h.u5.lens.len2 = f0->h.u5.lens.len3s = f0->h.u5.lens.len3 = 0;
+
+		if (!*s) break;
+
+		if (*s == '/') ++s;
+		len3 = s - filt0;
+		while (*s && *s != '/') ++s;
+		len4 = s - filt0;
+
+		f0->h.u5.lens.len2s = len3;
+		f0->h.u5.lens.len2  = len4 - len3;
+
+		if (!*s) break;
+
+		if (*s == '/') ++s;
+		len5 = s - filt0;
+		while (*s) ++s;
+		len6 = s - filt0;
+
+		f0->h.u5.lens.len3s = len5;
+		f0->h.u5.lens.len3  = len6 - len5;
+
+		break;
+	}
+
+	if ((len6-len5 > 0) && (len4-len3 == 0)) {
+		/* overlay but no secondary table.. */
+		return -1; /* bad parse */
+	}
+#if 0
+	{
+	  const char  *s1 = filt0+len1, *s2 = filt0+len3, *s3 = filt0+len5;
+	  int l1 = len2-len1, l2 = len4-len3, l3 = len6-len5;
+
+	  // hlog( LOG_DEBUG, "parse s-filter:  '%.*s'  '%.*s'  '%.*s'", l1, s1, l2, s2, l3, s3 );
+	}
+#endif
+	return 0;
+}
+
+
+int filter_parse(struct filter_t **ffp, const char *filt)
+{
+	struct filter_t f0;
+	int i;
+	const char *filt0 = filt;
+	const char *s;
+	char dummyc, dummy2;
+	struct filter_t *ff, *f;
+
+	ff = *ffp;
+	for ( ; ff && ff->h.next; ff = ff->h.next)
+	  ;
+	/* ff  points to last so far accumulated filter,
+	   if none were previously received, it is NULL.. */
+
+	memset(&f0, 0, sizeof(f0));
+	if (*filt == '-') {
+		f0.h.negation = 1;
+		++filt;
+	}
+	f0.h.type = *filt;
+
+	if (!strchr("abdefmopqrstuABDEFMOPQRSTU",*filt)) {
+	  // Not valid filter code
+	  // hlog(LOG_DEBUG, "Bad filter code: %s", filt0);
+	  if (debug)
+	    printf("Bad filter code: %s\n", filt0);
+	  return -1;
+	}
+
+	switch (f0.h.type) {
+	case 'a':
+	case 'A':
+		/*  a/latN/lonW/latS/lonE     Area filter -- OPTIMIZE!  */
+
+		f0.h.type = 'a'; // inside area
+
+		i = sscanf(filt+1, "/%f/%f/%f/%f%c%c",
+			   &f0.h.f_latN, &f0.h.u2.f_lonW,
+			   &f0.h.u1.f_latS, &f0.h.f_lonE, &dummyc, &dummy2);
+
+		if (i == 6 && dummyc == '/' && dummy2 == '-') {
+			i = 4;
+			f0.h.type = 'A'; // outside area!
+		}
+		if (i == 5 && dummyc == '-') {
+			i = 4;
+			f0.h.type = 'A'; // outside area!
+		}
+		if (i == 5 && dummyc == '/') {
+			i = 4;
+		}
+
+		if (i != 4) {
+		  // hlog(LOG_DEBUG, "Bad filter parse: %s", filt0);
+		  if (debug)
+		    printf("Bad filter parse: %s", filt0);
+		  return -1;
+		}
+
+		if (!( -90.01 < f0.h.f_latN && f0.h.f_latN <  90.01)) {
+		  // hlog(LOG_DEBUG, "Bad filter latN value: %s", filt0);
+		  if (debug)
+		    printf("Bad filter latN value: %s", filt0);
+		  return -2;
+		}
+		if (!(-180.01 < f0.h.u2.f_lonW && f0.h.u2.f_lonW < 180.01)) {
+		  // hlog(LOG_DEBUG, "Bad filter lonW value: %s", filt0);
+		  if (debug)
+		    printf("Bad filter lonW value: %s", filt0);
+		  return -2;
+		}
+		if (!( -90.01 < f0.h.u1.f_latS && f0.h.u1.f_latS <  90.01)) {
+		  // hlog(LOG_DEBUG, "Bad filter latS value: %s", filt0);
+		  if (debug)
+		    printf("Bad filter latS value: %s", filt0);
+		  return -2;
+		}
+		if (!(-180.01 < f0.h.f_lonE && f0.h.f_lonE < 180.01)) {
+		  // hlog(LOG_DEBUG, "Bad filter lonE value: %s", filt0);
+		  if (debug)
+		    printf("Bad filter lonE value: %s", filt0);
+		  return -2;
+		}
+
+		if (f0.h.u2.f_lonW > f0.h.f_lonE) {
+		  // wrong way, swap longitudes
+		  float t = f0.h.u2.f_lonW;
+		  f0.h.u2.f_lonW = f0.h.f_lonE;
+		  f0.h.f_lonE = t;
+		}
+		if (f0.h.u1.f_latS > f0.h.f_latN) {
+		  // wrong way, swap latitudes
+		  float t = f0.h.u1.f_latS;
+		  f0.h.u1.f_latS = f0.h.f_latN;
+		  f0.h.f_latN = t;
+		}
+
+		// hlog(LOG_DEBUG, "Filter: %s -> A %.3f %.3f %.3f %.3f", filt0, f0.h.f_latN, f0.h.f_lonW, f0.h.f_latS, f0.h.f_lonE);
+		
+		f0.h.f_latN    = filter_lat2rad(f0.h.f_latN);
+		f0.h.u2.f_lonW = filter_lon2rad(f0.h.u2.f_lonW);
+		
+		f0.h.u1.f_latS = filter_lat2rad(f0.h.u1.f_latS);
+		f0.h.f_lonE    = filter_lon2rad(f0.h.f_lonE);
+
+		break;
+
+	case 'b':
+	case 'B':
+		/*  b/call1/call2...   Budlist filter (*) */
+
+		i = filter_parse_one_callsignset(ffp, &f0, filt0, MatchWild );
+		if (i < 0)
+			return i;
+		if (i > 0) /* extended previous */
+			return 0;
+
+
+		break;
+	case 'd':
+	case 'D':
+		/* d/digi1/digi2...  	Digipeater filter (*)	*/
+
+		i = filter_parse_one_callsignset(ffp, &f0, filt0, MatchWild );
+		if (i < 0)
+			return i;
+		if (i > 0) /* extended previous */
+			return 0;
+
+		break;
+#if 0
+	case 'e':
+	case 'E':
+		/*   e/call1/call1/...  Entry station filter (*) */
+
+		i = filter_parse_one_callsignset(ffp, &f0, filt0, MatchWild );
+		if (i < 0)
+			return i;
+		if (i > 0) /* extended previous */
+			return 0;
+
+		break;
+#endif
+	case 'f':
+	case 'F':
+		/*  f/call/dist         Friend's range filter  */
+
+		i = sscanf(filt+1, "/%9[^/]/%f", f0.h.u5.refcallsign.callsign, &f0.h.u2.f_dist);
+		// negative distance means "outside this range."
+		// and makes most sense with overall negative filter!
+		if (i != 2 || (-0.1 < f0.h.u2.f_dist && f0.h.u2.f_dist < 0.1)) {
+		  // hlog(LOG_DEBUG, "Bad filter parse: %s", filt0);
+		  if (debug)
+		    printf("Bad filter parse: %s", filt0);
+		  return -1;
+		}
+
+		f0.h.u5.refcallsign.callsign[CALLSIGNLEN_MAX] = 0;
+		f0.h.u5.refcallsign.reflen = strlen(f0.h.u5.refcallsign.callsign);
+		f0.h.u3.numnames = 0; /* reusing this as "position-cache valid" flag */
+
+		// hlog(LOG_DEBUG, "Filter: %s -> F xxx %.3f", filt0, f0.h.u2.f_dist);
+
+		/* NOTE: Could do static location resolving at connect time, 
+		** and then use the same way as 'r' range does.  The friends
+		** are rarely moving...
+		*/
+
+		break;
+
+	case 'g':
+	case 'G':
+		//  g/call1/call2/     Group Messaging filter
+		i = filter_parse_one_callsignset(ffp, &f0, filt0, MatchWild );
+		if (i < 0)
+			return i;
+		if (i > 0) /* extended previous */
+			return 0;
+		break;
+
+	case 'm':
+	case 'M':
+		/*  m/dist            My range filter  */
+
+        	if (myloc_latstr == NULL) {
+                  printf("The M/radius_km  filter requires top-level  myloc  definition. It doesn't exist.\n");
+                  return -1;
+                }
+                
+                f0.h.type = 'r'; // internal implementation at Aprx is a RANGE filter.
+                f0.h.f_latN      = myloc_lat; // radians
+                f0.h.f_lonE      = myloc_lon; // radians
+                f0.h.u1.f_coslat = myloc_coslat;
+
+		i = sscanf(filt+1, "/%f", &f0.h.u2.f_dist);
+		if (i != 1 || f0.h.u2.f_dist < 0.1) {
+		  // hlog(LOG_DEBUG, "Bad filter parse: %s", filt0);
+		  if (debug)
+		    printf("Bad filter parse: %s", filt0);
+		  return -1;
+		}
+		f0.h.u3.numnames = 0; /* reusing this as "position-cache valid" flag */
+
+		// hlog(LOG_DEBUG, "Filter: %s -> M %.3f", filt0, f0.h.u2.f_dist);
+		break;
+
+	case 'o':
+	case 'O':
+		/* o/obje1/obj2...  	Object filter (*)	*/
+
+		i = filter_parse_one_callsignset(ffp, &f0, filt0, MatchWild );
+		if (i < 0)
+			return i;
+		if (i > 0) /* extended previous */
+			return 0;
+
+		break;
+
+	case 'p':
+	case 'P':
+		/* p/aa/bb/cc...  	Prefix filter
+		   Pass traffic with fromCall that start with aa or bb or cc...
+		*/
+		i = filter_parse_one_callsignset(ffp, &f0, filt0, MatchWild );
+		if (i < 0)
+			return i;
+		if (i > 0) /* extended previous */
+			return 0;
+
+		break;
+#if 0
+	case 'q':
+	case 'Q':
+		/* q/con/ana           q Contruct filter */
+		s = filt+1;
+		f0.h.type = 'q';
+		f0.h.u4.bitflags = 0; /* For QC_*  flags */
+
+		if (*s++ != '/') {
+		  // hlog(LOG_DEBUG, "Bad q-filter parse: %s", filt0);
+		  if (debug)
+		    printf("Bad q-filter parse: %s", filt0);
+		  return -1;
+		}
+		for ( ; *s && *s != '/'; ++s ) {
+			switch (*s) {
+			case 'C':
+				f0.h.u4.bitflags |= QC_C;
+				break;
+			case 'X':
+				f0.h.u4.bitflags |= QC_X;
+				break;
+			case 'U':
+				f0.h.u4.bitflags |= QC_U;
+				break;
+			case 'o':
+				f0.h.u4.bitflags |= QC_o;
+				break;
+			case 'O':
+				f0.h.u4.bitflags |= QC_O;
+				break;
+			case 'S':
+				f0.h.u4.bitflags |= QC_S;
+				break;
+			case 'r':
+				f0.h.u4.bitflags |= QC_r;
+				break;
+			case 'R':
+				f0.h.u4.bitflags |= QC_R;
+				break;
+			case 'Z':
+				f0.h.u4.bitflags |= QC_Z;
+				break;
+			case 'I':
+				f0.h.u4.bitflags |= QC_I;
+				break;
+			default:
+				// hlog(LOG_DEBUG, "Bad q-filter parse: %s", filt0);
+				if (debug)
+				  printf("Bad q-filter parse: %s", filt0);
+				return -1;
+			}
+		}
+		if (*s == '/') { /* second format */
+			++s;
+			if (*s == 'i' || *s == 'I') {
+				f0.h.u4.bitflags |= QC_AnalyticsI;
+				++s;
+			}
+			if (*s) {
+				// hlog(LOG_DEBUG, "Bad q-filter parse: %s", filt0);
+				if (debug)
+				  printf("Bad q-filter parse: %s", filt0);
+				return -1;
+			}
+		}
+		
+		break;
+#endif
+	case 'r':
+	case 'R':
+		/*  r/lat/lon/dist            Range filter  */
+
+		i = sscanf(filt+1, "/%f/%f/%f",
+			 &f0.h.f_latN, &f0.h.f_lonE, &f0.h.u2.f_dist);
+		// negative distance means "outside this range."
+		// and makes most sense with overall negative filter!
+		if (i != 3 || (-0.1 < f0.h.u2.f_dist && f0.h.u2.f_dist < 0.1)) {
+		  // hlog(LOG_DEBUG, "Bad filter parse: %s", filt0);
+		  if (debug)
+		    printf("Bad filter parse: %s", filt0);
+		  return -1;
+		}
+
+		if (!( -90.01 < f0.h.f_latN && f0.h.f_latN <  90.01)) {
+		  // hlog(LOG_DEBUG, "Bad filter lat value: %s", filt0);
+		  if (debug)
+		    printf("Bad filter lat value: %s", filt0);
+		  return -2;
+		}
+		if (!(-180.01 < f0.h.f_lonE && f0.h.f_lonE < 180.01)) {
+		  // hlog(LOG_DEBUG, "Bad filter lon value: %s", filt0);
+		  if (debug)
+		    printf("Bad filter lon value: %s", filt0);
+		  return -2;
+		}
+
+		// hlog(LOG_DEBUG, "Filter: %s -> R %.3f %.3f %.3f", filt0, f0.h.f_latN, f0.h.f_lonE, f0.h.u2.f_dist);
+
+		f0.h.f_latN = filter_lat2rad(f0.h.f_latN);
+		f0.h.f_lonE = filter_lon2rad(f0.h.f_lonE);
+
+		f0.h.u1.f_coslat = cosf( f0.h.f_latN ); /* Store pre-calculated COS of LAT */
+		break;
+
+	case 's':
+	case 'S':
+		/* s/pri/alt/over  	Symbol filter  */
+
+		i = filter_parse_one_s( &f0, ffp, filt0 );
+		if (i < 0) {
+		  // hlog(LOG_DEBUG, "Bad s-filter syntax: %s", filt0);
+		  if (debug)
+		    printf("Bad s-filter syntax: %s", filt0);
+		  return i;
+		}
+		if (i > 0) /* extended previous */
+			return 0;
+		break;
+
+	case 't':
+	case 'T':
+		/* t/..............
+		   t/............../call/km
+		*/
+		s = filt+1;
+		f0.h.type = 't';
+		f0.h.u4.bitflags = 0;
+		f0.h.u3.numnames = 0; /* reusing this as "position-cache valid" flag */
+
+		if (*s++ != '/') {
+		  // hlog(LOG_DEBUG, "Bad filter parse: %s", filt0);
+		  if (debug)
+		    printf("Bad t-filter syntax: %s", filt0);
+		  return -1;
+		}
+		for ( ; *s && *s != '/'; ++s ) {
+			switch (*s) {
+			case '*':
+				f0.h.u4.bitflags |= ~T_CWOP; /* "ALL" -- excluding CWOP */
+				break;
+                        case '3':
+				f0.h.u4.bitflags |= T_THIRDPARTY;
+                        	break;
+			case 'c': case 'C':
+				f0.h.u4.bitflags |= T_CWOP;
+				break;
+			case 'i': case 'I':
+				f0.h.u4.bitflags |= T_ITEM;
+				break;
+			case 'm': case 'M':
+				f0.h.u4.bitflags |= T_MESSAGE;
+				break;
+			case 'n': case 'N':
+				f0.h.u4.bitflags |= T_NWS;
+				break;
+			case 'o': case 'O':
+				f0.h.u4.bitflags |= T_OBJECT;
+				break;
+			case 'p': case 'P':
+				f0.h.u4.bitflags |= T_POSITION;
+				break;
+			case 'q': case 'Q':
+				f0.h.u4.bitflags |= T_QUERY;
+				break;
+			case 's': case 'S':
+				f0.h.u4.bitflags |= T_STATUS;
+				break;
+			case 't': case 'T':
+				f0.h.u4.bitflags |= T_TELEMETRY;
+				break;
+			case 'u': case 'U':
+				f0.h.u4.bitflags |= T_USERDEF;
+				break;
+			case 'w': case 'W':
+				f0.h.u4.bitflags |= T_WX;
+				break;
+			default:
+				// hlog(LOG_DEBUG, "Bad filter parse: %s", filt0);
+				if (debug)
+				  printf("Bad t-filter syntax: %s", filt0);
+				return -1;
+			}
+		}
+		if (*s == '/' && s[1] != 0) { /* second format */
+			i = sscanf(s, "/%9[^/]/%f%c", f0.h.u5.refcallsign.callsign, &f0.h.u2.f_dist, &dummyc);
+			// negative distance means "outside this range."
+			// and makes most sense with overall negative filter!
+			if ( i != 2 || (-0.1 < f0.h.u2.f_dist && f0.h.u2.f_dist < 0.1) || /* 0.1 km minimum radius */
+			     strlen(f0.h.u5.refcallsign.callsign) < CALLSIGNLEN_MIN ) {
+			  // hlog(LOG_DEBUG, "Bad filter parse: %s", filt0);
+			  if (debug)
+			    printf("Bad t-filter parse: %s", filt0);
+			  return -1;
+			}
+			f0.h.u5.refcallsign.callsign[CALLSIGNLEN_MAX] = 0;
+			f0.h.u5.refcallsign.reflen = strlen(f0.h.u5.refcallsign.callsign);
+			f0.h.type = 'T'; /* two variants... */
+		}
+
+		break;
+
+	case 'u':
+	case 'U':
+		/* u/unproto1/unproto2...  	Unproto filter (*)	*/
+
+		i = filter_parse_one_callsignset(ffp, &f0, filt0, MatchWild );
+		if (i < 0)
+			return i;
+		if (i > 0) /* extended previous */
+			return 0;
+
+		break;
+
+
+
+	default:;
+		/* No pre-parsers for other types */
+		// hlog(LOG_DEBUG, "Filter: %s", filt0);
+		if (debug)
+		  printf("Bad filter code: %s\n", filt0);
+		return -1;
+		break;
+	}
+
+	// if (!c) return 0; /* Just a verification scan, not actual fill in parse */
+	
+	/* OK, pre-parsing produced accepted result */
+#ifndef _FOR_VALGRIND_
+	f = cellmalloc(filter_cells);
+	if (!f) return -1;
+	*f = f0; /* store pre-parsed values */
+	if (strlen(filt0) < FILT_TEXTBUFSIZE) {
+		strcpy(f->textbuf, filt0);
+		f->h.text = f->textbuf;
+	} else
+		f->h.text = strdup(filt0); /* and copy of filter text */
+#else
+	f = calloc(1, sizeof(*f) + strlen(filt0));
+	*f = f0; /* store pre-parsed values */
+	f->h.text = f->textbuf;
+	strcpy(f->textbuf, filt); /* and copy of filter text */
+#endif
+
+	/* hlog(LOG_DEBUG, "parsed filter: t=%c n=%d '%s'", f->h.type, f->h.negation, f->h.text); */
+
+	/* link to the tail.. */
+	if (ff)
+		ffp = &ff->h.next;
+
+	*ffp = f;
+
+	return 0;
+}
+
+/* Discard the defined filter chain */
+void filter_free(struct filter_t *f)
+{
+	struct filter_t *fnext;
+
+	for ( ; f ; f = fnext ) {
+		fnext = f->h.next;
+		/* If not pointer to internal string, free it.. */
+#ifndef _FOR_VALGRIND_
+		if (f->h.text != f->textbuf)
+			free((void*)(f->h.text));
+		cellfree(filter_cells, f);
+#else
+		free(f);
+#endif
+	}
+}
+
+
+/*
+
+#
+# Input:  This[La]      Source Latitude, in radians
+#         This[Lo]      Source Longitude, in radians
+#         That[La]      Destination Latitude, in radians
+#         That[Lo]      Destination Longitude, in radians
+# Output: R[s]          Distance, in kilometers
+#
+
+function maidenhead_km_distance($This, $That) {
+
+    #Haversine Formula (from R.W. Sinnott, "Virtues of the Haversine", 
+    #Sky and Telescope, vol. 68, no. 2, 1984, p. 159): 
+
+    $dlon = $That[Lo] - $This[Lo];
+    $dlat = $That[La] - $This[La];
+
+    $sinDlat2 = sin($dlat/2);
+    $sinDlon2 = sin($dlon/2);
+    $a = ($sinDlat2 * $sinDlat2 +
+          cos($This[La]) * cos($That[La]) * $sinDlon2 * $sinDlon2);
+
+    # The Haversine Formula can be expressed in terms of a two-argument 
+    # inverse tangent function, atan2(y,x), instead of an inverse sine 
+    # as follows (no bulletproofing is needed for an inverse tangent): 
+
+    $c = 2.0 * atan2( sqrt($a), sqrt(1.0-$a) );
+    # $d = R * $c ; # Radius of ball times angle [radians] ...
+
+
+    $R[s] = rad2deg($c) * 111.2;
+
+    return($R);
+
+}
+
+*/
+
+static float maidenhead_km_distance(float lat1, float coslat1, float lon1, float lat2, float coslat2, float lon2)
+{
+	float sindlat2 = sinf((lat1 - lat2) * 0.5);
+	float sindlon2 = sinf((lon1 - lon2) * 0.5);
+
+	float a = (sindlat2 * sindlat2 +
+		   coslat1 * coslat2 * sindlon2 * sindlon2);
+
+	float c = 2.0 * atan2f( sqrtf(a), sqrtf(1.0 - a));
+
+	return ((111.2 * 180.0 / M_PI) * c);
+}
+
+
+/*
+ *
+ *  http://www.aprs-is.net/javaprssrvr/javaprsfilter.htm
+ *
+ */
+
+static int filter_process_one_a(struct pbuf_t *pb, struct filter_t *f)
+{
+	/* a/latN/lonW/latS/lonE  	Area filter
+
+	   The area filter works the same as range filter but the filter
+	   is defined as a box of coordinates. The coordinates can also
+	   been seen as upper left coordinate and lower right. Lat/lon
+	   are decimal degrees.   South and west are negative.
+
+	   Multiple area filters can be defined at the same time.
+
+	   Messages addressed to stations within the area are also passed.
+	   (by means of aprs packet parse finding out the location..)
+
+	   50-70 instances in APRS-IS core at any given time.
+	   Up to 2500 invocations per second.
+	*/
+	;
+	if (!(pb->flags & F_HASPOS)) /* packet with a position.. (msgs with RECEIVER's position) */
+		return 0;
+
+	if ((pb->lat <= f->h.f_latN) &&
+	    (pb->lat >= f->h.u1.f_latS) &&
+	    (pb->lng <= f->h.f_lonE) && /* East POSITIVE ! */
+	    (pb->lng >= f->h.u2.f_lonW)) {
+		/* Inside the box */
+		return f->h.negation ? 2 : 1;
+	} else if (f->h.type == 'A') {
+		/* Outside the box */
+		return f->h.negation ? 2 : 1;
+	}
+
+	return 0;
+}
+
+static int filter_process_one_b(struct pbuf_t *pb, struct filter_t *f)
+{
+	/* b/call1/call2...  	Budlist filter
+
+	   Pass all traffic FROM exact call: call1, call2, ...
+	   (* wild card allowed)
+
+	   50/70 instances in APRS-IS core at any given time.
+	   Up to 2500 invocations per second.
+	*/
+
+	struct filter_refcallsign_t ref;
+	int i = pb->srccall_end - pb->data;
+
+	if (i > CALLSIGNLEN_MAX) i = CALLSIGNLEN_MAX;
+
+	/* source address  "addr">... */
+        memset( &ref, 0, sizeof(ref) ); // clear it all
+	memcpy( ref.callsign, pb->data, i);
+
+	return filter_match_on_callsignset(&ref, i, f, MatchWild);
+}
+
+static int filter_process_one_d(struct pbuf_t *pb, struct filter_t *f)
+{
+	/* d/digi1/digi2...  	Digipeater filter
+
+	   The digipeater filter will match all packets that have been
+	   digipeated by a particular station(s) (the station's call
+	   is in the path).   This filter allows the * wildcard.
+
+	   25-35 instances in APRS-IS core at any given time.
+	   Up to 1300 invocations per second.
+	*/
+	struct filter_refcallsign_t ref;
+	const char *d = pb->srccall_end + 1 + pb->dstcall_len + 1; /* viacall start */
+	const char *q = pb->qconst_start-1;
+	int rc, i, j = 0;
+
+	// hlog( LOG_INFO, "digifilter:  '%.*s' -> '%.*s'  q-d=%d",
+	//       (int)(pb->packet_len < 50 ? pb->packet_len : 50),
+	//       pb->data, (int)i, d, (int)(q-d) );
+
+	for (i = 0; d < q; ) {
+		++j;
+		if (j > 10) break; // way too many callsigns... (code bug?)
+
+		if (*d == ',') ++d; // second round and onwards..
+		for (i = 0; i+d <= q && i <= CALLSIGNLEN_MAX; ++i) {
+			if (d[i] == ',')
+				break;
+		}
+
+		// hlog(LOG_INFO, "d:  -> (%d,%d) '%.*s'", (int)(d-pb->data), i, i, d);
+
+		// digipeater address  ",addr,"
+                memset( &ref, 0, sizeof(ref) ); // clear it all
+		memcpy( ref.callsign, d, i);
+
+		if (i > CALLSIGNLEN_MAX) i = CALLSIGNLEN_MAX;
+
+		rc = filter_match_on_callsignset(&ref, i, f, MatchWild);
+		if (rc) {
+			return (rc == 1);
+		}
+		d += i;
+	}
+	return 0;
+}
+
+#if 0
+static int filter_process_one_e(struct pbuf_t *pb, struct filter_t *f)
+{
+	/* e/call1/call1/...  	Entry station filter
+
+	   This filter matches all packets with the specified
+	   callsign-SSID(s) immediately following the q construct.
+	   This allows filtering based on receiving IGate, etc.
+	   Supports * wildcard.
+
+	   2-6 instances in APRS-IS core at any given time.
+	   Up to 200 invocations per second.
+	*/
+
+	struct filter_refcallsign_t ref;
+	const char *e = pb->qconst_start+4;
+	int         i = pb->entrycall_len;
+
+	if (i < 1) /* should not happen.. */
+		return 0; /* Bad Entry-station callsign */
+
+	/* entry station address  "qA*,addr," */
+	memset( &ref, 0, sizeof(ref) ); // clear it all
+	memcpy( ref.callsign, e, i);
+
+	return filter_match_on_callsignset(&ref, i, f, MatchWild);
+}
+#endif
+
+#ifndef DISABLE_IGATE
+static int filter_process_one_f(struct pbuf_t *pb, struct filter_t *f, historydb_t *historydb)
+{
+	/* f/call/dist  	Friend Range filter
+
+	   This is the same as the range filter except that the center is
+	   defined as the last known position of call.
+
+	   Multiple friend filters can be defined at the same time.
+
+	   Messages addressed to stations within the range are also passed.
+	   (by means of aprs packet parse finding out the location..)
+
+	   NOTE: Could do static location resolving at connect time, 
+	   and then use the same way as 'r' range does.  The friends
+	   are rarely moving...
+
+	   15-25 instances in APRS-IS core at any given time.
+	   Up to 900 invocations per second.
+
+	   Caching the historydb_lookup() result will lower CPU power
+	   spent on the historydb.
+	*/
+
+	history_cell_t *history;
+
+	float r;
+	float lat1, lon1, coslat1;
+	float lat2, lon2, coslat2;
+
+	const char *callsign = f->h.u5.refcallsign.callsign;
+	int i                = f->h.u5.refcallsign.reflen;
+
+	if (!(pb->flags & F_HASPOS)) { /* packet with a position.. (msgs with RECEIVER's position) */
+	  if (debug) printf("f-filter: no position -> return 0\n");
+		return 0; /* No position data... */
+	}
+
+	/* find friend's last location packet */
+	if (f->h.hist_age < tick.tv_sec) {
+		history = historydb_lookup( historydb, callsign, i );
+		f->h.hist_age = tick.tv_sec + hist_lookup_interval;
+		if (!history) {
+		  if (debug) printf("f-filter: no history lookup result (%*s) -> return 0\n", i, callsign );
+		  return 0; /* no lookup result.. */
+		}
+		f->h.u3.numnames = 1;
+		f->h.f_latN   = history->lat;
+		f->h.f_lonE   = history->lon;
+		f->h.u1.f_coslat = history->coslat;
+	}
+	if (!f->h.u3.numnames) {
+	  if (debug) printf("f-filter: no history lookup result (numnames == 0) -> return 0\n");
+	  return 0; /* histdb lookup cache invalid */
+	}
+
+	lat1    = f->h.f_latN;
+	lon1    = f->h.f_lonE;
+	coslat1 = f->h.u1.f_coslat;
+
+	lat2    = pb->lat;
+	lon2    = pb->lng;
+	coslat2 = pb->cos_lat;
+
+	r = maidenhead_km_distance(lat1, coslat1, lon1, lat2, coslat2, lon2);
+	if (debug) printf("f-filter: r=%.1f km\n", r);
+
+	if (f->h.u2.f_dist < 0.0) {
+		// Test for _outside_ the range
+		if (r > -f->h.u2.f_dist)  /* Range is more than given limit */
+			return (f->h.negation) ? 2 : 1;
+	} else {
+		// Test for _inside_ the range
+		if (r < f->h.u2.f_dist)  /* Range is less than given limit */
+			return (f->h.negation) ? 2 : 1;
+	}
+
+	return 0;
+}
+#endif
+
+static int filter_process_one_g(struct pbuf_t *pb, struct filter_t *f)
+{
+	/* g/call1/call2...  	Group Messaging filter
+
+	   Pass all message traffic TO calls call1/call2/...
+	   (* wild card allowed)
+
+	*/
+
+	struct filter_refcallsign_t ref;
+	int i = pb->dstname_len;
+
+	if (i > CALLSIGNLEN_MAX) i = CALLSIGNLEN_MAX;
+
+	/* source address  "addr">... */
+        memset( &ref, 0, sizeof(ref) ); // clear it all
+	memcpy( ref.callsign, pb->dstname, i);
+
+	return filter_match_on_callsignset(&ref, i, f, MatchWild);
+}
+
+
+
+#if 0  // No M filter implementation, but there is M filter parse producing R filter..
+static int filter_process_one_m(struct pbuf_t *pb, struct filter_t *f)
+{
+	/* m/dist  	My Range filter
+
+	   This is the same as the range filter except that the center is
+	   defined as the last known position of the logged in client.
+
+	   Messages addressed to stations within the range are also passed.
+	   (by means of aprs packet parse finding out the location..)
+
+	   NOTE:  MY RANGE is rarely moving, once there is a positional
+	   fix, it could stay fixed...
+
+	   80-120 instances in APRS-IS core at any given time.
+	   Up to 4200 invocations per second.
+
+	   Caching the historydb_lookup() result will lower CPU power
+	   spent on the historydb.
+
+           At Aprx: Implemented using Range filter, and prepared at parse time..
+	*/
+
+	float lat2, lon2, coslat2;
+	float r;
+
+	if (!(pb->flags & F_HASPOS)) /* packet with a position.. (msgs with RECEIVER's position) */
+		return 0;
+
+	lat2    = pb->lat;
+	lon2    = pb->lng;
+	coslat2 = pb->cos_lat;
+
+	r = maidenhead_km_distance(myloc_lat, myloc_coslat, myloc_lon, lat2, coslat2, lon2);
+	if (f->h.u2.f_dist < 0.0) {
+		// Test for _outside_ the range
+		if (r > -f->h.u2.f_dist)  /* Range is more than given limit */
+			return (f->h.negation) ? 2 : 1;
+	} else {
+		// Test for _inside_ the range
+		if (r < f->h.u2.f_dist)  /* Range is less than given limit */
+			return (f->h.negation) ? 2 : 1;
+	}
+
+	return 0;
+}
+#endif
+
+static int filter_process_one_o(struct pbuf_t *pb, struct filter_t *f)
+{
+	/* o/obj1/obj2...  	Object filter
+	   Pass all objects with the exact name of obj1, obj2, ...
+	   (* wild card allowed)
+	   PROBABLY ALSO ITEMs
+
+	   Usage frequency: 0.2%
+
+	   .. 2 cases in entire APRS-IS core at any time.
+	   About 50-70 invocations per second at peak.
+	*/
+	struct filter_refcallsign_t ref;
+	int i;
+	// const char *s;
+
+	if ( (pb->packettype & (T_OBJECT|T_ITEM)) == 0 ) { /* not an Object NOR Item */
+		if (debug) printf("o-filter: packet type not OBJECT nor ITEM\n");
+		return 0;
+	}
+
+	/* parse_aprs() has picked item/object name pointer and length.. */
+	// s = pb->srcname;
+	i = pb->srcname_len;
+	if (i < 1) {
+		if (debug) printf("o-filter: object/item name length < 1 at the packet\n");
+		return 0; /* Bad object/item name */
+        }
+
+	/* object name */
+	memset( &ref, 0, sizeof(ref) ); // clear it all
+	memcpy( ref.callsign, pb->srcname, i); // copy the interesting part
+
+	return filter_match_on_callsignset(&ref, i, f, MatchWild);
+}
+
+static int filter_process_one_p(struct pbuf_t *pb, struct filter_t *f)
+{
+
+	/* p/aa/bb/cc...  	Prefix filter
+	   Pass traffic with fromCall that start with aa or bb or cc...
+
+	   Usage frequency: 14.4%
+
+	   .. 80-100 cases in entire APRS-IS core at any time.
+	   Up to 3500 invocations per second at peak.
+	*/
+
+	struct filter_refcallsign_t ref;
+	int i = pb->srccall_end - pb->data;
+
+	if (i > CALLSIGNLEN_MAX) i = CALLSIGNLEN_MAX;
+
+	/* source address  "addr">... */
+	memset( &ref, 0, sizeof(ref) ); // clear it all
+	memcpy( ref.callsign, pb->data, i);
+
+	return filter_match_on_callsignset(&ref, i, f, MatchPrefix);
+}
+
+#if 0
+static int filter_process_one_q(struct pbuf_t *pb, struct filter_t *f)
+{
+	/* q/con/ana  	q Contruct filter
+
+	   q = q Construct command
+	   con = list of q Construct to pass (case sensitive)
+	   ana = analysis based on q Construct.
+
+	   I = Pass positions from IGATES identified by qAr or qAR.
+
+	   For example:
+	   q/C    Pass all traffic with qAC
+	   q/rR   Pass all traffic with qAr or qAR
+	   q//I   Pass all position packets from IGATES identified
+	          in other packets by qAr or qAR
+
+	   Usage frequency: 0.4%
+
+	   .. 2-6 cases in entire APRS-IS core at any time.
+	   Up to 200 invocations per second at peak.
+	*/
+
+	const char *e = pb->qconst_start+2;
+	int mask;
+
+	switch (*e) {
+	case 'C':
+		mask = QC_C;
+		break;
+	case 'X':
+		mask = QC_X;
+		break;
+	case 'U':
+		mask = QC_U;
+		break;
+	case 'o':
+		mask = QC_o;
+		break;
+	case 'O':
+		mask = QC_O;
+		break;
+	case 'S':
+		mask = QC_S;
+		break;
+	case 'r':
+		mask = QC_r;
+		break;
+	case 'R':
+		mask = QC_R;
+		break;
+	case 'Z':
+		mask = QC_Z;
+		break;
+	case 'I':
+		mask = QC_I;
+		break;
+	default:
+		return 0; /* Should not happen... */
+		break;
+	}
+
+	if (f->h.u4.bitflags & mask) {
+		/* Something matched! */
+		return 1;
+	}
+	if (f->h.u4.bitflags & QC_AnalyticsI) {
+		/* Oh ?  Analytical! 
+		   Has it ever been accepted into entry-igate database ? */
+		if (filter_entrycall_lookup(pb))
+			return 1; /* Found on entry-igate database! */
+	}
+
+	return 0; /* No match */
+}
+#endif
+
+static int filter_process_one_r(struct pbuf_t *pb, struct filter_t *f)
+{
+	/* r/lat/lon/dist  	Range filter
+
+	   Pass posits and objects within dist km from lat/lon.
+	   lat and lon are signed degrees, i.e. negative for West/South
+	   and positive for East/North.
+
+	   Multiple range filters can be defined at the same time.
+
+	   Messages addressed to stations within the range are also passed.
+	   (by means of aprs packet parse finding out the location..)
+
+	   About 120-150 r-filters in entire APRS-IS core at any given time.
+	   Up to 5200 invocations per second at peak.
+	*/
+
+	float lat1    = f->h.f_latN;
+	float lon1    = f->h.f_lonE;
+	float coslat1 = f->h.u1.f_coslat;
+	float r;
+
+	float lat2, lon2, coslat2;
+
+	if (!(pb->flags & F_HASPOS)) {
+	  /* packet with a position..
+	     (msgs with RECEIVER's position) */
+		return 0;
+	}
+
+	lat2    = pb->lat;
+	lon2    = pb->lng;
+	coslat2 = pb->cos_lat;
+
+	r = maidenhead_km_distance(lat1, coslat1, lon1, lat2, coslat2, lon2);
+
+	if (f->h.u2.f_dist < 0.0) {
+		// Test for _outside_ the range
+		if (r > -f->h.u2.f_dist)  /* Range is more than given limit */
+			return (f->h.negation) ? 2 : 1;
+	} else {
+		// Test for _inside_ the range
+		if (r < f->h.u2.f_dist)  /* Range is less than given limit */
+			return (f->h.negation) ? 2 : 1;
+	}
+
+	return 0;
+}
+
+static int filter_process_one_s(struct pbuf_t *pb, struct filter_t *f)
+{
+	/* s/pri/alt/over  	Symbol filter
+
+	   pri = symbols in primary table
+	   alt = symbols in alternate table
+	   over = overlay character (case sensitive)
+
+	   For example:
+	   s/->   This will pass all House and Car symbols (primary table)
+	   s//#   This will pass all Digi with or without overlay
+	   s//#/T This will pass all Digi with overlay of capital T
+
+	   About 10-15 s-filters in entire APRS-IS core at any given time.
+	   Up to 520 invocations per second at peak.
+	*/
+	const char symtable = (pb->symbol[0] == '/') ? '/' : '\\';
+	const char symcode  = pb->symbol[1];
+	const char symolay  = (pb->symbol[0] != symtable) ? pb->symbol[0] : 0;
+
+	// hlog( LOG_DEBUG, "s-filt %c|%c|%c  %s", symtable, symcode, symolay ? symolay : '-', f->h.text );
+
+	if (f->h.u4.len1 != 0) {
+		/* Primary table symbols */
+		if ( symtable == '/' &&
+		     memchr(f->h.text+f->h.u3.len1s, symcode, f->h.u4.len1) != NULL )
+			return f->h.negation ? 2 : 1;
+		// return 0;
+	}
+	if (f->h.u5.lens.len3 != 0) {
+		/* Secondary table with overlay */
+		if ( memchr(f->h.text+f->h.u5.lens.len3s, symolay, f->h.u5.lens.len3) == NULL )
+			return 0; // No match on overlay
+		if ( memchr(f->h.text+f->h.u5.lens.len2s, symcode, f->h.u5.lens.len2) == NULL )
+			return 0; // No match on overlay
+		return f->h.negation ? 2 : 1;
+	}
+	/* OK, no overlay... */
+	if (f->h.u5.lens.len2 != 0) {
+		/* Secondary table symbols */
+		if ( symtable != '/' &&
+		     memchr(f->h.text+f->h.u5.lens.len2s, symcode, f->h.u5.lens.len2) != NULL )
+			return f->h.negation ? 2 : 1;
+	}
+	/* No match */
+	return 0;
+}
+
+static int filter_process_one_t(struct pbuf_t *pb, struct filter_t *f, historydb_t *historydb)
+{
+	/* [-]t/poimntqsu3*c
+	   [-]t/poimntqsu3*c/call/km
+
+	   Type filter 	Pass all traffic based on packet type.
+	   One or more types can be defined at the same time, t/otq
+	   is a valid definition.
+
+	   c = CWOP (local extension)
+	   * = ALL  (local extension)
+
+	   i = Items
+	   m = Message
+	   n = NWS Weather & Weather Objects
+	   o = Objects
+	   p = Position packets
+	   q = Query
+	   s = Status
+	   t = Telemetry
+	   u = User-defined
+	   w = Weather
+           3 = 3rd party frame
+
+	   Note: The weather type filter also passes positions packets
+	   for positionless weather packets.
+	       
+	   The second format allows putting a radius limit around "call"
+	   (station callsign-SSID or object name) for the requested station
+	   types.
+
+	   About 40-60 s-filters in entire APRS-IS core at any given time.
+	   Up to 2100 invocations per second at peak.
+
+	   For the second format perhaps 2-3 in APRS-IS at any time.
+	   (mapping to 60-100 invocations per second)
+
+	   Usage examples:
+
+	   -t/c              Everything except CWOP
+	    t/.*./OH2RDY/50  Everything within 50 km of OH2RDY's last known position
+	                     ("." is dummy addition for C comments..)
+	*/
+	int rc = 0;
+	if (pb->packettype & f->h.u4.bitflags) /* u4.bitflags as comparison bitmask */
+		rc = 1;
+#if 0
+	if (!rc && (f->h.u4.bitflags & T_WX) && (pb->flags & F_HASPOS)) {
+		/* "Note: The weather type filter also passes positions packets
+		//        for positionless weather packets."
+		//
+		// 1) recognize positionless weather packets
+		// 2) register their source callsigns, do this in  input_parse
+		// 3) when filtering for weather data, check non-weather 
+		//    recognized packets against the database in point 2
+		// 4) pass on packets matching point 3
+		*/
+
+		rc = filter_wx_lookup(pb);
+	}
+#endif
+	/* Either it stops here, or it continues... */
+
+	if (rc && f->h.type == 'T') { /* Within a range of callsign ?
+				       * Rather rare..  perhaps 2-3 in APRS-IS.
+				       */
+		float range, r;
+		float lat1, lon1, coslat1;
+		float lat2, lon2, coslat2;
+#ifndef DISABLE_IGATE
+		const char *callsign    = f->h.u5.refcallsign.callsign;
+		const int   callsignlen = f->h.u5.refcallsign.reflen;
+		history_cell_t *history;
+#endif
+
+		/* hlog(LOG_DEBUG, "Type filter with callsign range used! '%s'", f->h.text); */
+
+		if (!(pb->flags & F_HASPOS)) /* packet with a position.. (msgs with RECEIVER's position) */
+			return 0; /* No positional data.. */
+
+		range = f->h.u2.f_dist;
+
+		/* So..  Now we have a callsign, and we have range.
+		   Lets find callsign's location, and range to that item..
+		   .. 60-100 lookups per second. */
+
+#ifndef DISABLE_IGATE
+		if (f->h.hist_age < tick.tv_sec) {
+			history = historydb_lookup( historydb, callsign, callsignlen );
+
+			/* hlog( LOG_DEBUG, "Type filter with callsign range used! call='%s', range=%.1f position %sfound",
+			//       callsign, range, i ? "" : "not ");
+			*/
+
+
+			if (!history) return 0; /* no lookup result.. */
+			f->h.u3.numnames = 1;
+			f->h.hist_age = tick.tv_sec + hist_lookup_interval;
+			f->h.f_latN   = history->lat;
+			f->h.f_lonE   = history->lon;
+			f->h.u1.f_coslat = history->coslat;
+		}
+#endif
+		if (!f->h.u3.numnames) return 0; /* No valid data at range center position cache */
+
+		lat1    = f->h.f_latN;
+		lon1    = f->h.f_lonE;
+		coslat1 = f->h.u1.f_coslat;
+
+		lat2    = pb->lat;
+		lon2    = pb->lng;
+		coslat2 = pb->cos_lat;
+
+		r = maidenhead_km_distance(lat1, coslat1, lon1, lat2, coslat2, lon2);
+
+		if (range < 0.0) {
+			// Test for _outside_ the range
+			if (r > -range)  /* Range is more than given limit */
+				return (f->h.negation) ? 2 : 1;
+		} else {
+			// Test for _inside_ the range
+			if (r < range)  /* Range is less than given limit */
+				return (f->h.negation) ? 2 : 1;
+		}
+
+		return 0; /* unimplemented! */
+	}
+
+	return (f->h.negation ? (rc+rc) : rc);
+}
+
+static int filter_process_one_u(struct pbuf_t *pb, struct filter_t *f)
+{
+	/* u/unproto1/unproto2/...  	Unproto filter
+
+	   This filter passes all packets with the specified destination
+	   callsign-SSID(s) (also known as the To call or unproto call).
+	   Supports * wild card.
+
+	   Seen hardly ever in APRS-IS core, some rare instances in Tier-2.
+	*/
+
+	struct filter_refcallsign_t ref;
+	const char *d = pb->srccall_end+1;
+	int i;
+
+	i = pb->dstcall_len;
+
+	if (i > CALLSIGNLEN_MAX) i = CALLSIGNLEN_MAX;
+
+	/* hlog( LOG_INFO, "unproto:  '%.*s' -> '%.*s'",
+	//       (int)(pb->packet_len < 30 ? pb->packet_len : 30), pb->data, (int)i, d);
+	*/
+
+	/* destination address  ">addr," */
+	memset( &ref, 0, sizeof(ref) ); // clear it all
+	memcpy( ref.callsign,   d, i);
+
+	return filter_match_on_callsignset(&ref, i, f, MatchWild);
+}
+
+static int filter_process_one(struct pbuf_t *pb, struct filter_t *f, historydb_t *historydb)
+{
+	int rc = 0;
+
+	if (debug>1) printf("filter_process_one() type=%c  '%s'\n",f->h.type, f->h.text);
+
+	switch (f->h.type) {
+
+	case 'a':
+	case 'A':
+		rc = filter_process_one_a(pb, f);
+		break;
+
+	case 'b':
+	case 'B':
+		rc = filter_process_one_b(pb, f);
+		break;
+	case 'd':
+	case 'D':
+		rc = filter_process_one_d(pb, f);
+		break;
+
+#if 0
+	case 'e':
+	case 'E':
+		rc = filter_process_one_e(pb, f);
+		break;
+#endif
+
+#ifndef DISABLE_IGATE
+	case 'f':
+	case 'F':
+		rc = filter_process_one_f(pb, f, historydb);
+		break;
+#endif
+        case 'g':
+        case 'G':
+		rc = filter_process_one_g(pb, f);
+		break;
+
+#if 0 // these are compiled as R filters, no M filters exist internally
+	case 'm':
+	case 'M':
+		rc = filter_process_one_m(pb, f);
+		break;
+#endif
+	case 'o':
+	case 'O':
+		rc = filter_process_one_o(pb, f);
+		break;
+
+	case 'p':
+	case 'P':
+		rc = filter_process_one_p(pb, f);
+		break;
+#if 0
+	case 'q':
+	case 'Q':
+		rc = filter_process_one_q(pb, f);
+		break;
+#endif
+	case 'r':
+	case 'R':
+		rc = filter_process_one_r(pb, f);
+		break;
+
+	case 's':
+	case 'S':
+		rc = filter_process_one_s(pb, f);
+		break;
+
+	case 't':
+	case 'T':
+		rc = filter_process_one_t(pb, f, historydb);
+		break;
+
+	case 'u':
+	case 'U':
+		rc = filter_process_one_u(pb, f);
+		break;
+
+	default:
+		rc = -1;
+		break;
+	}
+	// hlog(LOG_DEBUG, "filter '%s'  rc=%d", f->h.text, rc);
+
+	return rc;
+}
+
+int filter_process(struct pbuf_t *pb, struct filter_t *f, historydb_t *historydb)
+{
+	int seen_accept = 0;
+
+	for ( ; f; f = f->h.next ) {
+		int rc = filter_process_one(pb, f, historydb);
+		/* no reports to user about bad filters.. */
+		if (rc == 1)
+			seen_accept = 1;
+		else if (rc == 2)
+			return -1;
+			/* "2" reply means: "match, but don't pass.." */
+	}
+	return seen_accept;
+}
diff --git a/filter.c.2.06-to-head.diff b/filter.c.2.06-to-head.diff
new file mode 100644
index 0000000..14df525
--- /dev/null
+++ b/filter.c.2.06-to-head.diff
@@ -0,0 +1,585 @@
+Index: filter.c
+===================================================================
+--- filter.c	(revision 507)
++++ filter.c	(working copy)
+@@ -3,7 +3,7 @@
+  *          minimal requirement of esoteric facilities or           *
+  *          libraries of any kind beyond UNIX system libc.          *
+  *                                                                  *
+- * (c) Matti Aarnio - OH2MQK,  2007-2012                            *
++ * (c) Matti Aarnio - OH2MQK,  2007-2014                            *
+  *                                                                  *
+  ********************************************************************/
+ /*
+@@ -30,6 +30,7 @@
+   d/digi1/digi2...  	Digipeater filter (*)
+   e/call1/call1/...  	Entry station filter (*)
+   f/call/dist  		Friend Range filter
++  g/call1/call2..       Group Messaging filter (*)
+   m/dist  		My Range filter
+   o/obj1/obj2...  	Object filter (*)
+   p/aa/bb/cc...  	Prefix filter
+@@ -36,8 +37,8 @@
+   q/con/ana 	 	q Contruct filter
+   r/lat/lon/dist  	Range filter
+   s/pri/alt/over  	Symbol filter
+-  t/poimntqsu*c		Type filter
+-  t/poimntqsu*c/call/km	Type filter
++  t/poimntqsu3*c	Type filter
++  t/poimntqsu3*c/call/km Type filter
+   u/unproto1/unproto2/.. Unproto filter (*)
+ 
+   Sample usage frequencies (out of entire APRS-IS):
+@@ -338,7 +339,7 @@
+ 			if (f->len == keylen) {
+ 				int cmp = strncasecmp(f->callsign, uckey, keylen);
+ 				if (cmp == 0) { /* Have key match */
+-					f->expirytime = now.tv_sec + filter_entrycall_maxage;
++					f->expirytime = tick.tv_sec + filter_entrycall_maxage;
+ 					f2 = f;
+ 					break;
+ 				}
+@@ -356,11 +357,11 @@
+ #ifndef _FOR_VALGRIND_
+ 		f = cellmalloc(filter_entrycall_cells);
+ #else
+-		f = malloc(sizeof(*f));
++		f = calloc(1, sizeof(*f));
+ #endif
+ 		if (f) {
+ 			f->next  = *fp;
+-			f->expirytime = now.tv_sec + filter_entrycall_maxage;
++			f->expirytime = tick.tv_sec + filter_entrycall_maxage;
+ 			f->hash  = hash;
+ 			f->len   = keylen;
+ 			memcpy(f->callsign, uckey, keylen);
+@@ -405,7 +406,7 @@
+ 				int rc =  strncasecmp(f->callsign, key, keylen);
+ 				if (rc == 0) { /* Have key match, see if it is
+ 						  still valid entry ? */
+-					if (f->expirytime < now.tv_sec - 60) {
++                                	if ((f->expirytime - (tick.tv_sec - 60)) < 0) {
+ 						f2 = f;
+ 						break;
+ 					}
+@@ -432,7 +433,7 @@
+ 		fp = & filter_entrycall_hash[k];
+ 		while (( f = *fp )) {
+ 			/* Did it expire ? */
+-			if (f->expirytime <= now.tv_sec) {
++                  if ((f->expirytime - tick.tv_sec) <= 0) {
+ 				*fp = f->next;
+ 				f->next = NULL;
+ 				filter_entrycall_free(f);
+@@ -539,7 +540,7 @@
+ 			if (f->len == keylen) {
+ 				int cmp = memcmp(f->callsign, uckey, keylen);
+ 				if (cmp == 0) { /* Have key match */
+-					f->expirytime = now.tv_sec + filter_wx_maxage;
++					f->expirytime = tick.tv_sec + filter_wx_maxage;
+ 					f2 = f;
+ 					break;
+ 				}
+@@ -557,12 +558,12 @@
+ #ifndef _FOR_VALGRIND_
+ 		f = cellmalloc(filter_wx_cells);
+ #else
+-		f = malloc(sizeof(*f));
++		f = calloc(1, sizeof(*f));
+ #endif
+ 		++filter_wx_cellgauge;
+ 		if (f) {
+ 			f->next  = *fp;
+-			f->expirytime = now.tv_sec + filter_wx_maxage;
++			f->expirytime = tick.tv_sec + filter_wx_maxage;
+ 			f->hash  = hash;
+ 			f->len   = keylen;
+ 			memcpy(f->callsign, key, keylen);
+@@ -593,7 +594,7 @@
+ 				int rc = strncasecmp(f->callsign, key, keylen);
+ 				if (rc == 0) { /* Have key match, see if it is
+ 						  still valid entry ? */
+-					if (f->expirytime < now.tv_sec - 60) {
++                                  if ((f->expirytime - (tick.tv_sec - 60)) < 0) {
+ 						f2 = f;
+ 						break;
+ 					}
+@@ -621,7 +622,7 @@
+ 		fp = & filter_wx_hash[k];
+ 		while (( f = *fp )) {
+ 			/* Did it expire ? */
+-			if (f->expirytime <= now.tv_sec) {
++                	if ((f->expirytime - tick.tv_sec) <= 0) {
+ 				*fp = f->next;
+ 				f->next = NULL;
+ 				filter_wx_free(f);
+@@ -804,13 +805,27 @@
+ 	/* count the number of prefixes in there.. */
+ 	while (*p) {
+ 		if (*p) ++refmax;
+-		while (*p && *p != '/' && *p != ',') ++p;
+-		if (*p == '/' || *p == ',') ++p;
++		while (*p && *p != '/') ++p;
++		if (*p == '/') ++p;
+ 	}
+-	if (refmax == 0) return -1; /* No prefixes ?? */
++	if (refmax == 0) {
++          printf("Filter definition of '%s' has no prefixes defined.\n", filt0);
++          return -1; /* No prefixes ?? */
++        }
+ 
+-	refbuf = malloc(sizeof(*refbuf)*refmax);
+-	refcount = 0;
++	if (ff && ff->h.type == f0->h.type) { /* SAME TYPE,
++						 extend previous record! */
++		extend = 1;
++		refcount = ff->h.u3.numnames + refmax;
++		refbuf   = realloc(ff->h.u5.refcallsigns, sizeof(*refbuf) * refcount);
++		ff->h.u5.refcallsigns = refbuf;
++		refcount = ff->h.u3.numnames;
++	} else {
++		refbuf = calloc(1, sizeof(*refbuf)*refmax);
++		refcount = 0;
++		f0->h.u5.refcallsigns = refbuf;
++		f0->h.u3.numnames  = 0;
++	}
+ 
+ 	p = filt0;
+ 	if (*p == '-') ++p;
+@@ -824,24 +839,28 @@
+ 		memset(prefixbuf, 0, sizeof(prefixbuf));
+ 		i = 0;
+ 		wildcard = 0;
+-		while (*p != 0 && *p != '/' && *p != ',') {
++		while (*p != 0 && *p != '/') {
+                  	int c = *p++;
+ 			if (c == '*') {
+-				wildcard = 1;
+-				if (wildok != MatchWild)
+-					return -1;
+-				continue;
++                          wildcard = 1;
++                          if (wildok != MatchWild) {
++                            printf("Wild-card matching not permitted, yet filter definition says: '%s'\n", filt0);
++                            return -1;
++                          }
++                          continue;
+ 			}
+-                        ++i;
+-                        if (i < (CALLSIGNLEN_MAX)) {
+-                        	*k = c;
+-                                ++k;
++                        if (i < CALLSIGNLEN_MAX) {
++                          *k++ = c;
++                          ++i;
++                        } else {
++                          printf("Too long callsign string: '%s' input: '%s'\n", prefixbuf, filt0);
++                          return -1; // invalid input
+                         }
+ 		}
+ 		*k = 0;
+ 		/* OK, we have one prefix part collected, scan source until next '/' */
+-		if (*p != 0 && *p != '/' && *p != ',') ++p;
+-		if (*p == '/' || *p == ',') ++p;
++		if (*p != 0 && *p != '/') ++p;
++		if (*p == '/') ++p;
+ 		/* If there is more of patterns, the loop continues.. */
+ 
+ 		/* Store the refprefix */
+@@ -855,11 +874,10 @@
+ 		++refcount;
+ 	}
+ 
+-	f0->h.u5.refcallsigns = refbuf;
+-	f0->h.u3.numnames     = refcount;
++	f0->h.u3.numnames = refcount;
+ 	if (extend) {
+ 		char *s;
+-		ff->h.u3.numnames     = refcount;
++		ff->h.u3.numnames = refcount;
+ 		i = strlen(ff->h.text) + strlen(filt0)+2;
+ 		if (i <= FILT_TEXTBUFSIZE) {
+ 			/* Fits in our built-in buffer block - like previous..
+@@ -1081,7 +1099,6 @@
+ 
+ 
+ 		break;
+-#if 0
+ 	case 'd':
+ 	case 'D':
+ 		/* d/digi1/digi2...  	Digipeater filter (*)	*/
+@@ -1093,7 +1110,6 @@
+ 			return 0;
+ 
+ 		break;
+-#endif
+ #if 0
+ 	case 'e':
+ 	case 'E':
+@@ -1133,11 +1149,31 @@
+ 		*/
+ 
+ 		break;
+-#if 0
++
++	case 'g':
++	case 'G':
++		//  g/call1/call2/     Group Messaging filter
++		i = filter_parse_one_callsignset(ffp, &f0, filt0, MatchWild );
++		if (i < 0)
++			return i;
++		if (i > 0) /* extended previous */
++			return 0;
++		break;
++
+ 	case 'm':
+ 	case 'M':
+ 		/*  m/dist            My range filter  */
+ 
++        	if (myloc_latstr == NULL) {
++                  printf("The M/radius_km  filter requires top-level  myloc  definition. It doesn't exist.\n");
++                  return -1;
++                }
++                
++                f0.h.type = 'r'; // internal implementation at Aprx is a RANGE filter.
++                f0.h.f_latN      = myloc_lat; // radians
++                f0.h.f_lonE      = myloc_lon; // radians
++                f0.h.u1.f_coslat = myloc_coslat;
++
+ 		i = sscanf(filt+1, "/%f", &f0.h.u2.f_dist);
+ 		if (i != 1 || f0.h.u2.f_dist < 0.1) {
+ 		  // hlog(LOG_DEBUG, "Bad filter parse: %s", filt0);
+@@ -1149,7 +1185,7 @@
+ 
+ 		// hlog(LOG_DEBUG, "Filter: %s -> M %.3f", filt0, f0.h.u2.f_dist);
+ 		break;
+-#endif
++
+ 	case 'o':
+ 	case 'O':
+ 		/* o/obje1/obj2...  	Object filter (*)	*/
+@@ -1315,6 +1351,9 @@
+ 			case '*':
+ 				f0.h.u4.bitflags |= ~T_CWOP; /* "ALL" -- excluding CWOP */
+ 				break;
++                        case '3':
++				f0.h.u4.bitflags |= T_THIRDPARTY;
++                        	break;
+ 			case 'c': case 'C':
+ 				f0.h.u4.bitflags |= T_CWOP;
+ 				break;
+@@ -1409,7 +1448,7 @@
+ 	} else
+ 		f->h.text = strdup(filt0); /* and copy of filter text */
+ #else
+-	f = malloc(sizeof(*f) + strlen(filt0));
++	f = calloc(1, sizeof(*f) + strlen(filt0));
+ 	*f = f0; /* store pre-parsed values */
+ 	f->h.text = f->textbuf;
+ 	strcpy(f->textbuf, filt); /* and copy of filter text */
+@@ -1556,22 +1595,21 @@
+ 	if (i > CALLSIGNLEN_MAX) i = CALLSIGNLEN_MAX;
+ 
+ 	/* source address  "addr">... */
+-	memset( ref.callsign, 0, sizeof(ref.callsign));
++        memset( &ref, 0, sizeof(ref) ); // clear it all
+ 	memcpy( ref.callsign, pb->data, i);
+ 
+ 	return filter_match_on_callsignset(&ref, i, f, MatchWild);
+ }
+ 
+-#if 0
+ static int filter_process_one_d(struct pbuf_t *pb, struct filter_t *f)
+ {
+ 	/* d/digi1/digi2...  	Digipeater filter
+ 
+-	   The digipeater filter will pass all packets that have been
++	   The digipeater filter will match all packets that have been
+ 	   digipeated by a particular station(s) (the station's call
+ 	   is in the path).   This filter allows the * wildcard.
+ 
+-	   25-35 filters in use at any given time.
++	   25-35 instances in APRS-IS core at any given time.
+ 	   Up to 1300 invocations per second.
+ 	*/
+ 	struct filter_refcallsign_t ref;
+@@ -1585,9 +1623,9 @@
+ 
+ 	for (i = 0; d < q; ) {
+ 		++j;
+-		if (j > 10) break; /* way too many callsigns... */
++		if (j > 10) break; // way too many callsigns... (code bug?)
+ 
+-		if (*d == ',') ++d; /* second round and onwards.. */
++		if (*d == ',') ++d; // second round and onwards..
+ 		for (i = 0; i+d <= q && i <= CALLSIGNLEN_MAX; ++i) {
+ 			if (d[i] == ',')
+ 				break;
+@@ -1595,9 +1633,9 @@
+ 
+ 		// hlog(LOG_INFO, "d:  -> (%d,%d) '%.*s'", (int)(d-pb->data), i, i, d);
+ 
+-		/* digipeater address  ",addr," */
++		// digipeater address  ",addr,"
++                memset( &ref, 0, sizeof(ref) ); // clear it all
+ 		memcpy( ref.callsign, d, i);
+-		memset( ref.callsign+i, 0, sizeof(ref)-i );
+ 
+ 		if (i > CALLSIGNLEN_MAX) i = CALLSIGNLEN_MAX;
+ 
+@@ -1609,7 +1647,6 @@
+ 	}
+ 	return 0;
+ }
+-#endif
+ 
+ #if 0
+ static int filter_process_one_e(struct pbuf_t *pb, struct filter_t *f)
+@@ -1616,7 +1653,7 @@
+ {
+ 	/* e/call1/call1/...  	Entry station filter
+ 
+-	   This filter passes all packets with the specified
++	   This filter matches all packets with the specified
+ 	   callsign-SSID(s) immediately following the q construct.
+ 	   This allows filtering based on receiving IGate, etc.
+ 	   Supports * wildcard.
+@@ -1633,8 +1670,8 @@
+ 		return 0; /* Bad Entry-station callsign */
+ 
+ 	/* entry station address  "qA*,addr," */
++	memset( &ref, 0, sizeof(ref) ); // clear it all
+ 	memcpy( ref.callsign, e, i);
+-	memset( ref.callsign+i, 0, sizeof(ref)-i );
+ 
+ 	return filter_match_on_callsignset(&ref, i, f, MatchWild);
+ }
+@@ -1644,6 +1681,7 @@
+ static int filter_process_one_f(struct pbuf_t *pb, struct filter_t *f, historydb_t *historydb)
+ {
+ 	/* f/call/dist  	Friend Range filter
++
+ 	   This is the same as the range filter except that the center is
+ 	   defined as the last known position of call.
+ 
+@@ -1678,9 +1716,9 @@
+ 	}
+ 
+ 	/* find friend's last location packet */
+-	if (f->h.hist_age < now.tv_sec) {
++	if (f->h.hist_age < tick.tv_sec) {
+ 		history = historydb_lookup( historydb, callsign, i );
+-		f->h.hist_age = now.tv_sec + hist_lookup_interval;
++		f->h.hist_age = tick.tv_sec + hist_lookup_interval;
+ 		if (!history) {
+ 		  if (debug) printf("f-filter: no history lookup result (%*s) -> return 0\n", i, callsign );
+ 		  return 0; /* no lookup result.. */
+@@ -1720,10 +1758,34 @@
+ }
+ #endif
+ 
+-#if 0
++static int filter_process_one_g(struct pbuf_t *pb, struct filter_t *f)
++{
++	/* g/call1/call2...  	Group Messaging filter
++
++	   Pass all message traffic TO calls call1/call2/...
++	   (* wild card allowed)
++
++	*/
++
++	struct filter_refcallsign_t ref;
++	int i = pb->dstname_len;
++
++	if (i > CALLSIGNLEN_MAX) i = CALLSIGNLEN_MAX;
++
++	/* source address  "addr">... */
++        memset( &ref, 0, sizeof(ref) ); // clear it all
++	memcpy( ref.callsign, pb->dstname, i);
++
++	return filter_match_on_callsignset(&ref, i, f, MatchWild);
++}
++
++
++
++#if 0  // No M filter implementation, but there is M filter parse producing R filter..
+ static int filter_process_one_m(struct pbuf_t *pb, struct filter_t *f)
+ {
+ 	/* m/dist  	My Range filter
++
+ 	   This is the same as the range filter except that the center is
+ 	   defined as the last known position of the logged in client.
+ 
+@@ -1738,40 +1800,21 @@
+ 
+ 	   Caching the historydb_lookup() result will lower CPU power
+ 	   spent on the historydb.
++
++           At Aprx: Implemented using Range filter, and prepared at parse time..
+ 	*/
+ 
+-	float lat1, lon1, coslat1;
+ 	float lat2, lon2, coslat2;
+ 	float r;
+-	history_cell_t *history;
+ 
+-
+ 	if (!(pb->flags & F_HASPOS)) /* packet with a position.. (msgs with RECEIVER's position) */
+ 		return 0;
+ 
+-	if (!c->username) /* Should not happen... */
+-		return 0;
+-
+-	if (f->h.hist_age < now.tv_sec) {
+-		history = historydb_lookup( c->username, strlen(c->username) );
+-		f->h.hist_age = now.tv_sec + hist_lookup_interval;
+-		if (!history) return 0; /* no result */
+-		f->h.u3.numnames = 1;
+-		f->h.f_latN   = history->lat;
+-		f->h.f_lonE   = history->lon;
+-		f->h.u1.f_coslat = history->coslat;
+-	}
+-	if (!f->h.u3.numnames) return 0; /* cached lookup invalid.. */
+-
+-	lat1    = f->h.f_latN;
+-	lon1    = f->h.f_lonE;
+-	coslat1 = f->h.u1.f_coslat;
+-
+ 	lat2    = pb->lat;
+ 	lon2    = pb->lng;
+ 	coslat2 = pb->cos_lat;
+ 
+-	r = maidenhead_km_distance(lat1, coslat1, lon1, lat2, coslat2, lon2);
++	r = maidenhead_km_distance(myloc_lat, myloc_coslat, myloc_lon, lat2, coslat2, lon2);
+ 	if (f->h.u2.f_dist < 0.0) {
+ 		// Test for _outside_ the range
+ 		if (r > -f->h.u2.f_dist)  /* Range is more than given limit */
+@@ -1785,6 +1828,7 @@
+ 	return 0;
+ }
+ #endif
++
+ static int filter_process_one_o(struct pbuf_t *pb, struct filter_t *f)
+ {
+ 	/* o/obj1/obj2...  	Object filter
+@@ -1801,17 +1845,22 @@
+ 	int i;
+ 	// const char *s;
+ 
+-	if ( (pb->packettype & (T_OBJECT|T_ITEM)) == 0 ) /* not an Object NOR Item */
++	if ( (pb->packettype & (T_OBJECT|T_ITEM)) == 0 ) { /* not an Object NOR Item */
++		if (debug) printf("o-filter: packet type not OBJECT nor ITEM\n");
+ 		return 0;
++	}
+ 
+ 	/* parse_aprs() has picked item/object name pointer and length.. */
+ 	// s = pb->srcname;
+ 	i = pb->srcname_len;
+-	if (i < 1) return 0; /* Bad object/item name */
++	if (i < 1) {
++		if (debug) printf("o-filter: object/item name length < 1 at the packet\n");
++		return 0; /* Bad object/item name */
++        }
+ 
+ 	/* object name */
+-	memcpy( ref.callsign, pb->info_start+1, i);
+-	memset( ref.callsign+i, 0, sizeof(ref)-i );
++	memset( &ref, 0, sizeof(ref) ); // clear it all
++	memcpy( ref.callsign, pb->srcname, i); // copy the interesting part
+ 
+ 	return filter_match_on_callsignset(&ref, i, f, MatchWild);
+ }
+@@ -1834,8 +1883,8 @@
+ 	if (i > CALLSIGNLEN_MAX) i = CALLSIGNLEN_MAX;
+ 
+ 	/* source address  "addr">... */
++	memset( &ref, 0, sizeof(ref) ); // clear it all
+ 	memcpy( ref.callsign, pb->data, i);
+-	memset( ref.callsign+i, 0, sizeof(ref)-i );
+ 
+ 	return filter_match_on_callsignset(&ref, i, f, MatchPrefix);
+ }
+@@ -2006,7 +2055,7 @@
+ 	/* OK, no overlay... */
+ 	if (f->h.u5.lens.len2 != 0) {
+ 		/* Secondary table symbols */
+-		if ( symtable != '\\' &&
++		if ( symtable != '/' &&
+ 		     memchr(f->h.text+f->h.u5.lens.len2s, symcode, f->h.u5.lens.len2) != NULL )
+ 			return f->h.negation ? 2 : 1;
+ 	}
+@@ -2016,8 +2065,8 @@
+ 
+ static int filter_process_one_t(struct pbuf_t *pb, struct filter_t *f, historydb_t *historydb)
+ {
+-	/* [-]t/poimntqsu
+-	   [-]t/poimntqsu/call/km
++	/* [-]t/poimntqsu3*c
++	   [-]t/poimntqsu3*c/call/km
+ 
+ 	   Type filter 	Pass all traffic based on packet type.
+ 	   One or more types can be defined at the same time, t/otq
+@@ -2036,6 +2085,7 @@
+ 	   t = Telemetry
+ 	   u = User-defined
+ 	   w = Weather
++           3 = 3rd party frame
+ 
+ 	   Note: The weather type filter also passes positions packets
+ 	   for positionless weather packets.
+@@ -2100,7 +2150,7 @@
+ 		   .. 60-100 lookups per second. */
+ 
+ #ifndef DISABLE_IGATE
+-		if (f->h.hist_age < now.tv_sec) {
++		if (f->h.hist_age < tick.tv_sec) {
+ 			history = historydb_lookup( historydb, callsign, callsignlen );
+ 
+ 			/* hlog( LOG_DEBUG, "Type filter with callsign range used! call='%s', range=%.1f position %sfound",
+@@ -2110,7 +2160,7 @@
+ 
+ 			if (!history) return 0; /* no lookup result.. */
+ 			f->h.u3.numnames = 1;
+-			f->h.hist_age = now.tv_sec + hist_lookup_interval;
++			f->h.hist_age = tick.tv_sec + hist_lookup_interval;
+ 			f->h.f_latN   = history->lat;
+ 			f->h.f_lonE   = history->lon;
+ 			f->h.u1.f_coslat = history->coslat;
+@@ -2168,8 +2218,8 @@
+ 	*/
+ 
+ 	/* destination address  ">addr," */
++	memset( &ref, 0, sizeof(ref) ); // clear it all
+ 	memcpy( ref.callsign,   d, i);
+-	memset( ref.callsign+i, 0, sizeof(ref)-i );
+ 
+ 	return filter_match_on_callsignset(&ref, i, f, MatchWild);
+ }
+@@ -2191,12 +2241,12 @@
+ 	case 'B':
+ 		rc = filter_process_one_b(pb, f);
+ 		break;
+-#if 0
+ 	case 'd':
+ 	case 'D':
+ 		rc = filter_process_one_d(pb, f);
+ 		break;
+ 
++#if 0
+ 	case 'e':
+ 	case 'E':
+ 		rc = filter_process_one_e(pb, f);
+@@ -2209,7 +2259,12 @@
+ 		rc = filter_process_one_f(pb, f, historydb);
+ 		break;
+ #endif
+-#if 0
++        case 'g':
++        case 'G':
++		rc = filter_process_one_g(pb, f);
++		break;
++
++#if 0 // these are compiled as R filters, no M filters exist internally
+ 	case 'm':
+ 	case 'M':
+ 		rc = filter_process_one_m(pb, f);
diff --git a/historydb.c b/historydb.c
new file mode 100644
index 0000000..9952863
--- /dev/null
+++ b/historydb.c
@@ -0,0 +1,631 @@
+/********************************************************************
+ *  APRX -- 2nd generation receive-only APRS-i-gate with            *
+ *          minimal requirement of esoteric facilities or           *
+ *          libraries of any kind beyond UNIX system libc.          *
+ *                                                                  *
+ * (c) Matti Aarnio - OH2MQK,  2007-2014                            *
+ *                                                                  *
+ ********************************************************************/
+
+#include "aprx.h"
+
+#ifndef DISABLE_IGATE
+
+#include <strings.h>
+#include <ctype.h>
+#include <math.h>
+
+
+int lastposition_storetime = 3600; // 1 hour
+
+static historydb_t **_dbs;
+static int           _dbs_count;
+
+void historydb_nopos(void) {}         /* profiler call counter items */
+void historydb_nointerest(void) {}
+void historydb_hashmatch(void) {}
+void historydb_keymatch(void) {}
+void historydb_dataupdate(void) {}
+
+// Single aprx wide alloc system
+static cellarena_t   *historydb_cells;
+
+const int historydb_cellsize  = sizeof(struct history_cell_t);
+const int historydb_cellalign = __alignof__(struct history_cell_t);
+
+void historydb_init(void)
+{
+	// printf("historydb_init() sizeof(mutex)=%d sizeof(rwlock)=%d\n",
+	//       sizeof(pthread_mutex_t), sizeof(rwlock_t));
+
+	// _dbs = malloc(sizeof(void*));
+	// _dbs_count = 0;
+
+	historydb_cells = cellinit( "historydb",
+				    historydb_cellsize,
+				    historydb_cellalign, 
+				    CELLMALLOC_POLICY_FIFO,
+				    32 /* 32 kB */,
+				    0 /* minfree */ );
+}
+
+/* new instance - for new digipeater tx */
+historydb_t *historydb_new(void)
+{
+	historydb_t *db = calloc(1, sizeof(*db));
+
+	++_dbs_count;
+	_dbs = realloc(_dbs, sizeof(void*)*_dbs_count);
+	_dbs[_dbs_count-1] = db;
+
+	return db;
+}
+
+
+
+/* Called only under WR-LOCK */
+void historydb_free(struct history_cell_t *p)
+{
+	if (p->packet != p->packetbuf)
+		free(p->packet);
+	if (p->last_heard != p->last_heard_buf)
+		free(p->last_heard);
+
+	--p->db->historydb_cellgauge;
+
+	cellfree( historydb_cells, p );
+}
+
+/* Called only under WR-LOCK */
+struct history_cell_t *historydb_alloc(historydb_t *db, int packet_len)
+{
+	struct history_cell_t *ret = cellmalloc( historydb_cells );
+	if (!ret) return NULL;
+	++db->historydb_cellgauge;
+	ret->db = db;
+	ret->last_heard = ((top_interfaces_group <= MAX_IF_GROUP) ?
+			   ret->last_heard_buf :
+			   malloc(sizeof(time_t)*top_interfaces_group));
+	return ret;
+}
+
+/*
+ *     The  historydb_atend()  does exist primarily to make valgrind
+ *     happy about lost memory object tracking.
+ */
+void historydb_atend(void)
+{
+	int j, i;
+	for (j = 0; j < _dbs_count; ++j) {
+	  historydb_t *db = _dbs[j];
+	  struct history_cell_t *hp, *hp2;
+	  for (i = 0; i < HISTORYDB_HASH_MODULO; ++i) {
+	    hp = db->hash[i];
+	    while (hp) {
+	      hp2 = hp->next;
+	      historydb_free(hp);
+	      hp = hp2;
+	    }
+	  }
+	}
+}
+
+void historydb_dump_entry(FILE *fp, const struct history_cell_t *hp)
+{
+	fprintf(fp, "%ld\t", hp->arrivaltime);
+	(void)fwrite(hp->key, hp->keylen, 1, fp);
+	fprintf(fp, "\t");
+	fprintf(fp, "%d\t%d\t", hp->packettype, hp->flags);
+	fprintf(fp, "%f\t%f\t", hp->lat, hp->lon);
+	fprintf(fp, "%d\t", hp->packetlen);
+	(void)fwrite(hp->packet, hp->packetlen, 1, fp);
+	fprintf(fp, "\n"); /* newline */
+}
+
+void historydb_dump(const historydb_t *db, FILE *fp)
+{
+	/* Dump the historydb out on text format */
+	int i;
+	struct history_cell_t *hp;
+	time_t expirytime   = tick.tv_sec - lastposition_storetime;
+
+	for ( i = 0; i < HISTORYDB_HASH_MODULO; ++i ) {
+		hp = db->hash[i];
+		for ( ; hp ; hp = hp->next )
+                	if (timecmp(hp->arrivaltime, expirytime) > 0)
+				historydb_dump_entry(fp, hp);
+	}
+}
+
+
+static int foldhash( const unsigned int h1 )
+{
+	unsigned int h2 = h1 ^ (h1 >> 7) ^ (h1 >> 14); /* fold hash bits.. */
+	return (h2 % HISTORYDB_HASH_MODULO);
+}
+
+
+/* insert... */
+
+history_cell_t *historydb_insert(historydb_t *db, const struct pbuf_t *pb)
+{
+	return historydb_insert_(db, pb, 0);
+}
+
+history_cell_t *historydb_insert_(historydb_t *db, const struct pbuf_t *pb, const int insertall)
+{
+	int i;
+	unsigned int h1;
+	int isdead = 0, keylen;
+	struct history_cell_t **hp, *cp, *cp1;
+
+	time_t expirytime   = tick.tv_sec - lastposition_storetime;
+
+	char keybuf[CALLSIGNLEN_MAX+2];
+	char *s;
+
+	// (pb->flags & F_HASPOS) <-- that indicates that at parse time
+	//                            the packet either had a position, or
+	//                            a position information was supplemented
+	//                            to it via historydb lookup
+
+	if (!insertall && !(pb->packettype & T_POSITION)) {  // <-- packet has position data
+		++db->historydb_noposcount;
+		historydb_nopos(); /* debug thing -- profiling counter */
+		return NULL; /* No positional data... */
+	}
+
+	/* NOTE: Parser does set on MESSAGES the RECIPIENTS
+	**       location if such is known! We do not want them...
+	**       .. and several other cases where packet has no
+	**       positional data in it, but source callsign may
+	**       have previous entry with data.
+	*/
+
+	/* NOTE2: We could use pb->srcname, and pb->srcname_len here,
+	**        but then we would not know if this is a "kill-item"
+	*/
+
+	keybuf[CALLSIGNLEN_MAX] = 0;
+	if (pb->packettype & T_OBJECT) {
+		/* Pick object name  ";item  *" */
+		memcpy( keybuf, pb->info_start+1, CALLSIGNLEN_MAX+1);
+		keybuf[CALLSIGNLEN_MAX+1] = 0;
+		s = strchr(keybuf, '*');
+		if (s) *s = 0;
+		else {
+			s = strchr(keybuf, '_'); // kill an object!
+			if (s) {
+				*s = 0;
+				isdead = 1;
+			}
+		}
+		s = keybuf + strlen(keybuf);
+		for ( ; s > keybuf; --s ) {  // tail space padded..
+			if (*s == ' ') *s = ' ';
+			else break;
+		}
+
+	} else if (pb->packettype & T_ITEM) {
+		// Pick item name  ") . . . !"  or ") . . . _"
+		memcpy( keybuf, pb->info_start+1, CALLSIGNLEN_MAX+1);
+		keybuf[CALLSIGNLEN_MAX+1] = 0;
+		s = strchr(keybuf, '!');
+		if (s) *s = 0;
+		else {
+			s = strchr(keybuf, '_'); // kill an item!
+			if (s) {
+				*s = 0;
+				isdead = 1;
+			}
+		}
+
+	} else if (pb->packettype & T_MESSAGE) {
+		// Pick originator callsign
+		memcpy( keybuf, pb->data, CALLSIGNLEN_MAX) ;
+		s = strchr(keybuf, '>');
+		if (s) *s = 0;
+
+	} else if (pb->packettype & T_POSITION) {
+		// Pick originator callsign
+		memcpy( keybuf, pb->data, CALLSIGNLEN_MAX) ;
+		s = strchr(keybuf, '>');
+		if (s) *s = 0;
+
+	} else {
+        	if (insertall) {
+                	// Pick originator callsign
+                	memcpy( keybuf, pb->data, CALLSIGNLEN_MAX) ;
+                        s = strchr(keybuf, '>');
+                        if (s) *s = 0;
+
+                } else {
+
+                	historydb_nointerest(); // debug thing -- a profiling counter
+                        return NULL; // Not a packet with positional data, not interested in...
+                }
+	}
+	keylen = strlen(keybuf);
+
+	++db->historydb_inserts;
+
+	h1 = keyhash(keybuf, keylen, 0);
+	i  = foldhash(h1);
+	if (debug > 1) printf(" key='%s' hash=%d", keybuf, i);
+
+	cp = cp1 = NULL;
+	hp = &db->hash[i];
+
+	// scan the hash-bucket chain, and do incidential obsolete data discard
+	while (( cp = *hp )) {
+		if (timecmp(cp->arrivaltime, expirytime) < 0) {
+			// OLD...
+			*hp = cp->next;
+			cp->next = NULL;
+			historydb_free(cp);
+			continue;
+		}
+		if ( (cp->hash1 == h1)) {
+		       // Hash match, compare the key
+		    historydb_hashmatch(); // debug thing -- a profiling counter
+		    ++db->historydb_hashmatches;
+		    if ( cp->keylen == keylen &&
+			 (memcmp(cp->key, keybuf, keylen) == 0) ) {
+		  	// Key match!
+		    	historydb_keymatch(); // debug thing -- a profiling counter
+			++db->historydb_keymatches;
+			if (isdead) {
+				// Remove this key..
+				*hp = cp->next;
+				cp->next = NULL;
+				historydb_free(cp);
+				continue;
+			} else {
+				historydb_dataupdate(); // debug thing -- a profiling counter
+				// Update the data content
+				cp1 = cp;
+				if (pb->flags & F_HASPOS) {
+				  // Update coordinate, if available
+				  cp->lat         = pb->lat;
+				  cp->coslat      = pb->cos_lat;
+				  cp->lon         = pb->lng;
+				  cp->positiontime = pb->t;
+				}
+				cp->packettype  = pb->packettype;
+				cp->flags      |= pb->flags;
+
+				cp->arrivaltime = pb->t;
+				cp->flags       = pb->flags;
+				cp->packetlen   = pb->packet_len;
+				cp->last_heard[pb->source_if_group] = pb->t;
+				if ( cp->packet != cp->packetbuf )
+					free( cp->packet );
+
+				cp->packet = cp->packetbuf; // default case
+				if ( cp->packetlen > sizeof(cp->packetbuf) ) {
+				  // Needs bigger buffer than pre-allocated one,
+				  // thus it retrieves that one from heap.
+				  cp->packet = malloc( cp->packetlen );
+				}
+				memcpy( cp->packet, pb->data, cp->packetlen );
+			}
+		    }
+		} // .. else no match, advance hp..
+		hp = &(cp -> next);
+	}
+
+	if (!cp1 && !isdead) {
+		// Not found on this chain, append it!
+		cp = historydb_alloc(db, pb->packet_len);
+		cp->next = NULL;
+		memcpy(cp->key, keybuf, keylen);
+		cp->key[keylen] = 0; /* zero terminate */
+		cp->keylen = keylen;
+		cp->hash1 = h1;
+
+		cp->lat         = pb->lat;
+		cp->coslat      = pb->cos_lat;
+		cp->lon         = pb->lng;
+		cp->arrivaltime = pb->t;
+		cp->packettype  = pb->packettype;
+		cp->flags       = pb->flags;
+		cp->last_heard[pb->source_if_group] = pb->t;
+		if (pb->flags & F_HASPOS)
+		  cp->positiontime = pb->t;
+
+		cp->packetlen   = pb->packet_len;
+		cp->packet      = cp->packetbuf; // default case
+		if (cp->packetlen > sizeof(cp->packetbuf)) {
+		  // Needs bigger buffer than pre-allocated one,
+		  // thus it retrieves that one from heap.
+		  cp->packet = malloc( cp->packetlen );
+		}
+
+                // Initial value is 32.0 tokens to permit
+                // digipeat a packet source at the first
+                // time it has been heard -- including to
+                // possible multiple transmitters. Within
+                // about 5 seconds this will be dropped
+                // down to max burst rate of the srcratefilter
+                // parameter. This code does not know how
+                // many interfaces there are...
+                cp->tokenbucket = 32.0;
+
+		*hp = cp; 
+	}
+
+	return *hp;
+}
+
+history_cell_t *historydb_insert_heard(historydb_t *db, const struct pbuf_t *pb)
+{
+	int i;
+	unsigned int h1;
+	int keylen;
+	struct history_cell_t **hp, *cp, *cp1;
+
+	time_t expirytime   = tick.tv_sec - lastposition_storetime;
+
+	char keybuf[CALLSIGNLEN_MAX+2];
+	char *s;
+
+
+	/* NOTE: Parser does set on MESSAGES the RECIPIENTS
+	**       location if such is known! We do not want them...
+	**       .. and several other cases where packet has no
+	**       positional data in it, but source callsign may
+	**       have previous entry with data.
+	*/
+
+	/* NOTE2: We could use pb->srcname, and pb->srcname_len here,
+	**        but then we would not know if this is a "kill-item"
+	*/
+
+	keybuf[CALLSIGNLEN_MAX+1] = 0;
+
+	if (pb->packettype & T_OBJECT) {
+	  historydb_nointerest(); // debug thing -- a profiling counter
+	  if (debug > 1) printf(" .. objects not interested\n");
+	  return NULL; // Not interested in ";objects :"
+
+	} else if (pb->packettype & T_ITEM) {
+	  historydb_nointerest(); // debug thing -- a profiling counter
+	  if (debug > 1) printf(" .. items not interested\n");
+	  return NULL; // Not interested in ")items..."
+
+	} else if (pb->packettype & T_MESSAGE) {
+	  // Pick originator callsign
+	  //memcpy( keybuf, pb->data, CALLSIGNLEN_MAX) ;
+	  //s = strchr(keybuf, '>');
+	  //if (s) *s = 0;
+          memcpy(keybuf, pb->srcname, pb->srcname_len);
+          keybuf[pb->srcname_len] = 0;
+
+	} else if (pb->packettype & T_POSITION) {
+	  // Something with a position (but not an item or an object)
+	  //memcpy( keybuf, pb->data, CALLSIGNLEN_MAX) ;
+	  //s = strchr(keybuf, '>');
+	  //if (s) *s = 0;
+          memcpy(keybuf, pb->srcname, pb->srcname_len);
+          keybuf[pb->srcname_len] = 0;
+
+	} else {
+	  if (debug > 1) printf(" .. other not interested\n");
+	  historydb_nointerest(); // debug thing -- a profiling counter
+	  return NULL; // Not a packet with positional data, not interested in...
+	}
+	keylen = strlen(keybuf);
+
+	++db->historydb_inserts;
+
+	h1 = keyhash(keybuf, keylen, 0);
+	i  = foldhash(h1);
+	if (debug > 1) printf(" key='%s' hash=%d", keybuf, i);
+
+	cp1 = NULL;
+	hp = &db->hash[i];
+
+	// scan the hash-bucket chain, and do incidential obsolete data discard
+	while (( cp = *hp ) != NULL) {
+        	if (timecmp(cp->arrivaltime, expirytime) < 0) {
+			// OLD...
+			if (debug > 1) printf(" .. dropping old record\n");
+			*hp = cp->next;
+			cp->next = NULL;
+			historydb_free(cp);
+			continue;
+		}
+		if ( (cp->hash1 == h1)) {
+		       // Hash match, compare the key
+		    historydb_hashmatch(); // debug thing -- a profiling counter
+		    ++db->historydb_hashmatches;
+		    if (debug > 1) printf(" .. found matching hash");
+		    if ( cp->keylen == keylen &&
+			 (memcmp(cp->key, keybuf, keylen) == 0) ) {
+		  	// Key match!
+		        if (debug > 1) printf(" .. found matching key!\n");
+
+		    	historydb_keymatch(); // debug thing -- a profiling counter
+			++db->historydb_keymatches;
+
+			historydb_dataupdate(); // debug thing -- a profiling counter
+			// Update the data content
+			cp1 = cp;
+			if (pb->flags & F_HASPOS) {
+			  // Update coordinate, if available
+			  cp->lat         = pb->lat;
+			  cp->coslat      = pb->cos_lat;
+			  cp->lon         = pb->lng;
+			  cp->positiontime = pb->t;
+			  cp->arrivaltime  = pb->t;
+			}
+			cp->flags      |= pb->flags;
+
+			// Track packet source timestamps
+			cp->last_heard[pb->source_if_group] = pb->t;
+
+			// Don't save a message on top of positional packet
+			if (!(pb->packettype & T_MESSAGE)) {
+			  cp->packettype  = pb->packettype;
+			  cp->arrivaltime = pb->t;
+			  cp->flags       = pb->flags;
+			  cp->packetlen   = pb->packet_len;
+			  if ( cp->packet != cp->packetbuf )
+			    free( cp->packet );
+				  
+			  cp->packet = cp->packetbuf; // default case
+			  if ( cp->packetlen > sizeof(cp->packetbuf) ) {
+			    // Needs bigger buffer than pre-allocated one,
+			    // thus it retrieves that one from heap.
+			    cp->packet = malloc( cp->packetlen );
+			  }
+			  memcpy( cp->packet, pb->data, cp->packetlen );
+			}
+		    }
+		} // .. else no match, advance hp..
+		hp = &(cp -> next);
+	}
+
+	if (!cp1) {
+		if (debug > 1) printf(" .. inserting new history entry.\n");
+
+		// Not found on this chain, append it!
+		cp = historydb_alloc(db, pb->packet_len);
+		cp->next = NULL;
+		memcpy(cp->key, keybuf, keylen);
+		cp->key[keylen] = 0; /* zero terminate */
+		cp->keylen = keylen;
+		cp->hash1 = h1;
+
+		cp->lat         = pb->lat;
+		cp->coslat      = pb->cos_lat;
+		cp->lon         = pb->lng;
+		cp->arrivaltime = pb->t;
+		cp->packettype  = pb->packettype;
+		cp->flags       = pb->flags;
+		cp->last_heard[pb->source_if_group] = pb->t;
+		if (pb->flags & F_HASPOS)
+		  cp->positiontime = pb->t;
+
+		cp->packetlen   = pb->packet_len;
+		cp->packet      = cp->packetbuf; // default case
+		if (cp->packetlen > sizeof(cp->packetbuf)) {
+		  // Needs bigger buffer than pre-allocated one,
+		  // thus it retrieves that one from heap.
+		  cp->packet = malloc( cp->packetlen );
+		}
+
+		*hp = cp; 
+	}
+	else
+	  return cp1; // != NULL
+
+	return *hp;
+}
+
+
+/* lookup... */
+
+history_cell_t *historydb_lookup(historydb_t *db, const char *keybuf, const int keylen)
+{
+	int i;
+	unsigned int h1;
+	struct history_cell_t *cp;
+
+	// validity is 5 minutes shorter than expiration time..
+	time_t validitytime   = tick.tv_sec - lastposition_storetime + 5*60;
+
+	++db->historydb_lookups;
+
+	h1 = keyhash(keybuf, keylen, 0);
+	i  = foldhash(h1);
+
+	cp = db->hash[i];
+
+	if (debug > 1) printf("historydb_lookup(%*s) -> i=%d", keylen, keybuf, i);
+
+	for ( ; cp != NULL ; cp = cp->next ) {
+	  if ( (cp->hash1 == h1) &&
+	       // Hash match, compare the key
+	       (cp->keylen == keylen) ) {
+	    if (debug > 1) printf(" .. hash match");
+	    if (memcmp(cp->key, keybuf, keylen) == 0) {
+	      if (debug > 1) printf(" .. key match");
+	      // Key match!
+	      if (timecmp(cp->arrivaltime, validitytime) > 0) {
+		if (debug > 1) printf(" .. and not too old\n");
+		return cp;
+	      }
+	    }
+	  }
+	}
+	if (debug > 1) printf(" .. no match\n");
+	return NULL;
+}
+
+
+
+/*
+ *	The  historydb_cleanup()  exists to purge too old data out of
+ *	the database at regular intervals.  Call this about once a minute.
+ */
+
+static void historydb_cleanup(historydb_t *db)
+{
+	struct history_cell_t **hp, *cp;
+	int i, cleancount = 0;
+
+	if (debug > 1) printf("historydb_cleanup() ");
+
+	time_t expirytime   = tick.tv_sec - lastposition_storetime;
+
+	for (i = 0; i < HISTORYDB_HASH_MODULO; ++i) {
+		hp = &db->hash[i];
+
+		// multiple locks ? one for each bucket, or for a subset of buckets ?
+
+		while (( cp = *hp )) {
+                	if (timecmp(cp->arrivaltime, expirytime) < 0) {
+				// OLD...
+				*hp = cp->next;
+				cp->next = NULL;
+				historydb_free(cp);
+				++cleancount;
+				if (debug > 1) printf(" drop(%p) i=%d", cp, i);
+
+			} else {
+				/* No expiry, just advance the pointer */
+				hp = &(cp -> next);
+			}
+		}
+	}
+	if (debug > 1) printf(" .. done.\n");
+}
+
+
+static time_t next_cleanup_time;
+
+int  historydb_prepoll(struct aprxpolls *app)
+{
+	return 0;
+}
+
+int  historydb_postpoll(struct aprxpolls *app)
+{
+	int i;
+        // Limit next cleanup to be at most 60 second in future
+        // (just in case the system time jumped back)
+        if (next_cleanup_time >= tick.tv_sec+61) {
+          next_cleanup_time = tick.tv_sec + 60;
+        }
+	if (next_cleanup_time >= tick.tv_sec) return 0;
+	next_cleanup_time = tick.tv_sec + 60; // A minute from now..
+
+	for (i = 0; i < _dbs_count; ++i) {
+	  historydb_cleanup(_dbs[i]);
+	}
+
+	return 0;
+}
+
+#endif
diff --git a/historydb.h b/historydb.h
new file mode 100644
index 0000000..e52d637
--- /dev/null
+++ b/historydb.h
@@ -0,0 +1,101 @@
+/********************************************************************
+ *  APRX -- 2nd generation receive-only APRS-i-gate with            *
+ *          minimal requirement of esoteric facilities or           *
+ *          libraries of any kind beyond UNIX system libc.          *
+ *                                                                  *
+ * (c) Matti Aarnio - OH2MQK,  2007-2014                            *
+ *                                                                  *
+ ********************************************************************/
+
+
+/*
+ *	The historydb contains positional packet data in form of:
+ *	  - position packet
+ *	  - objects
+ *	  - items
+ *	Keying varies, origination callsign of positions, name
+ *	for object/item.
+ *
+ *	Inserting does incidential cleanup scanning while traversing
+ *	hash chains.
+ *
+ *	In APRS-IS there are about 25 000 distinct callsigns or
+ *	item or object names with position information PER WEEK.
+ *	DB lifetime of 48 hours cuts that down a bit more.
+ *	Memory usage is around 3-4 MB
+ *
+ *  --------------
+ *
+ *      On Tx-IGate the number of distinct callsigns is definitely
+ *      lower...
+ *
+ */
+
+#ifndef __HISTORYDB_H__
+#define __HISTORYDB_H__
+
+#ifdef HAVE_STDINT_H
+# include <stdint.h>
+#endif
+#define HISTORYDB_HASH_MODULO 128 /* fold bits: 7 & 14 */
+
+struct pbuf_t;      // forward declarator
+struct historydb_t; // forward..
+
+typedef struct history_cell_t {
+	struct history_cell_t *next;
+	struct historydb_t    *db;
+
+	time_t       arrivaltime;
+	time_t       positiontime; // When last position was received
+	time_t       *last_heard;  // Usually points to last_heard_buf[]
+	time_t	     last_heard_buf[MAX_IF_GROUP];
+
+	float	     tokenbucket; // Source callsign specific TokenBucket filter
+                                  // Digi allocates HistoryDb per transmitter.
+
+	uint16_t     packettype;
+	uint16_t     flags;
+	uint16_t     packetlen;
+	uint8_t	     keylen;
+	char         key[CALLSIGNLEN_MAX+2];
+
+	float	lat, coslat, lon;
+	uint32_t hash1;
+
+	char *packet;
+	char packetbuf[170]; /* Maybe a dozen packets are bigger than
+				170 bytes long out of some 17 000 .. */
+} history_cell_t;
+
+typedef struct historydb_t {
+	struct history_cell_t *hash[HISTORYDB_HASH_MODULO];
+
+	// monitor counters and gauges
+	long historydb_inserts;
+	long historydb_lookups;
+	long historydb_hashmatches;
+	long historydb_keymatches;
+	long historydb_cellgauge;
+	long historydb_noposcount;
+} historydb_t;
+
+
+extern void historydb_init(void);
+
+extern historydb_t *historydb_new(void);
+
+extern void historydb_dump(const historydb_t *, FILE *fp);
+
+extern void historydb_atend(void);
+
+extern int  historydb_prepoll(struct aprxpolls *app);
+extern int  historydb_postpoll(struct aprxpolls *app);
+
+/* insert and lookup... */
+extern history_cell_t *historydb_insert(historydb_t *db, const struct pbuf_t*);
+extern history_cell_t *historydb_insert_(historydb_t *, const struct pbuf_t *, const int);
+extern history_cell_t *historydb_insert_heard(historydb_t *db, const struct pbuf_t*);
+extern history_cell_t *historydb_lookup(historydb_t *db, const char *keybuf, const int keylen);
+
+#endif
diff --git a/hlog.c b/hlog.c
new file mode 100644
index 0000000..1966bb9
--- /dev/null
+++ b/hlog.c
@@ -0,0 +1,561 @@
+/*
+ *	aprsc
+ *
+ *	(c) Heikki Hannikainen, OH7LZB <hessu at hes.iki.fi>
+ *
+ *	This program is licensed under the BSD license, which can be found
+ *	in the file LICENSE.
+ *
+ */
+
+/*
+ *	log.c
+ *
+ *	logging facility with configurable log levels and
+ *	logging destinations
+ */
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <syslog.h>
+#include <unistd.h>
+#include <time.h>
+#include <sys/time.h>
+#include <string.h>
+#include <pthread.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/file.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#include "hlog.h"
+#include "hmalloc.h"
+#include "rwlock.h"
+
+int log_dest = L_DEFDEST;	/* Logging destination */
+int log_level = LOG_INFO;	/* Logging level */
+int log_facility = LOG_DAEMON;	/* Logging facility */
+char *log_name = NULL;		/* Logging name */
+
+char log_basename[] = "aprsc.log";
+char *log_dir = NULL;		/* Access log directory */
+char *log_fname = NULL;		/* Access log file name */
+int log_file = -1;		/* If logging to a file, the file name */
+rwlock_t log_file_lock = RWL_INITIALIZER;
+
+char accesslog_basename[] = "aprsc.access.log";
+char *accesslog_dir = NULL;	/* Access log directory */
+char *accesslog_fname = NULL;	/* Access log file name */
+int accesslog_file = -1;	/* Access log fd */
+rwlock_t accesslog_lock = RWL_INITIALIZER;
+
+int log_rotate_size = 0;	/* Rotate log when it reaches a given size */
+int log_rotate_num = 5;		/* How many logs to keep around */
+
+char *log_levelnames[] = {
+	"EMERG",
+	"ALERT",
+	"CRIT",
+	"ERROR",
+	"WARNING",
+	"NOTICE",
+	"INFO",
+	"DEBUG",
+	NULL
+};
+
+char *log_destnames[] = {
+	"none",
+	"stderr",
+	"syslog",
+	"file",
+	NULL
+};
+
+/*
+ *	Quote a string, C-style. dst will be null-terminated, always.
+ */
+
+static int str_quote(char *dst, int dst_len, const char *src, int src_len)
+{
+	int si;
+	int di = 0;
+	int dst_use_len = dst_len - 2; /* leave space for terminating NUL and escaping an escape  */
+	unsigned char c;
+	
+	for (si = 0; si < src_len; si++) {
+		if (di >= dst_use_len)
+			break;
+		
+		c = (unsigned char) src[si];
+		
+		/* printable ASCII */
+		if (c >= 0x20 && c < 0x7f) {
+			/* escape the escape (space reserved already) */
+			if (c == '\\')
+				dst[di++] = '\\';
+			
+			dst[di++] = c;
+			continue;
+		}
+		
+		/* hex escape, is going to take more space */
+		if (di >= dst_use_len - 4)
+			break;
+		
+		dst[di++] = '\\';
+		dst[di++] = 'x';
+		di += snprintf(dst + di, 3, "%.2X", c);
+	}
+	
+	dst[di++] = 0;
+	
+	return di;
+}
+
+/*
+ *	Append a formatted string to a dynamically allocated string
+ */
+
+char *str_append(char *s, const char *fmt, ...)
+{
+	va_list args;
+	char buf[LOG_LEN];
+	int len;
+	char *ret;
+	
+	va_start(args, fmt);
+	vsnprintf(buf, LOG_LEN, fmt, args);
+	va_end(args);
+	buf[LOG_LEN-1] = 0;
+	
+	len = strlen(s);
+	ret = hrealloc(s, len + strlen(buf) + 1);
+	strcpy(ret + len, buf);
+	
+	return ret;
+}
+
+/*
+ *	Pick a log level
+ */
+
+int pick_loglevel(char *s, char **names)
+{
+	int i;
+	
+	for (i = 0; (names[i]); i++)
+		if (!strcasecmp(s, names[i]))
+			return i;
+			
+	return -1;
+}
+
+/*
+ *	Open log
+ */
+ 
+int open_log(char *name, int reopen)
+{
+	if (!reopen)
+		rwl_wrlock(&log_file_lock);
+		
+	if (log_name)
+		hfree(log_name);
+		
+	if (!(log_name = hstrdup(name))) {
+		fprintf(stderr, "aprsc logger: out of memory!\n");
+		exit(1);
+	}
+	
+	if (log_dest == L_SYSLOG)
+		openlog(name, LOG_NDELAY|LOG_PID, log_facility);
+	
+	if (log_dest == L_FILE) {
+		if (log_fname)
+			hfree(log_fname);
+		
+		log_fname = hmalloc(strlen(log_dir) + strlen(log_basename) + 2);
+		sprintf(log_fname, "%s/%s", log_dir, log_basename);
+		
+		log_file = open(log_fname, O_WRONLY|O_CREAT|O_APPEND, S_IRUSR|S_IWUSR|S_IRGRP);
+		if (log_file < 0) {
+			fprintf(stderr, "aprsc logger: Could not open %s: %s\n", log_fname, strerror(errno));
+			exit(1);
+		}
+	}
+	
+	rwl_wrunlock(&log_file_lock);
+	
+	if (log_dest == L_FILE)
+		hlog(LOG_DEBUG, "Log file %s %sopened on fd %d", log_fname, (reopen) ? "re" : "", log_file);
+	
+	return 0;
+}
+
+/*
+ *	Close log
+ */
+ 
+int close_log(int reopen)
+{
+	hlog(LOG_DEBUG, "close_log");
+	
+	char *s = NULL;
+	if (log_name)
+		s = hstrdup(log_name);
+	
+	rwl_wrlock(&log_file_lock);
+	
+	if (log_name) {
+		hfree(log_name);
+		log_name = NULL;
+	}
+	
+	if (log_dest == L_SYSLOG) {
+		closelog();
+	} else if (log_dest == L_FILE) {
+		if (log_file >= 0) {
+			if (close(log_file))
+				fprintf(stderr, "aprsc logger: Could not close log file %s: %s\n", log_fname, strerror(errno));
+			log_file = -1;
+		}
+		if (log_fname) {
+			hfree(log_fname);
+			log_fname = NULL;
+		}
+	}
+	
+	if (reopen && s)
+		open_log(s, 1);
+	
+	if (!reopen)
+		rwl_wrunlock(&log_file_lock);
+	
+	if (s)
+		hfree(s);
+	
+	return 0;
+}
+
+/*
+ *	Rotate the log file
+ */
+
+int rotate_log(void)
+{
+	char *tmp;
+	int i;
+	char *r1, *r2;
+	
+	if (rwl_trywrlock(&log_file_lock)) {
+		fprintf(stderr, "failed to wrlock log_file_lock for rotation\n");
+		return 0;
+	}
+	
+	// check if still oversize and not rotated by another thread
+	off_t l = lseek(log_file, 0, SEEK_CUR);
+	if (l < log_rotate_size) {
+		rwl_wrunlock(&log_file_lock);
+		return 0;
+	}
+	
+	// rename
+	tmp = hmalloc(strlen(log_fname) + 6);
+	sprintf(tmp, "%s.tmp", log_fname);
+	if (rename(log_fname, tmp) != 0) {
+		fprintf(stderr, "aprsc logger: Failed to rename %s to %s: %s\n", log_fname, tmp, strerror(errno));
+		// continue anyway, try to reopen
+	}
+	
+	// reopen
+	if (close(log_file))
+		fprintf(stderr, "aprsc logger: Could not close log file %s: %s\n", log_fname, strerror(errno));
+	
+	log_file = open(log_fname, O_WRONLY|O_CREAT|O_APPEND, S_IRUSR|S_IWUSR|S_IRGRP);
+	if (log_file < 0) {
+		fprintf(stderr, "aprsc logger: Could not open %s: %s\n", log_fname, strerror(errno));
+		log_file = -1;
+	}
+	
+	rwl_wrunlock(&log_file_lock);
+	
+	// do the rest of the rotation
+	r1 = hmalloc(strlen(log_fname) + 16);
+	r2 = hmalloc(strlen(log_fname) + 16);
+	
+	for (i = log_rotate_num-1; i > 0; i--) {
+		sprintf(r1, "%s.%d", log_fname, i-1);
+		sprintf(r2, "%s.%d", log_fname, i);
+		if (rename(r1, r2) != 0 && errno != ENOENT) {
+			fprintf(stderr, "rename %s => %s failed:%s\n", r1, r2, strerror(errno));
+		}
+	}
+	
+	if (rename(tmp, r1) != 0) {
+		fprintf(stderr, "aprsc logger: Failed to rename %s to %s: %s\n", tmp, r1, strerror(errno));
+	}
+	
+	hfree(tmp);
+	hfree(r1);
+	hfree(r2);
+	
+	return 0;
+}
+
+static int hlog_write(int priority, const char *s)
+{
+	struct tm lt;
+	struct timeval tv;
+	char wb[LOG_LEN];
+	int len, w;
+	
+        // Wall clock time
+	gettimeofday(&tv, NULL);
+	gmtime_r(&tv.tv_sec, &lt);
+	
+	if (log_dest & L_STDERR) {
+		rwl_rdlock(&log_file_lock);
+		fprintf(stderr, "%4d/%02d/%02d %02d:%02d:%02d.%06d %s[%d:%lx] %s: %s\n",
+			lt.tm_year + 1900, lt.tm_mon + 1, lt.tm_mday, lt.tm_hour, lt.tm_min, lt.tm_sec, (int)tv.tv_usec,
+			(log_name) ? log_name : "aprsc", (int)getpid(), (unsigned long int)pthread_self(), log_levelnames[priority], s);
+		rwl_rdunlock(&log_file_lock);
+		
+	}
+	
+	if ((log_dest & L_FILE) && (log_file >= 0)) {
+		len = snprintf(wb, LOG_LEN, "%4d/%02d/%02d %02d:%02d:%02d.%06d %s[%d:%lx] %s: %s\n",
+			       lt.tm_year + 1900, lt.tm_mon + 1, lt.tm_mday, lt.tm_hour, lt.tm_min, lt.tm_sec, (int)tv.tv_usec,
+			       (log_name) ? log_name : "aprsc", (int)getpid(), (unsigned long int)pthread_self(), log_levelnames[priority], s);
+		wb[LOG_LEN-1] = 0;
+		rwl_rdlock(&log_file_lock);
+		if ((w = write(log_file, wb, len)) != len)
+			fprintf(stderr, "aprsc logger: Could not write to %s (fd %d): %s\n", log_fname, log_file, strerror(errno));
+		rwl_rdunlock(&log_file_lock);
+		
+		if (log_rotate_size) {
+			off_t l = lseek(log_file, 0, SEEK_CUR);
+			if (l >= log_rotate_size) {
+				rotate_log();
+			}
+		}
+		
+	}
+	
+	if (log_dest & L_SYSLOG) {
+		rwl_rdlock(&log_file_lock);
+		syslog(priority, "%s: %s", log_levelnames[priority], s);
+		rwl_rdunlock(&log_file_lock);
+	}
+	
+	return 1;
+}
+
+/*
+ *	Log a message with a packet (will be quoted)
+ */
+
+int hlog(int priority, const char *fmt, ...)
+{
+	va_list args;
+	char s[LOG_LEN];
+	
+	if (priority > 7)
+		priority = 7;
+	else if (priority < 0)
+		priority = 0;
+	
+	if (priority > log_level)
+		return 0;
+	
+	va_start(args, fmt);
+	vsnprintf(s, LOG_LEN, fmt, args);
+	va_end(args);
+	
+	return hlog_write(priority, s);
+}
+
+
+/*
+ *	Log a message, with a packet in the end.
+ *	Packet will be quoted.
+ */
+
+int hlog_packet(int priority, const char *packet, int packetlen, const char *fmt, ...)
+{
+	va_list args;
+	char s[LOG_LEN];
+	int l;
+	
+	if (priority > 7)
+		priority = 7;
+	else if (priority < 0)
+		priority = 0;
+	
+	if (priority > log_level)
+		return 0;
+	
+	va_start(args, fmt);
+	l = vsnprintf(s, LOG_LEN, fmt, args);
+	va_end(args);
+	
+	str_quote(s + l, LOG_LEN - l, packet, packetlen);
+	
+	return hlog_write(priority, s);
+}
+
+/*
+ *	Open access log
+ */
+
+int accesslog_open(char *logd, int reopen)
+{
+	if (!reopen)
+		rwl_wrlock(&accesslog_lock);
+	
+	if (accesslog_fname)
+		hfree(accesslog_fname);
+		
+	if (accesslog_dir)
+		hfree(accesslog_dir);
+		
+	accesslog_dir = hstrdup(logd);
+	accesslog_fname = hmalloc(strlen(accesslog_dir) + strlen(accesslog_basename) + 2);
+	sprintf(accesslog_fname, "%s/%s", accesslog_dir, accesslog_basename);
+	
+	accesslog_file = open(accesslog_fname, O_WRONLY|O_CREAT|O_APPEND, S_IRUSR|S_IWUSR|S_IRGRP);
+	if (accesslog_file < 0)
+		hlog(LOG_CRIT, "Could not open %s: %s", accesslog_fname, strerror(errno));
+	
+	rwl_wrunlock(&accesslog_lock);
+	
+	return accesslog_file;
+}
+
+/*
+ *	Close access log
+ */
+ 
+int accesslog_close(char *reopenpath)
+{
+	hlog(LOG_DEBUG, "Closing access log...");
+	rwl_wrlock(&accesslog_lock);
+	hlog(LOG_DEBUG, "Closing access log, got lock");
+	
+	if (close(accesslog_file))
+		hlog(LOG_CRIT, "Could not close %s: %s", accesslog_fname, strerror(errno));
+	hfree(accesslog_fname);
+	hfree(accesslog_dir);
+	accesslog_fname = accesslog_dir = NULL;
+	accesslog_file = -1;
+	
+	if (reopenpath) {
+		return accesslog_open(reopenpath, 1);
+	} else {
+		rwl_wrunlock(&accesslog_lock);
+		return 0;
+	}
+}
+
+/*
+ *	Log an access log message
+ */
+
+int accesslog(const char *fmt, ...)
+{
+	va_list args;
+	char s[LOG_LEN], wb[LOG_LEN];
+	time_t t;
+	struct tm lt;
+	int len;
+	ssize_t w;
+	
+	va_start(args, fmt);
+	vsnprintf(s, LOG_LEN, fmt, args);
+	va_end(args);
+	s[LOG_LEN-1] = 0;
+	
+	time(&t);
+	gmtime_r(&t, &lt);
+	
+	len = snprintf(wb, LOG_LEN, "[%4.4d/%2.2d/%2.2d %2.2d:%2.2d:%2.2d] %s\n",
+		lt.tm_year + 1900, lt.tm_mon + 1, lt.tm_mday, lt.tm_hour, lt.tm_min, lt.tm_sec, s);
+	wb[LOG_LEN-1] = 0;
+	
+	rwl_rdlock(&accesslog_lock);
+	if (accesslog_file >= 0) {
+		if ((w = write(accesslog_file, wb, len)) != len)
+			hlog(LOG_CRIT, "Could not write to %s (fd %d): %s", accesslog_fname, accesslog_file, strerror(errno));
+	} else {
+		if (accesslog_file != -666) {
+			hlog(LOG_ERR, "Access log not open, log lines are lost!");
+			accesslog_file = -666;
+		}
+	}
+	rwl_rdunlock(&accesslog_lock);
+	
+	return 1;
+}
+
+/*
+ *	Write my PID to file, after locking the pid file.
+ *	Leaves the file descriptor open so that the lock will be held
+ *	as long as the process is running.
+ */
+
+int pidfile_fd = -1;
+
+int writepid(char *name)
+{
+	int f;
+	char s[32];
+	int l;
+	
+	f = open(name, O_WRONLY|O_CREAT, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
+	if (f < 0) {
+		hlog(LOG_CRIT, "Could not open %s for writing: %s",
+			name, strerror(errno));
+		return 0;
+	}
+	
+	pidfile_fd = f;
+	
+	if (flock(f, LOCK_EX|LOCK_NB) < 0) {
+		if (errno == EWOULDBLOCK) {
+			hlog(LOG_CRIT, "Could not lock pid file file %s, another process has a lock on it. Another process running - bailing out.", name);
+		} else {
+			hlog(LOG_CRIT, "Failed to lock pid file %s: %s", name, strerror(errno));
+		}
+		return 0;
+	}
+	
+	l = snprintf(s, 32, "%ld\n", (long)getpid());
+	
+	if (ftruncate(f, 0) < 0) {
+		hlog(LOG_CRIT, "Could not truncate pid file %s: %s",
+			name, strerror(errno));
+		return 0;
+	}
+	
+	if (write(f, s, l) != l) {
+		hlog(LOG_CRIT, "Could not write pid to %s: %s",
+			name, strerror(errno));
+		return 0;
+	}
+	
+	return 1;
+}
+
+int closepid(void)
+{
+	if (pidfile_fd >= 0) {
+		if (close(pidfile_fd) != 0) {
+			hlog(LOG_CRIT, "Could not close pid file: %s", strerror(errno));
+			return -1;
+		}
+		pidfile_fd = -1;
+	}
+	
+	return 0;
+}
diff --git a/hlog.h b/hlog.h
new file mode 100644
index 0000000..486bee2
--- /dev/null
+++ b/hlog.h
@@ -0,0 +1,57 @@
+/*
+ *	aprsc
+ *
+ *	(c) Heikki Hannikainen, OH7LZB <hessu at hes.iki.fi>
+ *
+ *     This program is licensed under the BSD license, which can be found
+ *     in the file LICENSE.
+ *
+ */
+
+#ifndef LOG_H
+#define LOG_H
+
+#define LOG_LEN	2048
+
+#define L_STDERR        1		/* Log to stderror */
+#define L_SYSLOG        (1 << 1)	/* Log to syslog */
+#define L_FILE		(1 << 2)	/* Log to a file */
+
+#ifdef __CYGWIN__
+#define L_DEFDEST	L_FILE
+#else
+#define L_DEFDEST	L_STDERR
+#endif
+
+#define LOG_LEVELS "emerg alert crit err warning notice info debug"
+#define LOG_DESTS "syslog stderr file"
+
+#include <syslog.h>
+
+extern char *log_levelnames[];
+extern char *log_destnames[];
+
+extern int log_dest;    /* Logging destination */
+extern int log_level;	/* Logging level */
+extern char *log_dir;	/* Log directory */
+
+extern int log_rotate_size;	/* Rotate log when it reaches a given size */
+extern int log_rotate_num;	/* How many logs to keep around */
+
+
+extern char *str_append(char *s, const char *fmt, ...);
+
+extern int pick_loglevel(char *s, char **names);
+extern int open_log(char *name, int reopen);
+extern int close_log(int reopen);
+extern int hlog(int priority, const char *fmt, ...);
+extern int hlog_packet(int priority, const char *packet, int packetlen, const char *fmt, ...);
+
+extern int accesslog_open(char *logd, int reopen);
+extern int accesslog_close(char *reopenpath);
+extern int accesslog(const char *fmt, ...);
+
+extern int writepid(char *name);
+extern int closepid(void);
+
+#endif
diff --git a/igate.c b/igate.c
new file mode 100644
index 0000000..32c36bd
--- /dev/null
+++ b/igate.c
@@ -0,0 +1,650 @@
+/* **************************************************************** *
+ *                                                                  *
+ *  APRX -- 2nd generation receive-only APRS-i-gate with            *
+ *          minimal requirement of esoteric facilities or           *
+ *          libraries of any kind beyond UNIX system libc.          *
+ *                                                                  *
+ * (c) Matti Aarnio - OH2MQK,  2007-2014                            *
+ *                                                                  *
+ * IGATE:  Pass packets in between RF network and APRS-IS           *
+ *                                                                  *
+ * **************************************************************** */
+
+#include "aprx.h"
+
+
+const char *tnc2_verify_callsign_format(const char *t, int starok, int strictax25, const char *e)
+{
+	const char *s = t;
+
+	for (; *s && s < e; ++s) {
+		/* Valid station-id charset is:  [A-Z0-9] */
+		int c = *s;
+		if (!(('A' <= c && c <= 'Z') || ('0' <= c && c <= '9'))) {
+			/* Not A-Z, 0-9 */
+			break;
+		}
+	}
+	/* Now *s can be any of: '>,*-:' */
+	if (*s == '-') {
+		/* Minus and digits.. */
+		++s;
+		if (strictax25) {
+		  if ('1' <= *s && *s <= '9')
+		    ++s;
+		  if ('0' <= *s && *s <= '9')
+		    ++s;
+		} else {
+		  // Up to 2 of any alphanumeric
+		  if (('0' <= *s && *s <= '9') ||
+		      ('a' <= *s && *s <= 'z') ||
+		      ('A' <= *s && *s <= 'Z'))
+		    ++s;
+		  if (('0' <= *s && *s <= '9') ||
+		      ('a' <= *s && *s <= 'z') ||
+		      ('A' <= *s && *s <= 'Z'))
+		    ++s;
+		}
+	}
+
+	if (*s == '*' /* && starok */ )	/* Star is present at way too many
+					   SRC and DEST addresses, it is not
+					   limited to VIA fields :-(  */
+		++s;
+
+	if (s > e) {
+		if (debug)
+			printf("callsign scanner ran over end of buffer");
+		return NULL; /* Over the end-of-buffer */
+	}
+	if (s == t) {
+		if (debug)
+		  printf("%s callsign format verify got bad character: '%c' in string: '%.20s'\n", strictax25 ? "Strict":"Lenient", *s, t);
+		return NULL;	/* Too short ? */
+	}
+
+	if (*s != '>' && *s != ',' && *s != ':' && *s != 0) {
+		/* Terminates badly.. */
+		if (debug)
+			printf("%s callsign format verify got bad character: '%c' in string: '%.20s'\n", strictax25 ? "Strict":"Lenient", *s, t);
+		return NULL;
+	}
+
+	return s;
+}
+
+#ifndef DISABLE_IGATE
+
+
+/*
+ * igate start -- make TX-igate allocations and inits
+ */
+void igate_start()
+{
+	// Always relay all traffic from RF to APRSIS, other
+	// direction is handled per transmitter interface...
+	// enable_aprsis_rx_dupecheck();
+}
+
+static const char *tnc2_forbidden_source_stationid(const char *t, const int strictax25,const char *e)
+{
+	const char *s;
+
+	s = tnc2_verify_callsign_format(t, 0, strictax25, e);
+	if (!s)
+		return NULL;
+
+	if (memcmp("WIDE", t, 4) == 0 ||	/* just plain wrong setting */
+	    memcmp("RELAY", t, 5) == 0 ||	/* just plain wrong setting */
+	    memcmp("TRACE", t, 5) == 0 ||	/* just plain wrong setting */
+	    memcmp("TCPIP", t, 5) == 0 ||	/* just plain wrong setting */
+	    memcmp("TCPXX", t, 5) == 0 ||	/* just plain wrong setting */
+	    memcmp("N0CALL", t, 6) == 0 ||	/* TNC default setting */
+	    memcmp("NOCALL", t, 6) == 0)	/* TNC default setting */
+		return NULL;
+
+	return s;
+}
+
+static const char *tnc2_forbidden_destination_stationid(const char *t, const int strictax25, const char *e)
+{
+	const char *s;
+
+	s = tnc2_verify_callsign_format(t, 0, strictax25, e);
+	if (!s)
+		return NULL;
+
+	if (memcmp("TCPIP", t, 5) == 0 ||	/* just plain wrong */
+	    memcmp("TCPXX", t, 5) == 0 ||	/* Forbidden to gate */
+	    memcmp("NOGATE", t, 5) == 0 ||	/* Forbidden to gate */
+	    memcmp("RFONLY", t, 5) == 0 ||	/* Forbidden to gate */
+	    memcmp("N0CALL", t, 6) == 0 ||	/* TNC default setting */
+	    memcmp("NOCALL", t, 6) == 0)	/* TNC default setting */
+		return NULL;
+
+	return s;
+}
+
+static const char *tnc2_forbidden_via_stationid(const char *t, const int strictax25, const char *e)
+{
+	const char *s;
+
+	s = tnc2_verify_callsign_format(t, 1, strictax25, e);
+	if (!s)
+		return NULL;
+
+	if (memcmp("RFONLY", t, 6) == 0 ||
+	    memcmp("NOGATE", t, 6) == 0 ||
+	    memcmp("TCPIP", t, 5)  == 0 ||
+	    memcmp("TCPXX", t, 5)  == 0)
+		return NULL;
+
+	return s;
+}
+
+/*
+static int tnc2_forbidden_data(const char *t)
+{
+	int i;
+
+	for (i = 0; i < dataregscount; ++i) {
+		int stat = regexec(dataregs[i], t, 0, NULL, 0);
+		if (stat == 0)
+			return 1;	// MATCH!
+	}
+
+	return 0;
+}
+*/
+
+void verblog(const char *portname, int istx, const char *tnc2buf, int tnc2len) {
+    if (verbout) {
+        printf("%ld\t%-9s ", (long) tick.tv_sec, portname);
+	printf("%s \t", istx ? "T":"R");
+	fwrite(tnc2buf, tnc2len, 1, stdout);
+	printf("\n");
+    }
+}
+
+/*
+ * The  tnc2_rxgate()  is actual RX-iGate filter function, and processes
+ * prepated TNC2 format text presentation of the packet.
+ * It does presume that the record is in a buffer that can be written on!
+ */
+
+void igate_to_aprsis(const char *portname, const int tncid, const char *tnc2buf, int tnc2addrlen, int tnc2len, const int discard0, const int strictax25_)
+{
+	const char *tp, *t, *t0;
+	const char *s;
+	const char *ae;
+	const char *e;
+	int discard = discard0;
+	int strictax25 = strictax25_; // Callsigns per strict AX25 (not 3rd-party)
+
+	tp = tnc2buf;           // 3rd-party recursion moves tp
+	ae = tp + tnc2addrlen;  // 3rd-party recursion moves ae
+	e  = tp + tnc2len;      // stays the same all the time
+
+	rflog(portname, 'R', discard, tp, tnc2len);
+
+      redo_frame_filter:;
+
+	t  = tp;
+	t0 = NULL;
+
+	/* t == beginning of the TNC2 format packet */
+
+	/*
+	 * If any of following matches, discard the packet!
+	 * next if ($axpath =~ m/^WIDE/io); # Begins with = is sourced by..
+	 * next if ($axpath =~ m/^RELAY/io);
+	 * next if ($axpath =~ m/^TRACE/io);
+	 */
+	s = tnc2_forbidden_source_stationid(t, strictax25, e);
+	if (s)
+		t = (char *) s;
+	else {
+		/* Forbidden in source fields.. */
+		if (debug)
+			printf("TNC2 forbidden source stationid: '%.20s'\n", t);
+		goto discard;
+	}
+
+	/*  SOURCE>DESTIN,VIA,VIA:payload */
+
+	if (*t == '>') {
+		++t;
+	} else {
+		if (debug)
+		    printf("TNC2 bad address format, expected '>', got: '%.20s'\n", t);
+		goto discard;
+	}
+
+	s = tnc2_forbidden_destination_stationid(t, strictax25, e);
+	if (s)
+		t = (char *) s;
+	else {
+		if (debug)
+			printf("TNC2 forbidden (by REGEX) destination stationid: '%.20s'\n", t);
+		goto discard;
+	}
+
+	while (*t && t < ae) {
+		if (*t == ',') {
+			++t;
+		} else {
+			if (debug)
+				printf("TNC2 via address syntax bug, wanted ',' or ':', got: '%.20s'\n", t);
+			goto discard;
+		}
+
+		/*
+		 *  next if ($axpath =~ m/RFONLY/io); # Has any of these in via fields..
+		 *  next if ($axpath =~ m/TCPIP/io);
+		 *  next if ($axpath =~ m/TCPXX/io);
+		 *  next if ($axpath =~ m/NOGATE/io); # .. drop it.
+		 */
+
+		s = tnc2_forbidden_via_stationid(t, strictax25, e);
+		if (!s) {
+			/* Forbidden in via fields.. */
+			if (debug)
+				printf("TNC2 forbidden VIA stationid, got: '%.20s'\n", t);
+			goto discard;
+		} else
+			t = (char *) s;
+
+
+	}
+	/* Now we have processed the address, this should be ABORT time if
+	   the current character is not ':' !  */
+	if (*t == ':') {
+#if 0
+	  // *t++ = 0;	/* turn it to NUL character */
+#else
+	  /* Don't zero! */
+	  ++t;
+#endif
+	  ;
+	} else {
+		if (debug)
+			printf("TNC2 address parsing did not find ':':  '%.20s'\n",t);
+		goto discard;
+	}
+	t0 = t;  // Start of payload
+
+	/* Now 't' points to data.. */
+
+
+/*
+	if (tnc2_forbidden_data(t)) {
+		if (debug)
+			printf("Forbidden data in TNC2 packet - REGEX match");
+		goto discard;
+	}
+*/
+
+	/* Will not relay messages that begin with '?' char: */
+	if (*t == '?') {
+		if (debug)
+			printf("Will not relay packets where payload begins with '?'\n");
+		goto discard;
+	}
+
+	/* Messages begining with '}' char are 3rd-party frames.. */
+	if (*t == '}') {
+		/* DEBUG OUTPUT TO STDOUT ! */
+		verblog(portname, 0, tp, tnc2len);
+
+		strictax25 = 0;
+		/* Copy the 3rd-party message content into begining of the buffer... */
+		++t;				/* Skip the '}'		*/
+		tp = t;
+		tnc2len = e - t;		/* New length		*/
+		// end pointer (e) does not change
+		// Address end must be searched again
+		ae = memchr(tp, ':', tnc2len);
+		if (ae == NULL) {
+		  // Bad 3rd-party frame
+		  goto discard;
+		}
+		tnc2addrlen = (int)(ae - tp);
+
+		/* .. and redo the filtering. */
+		goto redo_frame_filter;
+	}
+
+
+
+	/* TODO: Verify message being of recognized APRS packet type */
+	/*   '\0x60', '\0x27':  MIC-E, len >= 9
+	 *   '!','=','/','{':   Normal or compressed location packet..
+	 *   '$':               NMEA data, if it begins as '$GP'
+	 *   '$':               WX data (maybe) if not NMEA data
+	 *   ';':               Object data, len >= 31
+	 *   ')':               Item data, len >= 18
+	 *   ':':               message, bulletin or aanouncement, len >= 11
+	 *   '<':               Station Capabilities, len >= 2
+	 *   '>':               Status report
+	 *   '}':               Third-party message
+	 * ...  and many more ...
+	 */
+
+	// FIXME: Duplicate filter messages to APRSIS
+	
+
+	/* _NO_ ending CRLF, the APRSIS subsystem adds it. */
+
+	/*
+	  printf("alen=%d  tlen=%d  tnc2buf=%s\n",t0-1-tnc2buf, e-t0, tnc2buf);
+	*/
+	discard = aprsis_queue(tp, tnc2addrlen, qTYPE_IGATED, portname, t0, e - t0); /* Send it.. */
+	/* DEBUG OUTPUT TO STDOUT ! */
+	verblog(portname, 0, tp, tnc2len);
+
+	// Log the innermost form of packet to be sent out..
+	if (tp != tnc2buf || discard != discard0)
+	  rflog(portname, 'R', discard, tp, tnc2len);
+
+	if (0) {
+ discard:;
+
+		discard = -1;
+	}
+
+	if (discard) {
+		erlang_add(portname, ERLANG_DROP, tnc2len, 1);
+	}
+}
+
+
+
+/* ---------------------------------------------------------- */
+
+
+/*
+ * Study APRS-IS received message's address header part
+ * to determine if it is not to be relayed back to RF..
+ */
+static int forbidden_to_gate_addr(const char *s)
+{
+	if (memcmp(s, "TCPXX", 5) == 0)
+	  return 1; /* Forbidden to be relayed */
+	if (memcmp(s, "NOGATE", 6) == 0)
+	  return 1; /* Forbidden to be relayed */
+	if (memcmp(s, "RFONLY", 6) == 0)
+	  return 1; /* Forbidden to be relayed */
+	if (memcmp(s, "qAX", 3) == 0)
+	  return 1;
+
+	return 0; /* Found nothing forbidden */
+}
+
+
+/*
+ * For APRSIS -> APRX -> RF gatewaying.
+ * Have to convert incoming TNC2 format messge to AX.25..
+ *
+ * See:  http://www.aprs-is.net/IGateDetails.aspx
+ *
+ * ----------------------------------------------------------------
+ * 
+ *  Gate message packets and associated posits to RF if
+ *
+ *  1. the receiving station has been heard within range within
+ *     a predefined time period (range defined as digi hops,
+ *     distance, or both).
+ *  2. the sending station has not been heard via RF within
+ *     a predefined time period (packets gated from the Internet
+ *     by other stations are excluded from this test).
+ *  3. the sending station does not have TCPXX, NOGATE, or RFONLY
+ *     in the header.
+ *  4. the receiving station has not been heard via the Internet
+ *     within a predefined time period.
+ *
+ * A station is said to be heard via the Internet if packets from
+ * the station contain TCPIP* or TCPXX* in the header or if gated
+ * (3rd-party) packets are seen on RF gated by the station and
+ * containing TCPIP or TCPXX in the 3rd-party header (in other
+ * words, the station is seen on RF as being an IGate).
+ *
+ * Gate all packets to RF based on criteria set by the sysop (such
+ * as callsign, object name, etc.).
+ *
+ * ----------------------------------------------------------------
+ *
+ * TODO:
+ *  a) APRS-IS relayed third-party frames are ignored.
+ *
+ *  3) The message path does not have TCPXX, NOGATE, RFONLY
+ *     in it.
+ *
+ * Following steps are done in  interface_receive_3rdparty()
+ *
+ *  1) The receiving station has been heard recently
+ *     within defined range limits, and more recently
+ *     than since given interval T1. (Range as digi-hops [N1]
+ *     or coordinates, or both.)
+ *
+ *  2) The sending station has not been heard via RF
+ *     within timer interval T2. (Third-party relayed
+ *     frames are not analyzed for this.)
+ *
+ *  4) the receiving station has not been heard via the Internet
+ *     within a predefined time period.
+ *     A station is said to be heard via the Internet if packets
+ *     from the station contain TCPIP* or TCPXX* in the header or
+ *     if gated (3rd-party) packets are seen on RF gated by the
+ *     station and containing TCPIP or TCPXX in the 3rd-party
+ *     header (in other words, the station is seen on RF as being
+ *     an IGate). 
+ *
+ * 5)  Gate all packets to RF based on criteria set by the sysop
+ *     (such as callsign, object name, etc.).
+ *
+ * c)  Drop everything else.
+ *
+ *  Paths
+ *
+ * IGates should use the 3rd-party format on RF of
+ * IGATECALL>APRS,GATEPATH}FROMCALL>TOCALL,TCPIP,IGATECALL*:original packet data
+ * where GATEPATH is the path that the gated packet is to follow
+ * on RF. This format will allow IGates to prevent gating the packet
+ * back to APRS-IS.
+ * 
+ * q constructs should never appear on RF.
+ * The I construct should never appear on RF.
+ * Except for within gated packets, TCPIP and TCPXX should not be
+ * used on RF.
+ */
+
+static void pick_heads(char *ax25, int headlen,
+		       char *heads[20], int *headscount) 
+{
+	char *p = ax25;
+	char *e = ax25 + headlen;
+
+	char *p0 = p;
+	// if (debug)printf(" head parse: ");
+	while (p <= e) {
+	  p0 = p;
+	  while (p <= e) {
+	    const char c = *p;
+	    if (c != '>' && c != ',' && c != ':') {
+	      ++p;
+	      continue;
+	    }
+	    *p++ = 0;
+	    if (*headscount >= 19)
+	      continue; /* too many head parts.. */
+	    heads[*headscount] = p0;
+	    *headscount += 1;
+	    // if (debug) printf("  %-9s", p0);
+	    break;
+	  }
+	}
+	heads[*headscount] = NULL;
+	// if (debug)printf("\n");
+}
+
+static void aprsis_commentframe(const char *tnc2buf, int tnc2len) {
+  // TODO .. #TICK -> #TOCK  ??
+}
+
+void igate_from_aprsis(const char *ax25, int ax25len)
+{
+	// const char *p = ax25;
+	int colonidx;
+	int ok_to_relay, i;
+	const char *b;
+	// const char *e = p + ax25len; /* string end pointer */
+//	char  axbuf[3000]; /* enough and then some more.. */
+	// char  axbuf2[1000]; /* enough and then some more.. */
+	char  *heads[20];
+	char  *headsbuf;
+	int    headscount = 0;
+//	char  *s;
+	char  *fromcall  = NULL;
+	char  *origtocall = NULL;
+
+	if (ax25[0] == '#') {  // Comment line, timer tick, something such...
+          aprsis_commentframe(ax25, ax25len);
+	  return;
+        }
+
+	if (ax25len > 520) {
+	  /* Way too large a frame... */
+	  if (debug)printf("APRSIS dataframe length is too large! (%d)\n",ax25len);
+	  return;
+	}
+
+	b = memchr(ax25, ':', ax25len);
+	if (b == NULL) {
+	  if (debug)printf("APRSIS dataframe does not have ':' in it\n");
+	  return; // Huh?  No double-colon on line, it is not proper packet line
+	}
+
+	colonidx = b-ax25;
+	if (colonidx+3 >= ax25len) {
+	  /* Not really any data there.. */
+	  if (debug)printf("APRSIS dataframe too short to contain anything\n");
+	  return;
+	}
+
+	rflog("APRSIS",'R',0,ax25, ax25len);
+
+	headsbuf = alloca(colonidx+1);
+	memcpy(headsbuf, ax25, colonidx+1);
+
+	headscount = 0;
+	pick_heads(headsbuf, colonidx, heads, &headscount);
+
+	ok_to_relay = 0;
+	if (headscount < 4) {
+	  // Less than 3 header fields coming from APRS-IS ?
+	  if (debug)
+	    printf("Not relayable packet! [1]\n");
+	  return;
+	}
+
+	if (memcmp(heads[1],"RXTLM-",6)==0) {
+	  if (debug)
+	    printf("Not relayable packet! [2]\n");
+	  return;
+	}
+
+	fromcall   = heads[0];
+	origtocall = heads[1];
+	for (i = 0; i < headscount; ++i) {
+	  /* 3) */
+	  if (forbidden_to_gate_addr(heads[i])) {
+	    if (debug)
+	      printf("Not relayable packet! [3]\n");
+	    return;
+	  }
+
+// FIXME: Hmm.. Really ??  q-construct analysis and "ok_to_relay" decission
+	  if (heads[i][0] == 'q' && heads[i][1] == 'A') {
+	    int qcode = heads[i][2];
+	    ok_to_relay = 1;
+
+	    // Depending on qA? value, following may
+	    // actually be fromcall, or some other..
+	    switch (qcode) {
+	    case 'X':
+	      ok_to_relay = 0;
+	      break;
+	    default:
+	      break;
+	    }
+	    
+	    heads[i] = NULL;
+	    break;
+	  }
+	}
+	if (!ok_to_relay) {
+	  if (debug)
+	    printf("Not relayable packet! [4]\n");
+	  return;
+	}
+
+	++b; /* Skip the ':' */
+
+	/* a) */
+	/* Check for forbidden things that cause dropping the packet */
+	if (*b == '}') { /* Third-party packet from APRS-IS */
+	  if (debug)
+	    printf("Not relayable packet! [5]\n");
+	  return; /* drop it */
+	}
+
+	// Following logic steps are done in  interface_receive_3rdparty!
+
+	// FIXME: 1) - verify receiving station has been heard recently on radio
+	// FIXME: 2) - sending station has not been heard recently on radio
+	// FIXME: 4) - the receiving station has not been heard via the Internet within a predefined time period.
+	// FIXME: f) - ??
+
+	if (debug) printf(".. igate from aprsis\n");
+
+	interface_receive_3rdparty( &aprsis_interface,
+				    fromcall, origtocall, "TCPIP",
+				    b, ax25len - (b-ax25) );
+}
+
+#endif
+
+/* ---------------------------------------------------------- */
+
+void rflog(const char *portname, char direction, int discard, const char *tnc2buf, int tnc2len)
+{
+	if (rflogfile) {
+		FILE *fp = NULL;
+		if (strcmp("-",rflogfile)==0) {
+		  if (debug < 2) return;
+		  fp = stdout;
+		} else {
+		  fp = fopen(rflogfile, "a");
+		}
+		
+		if (fp) {
+		  char timebuf[60];
+		  printtime(timebuf, sizeof(timebuf));
+	  
+		  (void)fprintf(fp, "%s %-9s ", timebuf, portname);
+		  (void)fprintf(fp, "%c ", direction);
+
+		  if (discard < 0) {
+		    fprintf(fp, "*");
+		  }
+		  if (discard > 0) {
+		    fprintf(fp, "#");
+		  }
+		  (void)fwrite( tnc2buf, tnc2len, 1, fp);
+		  (void)fprintf( fp, "\n" );
+
+		  if (fp != stdout)
+		    fclose(fp);
+		}
+	}
+}
diff --git a/install-sh b/install-sh
new file mode 100755
index 0000000..4fbbae7
--- /dev/null
+++ b/install-sh
@@ -0,0 +1,507 @@
+#!/bin/sh
+# install - install a program, script, or datafile
+
+scriptversion=2006-10-14.15
+
+# This originates from X11R5 (mit/util/scripts/install.sh), which was
+# later released in X11R6 (xc/config/util/install.sh) with the
+# following copyright and license.
+#
+# Copyright (C) 1994 X Consortium
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to
+# deal in the Software without restriction, including without limitation the
+# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+# sell copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC-
+# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+# Except as contained in this notice, the name of the X Consortium shall not
+# be used in advertising or otherwise to promote the sale, use or other deal-
+# ings in this Software without prior written authorization from the X Consor-
+# tium.
+#
+#
+# FSF changes to this file are in the public domain.
+#
+# Calling this script install-sh is preferred over install.sh, to prevent
+# `make' implicit rules from creating a file called install from it
+# when there is no Makefile.
+#
+# This script is compatible with the BSD install script, but was written
+# from scratch.
+
+nl='
+'
+IFS=" ""	$nl"
+
+# set DOITPROG to echo to test this script
+
+# Don't use :- since 4.3BSD and earlier shells don't like it.
+doit="${DOITPROG-}"
+if test -z "$doit"; then
+  doit_exec=exec
+else
+  doit_exec=$doit
+fi
+
+# Put in absolute file names if you don't have them in your path;
+# or use environment vars.
+
+mvprog="${MVPROG-mv}"
+cpprog="${CPPROG-cp}"
+chmodprog="${CHMODPROG-chmod}"
+chownprog="${CHOWNPROG-chown}"
+chgrpprog="${CHGRPPROG-chgrp}"
+stripprog="${STRIPPROG-strip}"
+rmprog="${RMPROG-rm}"
+mkdirprog="${MKDIRPROG-mkdir}"
+
+posix_glob=
+posix_mkdir=
+
+# Desired mode of installed file.
+mode=0755
+
+chmodcmd=$chmodprog
+chowncmd=
+chgrpcmd=
+stripcmd=
+rmcmd="$rmprog -f"
+mvcmd="$mvprog"
+src=
+dst=
+dir_arg=
+dstarg=
+no_target_directory=
+
+usage="Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE
+   or: $0 [OPTION]... SRCFILES... DIRECTORY
+   or: $0 [OPTION]... -t DIRECTORY SRCFILES...
+   or: $0 [OPTION]... -d DIRECTORIES...
+
+In the 1st form, copy SRCFILE to DSTFILE.
+In the 2nd and 3rd, copy all SRCFILES to DIRECTORY.
+In the 4th, create DIRECTORIES.
+
+Options:
+-c         (ignored)
+-d         create directories instead of installing files.
+-g GROUP   $chgrpprog installed files to GROUP.
+-m MODE    $chmodprog installed files to MODE.
+-o USER    $chownprog installed files to USER.
+-s         $stripprog installed files.
+-t DIRECTORY  install into DIRECTORY.
+-T         report an error if DSTFILE is a directory.
+--help     display this help and exit.
+--version  display version info and exit.
+
+Environment variables override the default commands:
+  CHGRPPROG CHMODPROG CHOWNPROG CPPROG MKDIRPROG MVPROG RMPROG STRIPPROG
+"
+
+while test $# -ne 0; do
+  case $1 in
+    -c) shift
+        continue;;
+
+    -d) dir_arg=true
+        shift
+        continue;;
+
+    -g) chgrpcmd="$chgrpprog $2"
+        shift
+        shift
+        continue;;
+
+    --help) echo "$usage"; exit $?;;
+
+    -m) mode=$2
+        shift
+        shift
+	case $mode in
+	  *' '* | *'	'* | *'
+'*	  | *'*'* | *'?'* | *'['*)
+	    echo "$0: invalid mode: $mode" >&2
+	    exit 1;;
+	esac
+        continue;;
+
+    -o) chowncmd="$chownprog $2"
+        shift
+        shift
+        continue;;
+
+    -s) stripcmd=$stripprog
+        shift
+        continue;;
+
+    -t) dstarg=$2
+	shift
+	shift
+	continue;;
+
+    -T) no_target_directory=true
+	shift
+	continue;;
+
+    --version) echo "$0 $scriptversion"; exit $?;;
+
+    --)	shift
+	break;;
+
+    -*)	echo "$0: invalid option: $1" >&2
+	exit 1;;
+
+    *)  break;;
+  esac
+done
+
+if test $# -ne 0 && test -z "$dir_arg$dstarg"; then
+  # When -d is used, all remaining arguments are directories to create.
+  # When -t is used, the destination is already specified.
+  # Otherwise, the last argument is the destination.  Remove it from $@.
+  for arg
+  do
+    if test -n "$dstarg"; then
+      # $@ is not empty: it contains at least $arg.
+      set fnord "$@" "$dstarg"
+      shift # fnord
+    fi
+    shift # arg
+    dstarg=$arg
+  done
+fi
+
+if test $# -eq 0; then
+  if test -z "$dir_arg"; then
+    echo "$0: no input file specified." >&2
+    exit 1
+  fi
+  # It's OK to call `install-sh -d' without argument.
+  # This can happen when creating conditional directories.
+  exit 0
+fi
+
+if test -z "$dir_arg"; then
+  trap '(exit $?); exit' 1 2 13 15
+
+  # Set umask so as not to create temps with too-generous modes.
+  # However, 'strip' requires both read and write access to temps.
+  case $mode in
+    # Optimize common cases.
+    *644) cp_umask=133;;
+    *755) cp_umask=22;;
+
+    *[0-7])
+      if test -z "$stripcmd"; then
+	u_plus_rw=
+      else
+	u_plus_rw='% 200'
+      fi
+      cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;;
+    *)
+      if test -z "$stripcmd"; then
+	u_plus_rw=
+      else
+	u_plus_rw=,u+rw
+      fi
+      cp_umask=$mode$u_plus_rw;;
+  esac
+fi
+
+for src
+do
+  # Protect names starting with `-'.
+  case $src in
+    -*) src=./$src ;;
+  esac
+
+  if test -n "$dir_arg"; then
+    dst=$src
+    dstdir=$dst
+    test -d "$dstdir"
+    dstdir_status=$?
+  else
+
+    # Waiting for this to be detected by the "$cpprog $src $dsttmp" command
+    # might cause directories to be created, which would be especially bad
+    # if $src (and thus $dsttmp) contains '*'.
+    if test ! -f "$src" && test ! -d "$src"; then
+      echo "$0: $src does not exist." >&2
+      exit 1
+    fi
+
+    if test -z "$dstarg"; then
+      echo "$0: no destination specified." >&2
+      exit 1
+    fi
+
+    dst=$dstarg
+    # Protect names starting with `-'.
+    case $dst in
+      -*) dst=./$dst ;;
+    esac
+
+    # If destination is a directory, append the input filename; won't work
+    # if double slashes aren't ignored.
+    if test -d "$dst"; then
+      if test -n "$no_target_directory"; then
+	echo "$0: $dstarg: Is a directory" >&2
+	exit 1
+      fi
+      dstdir=$dst
+      dst=$dstdir/`basename "$src"`
+      dstdir_status=0
+    else
+      # Prefer dirname, but fall back on a substitute if dirname fails.
+      dstdir=`
+	(dirname "$dst") 2>/dev/null ||
+	expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+	     X"$dst" : 'X\(//\)[^/]' \| \
+	     X"$dst" : 'X\(//\)$' \| \
+	     X"$dst" : 'X\(/\)' \| . 2>/dev/null ||
+	echo X"$dst" |
+	    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+		   s//\1/
+		   q
+		 }
+		 /^X\(\/\/\)[^/].*/{
+		   s//\1/
+		   q
+		 }
+		 /^X\(\/\/\)$/{
+		   s//\1/
+		   q
+		 }
+		 /^X\(\/\).*/{
+		   s//\1/
+		   q
+		 }
+		 s/.*/./; q'
+      `
+
+      test -d "$dstdir"
+      dstdir_status=$?
+    fi
+  fi
+
+  obsolete_mkdir_used=false
+
+  if test $dstdir_status != 0; then
+    case $posix_mkdir in
+      '')
+	# Create intermediate dirs using mode 755 as modified by the umask.
+	# This is like FreeBSD 'install' as of 1997-10-28.
+	umask=`umask`
+	case $stripcmd.$umask in
+	  # Optimize common cases.
+	  *[2367][2367]) mkdir_umask=$umask;;
+	  .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;;
+
+	  *[0-7])
+	    mkdir_umask=`expr $umask + 22 \
+	      - $umask % 100 % 40 + $umask % 20 \
+	      - $umask % 10 % 4 + $umask % 2
+	    `;;
+	  *) mkdir_umask=$umask,go-w;;
+	esac
+
+	# With -d, create the new directory with the user-specified mode.
+	# Otherwise, rely on $mkdir_umask.
+	if test -n "$dir_arg"; then
+	  mkdir_mode=-m$mode
+	else
+	  mkdir_mode=
+	fi
+
+	posix_mkdir=false
+	case $umask in
+	  *[123567][0-7][0-7])
+	    # POSIX mkdir -p sets u+wx bits regardless of umask, which
+	    # is incompatible with FreeBSD 'install' when (umask & 300) != 0.
+	    ;;
+	  *)
+	    tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$
+	    trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0
+
+	    if (umask $mkdir_umask &&
+		exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1
+	    then
+	      if test -z "$dir_arg" || {
+		   # Check for POSIX incompatibilities with -m.
+		   # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or
+		   # other-writeable bit of parent directory when it shouldn't.
+		   # FreeBSD 6.1 mkdir -m -p sets mode of existing directory.
+		   ls_ld_tmpdir=`ls -ld "$tmpdir"`
+		   case $ls_ld_tmpdir in
+		     d????-?r-*) different_mode=700;;
+		     d????-?--*) different_mode=755;;
+		     *) false;;
+		   esac &&
+		   $mkdirprog -m$different_mode -p -- "$tmpdir" && {
+		     ls_ld_tmpdir_1=`ls -ld "$tmpdir"`
+		     test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1"
+		   }
+		 }
+	      then posix_mkdir=:
+	      fi
+	      rmdir "$tmpdir/d" "$tmpdir"
+	    else
+	      # Remove any dirs left behind by ancient mkdir implementations.
+	      rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null
+	    fi
+	    trap '' 0;;
+	esac;;
+    esac
+
+    if
+      $posix_mkdir && (
+	umask $mkdir_umask &&
+	$doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir"
+      )
+    then :
+    else
+
+      # The umask is ridiculous, or mkdir does not conform to POSIX,
+      # or it failed possibly due to a race condition.  Create the
+      # directory the slow way, step by step, checking for races as we go.
+
+      case $dstdir in
+	/*) prefix=/ ;;
+	-*) prefix=./ ;;
+	*)  prefix= ;;
+      esac
+
+      case $posix_glob in
+        '')
+	  if (set -f) 2>/dev/null; then
+	    posix_glob=true
+	  else
+	    posix_glob=false
+	  fi ;;
+      esac
+
+      oIFS=$IFS
+      IFS=/
+      $posix_glob && set -f
+      set fnord $dstdir
+      shift
+      $posix_glob && set +f
+      IFS=$oIFS
+
+      prefixes=
+
+      for d
+      do
+	test -z "$d" && continue
+
+	prefix=$prefix$d
+	if test -d "$prefix"; then
+	  prefixes=
+	else
+	  if $posix_mkdir; then
+	    (umask=$mkdir_umask &&
+	     $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break
+	    # Don't fail if two instances are running concurrently.
+	    test -d "$prefix" || exit 1
+	  else
+	    case $prefix in
+	      *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;;
+	      *) qprefix=$prefix;;
+	    esac
+	    prefixes="$prefixes '$qprefix'"
+	  fi
+	fi
+	prefix=$prefix/
+      done
+
+      if test -n "$prefixes"; then
+	# Don't fail if two instances are running concurrently.
+	(umask $mkdir_umask &&
+	 eval "\$doit_exec \$mkdirprog $prefixes") ||
+	  test -d "$dstdir" || exit 1
+	obsolete_mkdir_used=true
+      fi
+    fi
+  fi
+
+  if test -n "$dir_arg"; then
+    { test -z "$chowncmd" || $doit $chowncmd "$dst"; } &&
+    { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } &&
+    { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false ||
+      test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1
+  else
+
+    # Make a couple of temp file names in the proper directory.
+    dsttmp=$dstdir/_inst.$$_
+    rmtmp=$dstdir/_rm.$$_
+
+    # Trap to clean up those temp files at exit.
+    trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0
+
+    # Copy the file name to the temp name.
+    (umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") &&
+
+    # and set any options; do chmod last to preserve setuid bits.
+    #
+    # If any of these fail, we abort the whole thing.  If we want to
+    # ignore errors from any of these, just make sure not to ignore
+    # errors from the above "$doit $cpprog $src $dsttmp" command.
+    #
+    { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } \
+      && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } \
+      && { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } \
+      && { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } &&
+
+    # Now rename the file to the real destination.
+    { $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null \
+      || {
+	   # The rename failed, perhaps because mv can't rename something else
+	   # to itself, or perhaps because mv is so ancient that it does not
+	   # support -f.
+
+	   # Now remove or move aside any old file at destination location.
+	   # We try this two ways since rm can't unlink itself on some
+	   # systems and the destination file might be busy for other
+	   # reasons.  In this case, the final cleanup might fail but the new
+	   # file should still install successfully.
+	   {
+	     if test -f "$dst"; then
+	       $doit $rmcmd -f "$dst" 2>/dev/null \
+	       || { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null \
+		     && { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; }; }\
+	       || {
+		 echo "$0: cannot unlink or rename $dst" >&2
+		 (exit 1); exit 1
+	       }
+	     else
+	       :
+	     fi
+	   } &&
+
+	   # Now rename the file to the real destination.
+	   $doit $mvcmd "$dsttmp" "$dst"
+	 }
+    } || exit 1
+
+    trap '' 0
+  fi
+done
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-end: "$"
+# End:
diff --git a/interface.c b/interface.c
new file mode 100644
index 0000000..0351de5
--- /dev/null
+++ b/interface.c
@@ -0,0 +1,1895 @@
+/* **************************************************************** *
+ *                                                                  *
+ *  APRX -- 2nd generation receive-only APRS-i-gate with            *
+ *          minimal requirement of esoteric facilities or           *
+ *          libraries of any kind beyond UNIX system libc.          *
+ *                                                                  *
+ * (c) Matti Aarnio - OH2MQK,  2007-2014                            *
+ *                                                                  *
+ * **************************************************************** */
+
+#include "aprx.h"
+#include <sys/socket.h>
+
+/*
+ *  The interface subsystem describes all interfaces in one
+ *  coherent way, independent of their actual implementation.
+ *
+ */
+
+/*
+
+<interface>
+   serial-device /dev/ttyUSB1 19200 8n1 KISS
+   tx-ok         false		# receive only (default)
+   callsign      OH2XYZ-R2	# KISS subif 0
+   initstring    "...."		# initstring option
+   timeout       900            # 900 seconds of no Rx
+</interface>
+
+<interface>
+   serial-device /dev/ttyUSB2 19200 8n1 KISS
+   initstring    "...."
+   timeout       900            # 900 seconds of no Rx
+   <kiss-subif 0>
+      callsign OH2XYZ-2
+      tx-ok    true		# This is our transmitter
+   </kiss-subif>
+   <kiss-subif 1>
+      callsign OH2XYZ-R3	# This is receiver
+      tx-ok    false		# receive only (default)
+   </kiss-subif>
+</interface>
+
+<interface>
+   tcp-device   172.168.1.1 4001 KISS
+   tx-ok         false		# receive only (default)
+   callsign      OH2XYZ-R4	# KISS subif 0
+   initstring    "...."		# initstring option
+   timeout       900            # 900 seconds of no Rx
+</interface>
+
+<interface>
+   ax25-device OH2XYZ-6		# Works only on Linux systems
+   tx-ok       true		# This is also transmitter
+</interface>
+
+ */
+
+struct aprx_interface **all_interfaces;
+int                     all_interfaces_count;
+int			top_interfaces_group;
+
+// Init-code stores this with ifindex = 0.
+// This is necessary even for system where igate is removed
+struct aprx_interface aprsis_interface = {
+	IFTYPE_APRSIS, 0, 0, 0, "APRSIS",
+	{'A'<<1,'P'<<1,'R'<<1,'S'<<1,'I'<<1,'S'<<1, 0x60},
+	0, NULL,
+	0, 0, 0, // subif, txrefcount, tx_ok
+        1, 1, 0, // telemeter-to-is, telemeter-to-rf, telemeter-newformat
+        0, NULL,
+	NULL,
+#ifdef ENABLE_AGWPE
+	NULL,
+#endif
+	NULL,
+	0, NULL
+};
+
+int interface_is_beaconable(const struct aprx_interface *aif)
+{
+	switch (aif->iftype) {
+	case IFTYPE_AX25:
+	case IFTYPE_SERIAL:
+	case IFTYPE_TCPIP:
+	case IFTYPE_NULL:
+	case IFTYPE_APRSIS:
+	  // case IFTYPE_AGWPE:
+	  // These are beaconable.
+	  return 1;
+
+	default:
+	  break;
+	}
+	return 0;
+}
+
+int interface_is_telemetrable(const struct aprx_interface *aif) {
+        // Check if the interface type is really an RF rx and/or tx
+	switch (aif->iftype) {
+	case IFTYPE_AX25:
+	case IFTYPE_SERIAL:
+	case IFTYPE_TCPIP:
+	  // case IFTYPE_AGWPE:
+	  // These are real interfaces, and telemetry sources
+	  return 1;
+
+	default:
+	  break;
+	}
+	return 0;
+}
+
+#ifndef DISABLE_IGATE
+/*
+ * A helper for interface_receive_ax25() - analyze 3rd-party packets received
+ * via radio.  If data content inside has path saying "TCPIP" or "TCPXX", consider
+ * the packet to be indication that fromcall is an IGate.
+ */
+static void rx_analyze_3rdparty( historydb_t *historydb, struct pbuf_t *pb )
+{
+	const char *e = pb->data + pb->packet_len - 6;
+	const char *p = pb->info_start;
+	int from_igate = 0;
+	history_cell_t *hist_rx;
+
+	if (!p) return; // Bad packet..
+	++p;
+
+	for ( ; p < e; ++p ) {
+	  if (*p == ':') break;
+	  if (*p == ',') {
+	    // The "TCPIP*" or "TCPXX*" will always have preceding ","
+	    if (memcmp(",TCPIP*", p, 7) == 0) {
+	      from_igate = 1;
+	      break;
+	    }
+	    if (memcmp(",TCPXX*", p, 7) == 0) {
+	      from_igate = 1;
+	      break;
+	    }
+	  } // Start with 'T'.
+	}
+
+	if (!from_igate) return;  // Not recognized as being sent from another TX-IGATE
+
+	// OK, this packet originated from an TX-IGATE
+
+	// Insert it afresh
+	hist_rx = historydb_insert_heard(historydb, pb);
+	if (hist_rx != NULL) {
+	  // Explicitly mark it as "received from APRSIS"
+	  // The packet was received from a TX-IGATE, therefore
+	  // the source of that packet is now logged as "from APRSIS".
+	  hist_rx->last_heard[0] = pb->t;
+	}
+}
+#endif
+
+static char *interface_default_aliases[] = { "RELAY","WIDE","TRACE" };
+
+static void interface_store(struct aprx_interface *aif)
+{
+	if (debug)
+	  printf("interface_store() aif->callsign = '%s'\n", aif->callsign);
+
+	// Init the interface specific Erlang accounting
+	erlang_add(aif->callsign, ERLANG_RX, 0, 0);
+
+	all_interfaces_count += 1;
+	all_interfaces = realloc(all_interfaces,
+				 sizeof(*all_interfaces) * all_interfaces_count);
+	all_interfaces[all_interfaces_count -1] = aif;
+	if (aif->ifindex < 0)
+	  aif->ifindex = all_interfaces_count -1;
+	if (aif->ifgroup < 0) {
+          aif->ifgroup = all_interfaces_count; // starting at 1. the 0 is for APRSIS
+          /* -- no hard upper limit anymore
+          if (aif->ifgroup >= MAX_IF_GROUP)
+            aif->ifgroup = MAX_IF_GROUP -1;
+          */
+        }
+	if (top_interfaces_group <= aif->ifgroup)
+	  top_interfaces_group = aif->ifgroup +1;
+}
+
+struct aprx_interface *find_interface_by_callsign(const char *callsign)
+{
+	int i;
+	for (i = 0; i < all_interfaces_count; ++i) {
+	  if ((all_interfaces[i]->callsign != NULL) &&
+	      (strcasecmp(callsign, all_interfaces[i]->callsign) == 0)) {
+	    return all_interfaces[i];
+	  }
+	}
+	return NULL; // Not found!
+}
+
+struct aprx_interface *find_interface_by_index(const int index)
+{
+	if (index >= all_interfaces_count ||
+	    index < 0) {
+	  return NULL; // Invalid index value
+	} else {
+	  return all_interfaces[index];
+	}
+}
+
+static int config_kiss_subif(struct configfile *cf, struct aprx_interface *aifp, char *param1, char *str, int maxsubif)
+{
+	struct aprx_interface *aif;
+	int   fail = 0;
+
+	char *name;
+	int   parlen = 0;
+
+	char *initstring = NULL;
+	int   initlength = 0;
+	char *callsign   = NULL;
+	int   subif      = 0;
+        int   tx_ok      = 0;
+        int   telemeter_to_is = 1;
+        int   telemeter_to_rf = 1;
+	int   aliascount = 0;
+	char **aliases   = NULL;
+	int   ifgroup    = -1;
+
+	const char *p = param1;
+	int c;
+
+        if (aifp == NULL || aifp->tty == NULL) {
+          printf("%s:%d ERROR: <kiss-subif> on bad type of <interface> entry.\n",
+                 cf->name, cf->linenum);
+          return 1;
+
+        }
+
+	for ( ; *p; ++p ) {
+		c = *p;
+		if ('0' <= c && c <= '9') {
+			subif = subif * 10 + (c - '0');
+		} else if (c == '>') {
+		  // all fine..
+		  break;
+		} else {
+		  // FIXME: <KISS-SubIF nnn>  parameter value is bad!
+		  printf("%s:%d ERROR: <kiss-subif %s parameter value is bad\n",
+			 cf->name, cf->linenum, param1);
+		  return 1;
+		}
+	}
+	if (subif >= maxsubif) {
+		// FIXME: <KISS-SubIF nnn>  parameter value is bad!
+		printf("%s:%d ERROR: <kiss-subif %s parameter value is too large for this KISS variant.\n",
+		       cf->name, cf->linenum, param1);
+		return 1;
+	}
+
+	while (readconfigline(cf) != NULL) {
+		if (configline_is_comment(cf))
+			continue;	/* Comment line, or empty line */
+
+		// It can be severely indented...
+		str = config_SKIPSPACE(cf->buf);
+
+		name = str;
+		str = config_SKIPTEXT(str, NULL);
+		str = config_SKIPSPACE(str);
+		config_STRLOWER(name);
+
+		param1 = str;
+		str = config_SKIPTEXT(str, &parlen);
+		str = config_SKIPSPACE(str);
+
+		if (strcmp(name, "</kiss-subif>") == 0) {
+		  break; // End of this sub-group
+		}
+
+		if (strcmp(name, "callsign") == 0) {
+
+		  if (strcasecmp(param1,"$mycall") == 0)
+		    callsign = strdup(mycall);
+		  else
+		    callsign = strdup(param1);
+
+		  if (!validate_callsign_input(callsign,tx_ok)) {
+		    if (tx_ok)
+		      printf("%s:%d ERROR: The CALLSIGN parameter on AX25-DEVICE must be of valid AX.25 format! '%s'\n",
+			     cf->name, cf->linenum, callsign);
+		    else
+		      printf("%s:%d ERROR: The CALLSIGN parameter on AX25-DEVICE must be of valid APRSIS format! '%s'\n",
+			     cf->name, cf->linenum, callsign);
+		    fail = 1;
+		    break;
+		  }
+
+		  if (find_interface_by_callsign(callsign) != NULL) {
+		    // An interface with THIS callsign does exist already!
+		    printf("%s:%d ERROR: Same callsign (%s) exists already on another interface.\n",
+			   cf->name, cf->linenum, callsign);
+		    fail = 1;
+		    continue;
+		  }
+
+		} else if (strcmp(name, "initstring") == 0) {
+
+                  if (initstring == NULL) {
+                    initlength = parlen;
+                    initstring = malloc(parlen);
+                    memcpy(initstring, param1, parlen);
+                  } else {
+		    printf("%s:%d ERROR: Double-definition of initstring parameter.\n",
+			   cf->name, cf->linenum);
+		    fail = 1;
+                    break;
+                  }
+
+		} else if (strcmp(name, "tx-ok") == 0) {
+		  if (!config_parse_boolean(param1, &tx_ok)) {
+		    printf("%s:%d ERROR: Bad TX-OK parameter value -- not a recognized boolean: %s\n",
+			   cf->name, cf->linenum, param1);
+		    fail = 1;
+		    break;
+		  }
+
+		} else if (strcmp(name, "telem-to-is") == 0) {
+		  if (!config_parse_boolean(param1, &telemeter_to_is)) {
+		    printf("%s:%d ERROR: Bad TELEM-TO-IS parameter value -- not a recognized boolean: %s\n",
+			   cf->name, cf->linenum, param1);
+		    fail = 1;
+		    break;
+		  }
+
+		} else if (strcmp(name, "telem-to-rf") == 0) {
+		  if (!config_parse_boolean(param1, &telemeter_to_rf)) {
+		    printf("%s:%d ERROR: Bad TELEM-TO-RF parameter value -- not a recognized boolean: %s\n",
+			   cf->name, cf->linenum, param1);
+		    fail = 1;
+		    break;
+		  }
+
+		} else if (strcmp(name, "alias") == 0) {
+		  char *k = strtok(param1, ",");
+		  for (; k ; k = strtok(NULL,",")) {
+		    ++aliascount;
+		    if (debug) printf(" n=%d alias='%s'\n",aliascount,k);
+		    aliases = realloc(aliases, sizeof(char*) * aliascount);
+		    aliases[aliascount-1] = strdup(k);
+		  }
+
+#ifndef DISABLE_IGATE
+		} else if (strcmp(name, "igate-group") == 0) {
+		  // param1 = integer 1 to N.
+		  ifgroup = atol(param1);
+		  if (ifgroup < 1) {
+		    printf("%s:%d ERROR: interface 'igate-group' parameter value: '%s'  is an integer with minimum value of 1.\n",
+			   cf->name, cf->linenum, param1);
+		    fail = 1;
+		    break;
+                    /* -- no hard upper limit anymore
+		  } else if (ifgroup >= MAX_IF_GROUP) {
+		    printf("%s:%d ERROR: interface 'igate-group' parameter value: '%s'  is an integer with maximum value of %d.\n",
+			   cf->name, cf->linenum, param1, MAX_IF_GROUP-1);
+		    fail = 1;
+		    break;
+                    */
+		  }
+#endif
+
+		} else {
+		  printf("%s:%d ERROR: Unrecognized <interface> block keyword: %s\n",
+			   cf->name, cf->linenum, name);
+		  fail = 1;
+		  break;
+		}
+	}
+	if (fail) {
+        ERRORMEMFREE:
+          if (aliases != NULL) free(aliases);
+          if (initstring != NULL) free(initstring);
+          return 1; // this leaks memory (but also diagnoses bad input)
+        }
+
+	if (callsign == NULL) {
+	  // FIXME: Must define at least a callsign!
+	  printf("%s:%d ERROR: <kiss-subif ..> MUST define CALLSIGN parameter!\n",
+		 cf->name, cf->linenum);
+          goto ERRORMEMFREE;
+	}
+
+	if (find_interface_by_callsign(callsign) != NULL) {
+	  // An interface with THIS callsign does exist already!
+	  printf("%s:%d ERROR: Same callsign (%s) exists already on another interface.\n",
+		 cf->name, cf->linenum, callsign);
+          goto ERRORMEMFREE;
+	}
+
+        if (debug)
+          printf(" Defining <kiss-subif %d>  callsign=%s txok=%s\n", subif, callsign,
+                 tx_ok ? "true":"false");
+
+
+	aif = malloc(sizeof(*aif));
+	memcpy(aif, aifp, sizeof(*aif));
+
+	aif->callsign = callsign;
+	parse_ax25addr(aif->ax25call, callsign, 0x60);
+	aif->subif    = subif;
+	aif->tx_ok    = tx_ok;
+        aif->telemeter_to_is = telemeter_to_is;
+        aif->telemeter_to_rf = telemeter_to_rf;
+        // aif->telemeter_newformat = ...
+	aif->ifindex  = -1; // system sets automatically at store time
+	aif->ifgroup  = ifgroup; // either user sets, or system sets at store time
+
+        aifp->tty->interface  [subif] = aif;
+        aifp->tty->ttycallsign[subif] = callsign;
+#ifdef PF_AX25	/* PF_AX25 exists -- highly likely a Linux system ! */
+        aifp->tty->netax25    [subif] = netax25_open(callsign);
+#endif
+        if (initstring != NULL) {
+          aifp->tty->initlen[subif]    = initlength;
+          aifp->tty->initstring[subif] = initstring;
+        }
+
+	if (aliascount == 0 || aliases == NULL) {
+	  aif->aliascount = 3;
+	  aif->aliases    = interface_default_aliases;
+	} else {
+	  aif->aliascount = aliascount;
+	  aif->aliases    = aliases;
+	}
+
+	return 0;
+}
+
+void interface_init()
+{
+	interface_store( &aprsis_interface );
+}
+
+int interface_config(struct configfile *cf)
+{
+	struct aprx_interface *aif = calloc(1, sizeof(*aif));
+
+	char  *name, *param1;
+	char  *str = cf->buf;
+	int    parlen     = 0;
+	int    have_fault = 0;
+	int    maxsubif   = 16;  // 16 for most KISS modes, 8 for SMACK
+	int    defined_subinterface_count = 0;
+	int    ifgroup    = -1;
+
+	aif->iftype = IFTYPE_UNSET;
+	aif->aliascount = 3;
+	aif->aliases    = interface_default_aliases;
+	aif->ifindex    = -1; // system sets automatically at store time
+	aif->ifgroup    = ifgroup; // either user sets, or system sets at store time
+        aif->tx_ok      = 0;
+        aif->telemeter_to_is = 1;
+        aif->telemeter_to_rf = 1;
+        aif->telemeter_newformat = 0;
+
+	while (readconfigline(cf) != NULL) {
+		if (configline_is_comment(cf))
+			continue;	/* Comment line, or empty line */
+
+		// It can be severely indented...
+		str = config_SKIPSPACE(cf->buf);
+
+		name = str;
+		str = config_SKIPTEXT(str, NULL);
+		str = config_SKIPSPACE(str);
+		config_STRLOWER(name);
+
+		param1 = str;
+		str = config_SKIPTEXT(str, &parlen);
+		str = config_SKIPSPACE(str);
+
+		if (strcmp(name, "</interface>") == 0) {
+		  // End of this interface definition
+
+		  // make the interface...
+
+		  break;
+		}
+		if (strcmp(name, "<kiss-subif") == 0) {
+		  if (config_kiss_subif(cf, aif, param1, str, maxsubif)) {
+		    // Bad inputs.. complained already
+		    have_fault = 1;
+		  }
+		  // Always count as defined, even when an error happened!
+		  ++defined_subinterface_count;
+
+		  continue;
+		}
+
+		// Interface parameters
+
+		if (strcmp(name,"ax25-device") == 0) {
+#ifdef PF_AX25		// PF_AX25 exists -- highly likely a Linux system !
+		  if (aif->iftype == IFTYPE_UNSET) {
+		    aif->iftype = IFTYPE_AX25;
+		    // aif->nax25p = NULL;
+		  } else {
+		    printf("%s:%d ERROR: Only single device specification per interface block!\n",
+			   cf->name, cf->linenum);
+		    have_fault = 1;
+		    continue;
+		  }
+
+		  if (strcasecmp(param1,"$mycall") == 0)
+		    param1 = strdup(mycall);
+
+		  if (!validate_callsign_input(param1,1)) {
+		    printf("%s:%d ERROR: The CALLSIGN parameter on AX25-DEVICE must be of valid AX.25 format! '%s'\n",
+			   cf->name, cf->linenum, param1);
+		    have_fault = 1;
+		    continue;
+		  }
+
+		  if (find_interface_by_callsign(param1) != NULL) {
+		    // An interface with THIS callsign does exist already!
+		    printf("%s:%d ERROR: Same callsign (%s) exists already on another interface.\n",
+			   cf->name, cf->linenum, param1);
+		    have_fault = 1;
+		    continue;
+		  }
+
+		  if (debug)
+		    printf("%s:%d: AX25-DEVICE '%s' '%s'\n",
+			   cf->name, cf->linenum, param1, str);
+
+		  aif->callsign = strdup(param1);
+		  parse_ax25addr(aif->ax25call, aif->callsign, 0x60);
+		  aif->nax25p = netax25_addrxport(param1, aif);
+		  if (aif->nax25p == NULL) {
+		    printf("%s:%d ERROR: Failed to open this AX25-DEVICE: '%s'\n",
+			   cf->name, cf->linenum, param1);
+		    have_fault = 1;
+		    continue;
+		  }
+#else
+		  printf("%s:%d ERROR: AX25-DEVICE interfaces are not supported at this system!\n",
+			 cf->name, cf->linenum, param1);
+		  have_fault = 1;
+#endif
+
+		} else if ((strcmp(name,"serial-device") == 0) && (aif->tty == NULL)) {
+
+		  if (aif->iftype == IFTYPE_UNSET) {
+		    aif->iftype              = IFTYPE_SERIAL;
+		    aif->tty                 = ttyreader_new();
+		    aif->tty->ttyname        = strdup(param1);
+		    aif->tty->interface[0]   = aif;
+		    aif->tty->ttycallsign[0] = mycall;
+
+		    // end processing registers it
+
+		  } else {
+		    printf("%s:%d ERROR: Only single device specification per interface block!\n",
+			   cf->name, cf->linenum);
+		    have_fault = 1;
+		    continue;
+		  }
+
+		  if (debug)
+		    printf(".. new style serial:  '%s' '%s'.. tncid=0\n",
+			   aif->tty->ttyname, str);
+
+		  have_fault |= ttyreader_parse_ttyparams(cf, aif->tty, str);
+
+		  switch (aif->tty->linetype) {
+		  case LINETYPE_KISSSMACK:
+		    maxsubif = 8;  // 16 for most KISS modes, 8 for SMACK
+		    break;
+		  case LINETYPE_KISSFLEXNET:
+		    // ???
+		    break;
+		  default:
+		    break;
+		  }
+
+		  // Always count as defined, even when an error happened!
+		  ++defined_subinterface_count;
+
+		} else if ((strcmp(name,"tcp-device") == 0) && (aif->tty == NULL)) {
+		  int len;
+		  char *host, *port;
+
+		  if (aif->iftype == IFTYPE_UNSET) {
+		    aif->iftype = IFTYPE_TCPIP;
+		    aif->tty = ttyreader_new();
+		    aif->tty->interface[0] = aif;
+		    aif->tty->ttycallsign[0]  = mycall;
+
+		    // end-step processing registers it
+
+		  } else {
+		    printf("%s:%d ERROR: Only single device specification per interface block!\n",
+			   cf->name, cf->linenum);
+		    have_fault = 1;
+		    continue;
+		  }
+
+		  host = param1;
+
+		  port = str;
+		  str = config_SKIPTEXT(str, NULL);
+		  str = config_SKIPSPACE(str);
+
+		  if (debug)
+		    printf(".. new style tcp!:  '%s' '%s' '%s'..\n",
+			   host, port, str);
+
+		  len = strlen(host) + strlen(port) + 8;
+
+		  aif->tty->ttyname = malloc(len);
+		  sprintf((char *) (aif->tty->ttyname), "tcp!%s!%s!", host, port);
+
+		  have_fault |= ttyreader_parse_ttyparams( cf, aif->tty, str );
+
+		  switch (aif->tty->linetype) {
+		  case LINETYPE_KISSSMACK:
+		    maxsubif = 8;  // 16 for most KISS modes, 8 for SMACK
+		    break;
+		  case LINETYPE_KISSFLEXNET:
+		    // ???
+		    break;
+		  default:
+		    break;
+		  }
+
+		  // Always count as defined, even when an error happened!
+		  ++defined_subinterface_count;
+
+		} else if (strcmp(name,"null-device") == 0) {
+		  if (aif->iftype == IFTYPE_UNSET) {
+		    aif->iftype = IFTYPE_NULL;
+		    // aif->nax25p = NULL;
+		  } else {
+		    printf("%s:%d ERROR: Only single device specification per interface block!\n",
+			   cf->name, cf->linenum);
+		    have_fault = 1;
+		    continue;
+		  }
+		  aif->tx_ok = 1;
+
+		  if (strcasecmp(param1,"$mycall") == 0)
+		    param1 = strdup(mycall);
+
+		  if (find_interface_by_callsign(param1) != NULL) {
+		    // An interface with THIS callsign does exist already!
+		    printf("%s:%d ERROR: Same callsign (%s) exists already on another interface.\n",
+			   cf->name, cf->linenum, param1);
+		    have_fault = 1;
+		    continue;
+		  }
+
+                  if (!have_fault) {
+		    aif->iftype = IFTYPE_TCPIP;
+		    aif->tty = ttyreader_new();
+		    aif->tty->interface[0] = aif;
+		    aif->tty->ttycallsign[0]  = mycall;
+                  }
+		  have_fault |= ttyreader_parse_nullparams(cf, aif->tty, str);
+
+
+		  if (debug)
+		    printf("%s:%d: NULL-DEVICE '%s' '%s'\n",
+			   cf->name, cf->linenum, param1, str);
+
+		  aif->callsign = strdup(param1);
+		  parse_ax25addr(aif->ax25call, aif->callsign, 0x60);
+
+
+#ifdef ENABLE_AGWPE
+		} else if ((strcmp(name,"agwpe-device") == 0) && (aif->tty == NULL)) {
+
+		  // agwpe-device hostname hostport callsign agwpeportnum
+
+		  int len;
+		  const char *hostname, *hostport;
+		  char *callsign, *agwpeportnum;
+
+		  if (aif->iftype == IFTYPE_UNSET) {
+		    aif->iftype = IFTYPE_AGWPE;
+		    aif->tty = ttyreader_new();
+		    aif->tty->interface[0] = aif;
+		    aif->tty->ttycallsign[0]  = mycall;
+
+		    // end-step processing registers it
+
+		  } else {
+		    printf("%s:%d ERROR: Only single device specification per interface block!\n",
+			   cf->name, cf->linenum);
+		    have_fault = 1;
+		    continue;
+		  }
+
+		  hostname = strdup(param1);
+		  hostport = str;
+		  str = config_SKIPTEXT(str, NULL);
+		  str = config_SKIPSPACE(str);
+		  hostport = strdup(hostport);
+
+		  callsign = str;
+		  str = config_SKIPTEXT(str, NULL);
+		  str = config_SKIPSPACE(str);
+
+		  agwpeportnum = str;
+		  str = config_SKIPTEXT(str, NULL);
+		  str = config_SKIPSPACE(str);
+
+		  if (debug)
+		    printf(".. AGWPE-DEVICE:  '%s' '%s' '%s' '%s' ('%s'...)\n",
+			   hostname, hostport, callsign, agwpeportnum, str);
+
+		  len = strlen(hostname) + strlen(hostport) + strlen(agwpeportnum) + 8;
+		  aif->tty->ttyname = malloc(len);
+		  sprintf((char *) (aif->tty->ttyname), "tcp!%s!%s[%s]",
+			  hostname, hostport, agwpeportnum);
+
+
+		  if (strcasecmp(callsign,"$mycall") == 0)
+		    callsign = strdup(mycall);
+		  else
+		    callsign = strdup(callsign);
+
+		  if (!validate_callsign_input(callsign,1)) {
+		    printf("%s:%d ERROR: The CALLSIGN parameter on AGWPE-DEVICE must be of valid AX.25 format! '%s'\n",
+			   cf->name, cf->linenum, callsign);
+		    have_fault = 1;
+		    continue;
+		  }
+
+		  if (find_interface_by_callsign(callsign) != NULL) {
+		    // An interface with THIS callsign does exist already!
+		    printf("%s:%d ERROR: Same callsign (%s) exists already on another interface.\n",
+			   cf->name, cf->linenum, callsign);
+		    have_fault = 1;
+		    continue;
+		  }
+
+		  aif->callsign = callsign;
+		  parse_ax25addr(aif->ax25call, aif->callsign, 0x60);
+		  aif->agwpe = agwpe_addport(hostname, hostport, agwpeportnum, aif);
+		  if (aif->agwpe == NULL) {
+		    printf("%s:%d ERROR: Failed to setup this AGWPE-DEVICE: '%s'\n",
+			   cf->name, cf->linenum, callsign);
+		    have_fault = 1;
+		    continue;
+		  }
+
+		  // Always count as defined, even when an error happened!
+		  ++defined_subinterface_count;
+#endif
+		} else if (strcmp(name,"tx-ok") == 0) {
+
+                  int bool;
+		  if (!config_parse_boolean(param1, &bool)) {
+		    printf("%s:%d ERROR: Bad TX-OK parameter value -- not a recognized boolean: %s\n",
+			   cf->name, cf->linenum, param1);
+		    have_fault = 1;
+		    continue;
+		  }
+                  aif->tx_ok = bool;
+		  if (bool && aif->callsign) {
+		    if (!validate_callsign_input(aif->callsign,bool)) {  // Transmitters REQUIRE valid AX.25 address
+		      printf("%s:%d: ERROR: TX-OK 'TRUE' -- BUT PREVIOUSLY SET CALLSIGN IS NOT VALID AX.25 ADDRESS \n",
+			     cf->name, cf->linenum);
+		      continue;
+		    }
+		  }
+
+		} else if (strcmp(name, "telem-to-is") == 0) {
+                  int bool;
+		  if (!config_parse_boolean(param1, &bool)) {
+		    printf("%s:%d ERROR: Bad TELEM-TO-IS parameter value -- not a recognized boolean: %s\n",
+			   cf->name, cf->linenum, param1);
+		    have_fault = 1;
+		    break;
+		  }
+                  aif->telemeter_to_is = bool;
+
+		} else if (strcmp(name, "telem-to-rf") == 0) {
+                  int bool;
+		  if (!config_parse_boolean(param1, &bool)) {
+		    printf("%s:%d ERROR: Bad TELEM-TO-RF parameter value -- not a recognized boolean: %s\n",
+			   cf->name, cf->linenum, param1);
+		    have_fault = 1;
+		    break;
+		  }
+                  aif->telemeter_to_rf = bool;
+
+		} else if (strcmp(name,"timeout") == 0) {
+		  if (config_parse_interval(param1, &(aif->timeout) ) ||
+		      (aif->timeout < 0) || (aif->timeout > 1200)) {
+		    aif->timeout = 0;
+		    printf("%s:%d ERROR: Bad TIMEOUT parameter value: '%s' accepted range: 0 to 1200 seconds.\n",
+			   cf->name, cf->linenum, param1);
+		    have_fault = 1;
+		    continue;
+		  }
+		  if (aif->tty != NULL) {
+		    aif->tty->read_timeout = aif->timeout;
+		  }
+
+		} else if (strcmp(name, "callsign") == 0) {
+		  if (strcasecmp(param1,"$mycall") == 0)
+		    param1 = strdup(mycall);
+
+		  if (find_interface_by_callsign(param1) != NULL) {
+		    // An interface with THIS callsign does exist already!
+		    printf("%s:%d ERROR: Same callsign (%s) exists already on another interface.\n",
+			   cf->name, cf->linenum, param1);
+		    have_fault = 1;
+		    continue;
+		  }
+
+		  if (!validate_callsign_input(param1, aif->tx_ok)) {
+		    if (aif->tx_ok && aif->iftype != IFTYPE_NULL) {
+		      printf("%s:%d ERROR: The CALLSIGN parameter on transmit capable interface must be of valid AX.25 format! '%s'\n",
+			     cf->name, cf->linenum, param1);
+		      have_fault = 1;
+		      continue;
+		    }
+		  }
+
+		  if (aif->callsign != NULL)
+		    free(aif->callsign);
+		  aif->callsign = strdup(param1);
+		  parse_ax25addr(aif->ax25call, aif->callsign, 0x60);
+		  if (aif->tty != NULL)
+		    aif->tty->ttycallsign[0] = aif->callsign;
+
+		  if (debug)
+		    printf("  callsign= '%s'\n", aif->callsign);
+
+		} else if (strcmp(name, "initstring") == 0) {
+		  
+		  if (aif->tty != NULL) {
+		    int   initlength = parlen;
+		    char *initstring = malloc(parlen);
+		    memcpy(initstring, param1, parlen);
+		    aif->tty->initstring[0] = initstring;
+		    aif->tty->initlen[0]    = initlength;
+		  }
+
+		} else if (strcmp(name, "alias") == 0) {
+		  char *k = strtok(param1, ",");
+		  if (aif->aliases == interface_default_aliases) {
+		    aif->aliascount = 0;
+		    aif->aliases = NULL;
+		  }
+		  for (; k ; k = strtok(NULL,",")) {
+		    aif->aliascount += 1;
+		    if (debug) printf(" n=%d alias='%s'\n",aif->aliascount,k);
+		    aif->aliases = realloc(aif->aliases, sizeof(char*) * aif->aliascount);
+		    aif->aliases[aif->aliascount-1] = strdup(k);
+		  }
+
+#ifndef DISABLE_IGATE
+		} else if (strcmp(name, "igate-group") == 0) {
+		  // param1 = integer 1 to N.
+		  ifgroup = atol(param1);
+		  if (ifgroup < 1) {
+		    printf("%s:%d ERROR: interface 'igate-group' parameter value: '%s'  is an integer with minimum value of 1.\n",
+			   cf->name, cf->linenum, param1);
+		    have_fault = 1;
+		    continue;
+                    /* -- no hard upper limit anymore
+		  } else if (ifgroup >= MAX_IF_GROUP) {
+		    printf("%s:%d ERROR: interface 'igate-group' parameter value: '%s'  is an integer with maximum value of %d.\n",
+			   cf->name, cf->linenum, param1, MAX_IF_GROUP-1);
+		    have_fault = 1;
+		    continue;
+                    */
+		  }
+#endif
+
+		} else {
+		  printf("%s:%d ERROR: Unknown <interface> config entry name: '%s'\n",
+			 cf->name, cf->linenum, name);
+		  have_fault = 1;
+		}
+	}
+
+
+	while (!have_fault &&
+	       aif->callsign == NULL &&
+	       (aif->iftype == IFTYPE_SERIAL || aif->iftype == IFTYPE_TCPIP) &&
+	       defined_subinterface_count == 1) {
+
+	        // First check if there already is an interface with $mycall
+		// callsign on it..
+	
+		if (find_interface_by_callsign(mycall) != NULL) {
+		  // An interface with $MYCALL callsign does exist already!
+		  printf("%s:%d ERROR: The $MYCALL callsign (%s) exists already on another interface.\n",
+			 cf->name, cf->linenum, mycall);
+		  have_fault = 1;
+		  break;
+		}
+
+		// Supply a default value
+		aif->callsign = strdup(mycall);
+		parse_ax25addr(aif->ax25call, aif->callsign, 0x60);
+		
+#ifdef PF_AX25	// PF_AX25 exists -- highly likely a Linux system !
+		// With enough defaults being used, the callsign is defined
+		// by global "macro"  mycall,  and never ends up activating
+		// the tty -> linux kernel kiss/smack pty  interface.
+		// This part does that final step for minimalistic config.
+		if (aif->tty != NULL &&
+		    aif->tty->netax25[0] == NULL &&
+		    aif->tty->ttycallsign[0] != NULL) {
+			aif->tty->netax25[0]
+			  = netax25_open(aif->tty->ttycallsign[0]);
+		}
+#endif
+		// Done it, leave..
+		break;
+	}
+
+	if (!have_fault) {
+		int i;
+
+		if (aif->tty != NULL) {
+		  // Register all tty subinterfaces
+                  if (debug) printf(" .. store tty subinterfaces\n");
+		  for (i = 0; i < maxsubif; ++i) {
+		    if (aif->tty->interface[i] != NULL) {
+                      if (debug) printf(" .. store interface[%d] callsign='%s'\n",i, aif->tty->interface[i]->callsign);
+		      interface_store(aif->tty->interface[i]);
+		    }
+		  }
+		} else {
+		  // Not TTY multiplexed ( = KISS ) interface,
+		  // register just the primary.
+		  aif->ifgroup = ifgroup; // either user sets, or system sets at store time
+		  interface_store(aif);
+
+                  if (debug) printf(" .. store other interface\n");
+
+		}
+
+		if (aif->iftype == IFTYPE_SERIAL)
+		  ttyreader_register(aif->tty);
+
+		if (aif->iftype == IFTYPE_TCPIP)
+		  ttyreader_register(aif->tty);
+
+	} else {
+        	if (aif->callsign) free(aif->callsign);
+                if (aif->tty) {
+                  if (aif->tty->ttyname) free((void*)(aif->tty->ttyname));
+                }
+                
+                free(aif);
+        }
+
+        // coverity[leaked_storage]
+	return have_fault;
+}
+
+
+/*
+ * Process received AX.25 packet
+ *   - from AIF do find all DIGIPEATERS wanting this source.
+ *   - If there are none, end processing.
+ *   - Parse the received frame for possible latter filters
+ *   - Feed the resulting parsed packet to each digipeater
+ *
+ *
+ * Tx-IGate rules:
+ *
+ // 2) - sending station has not been heard recently
+ //      on radio
+ // 1) - verify receiving station has been heard
+ //      recently on radio
+ // 4) - the receiving station has not been heard via
+ //      the Internet within a predefined time period.
+ //      (Note that _this_ packet is heard from internet,
+ //      so one must not confuse this to history..
+ //      Nor this siblings that are being created
+ //      one for each tx-interface...)
+ // 
+ //  A station is said to be heard via the Internet if packets
+ //  from the station contain TCPIP* or TCPXX* in the header or
+ //  if gated (3rd-party) packets are seen on RF gated by the
+ //  station and containing TCPIP or TCPXX in the 3rd-party
+ //  header (in other words, the station is seen on RF as being
+ //  an IGate). 
+ *
+ * That is, this part of code collects knowledge of RF-wise near-by TX-IGATEs.
+ */
+
+void interface_receive_ax25(const struct aprx_interface *aif,
+			    const char *ifaddress, const int is_aprs, const int ui_pid,
+			    const uint8_t *axbuf, const int axaddrlen, const int axlen,
+			    const char    *tnc2buf, const int tnc2addrlen, const int tnc2len)
+{
+	int i;
+	int digi_like_aprs = is_aprs;
+
+	if (aif == NULL) return;         // Not a real interface for digi use
+	if (aif->digisourcecount == 0) {
+	  if (debug>1) printf("interface_receive_ax25() no receivers for source %s\n",aif->callsign);
+	  return; // No receivers for this source
+	}
+
+	if (debug) printf("interface_receive_ax25() from %s axlen=%d tnc2len=%d\n",aif->callsign,axlen,tnc2len);
+
+
+	if (axaddrlen <= 14) return;     // SOURCE>DEST without any VIAs..
+	// Note: Above one disables MICe destaddress-SSID embedded
+	//       extremely compressed WIDEn-N notation.
+
+// FIXME: match ui_pid to list of UI PIDs that are treated with similar
+//        digipeat rules as is APRS New-N.
+
+	// ui_pid < 0 means that this frame is not an UI frame at all.
+	if (ui_pid >= 0)  digi_like_aprs = 1; // FIXME: more precise matching?
+
+
+	for (i = 0; i < aif->digisourcecount; ++i) {
+	    struct digipeater_source *digisource = aif->digisources[i];
+#ifndef DISABLE_IGATE
+            // Transmitter's HistoryDB
+	    historydb_t *historydb = digisource->parent->historydb;
+#endif
+
+	    // Allocate pbuf, it is born "gotten" (refcount == 1)
+	    struct pbuf_t *pb = pbuf_new(is_aprs, digi_like_aprs,
+                                         tnc2addrlen, tnc2buf, tnc2len,
+                                         axaddrlen, axbuf, axlen);
+	    if (pb == NULL) {
+	      // Urgh!  Can't do a thing to this!
+	      // Likely reason: axlen+tnc2len  > 2100 bytes!
+	      continue;
+	    }
+
+	    pb->source_if_group = aif->ifgroup;
+
+	    // If APRS packet, then parse for APRS meaning ...
+	    if (is_aprs) {
+		int rc = parse_aprs(pb,
+#ifndef DISABLE_IGATE
+				    historydb
+#else
+				    NULL
+#endif
+				    ); // don't look inside 3rd party
+		char *srcif = aif->callsign;
+		if (debug)
+		  printf(".. parse_aprs() rc=%s  type=0x%02x  srcif=%s  tnc2addr='%s'  info_start='%s'\n",
+			 rc ? "OK":"FAIL", pb->packettype, srcif, pb->data, pb->info_start);
+
+		// If there are no filters, permit all packets
+		if (digisource->src_filters != NULL) {
+		  int filter_discard =
+		    filter_process(pb,
+				   digisource->src_filters,
+#ifndef DISABLE_IGATE
+				   historydb // Transmitter HistoryDB
+#else
+				   NULL
+#endif
+				   );
+		  // filter_discard > 0: accept
+		  // filter_discard = 0: indifferent (not reject, not accept), tx-igate rules as is.
+		  // filter_discard < 0: reject
+		  if (debug)
+		    printf("source filtering result: %s\n",
+			   (filter_discard < 0 ? "DISCARD" :
+			    (filter_discard > 0 ? "ACCEPT" : "no-match")));
+
+		  if (filter_discard <= 0) {
+		    pbuf_put(pb);
+		    continue; // allow only explicitly accepted
+		  }
+		}
+
+#ifndef DISABLE_IGATE
+		// Find out IGATE callsign (if any), and record it on transmitter's historydb.
+		if (pb->packettype & T_THIRDPARTY) {
+		  rx_analyze_3rdparty( historydb, pb );
+		} else {
+		  // Everything else, feed to history-db
+		  historydb_insert_heard( historydb, pb );
+		}
+#endif
+	    }
+
+	    // Feed it to digipeater ...
+	    digipeater_receive( digisource, pb);
+
+	    // .. and finally free up the pbuf (if refcount goes to zero)
+	    pbuf_put(pb);
+	}
+}
+
+
+/*
+ * Process AX.25 packet transmit; beacons, digi output, igate output...
+ *
+ *   - aif:    output interface
+ *   - axaddr: ax.25 address
+ *   - axdata: payload content, with control and PID bytes prefixing them
+ */
+
+void interface_transmit_ax25(const struct aprx_interface *aif, uint8_t *axaddr, const int axaddrlen, const char *axdata, const int axdatalen)
+{
+	int axlen = axaddrlen + axdatalen;
+	uint8_t *axbuf;
+
+	if (debug) {
+	  const char *callsign = "";
+	  if (aif != NULL) callsign=aif->callsign;
+	  printf("interface_transmit_ax25(aif=%p[%s], .., axlen=%d)\n",
+		 aif, callsign, axlen);
+	}
+	if (axlen == 0) return;
+	if (aif == NULL) return;
+
+
+	switch (aif->iftype) {
+	case IFTYPE_SERIAL:
+	case IFTYPE_TCPIP:
+		// If there is linetype error, kisswrite detects it.
+		// Make it into single buffer to give to KISS sender
+                if (debug>2) {
+                  printf("serial_sendto() len=%d,%d: ",axaddrlen,axdatalen);
+                  hexdumpfp(stdout, axaddr, axaddrlen, 1);
+                  printf(" // ");
+                  hexdumpfp(stdout, (uint8_t*)axdata, axdatalen, 0);
+                  printf("\n");
+                }
+
+		axbuf = alloca(axlen);
+		memcpy(axbuf, axaddr, axaddrlen);
+		memcpy(axbuf + axaddrlen, axdata, axdatalen);
+		kiss_kisswrite(aif->tty, aif->subif, axbuf, axlen);
+		break;
+#ifdef PF_AX25	/* PF_AX25 exists -- highly likely a Linux system ! */
+	case IFTYPE_AX25:
+		// The Linux netax25 sender takes same data as this interface
+		netax25_sendto( aif->nax25p,
+				axaddr, axaddrlen,
+				axdata, axdatalen );
+		break;
+#endif
+#ifdef ENABLE_AGWPE
+	case IFTYPE_AGWPE:
+		agwpe_sendto( aif->agwpe,
+			      axaddr, axaddrlen,
+			      axdata, axdatalen );
+		break;
+#endif
+	case IFTYPE_NULL:
+		// Efficient transmitter :-)
+		if (debug>1)
+			printf("tx null-device: %s\n", aif->callsign);
+
+                if (debug>2) {
+                  printf("null_sendto() len=%d,%d ",axaddrlen,axdatalen);
+                  hexdumpfp(stdout, axaddr, axaddrlen, 1);
+                  printf(" // ");
+                  hexdumpfp(stdout, (uint8_t*)axdata, axdatalen, 0);
+                  printf("\n");
+                }
+
+		// Account the transmission anyway ;-)
+		erlang_add(aif->callsign, ERLANG_TX, axaddrlen+axdatalen + 10, 1);
+		break;
+	default:
+		break;
+	}
+}
+
+#ifndef DISABLE_IGATE
+/*
+ * Process received AX.25 packet  -- for APRSIS
+ *   - from AIF do find all DIGIPEATERS wanting this source.
+ *   - If there are none, end processing.
+ *   - Parse the received frame for possible latter filters
+ *   - Feed the resulting parsed packet to each digipeater
+ *
+ * See:  http://www.aprs-is.net/IGateDetails.aspx
+ *
+ *  Paths
+ *
+ * IGates should use the 3rd-party format on RF of
+ * IGATECALL>APRS,GATEPATH}FROMCALL>TOCALL,TCPIP,IGATECALL*:original packet data
+ * where GATEPATH is the path that the gated packet is to follow
+ * on RF. This format will allow IGates to prevent gating the packet
+ * back to APRS-IS.
+ * 
+ * q constructs should never appear on RF.
+ * The I construct should never appear on RF.
+ * Except for within gated packets, TCPIP and TCPXX should not be
+ * used on RF.
+ *
+ * Part of the Tx-IGate logic is here because we use pbuf_t data blocks:
+ *
+ *  1) The receiving station has been heard recently
+ *     within defined range limits, and more recently
+ *     than since given interval T1. (Range as digi-hops [N1]
+ *     or coordinates, or both.)
+ *
+ *  2) The sending station has not been heard via RF
+ *     within timer interval T2. (Third-party relayed
+ *     frames are not analyzed for this.)
+ *
+ *  4) the receiving station has not been heard via the Internet
+ *     within a predefined time period.
+ *     A station is said to be heard via the Internet if packets
+ *     from the station contain TCPIP* or TCPXX* in the header or
+ *     if gated (3rd-party) packets are seen on RF gated by the
+ *     station and containing TCPIP or TCPXX in the 3rd-party
+ *     header (in other words, the station is seen on RF as being
+ *     an IGate). 
+ *
+ * 5)  Gate all packets to RF based on criteria set by the sysop
+ *     (such as callsign, object name, etc.).
+ *
+ * c)  Drop everything else.
+ */
+
+static uint8_t toaprs[7] =    { 'A'<<1,'P'<<1,'R'<<1,'S'<<1,' '<<1,' '<<1,0x60 };
+
+void interface_receive_3rdparty( const struct aprx_interface *aif,
+				 const char *fromcall,
+				 const char *origtocall,
+				 const char *gwtype,
+				 const char *tnc2data,
+				 const int tnc2datalen )
+{
+	int d; // digipeater index
+
+	char     tnc2buf1[2800];
+	uint8_t  ax25buf1[2800];
+
+	time_t recent_time = tick.tv_sec - 3600; // "recent" = 1 hour
+        uint16_t filter_packettype = 0;
+        int ax25addrlen1;
+        int ax25len1;
+        int rc, tnc2addrlen1, tnc2len1;
+        uint8_t *a;
+        char    *t;
+        struct pbuf_t *pb;
+
+
+	if (debug)
+	  printf("interface_receive_3rdparty() aif=%p, aif->digicount=%d\n",
+		 aif, aif ? aif->digisourcecount : -1);
+
+
+	if (aif == NULL) {
+	  return;         // Not a real interface for digi use
+	}
+
+
+        // We have to recognize incoming messages targeted to
+        // this server.  For this we need to parse the TNC2 frame.
+        // 
+        // We have a also filter statements to process here,
+        // we need to turn incoming APRSIS frame to something
+        // that the filter can process:
+        
+        // Incoming:
+        //   EI7IG-1>APRS,TCPIP*,qAC,T2IRELAND:@262231z5209.97N/00709.65W_238/019g019t049P006h95b10290.wview_5_19_0
+        // Filtered:
+        //   EI7IG-1>APRS:@262231z5209.97N/00709.65W_238/019g019t049P006h95b10290.wview_5_19_0
+
+        a = ax25buf1;
+        parse_ax25addr( a, tocall, 0x60 );
+        a += 7;
+        parse_ax25addr( a, fromcall, 0x60 );
+        a += 7;
+        // No need to add generated VIA address component
+        // to this filter input data
+        a[-1] |= 0x01; // end-of-address bit
+        ax25addrlen1 = a - ax25buf1;
+        *a++ = 0x03;
+        *a++ = 0xF0;
+        if ((sizeof(ax25buf1) - tnc2datalen) <= (a-ax25buf1)) {
+          if (debug) printf(" .. data does not fit on ax25buf");
+          return;
+        }
+
+        memcpy( a, tnc2data, tnc2datalen );
+        a += tnc2datalen;
+        ax25len1 = (a - ax25buf1);
+
+        t = tnc2buf1;
+        t += sprintf(t, "%s>%s:", fromcall, origtocall);
+        tnc2addrlen1 = t - tnc2buf1 - 1;
+        if ((sizeof(tnc2buf1) - tnc2datalen) <= (t-tnc2buf1)) {
+          if (debug) printf(" .. data does not fit on tnc2buf");
+          return;
+        }
+        memcpy(t, tnc2data, tnc2datalen);
+        t += tnc2datalen;
+        tnc2len1 = (t - tnc2buf1);
+
+        // Allocate temporary pbuf for filter call use
+        pb = pbuf_new(1 /*is_aprs*/, 1 /* digi_like_aprs */, 
+                      tnc2addrlen1, tnc2buf1, tnc2len1,
+                      ax25addrlen1, ax25buf1, ax25len1);
+        if (pb == NULL) {
+          // Urgh!  Can't do a thing to this!
+          // Likely reason: ax25len+tnc2len  > 2100 bytes!
+          if (debug) printf("pbuf_new() returned NULL! Discarding!\n");
+          return;
+        }
+
+        pb->source_if_group = 0; // 3rd-party frames are always from APRSIS
+
+
+        // This is APRS packet, parse for APRS meaning ...
+        rc = parse_aprs(pb, NULL); // look inside 3rd party -- historydb is looked up again below
+        if (debug) {
+          const char *srcif = aif->callsign ? aif->callsign : "??";
+          printf(".. parse_aprs() rc=%s  type=0x%02x srcif=%s tnc2addr='%s'  info_start='%s'\n",
+                 rc ? "OK":"FAIL", pb->packettype, srcif, pb->data,
+                 pb->info_start);
+        }
+
+        filter_packettype = pb->packettype;
+
+        // Check if it is a message destined to myself, and process if so.
+        rc = process_message_to_myself(aif, pb);
+
+        // Drop the temporary pbuf..
+        pbuf_put(pb);
+
+        if (rc != 0) {
+          return; // Processed as message-to-myself
+        }
+
+	if (aif->digisourcecount == 0) {
+	  return; // No receivers for this source
+	}
+
+	// Feed it to digipeaters ...
+	for (d = 0; d < aif->digisourcecount; ++d) {
+	  struct digipeater_source *digisrc = aif->digisources[d];
+	  struct digipeater        *digi    = digisrc->parent;
+	  struct aprx_interface    *tx_aif  = digi->transmitter;
+#ifndef DISABLE_IGATE
+	  historydb_t            *historydb = digi->historydb;
+#endif
+	  char *srcif;
+	  int  discard_this, filter_discard;
+          char     tnc2buf[2800];
+          uint8_t  ax25buf[2800];
+          int ax25addrlen, ax25len;
+          int tnc2addrlen, tnc2len;
+
+          // This is APRS packet, parse for APRS meaning ...
+          rc = parse_aprs(pb,
+#ifndef DISABLE_IGATE
+                          historydb // Transmitter HistoryDB
+#else
+                          NULL
+#endif
+                          ); // look inside 3rd party -- TODO: but what HISTORYDB ?
+          if (debug) {
+            const char *srcif = aif->callsign ? aif->callsign : "??";
+            printf(".. parse_aprs() rc=%s  type=0x%02x srcif=%s tnc2addr='%s'  info_start='%s'\n",
+                   rc ? "OK":"FAIL", pb->packettype, srcif, pb->data,
+                   pb->info_start);
+          }
+
+
+	  // Produced 3rd-party packet:
+	  //   IGATECALL>APRS,GATEPATH:}FROMCALL>TOCALL,TCPIP,IGATECALL*:original packet data
+
+	  if (debug) printf("## produce 3rd-party frame for transmit:\n");
+	  // Parse the TNC2 format to AX.25 format
+	  // using ax25buf[] storage area.
+	  memcpy(ax25buf,    toaprs, 7);           // AX.25 DEST call
+
+	  // FIXME: should this be IGATECALL, not tx_aif->ax25call ??
+	  memcpy(ax25buf+7,  tx_aif->ax25call, 7); // AX.25 SRC call
+
+	  a = ax25buf + 2*7;
+
+          if ((filter_packettype & T_MESSAGE) != 0 && digisrc->msg_path != NULL) {
+            if (digisrc->msg_path != NULL) {
+              memcpy(a, digisrc->msgviapath, 7);    // AX.25 VIA call for a Message
+              a += 7;
+            }
+          } else {
+            if (digisrc->via_path != NULL) {
+              memcpy(a, digisrc->ax25viapath, 7);    // AX.25 VIA call
+              a += 7;
+            }
+          }
+
+	  *(a-1) |= 0x01;                  // DEST,SRC(,VIA1) - end-of-address bit
+	  ax25addrlen = a - ax25buf;
+
+	  if (debug>2) {
+	    printf("ax25hdr ");
+	    hexdumpfp(stdout, ax25buf, ax25addrlen, 1);
+	    printf("\n");
+	  }
+
+	  *a++ = 0x03; // UI
+	  *a++ = 0xF0; // PID = 0xF0
+
+	  a += sprintf((char*)a, "}%s>%s,%s,%s*:",
+		       fromcall, origtocall, gwtype, tx_aif->callsign );
+	  ax25len = a - ax25buf;
+	  if (tnc2datalen + ax25len > sizeof(ax25buf)) {
+	    // Urgh...  Can not fit it in :-(
+	    if(debug)printf("data does not fit into ax25buf: %d > %d\n",
+			    tnc2datalen+ax25len, (int)sizeof(ax25buf));
+	    continue;
+	  }
+	  memcpy(a, tnc2data, tnc2datalen);
+	  ax25len += tnc2datalen;
+
+	  // AX.25 packet is built, now build TNC2 version of it
+	  t = tnc2buf;
+	  t += sprintf(t, "%s>%s", tx_aif->callsign, tocall);
+          if ((filter_packettype & T_MESSAGE) != 0 && digisrc->msg_path != NULL) {
+            if (digisrc->msg_path != NULL) {
+              t += sprintf(t, ",%s", digisrc->msg_path);
+            }
+          } else {
+            if (digisrc->via_path != NULL) {
+              t += sprintf(t, ",%s", digisrc->via_path);
+            }
+          }
+	  if (debug>1)printf(" tnc2addr = %s\n", tnc2buf);
+
+	  tnc2addrlen = t - tnc2buf;
+	  *t++ = ':';
+	  t += sprintf(t, "}%s>%s,%s,%s*:",
+		       fromcall, origtocall, gwtype, tx_aif->callsign );
+	  if (tnc2datalen + (t-tnc2buf) +4 > sizeof(tnc2buf)) {
+	    // Urgh...  Can not fit it in :-(
+	    if(debug)printf("data does not fit into tnc2buf: %d > %d\n",
+			    (int)(tnc2datalen+(t-tnc2buf)+4),
+			    (int)sizeof(tnc2buf));
+	    continue;
+	  }
+	  memcpy(t, tnc2data, tnc2datalen);
+	  t += tnc2datalen;
+	  tnc2len = (t - tnc2buf);
+
+	  // Allocate pbuf, it is born "gotten" (refcount == 1)
+	  pb = pbuf_new(1 /*is_aprs*/, 1 /* digi_like_aprs */,
+                        tnc2addrlen, tnc2buf, tnc2len,
+                        ax25addrlen, ax25buf, ax25len);
+	  if (pb == NULL) {
+	    // Urgh!  Can't do a thing to this!
+	    // Likely reason: ax25len+tnc2len  > 2100 bytes!
+	    if (debug) printf("pbuf_new() returned NULL! Discarding!\n");
+	    continue;
+	  }
+
+	  pb->source_if_group = 0; // 3rd-party frames are always from APRSIS
+	  srcif = aif->callsign ? aif->callsign : "??";
+
+	  // This is APRS packet, parse for APRS meaning ...
+	  rc = parse_aprs(pb, historydb); // look inside 3rd party
+	  if (debug)
+	    printf(".. parse_aprs() rc=%s  type=0x%02x srcif=%s tnc2addr='%s'  info_start='%s'\n",
+		   rc ? "OK":"FAIL", pb->packettype, srcif, pb->data,
+		   pb->info_start);
+
+          // 1) - verify receiving station has been heard
+          //      recently on radio
+          // 2) - sending station has not been heard recently
+          //      on radio
+          // 4) - the receiving station has not been heard via
+          //      the Internet within a predefined time period.
+          //      (Note that _this_ packet is heard from internet,
+          //      so one must not confuse this to history..
+          //      Nor this siblings that are being created
+          //      one for each tx-interface...)
+	  // 
+	  //  A station is said to be heard via the Internet if packets
+	  //  from the station contain TCPIP* or TCPXX* in the header or
+	  //  if gated (3rd-party) packets are seen on RF gated by the
+	  //  station and containing TCPIP or TCPXX in the 3rd-party
+	  //  header (in other words, the station is seen on RF as being
+	  //  an IGate). 
+
+
+	  // Message Tx-IGate rules..
+	  discard_this = 0;
+
+	  if (pb->dstname == NULL) {
+	    // Sanity -- not a message..
+	    discard_this = 1;
+	  }
+	  if (filter_packettype == 0)
+	    filter_packettype = pb->packettype;
+	  if ((filter_packettype & T_MESSAGE) == 0) {
+	    // Not a message packet
+	    discard_this = 1;
+	  }
+	  if ((filter_packettype & (T_NWS)) != 0) {
+	    // Not a weather alert packet
+	    discard_this = 1;
+	  }
+
+	  // Accept/Reject the packet by digipeater rx filter?
+	  filter_discard = 0;
+	  if (digisrc->src_filters == NULL) {
+	    // No filters defined, default Tx-iGate rules apply
+	  } else {
+
+	    if (debug) printf("## process source filter\n");
+
+	    {
+	      // Stores position, and message references
+	      void *v = historydb_insert_heard( historydb, pb );
+	      if (debug) printf("historydb_insert_heard(APRSIS) v=%p\n", v);
+	    }
+
+	    filter_discard = filter_process(pb, digisrc->src_filters, historydb);
+
+	    if (debug) printf("filter says: %d (%s)\n", filter_discard, (filter_discard > 0 ? "accept" : (filter_discard == 0 ? "indifferent" : "reject")));
+
+            // filter_discard > 0: accept
+            // filter_discard = 0: indifferent (not reject, not accept), tx-igate rules as is.
+            // filter_discard < 0: reject
+
+            // Manual filter says: Reject!
+	    if (filter_discard < 0) {
+	      if (debug) printf("REJECTED!\n");
+              discard_this = 1;
+	    }
+            // Manual filter says: Accept!
+            if (discard_this && filter_discard > 0) {
+              if (debug) printf("filters say: send!\n");
+	    discard_this = 0;
+            }
+	  }
+
+
+	  if (!discard_this && pb->dstname != NULL) {
+	    // 1) - verify receiving station has been heard
+	    //      recently on radio
+	    char recipient[10];
+	    history_cell_t *hist_rx;
+            int i = 0;
+            while ( i < 9 && pb->dstname[i] != 0 && pb->dstname[i] != ' ' ) {
+              recipient[i] = pb->dstname[i];
+              ++i;
+            }
+            recipient[i] = 0;
+
+            pb->dstname_len = strlen(recipient);
+
+	    // FIXME?  Should test all SSIDs of this target callsign,
+	    //         not just this one target,
+	    //         if this is a T_MESSAGE!  (strange BoB rules...)
+
+	    hist_rx = historydb_lookup(historydb, recipient, strlen(recipient));
+	    if (hist_rx == NULL) {
+	      if (debug) printf("No history entry for receiving call: '%s'  DISCARDING.\n", recipient);
+	      discard_this = 1;
+	    }
+	    // See that it has 'heard on radio' flag on this tx interface
+	    if (hist_rx != NULL && discard_this == 0) {
+	      if (timecmp(hist_rx->last_heard[tx_aif->ifgroup], recent_time) >= 0) {
+		// Heard recently enough
+		discard_this = 0;
+		if (debug) printf("History entry for receiving call '%s' from RADIO is recent enough.  KEEPING.\n", recipient);
+	      }
+	    }
+
+	    // FIXME: Check that recipient is in our service area
+	    //        a) coordinate is "near by"
+	    //        b) last known hop-count is low enough
+	    //           (FIXME: RF hop-count recording infra needed!)
+
+	    // 4) the receiving station has not been heard via the internet
+	    if (hist_rx != NULL && timecmp(hist_rx->last_heard[0], recent_time) > 0) {
+	      // "is heard recently via internet"
+	      discard_this = 1;
+	      if (debug) printf("History entry for sending call '%s' from APRSIS is too new.  DISCARDING.\n", fromcall);
+	    }
+	  }
+
+	  if (!discard_this) {
+	    history_cell_t *hist_tx = historydb_lookup(historydb, fromcall, strlen(fromcall));
+	    // If no history entry for this tx callsign,
+	    // then rules 2 and 4 permit tx-igate
+	    if (hist_tx != NULL) {
+	      // There is a history entry for this tx callsign, check rules 2+4
+	      // 2) Sending station has not been heard recently on radio (this target)
+	      if (timecmp(hist_tx->last_heard[tx_aif->ifgroup], recent_time) > 0) {
+		// "is heard recently"
+		discard_this = 1;
+		if (debug) printf("History entry for sending call '%s' from RADIO is too new.  DISCARDING.\n", fromcall);
+	      }
+	    }
+	  }
+
+	  {
+	    // Stores position, and message references
+	    void *v = historydb_insert_heard( historydb, pb );
+	    if (debug) printf("historydb_insert_heard(APRSIS) v=%p\n",v);
+	  }
+
+	  if (filter_discard > 0 || (filter_discard == 0 && !discard_this)) {
+	    // Not discarding - approved for transmission
+
+	    if ((filter_packettype & T_POSITION) == 0) {
+	      // TODO: For position-less packets send at first a position packet
+	      //       for same source call sign -- if available.
+	      
+	    }
+
+	    if (debug) printf("Send to digipeater\n");
+	    digipeater_receive( digisrc, pb);
+	  } else {
+	    if (debug) printf("DISCARDED! (filter_discard=%d, discard_this=%d)\n",filter_discard, discard_this);
+	  }
+
+	  // .. and finally free up the pbuf (if refcount goes to 0)
+	  pbuf_put(pb);
+	}
+}
+
+/*
+ * See if this is a message that is destined to myself
+ */
+
+#define DSTNAMELEN 16  /* 8+1+2+1 = 12, use 16 for stack align */
+
+static int dstname_is_myself(const struct pbuf_t*const pb, char *dstname, const struct aprx_interface**aifp)
+{
+	struct aprx_interface *aif;
+
+	// Copy message destination, if available.
+        *dstname = 0; // always clear first..
+        if (pb->dstname != NULL) {
+          strncpy(dstname, pb->dstname, DSTNAMELEN-1);
+          dstname[DSTNAMELEN-1] = 0;
+        }
+
+        if (strcmp(dstname, mycall) == 0) {
+          // To MYCALL account
+          return 1;
+        }
+        if (aprsis_loginid != NULL && strcmp(dstname, aprsis_loginid) == 0) {
+          // To APRSIS login account
+          return 1;
+        }
+
+        // Maybe one of my transmitters?
+        aif = find_interface_by_callsign(dstname);
+        if (aif != NULL && aif->tx_ok) {
+          // To one of my transmitter interfaces
+          *aifp = aif;
+          return 1;
+        }
+        // None of my identities
+        return 0;
+}
+
+/*
+ * Ack the message 
+ */
+static void ack_message(const struct aprx_interface *const srcif, const struct aprx_interface *const aif, const struct pbuf_t*const pb, const struct aprs_message_t*const am, const char*const dstname)
+{
+	// ACK message to APRSIS is simple(ish), routing it is another thing..
+	if (srcif == &aprsis_interface) {
+          char destbuf[50];
+          int destlen = sprintf(destbuf, "%s>APRS,TCPIP*", dstname);
+          char txt[50];
+          int txtlen;
+          char *t = txt;
+          const char *s = pb->srcname;
+          int i;
+          *t++ = ':';
+          for (i = 0; i < 9 && i < pb->srcname_len; ++i) {
+            *t++ = *s++;
+          }
+          for ( ; i < 9 ; ++i) {
+            *t++ = ' ';
+          }
+          *t++ = ':';
+          *t++ = 'a';
+          *t++ = 'c';
+          *t++ = 'k';
+          for (i = 0, s = am->msgid; i < am->msgid_len; ++i) {
+            *t++ = *s++;
+          }
+          txtlen = t - txt;
+
+          aprsis_queue(destbuf, destlen,
+                       qTYPE_LOCALGEN,
+                       aprsis_login, txt, txtlen);
+          return;
+        }
+        // TODO: ACK things sent via radio interfaces?
+}
+
+/*
+ * A message is destined to myself, lets look closer..
+ * Return non-zero if it was recognized as targeted to this node.
+ */
+int process_message_to_myself(const struct aprx_interface*const srcif, const struct pbuf_t*const pb)
+{
+	struct aprs_message_t am;
+        int rc;
+        const struct aprx_interface*aif = srcif;
+	char dstname[DSTNAMELEN];
+
+        if ((pb->packettype & T_MESSAGE) == 0) {
+          return 0; // Not a message!
+        }
+
+        if (!dstname_is_myself(pb, dstname, &aif)) {
+          // Not destined to me
+          // This will also reject bulletins, which one is not supposed to ACK anyway..
+          return 0;
+        }
+
+        rc = parse_aprs_message(pb, &am);
+        if (rc != 0) {
+          // Not acceptable parse result
+          return 0;
+        }
+
+        // Whatever message, syslog it.
+        syslog(LOG_INFO, "%*s", pb->packet_len, pb->data);
+
+        if (am.is_rej || am.is_ack) {
+          // A REJect or ACKnowledge received, drop.
+          return 1;
+        }
+
+        // If there is msgid in the message -> I need to ACK it.
+        if (am.msgid != NULL) {
+          ack_message(srcif, aif, pb, &am, dstname);
+        }
+
+        // TODO: Process the message ?
+
+        return 1;
+}
+#endif
+
+/*
+ * Process transmit of APRS beacons
+ *
+ * Note:  txbuf  starts if AX.25 Control+PID bytes!
+ */
+
+int interface_transmit_beacon(const struct aprx_interface *aif, const char *src, const char *dest, const char *via, const char *txbuf, const int txlen)
+{
+	uint8_t ax25addr[90];
+	int     ax25addrlen;
+	int	have_fault = 0;
+	int	viaindex   = 1; // First via field will be index 2
+	char    axaddrbuf[128];
+	char    *a = axaddrbuf;
+	dupecheck_t *dupechecker;
+        int     axlen;
+
+	if (debug)
+	  printf("interface_transmit_beacon() aif=%p, aif->txok=%d aif->callsign='%s'\n",
+		 aif, aif && aif->tx_ok ? 1 : 0, aif ? aif->callsign : "<nil>");
+
+	if (aif == NULL)    return 0;
+	if (!aif->tx_ok) return 0; // Sorry, no Tx
+
+	dupechecker = digipeater_find_dupecheck(aif);
+
+	// _FOR_VALGRIND_  -- and just in case for normal use
+	memset(ax25addr, 0, sizeof(ax25addr));
+	memset(axaddrbuf, 0, sizeof(axaddrbuf));
+	
+	if (parse_ax25addr(ax25addr +  7, src,  0x60)) {
+	  if (debug) printf("parse_ax25addr('%s') failed. [1]\n", src);
+	  return -1;
+	}
+	if (parse_ax25addr(ax25addr +  0, dest, 0x60)) {
+	  if (debug) printf("parse_ax25addr('%s') failed. [2]\n", dest);
+	  return -1;
+	}
+	ax25addrlen = 14; // Initial Src+Dest without any Via.
+
+	a += sprintf(axaddrbuf, "%s>%s", src, dest);
+	*a = 0;
+        axlen = a - axaddrbuf;
+
+	if (via != NULL) {
+	  char viafield[12];
+          int  vialen = strlen(via);
+	  const char *s, *p = via;
+	  const char *ve = via + vialen;
+
+	  *a++ = ',';
+          axlen = a - axaddrbuf;
+          if (vialen > (sizeof(axaddrbuf)-axlen-3))
+            vialen = (sizeof(axaddrbuf)-axlen-3);
+          if (vialen > 0) {
+            memcpy(a, via, vialen);
+            a += vialen;
+          }
+          *a = 0;
+          axlen = a - axaddrbuf;
+
+	  while (p < ve) {
+	    int len;
+	    
+	    for (s = p; s < ve; ++s) {
+	      if (*s == ',') {
+		break;
+	      }
+	    }
+	    // [p..s] is now one VIA field.
+	    if (s == p) {  // BAD!
+	      have_fault = 1;
+	      if (debug>1) printf(" S==P ");
+	      break;
+	    }
+	    ++viaindex;
+	    if (viaindex >= 10) {
+	      if (debug) printf("too many via-fields: '%s'\n", via);
+	      return -1; // Too many VIA fields
+	    }
+
+	    len = s - p;
+	    if (len >= sizeof(viafield)) len = sizeof(viafield)-1;
+	    memcpy(viafield, p, len);
+	    viafield[len] = 0;
+	    if (*s == ',') ++s;
+	    p = s;
+	    // VIA-field picked up, now parse it..
+
+	    if (parse_ax25addr(ax25addr + viaindex * 7, viafield, 0x60)) {
+	      // Error on VIA field value
+	      if (debug) printf("parse_ax25addr('%s') failed. [3]\n", viafield);
+	      return -1;
+	    }
+	    ax25addrlen += 7;
+	  }
+	}
+
+	if (have_fault) {
+	  if (debug) {
+	    printf("observed a fault in inputs of interface_transmit_beacon()\n");
+	  }
+	  return 1;
+	}
+
+	ax25addr[ax25addrlen-1] |= 0x01; // set address field end bit
+
+
+	// Feed to dupe-filter (transmitter specific)
+	// this means we have already seen it, and when 
+	// it comes back from somewhere, we do not digipeat
+	// it ourselves.
+
+	if (dupechecker != NULL)
+	  dupecheck_aprs( dupechecker,
+			  axaddrbuf, strlen(axaddrbuf),
+			  txbuf+2, txlen-2  ); // ignore Ctrl+PID
+
+	// Transmit it to actual radio interface
+
+	interface_transmit_ax25( aif,
+				 ax25addr, ax25addrlen,
+				 txbuf, txlen);
+
+
+	if (rflogfile) {
+	  char    *axbuf;
+
+	  axbuf = alloca(axlen+txlen+3);
+          memcpy( axbuf, axaddrbuf, axlen );
+	  a = axbuf + axlen;
+	  *a++ = ':';
+	  memcpy(a, txbuf+2, txlen-2); // forget control+pid bytes..
+	  a += txlen -2;   // final assembled message end pointer
+
+	  rflog(aif->callsign, 'T', 0, axbuf, a - axbuf);
+	}
+
+	return 0;
+}
diff --git a/keyhash.c b/keyhash.c
new file mode 100644
index 0000000..8230d1a
--- /dev/null
+++ b/keyhash.c
@@ -0,0 +1,91 @@
+/********************************************************************
+ *  APRX -- 2nd generation receive-only APRS-i-gate with            *
+ *          minimal requirement of esoteric facilities or           *
+ *          libraries of any kind beyond UNIX system libc.          *
+ *                                                                  *
+ * (c) Matti Aarnio - OH2MQK,  2007-2014                            *
+ *                                                                  *
+ ********************************************************************/
+
+/*
+ * Keyhash routines for the system.
+ *
+ * What is needed is _fast_ hash function.  Preferrably arithmethic one,
+ * which does not need table lookups, and can work with aligned 32 bit
+ * data -- but also on unaligned, and on any byte counts...
+ *
+ * Contenders:
+ *   http://burtleburtle.net/bob/c/lookup3.c
+ *   http://www.ibiblio.org/pub/Linux/devel/lang/c/mph-1.2.tar.gz
+ *   http://www.concentric.net/~Ttwang/tech/inthash.htm
+ *   http://isthe.com/chongo/tech/comp/fnv/
+ *
+ * Currently using FNV-1a
+ *
+ */
+
+/*
+//  FNV-1a  hash from   http://isthe.com/chongo/tech/comp/fnv/
+//
+//  It is algorithmic hash without memory lookups.
+//  Compiler seems to prefer actual multiplication over a bunch of
+//  fixed shifts and additions.
+*/
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include "keyhash.h"
+
+void keyhash_init(void) { }
+
+uint32_t __attribute__((pure)) keyhash(const void const *p, int len, uint32_t hash)
+{
+	const uint8_t *u = p;
+	int i;
+#define FNV_32_PRIME     16777619U
+#define FNV_32_OFFSET  2166136261U
+
+	if (hash == 0)
+        	hash = (uint32_t)FNV_32_OFFSET;
+
+	for (i = 0; i < len; ++i, ++u) {
+#if defined(NO_FNV_GCC_OPTIMIZATION)
+		hash *= FNV_32_PRIME;
+#else
+		hash += (hash<<1) + (hash<<4) + (hash<<7) +
+		        (hash<<8) + (hash<<24);
+#endif
+		hash ^= (uint32_t) *u;
+	}
+	return hash;
+}
+
+/* The data material is known to contain ASCII, and if any value in there
+ * is a lower case letter, it is first converted to upper case one.
+*/
+uint32_t __attribute__((pure)) keyhashuc(const void const *p, int len, uint32_t hash)
+{
+	const uint8_t *u = p;
+	int i;
+
+	if (hash == 0)
+        	hash = (uint32_t)FNV_32_OFFSET;
+
+	for (i = 0; i < len; ++i, ++u) {
+#if defined(NO_FNV_GCC_OPTIMIZATION)
+		hash *= FNV_32_PRIME;
+#else
+		hash += (hash<<1) + (hash<<4) + (hash<<7) +
+		        (hash<<8) + (hash<<24);
+#endif
+		uint32_t c = *u;
+		// Is it lower case ASCII letter ?
+		if ('a' <= c && c <= 'z') {
+			// convert to upper case.
+			c -= ('a' - 'A');
+		}
+		hash ^= c;
+	}
+	return hash;
+}
diff --git a/keyhash.h b/keyhash.h
new file mode 100644
index 0000000..d8f6377
--- /dev/null
+++ b/keyhash.h
@@ -0,0 +1,17 @@
+/********************************************************************
+ *  APRX -- 2nd generation receive-only APRS-i-gate with            *
+ *          minimal requirement of esoteric facilities or           *
+ *          libraries of any kind beyond UNIX system libc.          *
+ *                                                                  *
+ * (c) Matti Aarnio - OH2MQK,  2007-2014                            *
+ *                                                                  *
+ ********************************************************************/
+
+#ifndef KEYHASH_H
+#define KEYHASH_H
+
+extern void         keyhash_init(void);
+extern unsigned int keyhash(const void *s, int slen, unsigned int hash0);
+extern unsigned int keyhashuc(const void *s, int slen, unsigned int hash0);
+
+#endif
diff --git a/kiss.c b/kiss.c
new file mode 100644
index 0000000..b6c5e7b
--- /dev/null
+++ b/kiss.c
@@ -0,0 +1,710 @@
+/* **************************************************************** *
+ *                                                                  *
+ *  APRX -- 2nd generation receive-only APRS-i-gate with            *
+ *          minimal requirement of esoteric facilities or           *
+ *          libraries of any kind beyond UNIX system libc.          *
+ *                                                                  *
+ * (c) Matti Aarnio - OH2MQK,  2007-2014                            *
+ *                                                                  *
+ * **************************************************************** */
+
+#include "aprx.h"
+
+
+/*
+ *  kissprocess()  --  the S->rdline[]  array has a KISS frame after
+ *  KISS escape decode.  The frame begins with KISS command byte, then
+ *  AX25 headers and payload, and possibly a CRC-checksum.
+ *  Frame length is in S->rdlinelen variable.
+ */
+
+/* KA9Q describes the KISS frame format as follows:
+
+   http://www.ka9q.net/papers/kiss.html
+
+   - - - - - - - - -
+   4. Control of the KISS TNC
+
+   To distinguish between command and data frames on the host/TNC link,
+   the first byte of each asynchronous frame between host and TNC is
+   a "type" indicator.
+
+   This type indicator byte is broken into two 4-bit nibbles so that
+   the low-order nibble indicates the command number (given in the table
+   below) and the high-order nibble indicates the port number for that
+   particular command. In systems with only one HDLC port, it is by definition
+   Port 0. In multi-port TNCs, the upper 4 bits of the type indicator
+   byte can specify one of up to sixteen ports. The following commands
+   are defined in frames to the TNC (the "Command" field is in hexadecimal):
+
+   . . . . . .
+
+   CMD code 0 is for the data frame, and is only one present coming from
+   TNC to host.
+
+   - - - - - - - - -
+
+   SYMEK et al. have defined a way to run CRC inside KISS frames to
+   verify that the KISS-frame itself is correct:
+
+   http://www.symek.com/g/smack.html
+   http://www.ir3ip.net/iw3fqg/doc/smak.htm
+
+   SMACK variation recycles the top-most bit of the TNC-id nibble, and
+   thus permits up to 8 TNC ports on line.  Top-most bit is always one
+   on SMACK frames.
+
+   SMACK runs CRC16 over whole KISS frame buffer, including the CMD byte.
+   The CRC-code is thus _different_ from what will be sent out on radio,
+   the latter being CRC-CCITT (see further below):
+
+      Following CRC16-polynome is used:
+
+         X^16 + X^15 + X^2 + 1
+
+      The CRC-generator is preset to zero.
+
+   Chosen initialize to zero does mean that after a correct packet with a
+   correct checksum is ran thru this CRC, the output checksum will be zero.
+
+
+   - - - - - - - - -
+
+	Where is FLEXNET specification?
+	
+
+*/
+
+
+
+/*
+ * kissencoder():  If  (cmdbyte & 0x80) is set,  then this
+ *                 produces SMACK format frame, otherwise 
+ *                 plain KISS.
+ *
+ */
+
+int kissencoder( void *kissbuf, int kissspace, LineType linetype,
+		 const void *pktbuf, int pktlen, int cmdbyte )
+{
+	uint8_t *kb = kissbuf;
+	uint8_t *ke = kb + kissspace - 3;
+	const uint8_t *pkt = pktbuf;
+	int i;
+	uint16_t crc16;
+	uint16_t crcflex;
+
+	crc16   = crc16_table[cmdbyte & 0xFF];
+	crcflex = 0xff00 ^ crc_flex_table[(~cmdbyte) & 0xff];
+
+	/* Expect the KISS buffer to be at least ... 8 bytes.. */
+
+	*kb++ = KISS_FEND;
+	*kb++ = cmdbyte;
+
+	for (i = 0; i < pktlen && kb < ke; ++i, ++pkt) {
+		// Calc CRCs while encoding data..
+		int b = *pkt;
+		crc16 = ((crc16 >> 8) & 0xff) ^ crc16_table[(crc16 ^ b) & 0xFF];
+		crcflex = (crcflex << 8) ^ crc_flex_table[((crcflex >> 8) ^ b) & 0xff];
+
+		if (b == KISS_FEND) {
+			*kb++ = KISS_FESC;
+			*kb++ = KISS_TFEND;
+		} else {
+			*kb++ = b;
+			if (b == KISS_FESC)
+				*kb++ = KISS_TFESC;
+		}
+	}
+	/* If caller is asking for SMACK format frame, then
+	   store calculated CRC on frame. - CRC-bytes must be KISS escaped! */
+	/* If caller is asking for SMACK/FLEXNET format frame, then
+	   store calculated CRC on frame. - CRC-bytes must be KISS escaped! */
+	if (linetype == LINETYPE_KISSSMACK ||
+	    linetype == LINETYPE_KISSFLEXNET) {
+		int crc, b;
+		if (linetype == LINETYPE_KISSSMACK) {
+		  crc = crc16;
+		} else if (linetype == LINETYPE_KISSFLEXNET) {
+		  crc = crcflex;
+		} else {
+                  // Silence compiler warning, this branch is never reached..
+                  crc = 0;
+                }
+
+		b = crc & 0xFF;		/* low crc byte */
+		if (b == KISS_FEND) {
+		  if (kb < ke)
+		    *kb++ = KISS_FESC;
+		  if (kb < ke)
+		    *kb++ = KISS_TFEND;
+		} else {
+		  if (kb < ke)
+		    *kb++ = b;
+		  if (b == KISS_FESC && kb < ke)
+		    *kb++ = KISS_TFESC;
+		}
+		b = (crc >> 8) & 0xFF;	/* high crc byte */
+		if (b == KISS_FEND) {
+		  if (kb < ke)
+		    *kb++ = KISS_FESC;
+		  if (kb < ke)
+		    *kb++ = KISS_TFEND;
+		} else {
+		  if (kb < ke)
+		    *kb++ = b;
+		  if (b == KISS_FESC && kb < ke)
+		    *kb++ = KISS_TFESC;
+		}
+	}
+	if (kb < ke) {
+		*kb++ = KISS_FEND;
+		return (kb - (uint8_t *) (kissbuf));
+	} else {
+		/* Didn't fit in... */
+		return 0;
+	}
+}
+
+
+static int kissprocess(struct serialport *S)
+{
+	int i;
+	int cmdbyte = S->rdline[0];
+	int tncid = (cmdbyte >> 4) & 0x0F;
+
+	/* --
+	 * C0 00
+	 * 82 A0 B4 9A 88 A4 60
+	 * 9E 90 64 90 A0 9C 72
+	 * 9E 90 64 A4 88 A6 E0
+	 * A4 8C 9E 9C 98 B2 61
+	 * 03 F0
+	 * 21 36 30 32 39 2E 35 30 4E 2F 30 32 35 30 35 2E 34 33 45 3E 20 47 43 53 2D 38 30 31 20
+	 * C0
+	 * --
+	 */
+
+	/* printf("kissprocess()  cmdbyte=%02X len=%d ",cmdbyte,S->rdlinelen); */
+
+	/* Ok, cmdbyte tells us something, and we should ignore the
+	   frame if we don't know it... */
+
+	if ((cmdbyte & 0x0F) != 0) {
+		/* There should NEVER be any other value in the CMD bits
+		   than 0  coming from TNC to host! */
+		/* printf(" ..bad CMD byte\n"); */
+		if (debug) {
+		  printf("%ld\tTTY %s: Bad CMD byte on KISS frame: ", tick.tv_sec, S->ttyname);
+		  hexdumpfp(stdout, S->rdline, S->rdlinelen, 1);
+		  printf("\n");
+		}
+		erlang_add(S->ttycallsign[tncid], ERLANG_DROP, S->rdlinelen, 1);	/* Account one packet */
+		return -1;
+	}
+
+	if (S->linetype == LINETYPE_KISS && (cmdbyte & 0x20)) {
+	  // Huh?  Perhaps a FLEXNET packet?
+	  int crcflex = calc_crc_flex(S->rdline, S->rdlinelen);
+	  if (crcflex == 0x7070) {
+	    if (debug) printf("ALERT: Looks like received KISS frame is a FLEXNET with CRC!\n");
+	    S->linetype = LINETYPE_KISSFLEXNET;
+	  }
+	}
+	if (S->linetype == LINETYPE_KISS && (cmdbyte & 0x80)) {
+	  // Huh?  Perhaps a SMACK packet?
+	  int smack_ok = check_crc_16(S->rdline, S->rdlinelen);
+	  if (smack_ok == 0) {
+	    if (debug) printf("ALERT: Looks like received KISS frame is a SMACK with CRC!\n");
+	    S->linetype = LINETYPE_KISSSMACK;
+	  }
+	}
+
+	/* Are we expecting FLEXNET KISS ? */
+	if (S->linetype == LINETYPE_KISSFLEXNET && (cmdbyte & 0x20)) {
+	    int crc;
+	    tncid &= ~0x20; // FlexNet puts 0x20 as indication of CRC presence..
+
+	    if (S->ttycallsign[tncid] == NULL) {
+	      /* D'OH!  received packet on multiplexer tncid without
+		 callsign definition!  We discard this packet! */
+	      if (debug > 0) {
+		printf("%ld\tTTY %s: Bad TNCID on CMD byte on a KISS frame: %02x  No interface configured for it! ", tick.tv_sec, S->ttyname, cmdbyte);
+		hexdumpfp(stdout, S->rdline, S->rdlinelen, 1);
+		printf("\n");
+	      }
+	      erlang_add(S->ttycallsign[tncid], ERLANG_DROP, S->rdlinelen, 1);	/* Account one packet */
+	      return -1;
+	    }
+	    crc = calc_crc_flex(S->rdline, S->rdlinelen);
+	    if (crc != 0x7070) {
+	      if (debug) {
+		printf("%ld\tTTY %s tncid %d: Received FLEXNET frame with invalid CRC %04x: ",
+		       tick.tv_sec, S->ttyname, tncid, crc);
+		hexdumpfp(stdout, S->rdline, S->rdlinelen, 1);
+		printf("\n");
+	      }
+	      erlang_add(S->ttycallsign[tncid], ERLANG_DROP, S->rdlinelen, 1);  // Account one packet
+	      return -1;	// The CRC was invalid..
+	    }
+	    S->rdlinelen -= 2; // remove 2 bytes!
+	}
+
+	/* Are we excepting BPQ "CRC" (XOR-sum of data) */
+	if (S->linetype == LINETYPE_KISSBPQCRC) {
+		/* TODO: in what conditions the "CRC" is calculated and when not ? */
+		int xorsum = 0;
+
+		if (S->ttycallsign[tncid] == NULL) {
+		  /* D'OH!  received packet on multiplexer tncid without
+		     callsign definition!  We discard this packet! */
+		  if (debug > 0) {
+		    printf("%ld\tTTY %s: Bad TNCID on CMD byte on a KISS frame: %02x  No interface configured for it! ", tick.tv_sec, S->ttyname, cmdbyte);
+		    hexdumpfp(stdout, S->rdline, S->rdlinelen, 1);
+		    printf("\n");
+		  }
+		  erlang_add(S->ttycallsign[tncid], ERLANG_DROP, S->rdlinelen, 1);	/* Account one packet */
+		  return -1;
+		}
+
+		for (i = 1; i < S->rdlinelen; ++i)
+			xorsum ^= S->rdline[i];
+		xorsum &= 0xFF;
+		if (xorsum != 0) {
+			if (debug) {
+			  printf("%ld\tTTY %s tncid %d: Received bad BPQCRC: %02x: ", tick.tv_sec, S->ttyname, tncid, xorsum);
+			  hexdumpfp(stdout, S->rdline, S->rdlinelen, 1);
+			  printf("\n");
+			}
+			erlang_add(S->ttycallsign[tncid], ERLANG_DROP, S->rdlinelen, 1);	/* Account one packet */
+			return -1;
+		}
+		S->rdlinelen -= 1;	/* remove the sum-byte from tail */
+		if (debug > 2)
+			printf("%ld\tTTY %s tncid %d: Received OK BPQCRC frame\n", tick.tv_sec, S->ttyname, tncid);
+	}
+	/* Are we expecting SMACK ? */
+	if (S->linetype == LINETYPE_KISSSMACK) {
+
+	    tncid &= 0x07;	/* Chop off top bit */
+
+	    if (S->ttycallsign[tncid] == NULL) {
+	      /* D'OH!  received packet on multiplexer tncid without
+		 callsign definition!  We discard this packet! */
+	      if (debug > 0) {
+		printf("%ld\tTTY %s: Bad TNCID on CMD byte on a KISS frame: %02x  No interface configured for it! ", tick.tv_sec, S->ttyname, cmdbyte);
+		hexdumpfp(stdout, S->rdline, S->rdlinelen, 1);
+		printf("\n");
+	      }
+	      erlang_add(S->ttycallsign[tncid], ERLANG_DROP, S->rdlinelen, 1);	/* Account one packet */
+	      return -1;
+	    }
+
+	    if ((cmdbyte & 0x8F) == 0x80) {
+	        /* SMACK data frame */
+
+		if (debug > 3)
+		    printf("%ld\tTTY %s tncid %d: Received SMACK frame\n", tick.tv_sec, S->ttyname, tncid);
+
+		if (!(S->smack_subids & (1 << tncid))) {
+		    if (debug)
+			printf("%ld\t... marking received SMACK\n", tick.tv_sec);
+		}
+		S->smack_subids |= (1 << tncid);
+
+		/* It is SMACK frame -- KISS with CRC16 at the tail.
+		   Now we ignore the TNC-id number field.
+		   Verify the CRC.. */
+
+		// Whole buffer including CMD-byte!
+		if (check_crc_16(S->rdline, S->rdlinelen) != 0) {
+			if (debug) {
+			  printf("%ld\tTTY %s tncid %d: Received SMACK frame with invalid CRC: ",
+				 tick.tv_sec, S->ttyname, tncid);
+			  hexdumpfp(stdout, S->rdline, S->rdlinelen, 1);
+			  printf("\n");
+			}
+			erlang_add(S->ttycallsign[tncid], ERLANG_DROP, S->rdlinelen, 1);  // Account one packet
+			return -1;	/* The CRC was invalid.. */
+		}
+
+		S->rdlinelen -= 2;	/* Chop off the two CRC bytes */
+
+	    } else if ((cmdbyte & 0x8F) == 0x00) {
+	    	/*
+		 * Expecting SMACK data, but got plain KISS data.
+		 * Send a flow-rate limited probes to TNC to enable
+		 * SMACK -- lets use 30 minutes window...
+		 */
+
+
+		S->smack_subids &= ~(1 << tncid); // Turn off the SMACK mode indication bit..
+
+		if (debug > 2)
+		    printf("%ld\tTTY %s tncid %d: Expected SMACK, got KISS.\n", tick.tv_sec, S->ttyname, tncid);
+
+		if (timecmp(S->smack_probe[tncid], tick.tv_sec) < 0) {
+		    uint8_t probe[4];
+		    uint8_t kissbuf[12];
+		    int kisslen;
+
+		    probe[0] = cmdbyte | 0x80;  /* Make it into SMACK */
+		    probe[1] = 0;
+
+		    /* Convert the probe packet to KISS frame */
+		    kisslen = kissencoder( kissbuf, sizeof(kissbuf), S->linetype,
+					   &(probe[1]), 1, probe[0] );
+
+		    /* Send probe message..  */
+		    if (S->wrlen + kisslen < sizeof(S->wrbuf)) {
+			/* There is enough space in writebuf! */
+
+			memcpy(S->wrbuf + S->wrlen, kissbuf, kisslen);
+			S->wrlen += kisslen;
+			/* Flush it out..  and if not successfull,
+			   poll(2) will take care of it soon enough.. */
+			ttyreader_linewrite(S);
+
+			S->smack_probe[tncid] = tick.tv_sec + 1800; /* 30 minutes */
+
+			if (debug)
+			    printf("%ld\tTTY %s tncid %d: Sending SMACK activation probe packet\n", tick.tv_sec, S->ttyname, tncid);
+
+		    }
+		    /* Else no space to write ?  Huh... */
+		}
+	    } else {
+		// Else...  there should be no other kind data frames
+		if (debug) {
+		    printf("%ld\tTTY %s: Bad CMD byte on expected SMACK frame: %02x, len=%d: ",
+			   tick.tv_sec, S->ttyname, cmdbyte, S->rdlinelen);
+		    hexdumpfp(stdout, S->rdline, S->rdlinelen, 1);
+		    printf("\n");
+		}
+		erlang_add(S->ttycallsign[tncid], ERLANG_DROP, S->rdlinelen, 1);	/* Account one packet */
+		return -1;
+	    }
+	}
+
+	/* Are we expecting Basic KISS ? */
+	if (S->linetype == LINETYPE_KISS) {
+	    if (S->ttycallsign[tncid] == NULL) {
+	      /* D'OH!  received packet on multiplexer tncid without
+		 callsign definition!  We discard this packet! */
+	      if (debug > 0) {
+		printf("%ld\tTTY %s: Bad TNCID on CMD byte on a KISS frame: %02x  No interface configured for it! ", tick.tv_sec, S->ttyname, cmdbyte);
+		hexdumpfp(stdout, S->rdline, S->rdlinelen, 1);
+		printf("\n");
+	      }
+	      erlang_add(S->ttycallsign[tncid], ERLANG_DROP, S->rdlinelen, 1);	/* Account one packet */
+	      return -1;
+	    }
+	}
+
+
+	if (S->rdlinelen < 17) {
+		/* 7+7+2 bytes of minimal AX.25 frame + 1 for KISS CMD byte */
+
+		/* Too short frame.. */
+		/* printf(" ..too short a frame for anything\n");  */
+		erlang_add(S->ttycallsign[tncid], ERLANG_DROP, S->rdlinelen, 1);	/* Account one packet */
+		return -1;
+	}
+
+	/* Valid AX.25 HDLC frame byte sequence is now at
+	   S->rdline[1..S->rdlinelen-1]
+	 */
+
+	/* Send the frame to APRS-IS, return 1 if valid AX.25 UI message, does not
+	   validate against valid APRS message rules... (TODO: it could do that too) */
+
+	// The AX25_TO_TNC2 does validate the AX.25 packet,
+	// converts it to "TNC2 monitor format" and sends it to
+	// Rx-IGate functionality.  Returns non-zero only when
+	// AX.25 header is OK, and packet is sane.
+
+	erlang_add(S->ttycallsign[tncid], ERLANG_RX, S->rdlinelen, 1);	/* Account one packet */
+
+	if (ax25_to_tnc2(S->interface[tncid], S->ttycallsign[tncid], tncid,
+			 cmdbyte, S->rdline + 1, S->rdlinelen - 1)) {
+		// The packet is valid per AX.25 header bit rules.
+
+#ifdef PF_AX25	/* PF_AX25 exists -- highly likely a Linux system ! */
+		/* Send the frame without cmdbyte to internal AX.25 network */
+		if (S->netax25[tncid] != NULL)
+			netax25_sendax25(S->netax25[tncid], S->rdline + 1, S->rdlinelen - 1);
+#endif
+
+	} else {
+	  // The packet is not valid per AX.25 header bit rules
+	  erlang_add(S->ttycallsign[tncid], ERLANG_DROP, S->rdlinelen, 1);	/* Account one packet */
+
+	  if (aprxlogfile) {
+            // NOT replaced with aprxlog() -- because this is a bit more complicated..
+	    FILE *fp = fopen(aprxlogfile, "a");
+	    if (fp) {
+	      char timebuf[60];
+	      printtime(timebuf, sizeof(timebuf));
+              setlinebuf(fp);
+
+	      fprintf(fp, "%s ax25_to_tnc2(%s,len=%d) rejected the message: ", timebuf, S->ttycallsign[tncid], S->rdlinelen-1);
+	      hexdumpfp(fp, S->rdline, S->rdlinelen, 1);
+	      fprintf(fp, "\n");
+	      fclose(fp);
+	    }
+	  }
+	}
+
+	return 0;
+}
+
+
+/*
+ * ttyreader_pullkiss()  --  pull KISS (or KISS+CRC) frame, and call KISS processor
+ */
+
+int kiss_pullkiss(struct serialport *S)
+{
+	/* printf("ttyreader_pullkiss()  rdlen=%d rdcursor=%d, state=%d\n",
+	   S->rdlen, S->rdcursor, S->kissstate); fflush(stdout); */
+
+	/* At incoming call there is at least one byte in between
+	   S->rdcursor and S->rdlen  */
+
+	/* Phases:
+	   kissstate == 0: hunt for KISS_FEND, discard everything before it.
+	   kissstate != 0: reading has globbed up preceding KISS_FENDs
+	   ("HDLC flags") and the cursor is in front of a frame
+	 */
+
+	/* There are TNCs that use "shared flags" - only one FEND in between
+	   data frames. */
+
+	if (S->kissstate == KISSSTATE_SYNCHUNT) {
+		/* Hunt for KISS_FEND, discard everything until then! */
+		int c;
+		for (;;) {
+			c = ttyreader_getc(S);
+			if (c < 0)
+				return c;	/* Out of buffer, stay in state,
+						   return latter when there is some
+						   refill */
+			if (c == KISS_FEND)	/* Found the sync-byte !  change state! */
+				break;
+		}
+		S->kissstate = KISSSTATE_COLLECTING;
+	}
+
+
+	if (S->kissstate != KISSSTATE_SYNCHUNT) {
+		/* Normal processing mode */
+
+		int c;
+
+		for (;;) {
+			c = ttyreader_getc(S);
+			if (c < 0)
+				return c;	/* Out of input stream, exit now,
+						   come back latter.. */
+
+			/* printf(" %02X", c);
+			   if (c == KISS_FEND) { printf("\n");fflush(stdout); }  */
+
+			if (c == KISS_FEND) {
+				/* Found end-of-frame character -- or possibly beginning..
+				   This never exists in datastream except as itself. */
+
+				if (S->rdlinelen > 0) {
+					/* Non-zero sized frame  Process it away ! */
+					kissprocess(S);
+					S->kissstate =
+						KISSSTATE_COLLECTING;
+					S->rdlinelen = 0;
+				}
+
+				/* rdlinelen == 0 because we are receiving consequtive
+				   FENDs, or just processed our previous frame.  Treat
+				   them the same: discard this byte. */
+
+				continue;
+			}
+
+			if (S->kissstate == KISSSTATE_KISSFESC) {
+
+				/* We have some char, state switches to normal collecting */
+				S->kissstate = KISSSTATE_COLLECTING;
+
+				if (c == KISS_TFEND)
+					c = KISS_FEND;
+				else if (c == KISS_TFESC)
+					c = KISS_FESC;
+				else
+					continue;	/* Accepted chars after KISS_FESC
+							   are only TFEND and TFESC.
+							   Others must be discarded. */
+
+			} else {	/* Normal collection mode */
+
+				if (c == KISS_FESC) {
+					S->kissstate = KISSSTATE_KISSFESC;
+					continue;	/* Back to top of the loop and continue.. */
+				}
+
+			}
+
+
+			if (S->rdlinelen >= (sizeof(S->rdline) - 3)) {
+				/* Too long !  Way too long ! */
+
+				S->kissstate = KISSSTATE_SYNCHUNT;	/* Sigh.. discard it. */
+				S->rdlinelen = 0;
+				if (debug) {
+				  printf("%ld\tTTY %s: Too long frame to be KISS: ", tick.tv_sec, S->ttyname);
+				  hexdumpfp(stdout, S->rdline, S->rdlinelen, 1);
+				  printf("\n");
+				}
+				continue;
+			}
+
+			/* Put it on record store: */
+			S->rdline[S->rdlinelen++] = c;
+		}		/* .. for(..) loop of data collecting */
+
+	}
+	/* .. normal consumption mode ... */
+	return 0;
+}
+
+
+/*
+ *  kiss_kisswrite()  -- write out buffered data
+ */
+void kiss_kisswrite(struct serialport *S, const int tncid, const uint8_t *ax25raw, const int ax25rawlen)
+{
+	int i, len, ssid;
+	uint8_t kissbuf[2300];
+
+	if (debug) {
+	  printf("kiss_kisswrite(->%s, axlen=%d)", S->ttycallsign[tncid], ax25rawlen);
+	}
+	if (S->fd < 0) {
+	  if (debug)
+	    printf("NOTE: Write to non-open serial port discarded.");
+	  return;
+	}
+
+
+	if ((S->linetype != LINETYPE_KISS)        && (S->linetype != LINETYPE_KISSSMACK) &&
+	    (S->linetype != LINETYPE_KISSFLEXNET) && (S->linetype != LINETYPE_KISSBPQCRC)) {
+		if (debug)
+		  printf("WARNING: WRITING KISS FRAMES ON SERIAL/TCP LINE OF NO KISS TYPE IS UNSUPPORTED!\n");
+		return;
+	}
+
+
+	if ((S->wrlen == 0) || (S->wrlen > 0 && S->wrcursor >= S->wrlen)) {
+		S->wrlen = S->wrcursor = 0;
+	} else {
+	  /* There is some data in between wrcursor and wrlen */
+	  len = S->wrlen - S->wrcursor;
+	  if (len > 0) {
+	    i = write(S->fd, S->wrbuf + S->wrcursor, len);
+	  } else
+	    i = 0;
+	  if (i > 0) {		/* wrote something */
+	    S->wrcursor += i;
+	    len = S->wrlen - S->wrcursor;
+	    if (len == 0) {
+	      S->wrcursor = S->wrlen = 0;	/* wrote all ! */
+	    } else {
+	      /* compact the buffer a bit */
+	      memcpy(S->wrbuf, S->wrbuf + S->wrcursor, len);
+	      S->wrcursor = 0;
+	      S->wrlen = len;
+	    }
+	  }
+	}
+
+	ssid = (tncid << 4) | ((S->linetype == LINETYPE_KISSSMACK) ? 0x80 : 0x00);
+	if (S->linetype == LINETYPE_KISSFLEXNET)  ssid |= 0x20; // CRC presence
+
+	len = kissencoder( kissbuf, sizeof(kissbuf), S->linetype, ax25raw, ax25rawlen, ssid );
+
+	if (debug>2) {
+	  printf("kiss-encoded: ");
+	  hexdumpfp(stdout, kissbuf, len, 1);
+	  printf("\n");
+	}
+
+	// Will the KISS encoded frame fit in the link buffer?
+	if ((S->wrlen + len) < sizeof(S->wrbuf)) {
+		memcpy(S->wrbuf + S->wrlen, kissbuf, len);
+		S->wrlen += len;
+		erlang_add(S->ttycallsign[tncid], ERLANG_TX, ax25rawlen, 1);
+
+		if (debug)
+		  printf(" .. put %d bytes of KISS frame on IO buffer\n",len);
+	} else {
+		// No fit!
+		if (debug)
+		  printf(" .. %d bytes of KISS frame did not fit on IO buffer\n",len);
+		return;
+	}
+
+	// Try to write it immediately
+	len = S->wrlen - S->wrcursor;
+	if (len > 0)
+	  i = write(S->fd, S->wrbuf + S->wrcursor, len);
+	else
+	  i = 0;
+	if (i > 0) {		/* wrote something */
+		S->wrcursor += i;
+		len = S->wrlen - S->wrcursor; /* all done? */
+		if (len == 0) {
+			S->wrcursor = S->wrlen = 0;	/* wrote all ! */
+		} else {
+			/* compact the buffer a bit */
+			memcpy(S->wrbuf, S->wrbuf + S->wrcursor, len);
+			S->wrcursor = 0;
+			S->wrlen = len;
+		}
+	}
+}
+
+
+void kiss_poll(struct serialport *S)
+{
+	uint8_t probe[1];
+        uint8_t kissbuf[12];
+        int kisslen;
+        int tncid;
+
+        for (tncid = 0; tncid < 16; ++tncid) {
+
+		if (S->interface[tncid] == NULL) {
+			// No sub-interface here..
+			continue;
+                }
+
+                probe[0] = 0x0E | (tncid << 4);
+
+                /* Convert the probe packet to KISS frame */
+                kisslen = kissencoder( kissbuf, sizeof(kissbuf), S->linetype,
+                                       &(probe[0]), 0, probe[0] );
+                
+                /* Send probe message..  */
+                if (S->wrlen + kisslen < sizeof(S->wrbuf)) {
+                	/* There is enough space in writebuf! */
+          
+	        	memcpy(S->wrbuf + S->wrlen, kissbuf, kisslen);
+                        S->wrlen += kisslen;
+                        /* Flush it out..  and if not successfull,
+                           poll(2) will take care of it soon enough.. */
+                        ttyreader_linewrite(S);
+          
+                        if (debug)
+                          printf("%ld.%06d\tTTY %s tncid %d: Sending KISS POLL\n", (long)tick.tv_sec, (int)tick.tv_usec, S->ttyname, tncid);
+		}
+	}
+}
diff --git a/logrotate.aprx.in b/logrotate.aprx.in
new file mode 100644
index 0000000..212152d
--- /dev/null
+++ b/logrotate.aprx.in
@@ -0,0 +1,8 @@
+ at VARLOG@/aprx-rf.log @VARLOG@/aprx.log  @VARLOG@/dprs.log  @VARLOG@/erlang.log {
+	weekly
+	rotate 4
+	compress
+	missingok
+	notifempty
+	create 644 root adm
+}
diff --git a/man-to-html.sh b/man-to-html.sh
new file mode 100644
index 0000000..a9903fa
--- /dev/null
+++ b/man-to-html.sh
@@ -0,0 +1,118 @@
+#! /bin/sh
+
+## man-page to HTML format converter, when existing ones
+## were seriously unacceptable form...
+##
+## By Matti Aarnio, OH2MQK, <oh2mqk at sral.fi>, about 1995
+
+unset LC_CTYPE
+
+LANG=en_US
+export LANG
+
+TERM=xterm
+export TERM
+
+COLUMNS=80
+export COLUMNS
+
+LINES=9999
+export LINES
+
+
+echo "<HTML><HEAD><TITLE>"
+basename "$1"
+echo '</TITLE></HEAD><BODY BGCOLOR=white><PRE>'
+groff -t -man -Tascii -P-c "$1" | \
+    perl -e '
+        #select STDIN; $| = 1;
+        select STDERR; $| = 1;
+        #select STDOUT; $| = 1;
+        $h = "\010";
+        $c0 = undef;
+        while(read(STDIN,$c,1) > 0) {
+
+#printf STDERR "c0 = \"%s\"  c = \"%s\"\n",
+#	      !defined $c0 ? "<UNDEF>" : (ord($c0) < 32 ?
+# 				          sprintf("\\%03o",ord($c0)): $c0),
+#	      ord($c) < 32 ? sprintf("\\%03o",ord($c)) : $c;
+
+          if (defined $c0) {
+            if ($c eq $h) {
+              # X ^H * -> bold/italic/something
+              read(STDIN,$c1,1);
+
+#printf STDERR " .. c1 = \"%s\"\n",
+#	      ord($c1) < 32 ? sprintf("\\%03o",ord($c1)) : $c1;
+
+              if ($c0 eq $c1) {
+                # bold
+	        if    ($c0 eq "&") { $c0 = "&"; }
+		elsif ($c0 eq "<") { $c0 = "<";  }
+		elsif ($c0 eq ">") { $c0 = ">";  }
+                printf STDOUT "<B>%s</B>",$c0;
+              } elsif ($c0 eq "_") {
+                # italic
+	        if    ($c1 eq "&") { $c1 = "&"; }
+		elsif ($c1 eq "<") { $c1 = "<";  }
+		elsif ($c1 eq ">") { $c1 = ">";  }
+                printf STDOUT "<I>%s</I>",$c1;
+              } elsif ($c0.$c1 eq "+o") {
+                # Bullet
+                printf STDOUT "<B>•</B>";
+              } else {
+                # something -- overstrike ?
+	        if    ($c1 eq "&") { $c1 = "&"; }
+		elsif ($c1 eq "<") { $c1 = "<";  }
+		elsif ($c1 eq ">") { $c1 = ">";  }
+                printf STDOUT "<B>%s</B>",$c1;
+              }
+              $c0 = undef;
+              if ($c1 eq "\n") { printf STDOUT "\n"; }
+            } else {
+              # Not  X ^H *, but X is defined.
+              if    ($c0 eq "&") { $c0 = "&"; }
+	      elsif ($c0 eq "<") { $c0 = "<";  }
+	      elsif ($c0 eq ">") { $c0 = ">";  }
+              printf STDOUT "%s",$c0;
+              $c0 = $c;
+            }
+          } else {
+            # $c0 not defined!
+            $c0 = $c;
+          }
+        } # ... while()
+        if ($c0) { printf STDOUT "%s",$c0; }' |  \
+    perl -ne '
+        s{</B>(\s*)<B>}{\1}og;
+        s{</I>(\s*)<I>}{\1}og;
+        s{</U>(\s*)<U>}{\1}og;
+        s{</I><B>_</B><I>}{_}og;
+	# Ordinary man-pages
+        s{<I>([-.0-9a-zA-Z_]+)</I>\((\dzm)\)}{<A HREF="\1.\2.html"><I>\1</I>(\2)</A>}og;
+
+	# Ordinary PERL PODs
+        s{<I>([-.0-9a-zA-Z_]+::[-.0-9a-zA-Z_]+)</I>\((\d\w+)\)}{<A HREF="\1.\2.html"><I>\1</I>(\2)</A>}og;
+	print;' | \
+    perl -e '
+	@labels=();
+	while (<STDIN>) {
+	  if (m{^<B>(.*)</B>$}o) {
+	    my $n = $1; $n =~ s/ /_/g;
+	    printf "<A NAME=\"%s\"></A>",$n;
+	    push @labels, $n;
+	  }
+	  if (m{^   <B>(.*)</B>$}o) {
+	    my $n = $1; $n =~ s/ /_/g;
+	    printf "<A NAME=\"%s\"></A>",$n;
+	    push @labels, $n;
+	  }
+	  print;
+	}
+	printf "<p><p>\n<ul></n";
+	foreach $n (@labels) {
+	    printf "<li> <A HREF=\"#%s\">%s</A>\n",$n,$n;
+	}
+	printf "</ul>\n";
+	'
+echo "</PRE></BODY></HTML>"
diff --git a/netax25.c b/netax25.c
new file mode 100644
index 0000000..65867c9
--- /dev/null
+++ b/netax25.c
@@ -0,0 +1,810 @@
+/* **************************************************************** *
+ *                                                                  *
+ *  APRX -- 2nd generation receive-only APRS-i-gate with            *
+ *          minimal requirement of esoteric facilities or           *
+ *          libraries of any kind beyond UNIX system libc.          *
+ *                                                                  *
+ * (c) Matti Aarnio - OH2MQK,  2007-2014                            *
+ *                                                                  *
+ * NETAX25:  Listen on (Linux) AX.25 socket and pick all AX.25      *
+ *           data packets     ...    actually don't pick those      *
+ *           that are going outwards.  All incoming ones do pick.   *
+ *                                                                  *
+ * **************************************************************** */
+
+#include "aprx.h"
+
+
+#ifdef PF_AX25	/* PF_AX25 exists -- highly likely a Linux system ! */
+
+#include <sys/ioctl.h>
+#include <net/if.h>
+#include <netpacket/packet.h>
+#include <netinet/if_ether.h>
+
+#include <netinet/in.h>
+
+#include <netax25/ax25.h>
+
+
+/*
+ * Link-level device access
+ *
+ * s = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_AX25));
+ *
+ */
+
+/*
+struct sockaddr_ll
+  {
+    unsigned short int sll_family;
+    unsigned short int sll_protocol;
+    int sll_ifindex;
+    unsigned short int sll_hatype;
+    unsigned char sll_pkttype;
+    unsigned char sll_halen;
+    unsigned char sll_addr[8];
+  };
+
+SOCK_RAW Sending uses  sll_ifindex  and  sll_protocol
+
+*/
+
+struct netax25_dev {
+	int		ifindex;
+	int16_t		protocol;
+	uint8_t		ax25addr[7];
+	uint8_t		rxok;
+	//uint8_t	txok;
+	uint8_t         scan;
+	char		devname[IFNAMSIZ];
+	char		callsign[10];
+	const struct aprx_interface *interface;
+};
+
+
+static struct netax25_dev **netax25_devs;
+static int                  netax25_devcount;
+
+
+
+/*
+ *  Talking to Linux kernel 2.6.x, using SMACK type frames
+ *  on each configured serial port callsign -> ptymux 
+ *  writer channel.  If system does not write correct SMACK
+ *  frame on that KISS port for any number of reasons,
+ *  including writing incompletely buffered data, then
+ *  kernel will be able to notice that frame it received
+ *  is not valid, and discards it.  (Maybe... P = 2^-16 to
+ *  accepting of error frame in spite of these controls.)
+ */
+
+struct netax25_pty {
+	int                          fd;
+	int			     ifindex;
+	const char                  *callsign;
+	const struct aprx_interface *interface;
+	struct sockaddr_ax25         ax25addr;
+};
+
+
+static int rx_socket = -1;
+static int tx_socket = -1;
+
+static struct netax25_pty **ax25rxports;
+static int                  ax25rxportscount;
+
+static char **ax25ttyports;
+static int   *ax25ttyfds;
+static int    ax25ttyportscount;
+
+
+
+
+
+#if defined(HAVE_OPENPTY)
+#ifdef HAVE_PTY_H
+#include <pty.h>
+#endif
+
+static void netax25_addttyport(const char *callsign,
+			       const int masterfd, const int slavefd);
+
+static const void* netax25_openpty(const char *mycall)
+{
+	int rc;
+	int disc;
+	struct termios tio;
+	char devname[64];
+	uint8_t ax25call[64]; // overlarge for AX.25 - which needs only 7 bytes, but valgrind whines..
+	struct ifreq ifr;
+	int fd = -1;
+	struct netax25_pty *nax25 = NULL;
+	int pty_master, pty_slave;
+
+	if (!mycall)
+		return NULL;		/* No mycall, no ptys! */
+
+	memset(ax25call, 0, sizeof(ax25call)); // valgrind
+	if (parse_ax25addr(ax25call, mycall, 0x60)) {
+		// Not valid per AX.25 rules
+	  if (debug)
+	    printf(" netax25_openpty('%s') failed to parse the parameter string as valid AX.25 callsign. Not opening kernel pty.\n", mycall);
+		return NULL;
+	}
+
+	memset(devname, 0, sizeof(devname)); // valgrind
+	rc = openpty(&pty_master, &pty_slave, devname, NULL, NULL);
+
+	if (debug)
+		printf("openpty() rc=%d name='%s' master=%d slave=%d\n",
+		       rc, devname, pty_master, pty_slave);
+
+	if (rc != 0 || pty_slave < 0) {
+	      error_exit:;
+		if (pty_master >= 0)
+			close(pty_master);
+		pty_master = -1;
+		if (pty_slave >= 0)
+			close(pty_slave);
+		pty_slave = -1;
+		if (fd >= 0)
+			close(fd);
+		if (debug)
+		  printf("netax25_openpty() error exit.\n");
+
+
+                if (nax25 != NULL) free(nax25);
+
+		return NULL;		/* D'uh.. */
+	}
+
+	nax25 = calloc( 1,sizeof(*nax25) );
+	nax25->fd       = pty_master;
+	nax25->ifindex  = -1;
+	nax25->callsign = mycall;
+
+	nax25->ax25addr.sax25_family = PF_AX25;
+	nax25->ax25addr.sax25_ndigis = 0;
+	memcpy(&nax25->ax25addr.sax25_call, ax25call, 7);
+
+	/* setup termios parameters for this line.. */
+	memset(&tio, 0, sizeof(tio)); // please valgrind
+	aprx_cfmakeraw(&tio, 0);
+	tio.c_cc[VMIN] = 1;	/* pick at least one char .. */
+	tio.c_cc[VTIME] = 3;	/* 0.3 seconds timeout - 36 chars @ 1200 baud */
+	tio.c_cflag |= (CREAD | CLOCAL);
+	cfsetispeed(&tio, B38400);	/* Pseudo-tty -- pseudo speed */
+	cfsetospeed(&tio, B38400);
+	rc = tcsetattr(pty_slave, TCSANOW, &tio);
+	if (rc < 0)
+		goto error_exit;
+
+	/* The pty_slave will get N_AX25 discipline attached on itself.. */
+	disc = N_AX25;
+	rc = ioctl(pty_slave, TIOCSETD, &disc);
+	if (rc < 0)
+		goto error_exit;
+
+	rc = ioctl(pty_slave, SIOCGIFNAME, devname);
+	if (rc < 0)
+		goto error_exit;
+
+	/* Convert mycall[] to AX.25 format callsign */
+	rc = ioctl(pty_slave, SIOCSIFHWADDR, ax25call);
+	if (rc < 0)
+		goto error_exit;
+
+	/* Now set encapsulation.. */
+	disc = 4;
+	rc = ioctl(pty_slave, SIOCSIFENCAP, &disc);
+	if (rc < 0)
+		goto error_exit;
+
+	/* Then final tricks to start the interface... */
+	fd = socket(AF_INET, SOCK_DGRAM, 0);
+	if (fd < 0)
+		goto error_exit;
+
+	memset(&ifr, 0, sizeof(ifr)); // please valgrind
+	strncpy(ifr.ifr_name, devname, sizeof(ifr.ifr_name));
+        ifr.ifr_name[sizeof(ifr.ifr_name)-1] = 0;
+
+	ifr.ifr_mtu = 512;
+	rc = ioctl(fd, SIOCSIFMTU, &ifr);
+	if (rc < 0)
+		goto error_exit;
+
+	ifr.ifr_flags = IFF_UP | IFF_RUNNING | IFF_NOARP;
+	rc = ioctl(fd, SIOCSIFFLAGS, &ifr);
+	if (rc < 0)
+		goto error_exit;
+
+	close(fd);
+
+	/* OK, we write and read on pty_master, the pty_slave is now
+	   attached on kernel side AX.25 interface with call: mycall */
+
+	netax25_addttyport( mycall, pty_master, pty_slave );
+
+	return (void*) nax25;
+}
+
+void netax25_sendax25(const void *nax25p, const void *ax25, int ax25len)
+{
+	int rc, p;
+	uint8_t ax25buf[2100];
+	const struct netax25_pty *nax25 = nax25p;
+
+	/* kissencoder() takes AX.25 frame, and adds framing + cmd-byte */
+	rc = kissencoder(ax25buf, sizeof(ax25buf), LINETYPE_KISSSMACK,
+			 ax25, ax25len, 0x80);
+	if (rc < 0)
+		return;
+	ax25len = rc;
+
+	if (debug>2) {
+	  printf("netax25_sendax25() len=%d ",ax25len);
+	  hexdumpfp(stdout, ax25, ax25len, 1);
+	  printf("\n");
+	}
+
+
+	/* Try to write it to the PTY */
+	p = 0;
+	rc = write(nax25->fd, ax25buf + p, ax25len - p);
+	if (rc < 0) rc = 0; // error hickup..
+	p += rc; rc = 0;
+	if (p < ax25len) { // something left unwritten
+		rc = write(nax25->fd, ax25buf + p, ax25len - p);
+		if (rc < 0) rc = 0; // error hickup..
+	}
+	p += rc; rc = 0;
+	if (p < ax25len) { // something left unwritten
+		rc = write(nax25->fd, ax25buf + p, ax25len - p);
+		if (rc < 0) rc = 0; // error hickup..
+	}
+	p += rc; rc = 0;
+	// Now it either succeeded, or it failed.
+	// in both cases we give up on this frame.
+	if (p < ax25len) {
+	  if (aprxlogfile) {
+            aprxlog("netax25_sendax25(%s,len=%d) wrote %d bytes\n", nax25->callsign, ax25len, p);
+	  }
+	}
+}
+
+#else /* !HAVE_OPENPTY */
+
+static const void* netax25_openpty(const char *mycall)
+{
+	return NULL;
+}
+
+void netax25_sendax25(const void *nax25, const void *ax25, int ax25len)
+{
+}
+#endif				/* HAVE_OPENPTY */
+
+static int is_ax25ttyport(const char *callsign)
+{
+	int i;
+	for (i = 0; i < ax25ttyportscount; ++i) {
+		if (strcmp(callsign,ax25ttyports[i]) == 0)
+			return 1; // Have match
+	}
+	return 0; // No match
+}
+
+
+static int scan_linux_devices(void) {
+	FILE *fp;
+	struct ifreq ifr;
+	char buffer[512], *s;
+	int fd;
+	struct netax25_dev ax25dev, *d;
+	int i;
+
+	// Mark all devices ready for scanning
+	for (i = 0; i < netax25_devcount; ++i)
+	  netax25_devs[i]->scan = 0;
+
+	fd = socket(PF_FILE, SOCK_DGRAM, 0);
+	if (fd < 0) {
+	  // ... error
+	  if (debug)printf("Can not create socket(PF_FILE,SOCK_DGRAM,0); errno=%d\n", errno);
+	  return -1;
+	}
+	fp = fopen("/proc/net/dev", "r");
+	if (fp == NULL) {
+	  if (debug)printf("Can not open /proc/net/dev for reading; errno=%d\n", errno);
+	  close(fd);
+	  // ... error
+	  return -1;
+	}
+	// Two header lines
+	s = fgets(buffer, sizeof(buffer), fp);
+	s = fgets(buffer, sizeof(buffer), fp);
+	// Then network interface names
+	while (!feof(fp)) {
+	  if (!fgets(buffer, sizeof(buffer), fp))
+	    break; // EOF
+	  s = strchr(buffer, ':');
+	  if (s) *s = 0;
+	  s = buffer;
+	  while (*s == ' '||*s == '\t') ++s;
+	  memset(&ifr, 0, sizeof(ifr)); // please valgrind
+	  strncpy(ifr.ifr_name, s, IFNAMSIZ-1);
+	  ifr.ifr_name[IFNAMSIZ-1] = 0;
+
+	  // Is it active?
+	  if (ioctl(fd, SIOCGIFFLAGS, &ifr) < 0) {
+	    // error
+	    continue;
+	  }
+	  if (!(ifr.ifr_flags & IFF_UP))
+	    continue;  // not active, try next
+	  
+	  // Does it have AX.25 HW address ?
+	  if (ioctl(fd, SIOCGIFHWADDR, &ifr) < 0) {
+	    // Error
+	    continue;
+	  }
+	  if (ifr.ifr_hwaddr.sa_family != ARPHRD_AX25)
+	    continue;  // Not AX.25 HW address, try next
+
+	  memset(&ax25dev, 0, sizeof(ax25dev));
+	  memcpy(ax25dev.devname,  ifr.ifr_name, IFNAMSIZ);
+	  memcpy(ax25dev.ax25addr, ifr.ifr_hwaddr.sa_data, 7); // AX.25 address
+	  ax25_to_tnc2_fmtaddress(ax25dev.callsign, ax25dev.ax25addr, 0); // in text
+
+	  if (ioctl(fd, SIOCGIFINDEX, &ifr) < 0) {
+	    // Error
+	    continue;
+	  }
+	  ax25dev.ifindex = ifr.ifr_ifindex;
+
+	  // Store/Update internal kernel interface index list
+
+	  d = NULL;
+	  for (i = 0; i < netax25_devcount; ++i) {
+	    d = netax25_devs[i];
+	    if (d->ifindex == ax25dev.ifindex) {
+	      d->scan = 1;  // The ifindex does not change during interface lifetime
+	      break;
+	    }
+	    d = NULL;
+	  }
+	  if (d == NULL) {
+	    // Not in known interfaces, add a new one..
+	    d = malloc(sizeof(*d));
+	    ++netax25_devcount;
+	    netax25_devs = realloc( netax25_devs,
+				    sizeof(void*) * netax25_devcount );
+	    netax25_devs[netax25_devcount-1] = d;
+	    memcpy(d, &ax25dev, sizeof(*d));
+	    d->scan = 1;
+	    d->rxok = !is_ax25ttyport(d->callsign);
+	  }
+
+	}
+	fclose(fp);
+	close(fd);
+	// Remove devices no longer known
+	for (i = 0; i < netax25_devcount; ++i) {
+	  if (netax25_devs[i]->scan == 0) {
+	    int j;
+	    if (debug>1)printf("Compating netax25_devs[] i=%d callsign=%s\n",
+			       i, netax25_devs[i]->callsign);
+	    free(netax25_devs[i]);
+	    for (j = i+1; j < netax25_devcount; ++j) {
+	      netax25_devs[j-1] = netax25_devs[j];
+	    }
+	    --netax25_devcount;
+	  }
+	}
+
+	// Link interfaces
+	for (i = 0; i < netax25_devcount; ++i) {
+	  int j;
+	  struct netax25_dev *d = netax25_devs[i];
+	  for (j = 0; j < ax25rxportscount; ++j) {
+	    if (strcmp(ax25rxports[j]->callsign,d->callsign) == 0) {
+	      d->interface = ax25rxports[j]->interface;
+	      ax25rxports[j]->ifindex = d->ifindex;
+	    }
+	  }
+	}
+
+	return 0;
+}
+
+
+
+
+/* config interface:  ax25-rxport: callsign */
+void *netax25_addrxport(const char *callsign, const struct aprx_interface *interface)
+{
+	struct netax25_pty *nax25p = calloc(1, sizeof(*nax25p));
+
+	nax25p->fd        = -1;
+	nax25p->interface = interface;
+	nax25p->ax25addr.sax25_family = PF_AX25;
+	nax25p->ax25addr.sax25_ndigis = 0;
+
+	if (interface == NULL) {  // Old config style
+	  if (parse_ax25addr((uint8_t*)&nax25p->ax25addr.sax25_call, callsign, 0x60)) {
+	    // Not valid per AX.25 rules
+            free(nax25p);
+	    return NULL;
+	  }
+	  nax25p->callsign  = strdup(callsign);
+	} else {  // new config fule
+	  memcpy(&nax25p->ax25addr.sax25_call, interface->ax25call, sizeof(interface->ax25call));
+	  nax25p->callsign  = interface->callsign;
+	}
+
+	ax25rxports = realloc(ax25rxports,
+			      sizeof(struct netax25_pty*) * (ax25rxportscount + 1));
+	ax25rxports[ax25rxportscount++] = nax25p;
+
+	return nax25p;
+}
+
+static void netax25_addttyport(const char *callsign,
+			       const int masterfd, const int slavefd)
+{
+	ax25ttyports = realloc(ax25ttyports,
+			       sizeof(void *) * (ax25ttyportscount + 1));
+	ax25ttyfds   = realloc(ax25ttyfds,
+			       sizeof(int) * (ax25ttyportscount + 1));
+	ax25ttyports[ax25ttyportscount] = strdup(callsign);
+	ax25ttyfds  [ax25ttyportscount] = masterfd; /* slavefd forgotten */
+	++ax25ttyportscount;
+}
+
+
+/* Nothing much in early init */
+void netax25_init(void)
+{
+}
+
+/* .. but all things in late start.. */
+void netax25_start(void)
+{
+	int i;
+	int rx_protocol;
+
+	rx_socket = -1;			/* Initialize for early bail-out  */
+	tx_socket = -1;
+
+	if (!ax25rxports) return;	/* No configured receiver ports.
+					   No receiver socket creation. */
+
+	rx_protocol = ETH_P_AX25;	/* Choosing ETH_P_ALL would pick also
+					   outbound packets, but also all of
+					   the ethernet traffic..  ETH_P_AX25
+					   picks only inbound-at-ax25-devices
+					   ..packets.  */
+
+	rx_socket = socket(PF_PACKET, SOCK_RAW, htons(rx_protocol));
+	tx_socket = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_AX25));
+
+	if (rx_socket < 0) {
+		i = errno;
+		/* D'uh..  could not open it, report and leave it at that. */
+		fprintf(stderr,
+			"aprx: Could not open socket(PF_PACKET,SOCK_RAW,ETH_P_AX25) for listening.  Errno=%d (%s)"
+			" -- not a big deal unless you want to receive via AX.25 sockets.\n",
+			i, strerror(i));
+		return;
+	}
+
+	if (tx_socket < 0) {
+		i = errno;
+		/* D'uh..  could not open it, report and leave it at that. */
+		fprintf(stderr,
+			"aprx: Could not open socket(PF_PACKET,SOCK_RAW,ETH_P_AX25) for sending.  Errno=%d (%s)"
+			" -- not a big deal unless you want to send via AX.25 sockets.\n",
+			i, strerror(i));
+		return;
+	}
+
+	if (rx_socket >= 0)
+		fd_nonblockingmode(rx_socket);
+}
+
+
+/* .. but all things in late start.. */
+const void* netax25_open(const char *ifcallsign)
+{
+	return netax25_openpty(ifcallsign);
+}
+
+static struct timeval next_scantime;
+
+static void netax25_resettimer(void*arg)
+{
+	struct timeval *tv = (struct timeval *)arg;
+	tv_timeradd_seconds(tv, &tick, 60);
+        scan_linux_devices();
+}
+
+int netax25_prepoll(struct aprxpolls *app)
+{
+	struct pollfd *pfd;
+	int i;
+
+        if (next_scantime.tv_sec == 0) next_scantime = tick;
+
+        if (time_reset) {
+        	netax25_resettimer(&next_scantime);
+        }
+
+	if (rx_socket >= 0) {
+		/* FD is open, lets mark it for poll read.. */
+		pfd = aprxpolls_new(app);
+		pfd->fd = rx_socket;
+		pfd->events = POLLIN | POLLPRI;
+		pfd->revents = 0;
+	}
+
+	/* read from PTY masters */
+	for (i = 0; i < ax25ttyportscount; ++i) {
+		if (ax25ttyfds[i] >= 0) {
+		  pfd = aprxpolls_new(app);
+		  pfd->fd = ax25ttyfds[i];
+		  pfd->events = POLLIN | POLLPRI;
+		  pfd->revents = 0;
+		}
+	}
+
+	return 1;
+}
+
+static int rxsock_read( const int fd )
+{
+	struct sockaddr_ll sll;
+	socklen_t sllsize;
+	int rcvlen, ifindex, i;
+	struct netax25_dev *netdev;
+	uint8_t rxbuf[3000];
+
+	sllsize = sizeof(sll);
+	rcvlen = recvfrom(fd, rxbuf, sizeof(rxbuf), 0, (struct sockaddr*)&sll, &sllsize);
+
+	if (rcvlen < 0) {
+		return 0;	/* No more at this time.. */
+	}
+
+/*
+struct sockaddr_ll
+  {
+    unsigned short int sll_family;	= PF_PACKET
+    unsigned short int sll_protocol;	= 200 ?
+    int sll_ifindex;			= 4
+    unsigned short int sll_hatype;	= 3 = SOCK_RAW ?
+    unsigned char sll_pkttype;		= 0
+    unsigned char sll_halen;		= 0
+    unsigned char sll_addr[8];		= random
+  };
+
+netax25rx packet len=54 from rx_socket;  family=17 protocol=200 ifindex=4 hatype=3
+					 pkttype=0 halen=0  addr=84:f9:ca:bf:d7:04:f3:b7
+
+Data:  00 82 a0 aa 64 6a 9c e0 9e 90 70 9a b0 94 60 ae 92 88 8a 64 40 61 03 f0 3d 36 33 35 33 2e ...
+Text:  00 82 a0 aa  d  j 9c e0 9e 90  p 9a b0 94  ` ae 92 88 8a  d  @  a 03 f0  =  6  3  5  3  . ...
+AX25:  00  A  P  U  2  5  N  p  O  H  8  M  X  J  0  W  I  D  E  2     0 01  x 1e 1b 19 1a 19 17 ...
+
+Leads with 00 byte, then AX.25 address..
+
+*/
+
+	if (sll.sll_family   != PF_PACKET         ||
+	    sll.sll_protocol != htons(ETH_P_AX25) ||
+	    sll.sll_hatype   != SOCK_RAW          ||
+	    sll.sll_pkttype  != 0                 ||
+	    sll.sll_halen    != 0                 ||
+	    rxbuf[0]         != 0 ) {
+	  return 1; // Not of our interest
+	}
+	ifindex = sll.sll_ifindex;
+
+	if (debug>1) {
+	  printf("netax25rx packet len=%d from rx_socket;  family=%d protocol=%x ifindex=%d hatype=%d pkttype=%d halen=%d\n",
+		 rcvlen, sll.sll_family, sll.sll_protocol, sll.sll_ifindex, sll.sll_hatype, sll.sll_pkttype, sll.sll_halen);
+/*
+	  printf(" addr=%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n",
+		 sll.sll_addr[0],sll.sll_addr[1],sll.sll_addr[2],sll.sll_addr[3],
+		 sll.sll_addr[4],sll.sll_addr[5],sll.sll_addr[6],sll.sll_addr[7]);
+
+		  int i;
+		  printf("Data: ");
+		  for (i = 0; i < rcvlen; ++i)
+		    printf(" %02x", rxbuf[i]);
+		  printf("\n");
+		  printf("Text: ");
+		  for (i = 0; i < rcvlen; ++i) {
+		    uint8_t c = rxbuf[i];
+		    if (32 <= c && c <= 126)
+		      printf("  %c", c);
+		    else
+		      printf(" %02x", c);
+		  }
+		  printf("\n");
+		  printf("AX25: ");
+		  for (i = 0; i < rcvlen; ++i) {
+		    uint8_t c = rxbuf[i] >> 1;
+		    if (32 <= c && c <= 126)
+		      printf("  %c", c);
+		    else
+		      printf(" %02x", c);
+		  }
+		  printf("\n");
+*/
+ 	}
+
+	netdev = NULL;
+	for (i = 0; i < netax25_devcount; ++i) {
+	  if (netax25_devs[i]->ifindex == ifindex) {
+	    netdev = netax25_devs[i];
+	    break;
+	  }
+	}
+	if (netdev == NULL) {
+	  // Not found from Ax.25 devices
+	  if (debug>1) printf(".. not from known AX.25 device\n");
+	  return 1;
+	}
+        if (netdev->interface == NULL) {
+	  if (debug>1) printf(".. not from AX.25 device configured for receiving.\n");
+          return 1;
+        }
+
+	if (debug) printf("Received frame of %d bytes from %s: %s\n",
+			  rcvlen, netdev->devname, netdev->callsign);
+
+	// if (is_ax25ttyport(netdev->callsign)) {
+	if (!netdev->rxok) {
+		if (debug > 1) {
+		  printf("%s is ttyport which we serve.\n",netdev->callsign);
+		}
+		return 1; // We drop our own packets, if we ever see them
+	}
+
+	/// Now: actual AX.25 frame reception,
+	//   and transmit via ax25_to_tnc2() !
+
+	/*
+	 * "+10" is a magic constant for trying
+	 * to estimate channel occupation overhead
+	 */
+	erlang_add(netdev->callsign, ERLANG_RX, rcvlen + 10, 1); // rxsock_read()
+
+	// Send it to Rx-IGate, validates also AX.25 header bits,
+	// and returns non-zero only when things are OK for processing.
+	// Will internally also send to interface layer, if OK.
+	if (ax25_to_tnc2(netdev->interface, netdev->callsign, 0, rxbuf[0], rxbuf + 1, rcvlen - 1)) {
+	  // The packet is valid per AX.25 header bit rules.
+	  // ax25_to_tnc2() did send the packet to rx-igate
+	  ;
+	} else {
+	  // The packet is not valid per AX.25 header bit rules
+	  erlang_add(netdev->callsign, ERLANG_DROP, rcvlen+10, 1);	/* Account one packet */
+
+	  if (aprxlogfile) {
+	    FILE *fp = fopen(aprxlogfile, "a");
+	    if (fp) {
+	      char timebuf[60];
+	      printtime(timebuf, sizeof(timebuf));
+
+	      fprintf(fp, "%s ax25_to_tnc2(%s,len=%d) rejected the message: ", timebuf, netdev->callsign, rcvlen);
+	      hexdumpfp(fp, rxbuf, rcvlen, 1);
+	      fprintf(fp, "\n");
+	      fclose(fp);
+	    }
+	  }
+	}
+
+	return 1;
+}
+
+static void discard_read_fd( const int fd )
+{
+	char buf[2000];
+	(void)read(fd, buf, sizeof(buf));
+}
+
+
+int netax25_postpoll(struct aprxpolls *app)
+{
+	int i, j;
+	struct pollfd *pfd;
+	// char ifaddress[10];
+
+        assert(app->polls != NULL);
+
+        if (tv_timercmp(&tick, &next_scantime) > 0) {
+        	scan_linux_devices();
+                // Rescan every 60 seconds, on the dot.
+                tv_timeradd_seconds(&next_scantime, &next_scantime, 60);
+        }
+
+	pfd = app->polls;
+
+	if (rx_socket < 0)
+		return 0;
+
+	for (i = 0; i < app->pollcount; ++i, ++pfd) {
+	  if ((pfd->fd == rx_socket) &&
+	      (pfd->revents & (POLLIN | POLLPRI))) {
+	    /* something coming in.. */
+	    rxsock_read( rx_socket );
+	  }
+	  for (j = 0; j < ax25ttyportscount; ++j) {
+	    if ((pfd->revents & (POLLIN | POLLPRI)) &&
+		(ax25ttyfds[j] == pfd->fd)) {
+	      discard_read_fd(ax25ttyfds[j]);
+	    }
+	  }
+	}
+	
+	return 0;
+}
+
+
+
+void netax25_sendto(const void *nax25p, const uint8_t *axaddr, const int axaddrlen, const char *axdata, const int axdatalen)
+{
+	const struct netax25_pty *nax25 = nax25p;
+	struct sockaddr_ll sll;
+	char c0[1];
+	struct iovec iovec[3];
+	struct msghdr mh;
+	int i, len;
+
+	if (tx_socket < 0) {
+	  if (debug>1) printf("netax25_sendto() tx_socket = -1, can not do..\n");
+	  return; // D'uh..
+	}
+	if (nax25->ifindex < 0) {
+	  if (debug>1) printf("netax25_sendto() ifindex < 0, can not do..\n");
+	  return; // D'uh..
+	}
+
+	if (debug>2) {
+	  printf("netax25_sendto() len=%d,%d ",axaddrlen,axdatalen);
+	  hexdumpfp(stdout, axaddr, axaddrlen, 1);
+	  printf(" // ");
+	  hexdumpfp(stdout, (uint8_t*)axdata, axdatalen, 0);
+	  printf("\n");
+	}
+
+	memset(&sll, 0, sizeof(sll));
+	sll.sll_family   = PF_PACKET;
+	sll.sll_ifindex  = nax25->ifindex;
+	sll.sll_protocol = htons(ETH_P_AX25);
+	sll.sll_hatype   = SOCK_RAW;
+
+	c0[0] = 0;
+	iovec[0].iov_base = c0;
+	iovec[0].iov_len  = 1;
+	iovec[1].iov_base = (void*)axaddr; // silence the compiler
+	iovec[1].iov_len  = axaddrlen;
+	iovec[2].iov_base = (void*)axdata; // silence the compiler
+	iovec[2].iov_len  = axdatalen;
+	len = 1+axaddrlen+axdatalen; // for debugging
+
+	memset(&mh, 0, sizeof(mh));
+	mh.msg_name    = &sll;
+	mh.msg_namelen = sizeof(sll);
+	mh.msg_iov     = iovec;
+	mh.msg_iovlen  = 3;
+
+	errno = 0;
+	i = sendmsg(tx_socket, &mh, 0);
+	if (debug>1)printf("netax25_sendto() the sendmsg len=%d rc=%d errno=%d\n", len, i, errno);
+
+	erlang_add(nax25->callsign, ERLANG_TX, axaddrlen+axdatalen + 10, 1);  // netax25_sendto()
+}
+#endif
diff --git a/netresolver.c b/netresolver.c
new file mode 100644
index 0000000..85960f2
--- /dev/null
+++ b/netresolver.c
@@ -0,0 +1,151 @@
+/* **************************************************************** *
+ *                                                                  *
+ *  APRX -- 2nd generation receive-only APRS-i-gate with            *
+ *          minimal requirement of esoteric facilities or           *
+ *          libraries of any kind beyond UNIX system libc.          *
+ *                                                                  *
+ * (c) Matti Aarnio - OH2MQK,  2007-2014                            *
+ *                                                                  *
+ * **************************************************************** */
+#include "aprx.h"
+
+#if defined(HAVE_PTHREAD_CREATE) && defined(ENABLE_PTHREAD)
+#include <signal.h>
+#include <pthread.h>
+pthread_t      netresolv_thread;
+pthread_attr_t pthr_attrs;
+#endif
+
+static int                 nrcount;
+static struct netresolver **nr;
+static int                 netresolv_die_now;
+
+static int RE_RESOLVE_INTERVAL = 300; // 15 minutes ?
+
+struct netresolver *netresolv_add(const char *hostname, const char *port) {
+	struct netresolver *n = malloc(sizeof(*n));
+	memset(n, 0, sizeof(*n));
+	n->hostname   = hostname;
+	n->port       = port;
+	n->ai.ai_addr = &n->sa;
+
+	++nrcount;
+	nr = realloc(nr, sizeof(void*)*nrcount);
+	nr[nrcount-1] = n;
+	return n;
+}
+
+
+static void resolve_all(void) {
+	int i;
+
+	if (debug>1)
+	  printf("netresolve nrcount=%d\n", nrcount);
+
+	for (i = 0; i < nrcount; ++i) {
+		struct netresolver *n = nr[i];
+		struct addrinfo *ai, req;
+		int rc;
+
+                timetick();
+
+		if (timecmp(n->re_resolve_time, tick.tv_sec) > 0) {
+		  // Not yet to re-resolve this one
+		  if (debug>1)
+		    printf("nr[%d] re_resolve_time in future (%d secs)\n",
+			   i, (int)(n->re_resolve_time - tick.tv_sec));
+		  continue;
+		}
+
+		memset(&req, 0, sizeof(req));
+		req.ai_socktype = SOCK_STREAM;
+		req.ai_protocol = IPPROTO_TCP;
+		req.ai_flags = 0;
+#if 1
+		req.ai_family = AF_UNSPEC;	/* IPv4 and IPv6 are both OK */
+#else
+		req.ai_family = AF_INET;	/* IPv4 only */
+#endif
+		ai = NULL;
+
+		rc = getaddrinfo(n->hostname, n->port, &req, &ai);
+		if (rc != 0) {
+		  // re-resolving failed, discard possible junk result
+		  if (debug>1)
+		    printf("nr[%d] resolving of %s:%s failed, error: %s\n",
+			   i, n->hostname, n->port, gai_strerror(errno));
+		  if (ai != NULL)
+		    freeaddrinfo(ai);
+		  continue;
+		}
+
+		if (debug>1)
+		  printf("nr[%d] resolving of %s:%s success!\n",
+			 i, n->hostname, n->port);
+
+                timetick();
+
+		// Make local static copy of first result
+		memcpy(&n->sa, ai->ai_addr, ai->ai_addrlen);
+		n->ai.ai_flags     = ai->ai_flags;
+		n->ai.ai_family    = ai->ai_family;
+		n->ai.ai_socktype  = ai->ai_socktype;
+		n->ai.ai_protocol  = ai->ai_protocol;
+		n->ai.ai_addrlen   = ai->ai_addrlen;
+		n->ai.ai_addrlen   = ai->ai_addrlen;
+
+		freeaddrinfo(ai);
+		n->re_resolve_time  = tick.tv_sec + RE_RESOLVE_INTERVAL;
+	}
+}
+
+
+#if defined(HAVE_PTHREAD_CREATE) && defined(ENABLE_PTHREAD)
+static void netresolv_runthread(void) {
+	sigset_t sigs_to_block;
+
+	sigemptyset(&sigs_to_block);
+	sigaddset(&sigs_to_block, SIGALRM);
+	sigaddset(&sigs_to_block, SIGINT);
+	sigaddset(&sigs_to_block, SIGTERM);
+	sigaddset(&sigs_to_block, SIGQUIT);
+	sigaddset(&sigs_to_block, SIGHUP);
+	sigaddset(&sigs_to_block, SIGURG);
+	sigaddset(&sigs_to_block, SIGPIPE);
+	sigaddset(&sigs_to_block, SIGUSR1);
+	pthread_sigmask(SIG_BLOCK, &sigs_to_block, NULL);
+
+	// the main program can cancel us at will
+	pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
+
+	while (!die_now) {
+	  poll(NULL, 0, 30000); // Sleep 30 seconds (in a reliable way)
+	  resolve_all();
+	}
+}
+#endif
+
+// Start netresolver thread, but at first run one round of resolving!
+void netresolv_start(void) {
+	resolve_all();
+
+#if defined(HAVE_PTHREAD_CREATE) && defined(ENABLE_PTHREAD)
+	pthread_attr_init(&pthr_attrs);
+	/* 64 kB stack is enough for this thread (I hope!)
+	   default of 2 MB is way too much...*/
+	pthread_attr_setstacksize(&pthr_attrs, 64*1024);
+
+	pthread_create(&netresolv_thread, &pthr_attrs, (void*)netresolv_runthread, NULL);
+
+#endif
+}
+
+// Shutdown the netresolver thread
+void netresolv_stop(void)
+{
+	die_now = 1;
+#if defined(HAVE_PTHREAD_CREATE) && defined(ENABLE_PTHREAD)
+	pthread_cancel(netresolv_thread);
+	pthread_join(netresolv_thread, NULL);
+#endif
+}
diff --git a/parse_aprs.c b/parse_aprs.c
new file mode 100644
index 0000000..f8b0bd3
--- /dev/null
+++ b/parse_aprs.c
@@ -0,0 +1,1416 @@
+/*
+ *	aprsc
+ *
+ *	(c) Heikki Hannikainen, OH7LZB <hessu at hes.iki.fi>
+ *
+ *     This program is licensed under the BSD license, which can be found
+ *     in the file LICENSE.
+ *	
+ */
+
+/*
+ *	A simple APRS parser for aprsc. Translated from Ham::APRS::FAP
+ *	perl module (by OH2KKU).
+ *
+ *	Only needs to get lat/lng out of the packet, other features would
+ *	be unnecessary in this application, and slow down the parser.
+ *      ... but lets still classify the packet, output filter needs that.
+ *	
+ */
+
+#include "aprx.h"
+#include <math.h>
+
+#define DEBUG_LOG(...) if(debug)printf(__VA_ARGS__)
+
+
+/*
+ *	Check if the given character is a valid symbol table identifier
+ *	or an overlay character. The set is different for compressed
+ *	and uncompressed packets - the former has the overlaid number (0-9)
+ *	replaced with n-j.
+ */
+
+static int valid_sym_table_compressed(char c)
+{
+	return (c == '/' || c == '\\' || (c >= 0x41 && c <= 0x5A)
+		    || (c >= 0x61 && c <= 0x6A)); /* [\/\\A-Za-j] */
+}
+
+static int valid_sym_table_uncompressed(char c)
+{
+	return (c == '/' || c == '\\' || (c >= 0x41 && c <= 0x5A)
+		    || (c >= 0x30 && c <= 0x39)); /* [\/\\A-Z0-9] */
+}
+
+/*
+ *	Fill the pbuf_t structure with a parsed position and
+ *	symbol table & code. Also does range checking for lat/lng
+ *	and pre-calculates cosf(lat) for range filters.
+ */
+
+static int pbuf_fill_pos(struct pbuf_t *pb, const float lat, const float lng, const char sym_table, const char sym_code)
+{
+	int bad = 0;
+	/* symbol table and code */
+	pb->symbol[0] = sym_table;
+	pb->symbol[1] = sym_code;
+	pb->symbol[2] = 0;
+	
+	/* Is it perhaps a weather report ? */
+	if (sym_code == '_' && (sym_table == '/' || sym_table == '\\')) 
+		pb->packettype |= T_WX;
+	if (sym_code == '@' && (sym_table == '/' || sym_table == '\\')) 
+		pb->packettype |= T_WX;	/* Hurricane */
+
+	bad |= (lat < -89.9 && -0.0001 <= lng && lng <= 0.0001);
+	bad |= (lat >  89.9 && -0.0001 <= lng && lng <= 0.0001);
+
+	if (-0.0001 <= lat && lat <= 0.0001) {
+	  bad |= ( -0.0001 <= lng && lng <= 0.0001);
+	  bad |= ( -90.01  <= lng && lng <= -89.99);
+	  bad |= (  89.99  <= lng && lng <=  90.01);
+	}
+
+
+	if (bad || lat < -90.0 || lat > 90.0 || lng < -180.0 || lng > 180.0) {
+		if (debug)
+			printf("\tposition out of range: lat %.3f lng %.3f", lat, lng);
+
+		return 0; /* out of range */
+	}
+	
+	if (debug)
+		printf("\tposition ok: lat %.3f lng %.3f", lat, lng);
+
+	/* Pre-calculations for A/R/F/M-filter tests */
+	pb->lat     = filter_lat2rad(lat);  /* deg-to-radians */
+	pb->cos_lat = cosf(pb->lat);        /* used in range filters */
+	pb->lng     = filter_lon2rad(lng);  /* deg-to-radians */
+	
+	pb->flags |= F_HASPOS;	/* the packet has positional data */
+
+	return 1;
+}
+
+/*
+ *	Parse symbol from destination callsign
+ */
+
+static int get_symbol_from_dstcall_twochar(const char c1, const char c2, char *sym_table, char *sym_code)
+{
+	//hlog(LOG_DEBUG, "\ttwochar %c %c", c1, c2);
+	if (c1 == 'B') {
+		if (c2 >= 'B' && c2 <= 'P') {
+			*sym_table = '/';
+			*sym_code = c2 - 'B' + '!';
+			return 1;
+		}
+		return 0;
+	}
+	
+	if (c1 == 'P') {
+		if (c2 >= '0' && c2 <= '9') {
+			*sym_table = '/';
+			*sym_code = c2;
+			return 1;
+		}
+		if (c2 >= 'A' && c2 <= 'Z') {
+			*sym_table = '/';
+			*sym_code = c2;
+			return 1;
+		}
+		return 0;
+	}
+	
+	if (c1 == 'M') {
+		if (c2 >= 'R' && c2 <= 'X') {
+			*sym_table = '/';
+			*sym_code = c2 - 'R' + ':';
+			return 1;
+		}
+		return 0;
+	}
+	
+	if (c1 == 'H') {
+		if (c2 >= 'S' && c2 <= 'X') {
+			*sym_table = '/';
+			*sym_code = c2 - 'S' + '[';
+			return 1;
+		}
+		return 0;
+	}
+	
+	if (c1 == 'L') {
+		if (c2 >= 'A' && c2 <= 'Z') {
+			*sym_table = '/';
+			*sym_code = c2 - 'A' + 'a';
+			return 1;
+		}
+		return 0;
+	}
+	
+	if (c1 == 'J') {
+		if (c2 >= '1' && c2 <= '4') {
+			*sym_table = '/';
+			*sym_code = c2 - '1' + '{';
+			return 1;
+		}
+		return 0;
+	}
+	
+	if (c1 == 'O') {
+		if (c2 >= 'B' && c2 <= 'P') {
+			*sym_table = '\\';
+			*sym_code = c2 - 'B' + '!';
+			return 1;
+		}
+		return 0;
+	}
+	
+	if (c1 == 'A') {
+		if (c2 >= '0' && c2 <= '9') {
+			*sym_table = '\\';
+			*sym_code = c2;
+			return 1;
+		}
+		if (c2 >= 'A' && c2 <= 'Z') {
+			*sym_table = '\\';
+			*sym_code = c2;
+			return 1;
+		}
+		return 0;
+	}
+	
+	if (c1 == 'N') {
+		if (c2 >= 'R' && c2 <= 'X') {
+			*sym_table = '\\';
+			*sym_code = c2 - 'R' + ':';
+			return 1;
+		}
+		return 0;
+	}
+	
+	if (c1 == 'D') {
+		if (c2 >= 'S' && c2 <= 'X') {
+			*sym_table = '\\';
+			*sym_code = c2 - 'S' + '[';
+			return 1;
+		}
+		return 0;
+	}
+	
+	if (c1 == 'S') {
+		if (c2 >= 'A' && c2 <= 'Z') {
+			*sym_table = '\\';
+			*sym_code = c2 - 'A' + 'a';
+			return 1;
+		}
+		return 0;
+	}
+	
+	if (c1 == 'Q') {
+		if (c2 >= '1' && c2 <= '4') {
+			*sym_table = '\\';
+			*sym_code = c2 - '1' + '{';
+			return 1;
+		}
+		return 0;
+	}
+	
+	return 0;
+}
+
+static int get_symbol_from_dstcall(struct pbuf_t *pb, char *sym_table, char *sym_code)
+{
+	const char *d_start;
+	char type;
+	char overlay;
+	int sublength;
+	int numberid;
+	
+	/* check that the destination call exists and is of the right size for symbol */
+	d_start = pb->srccall_end+1;
+	if (pb->dstcall_end_or_ssid - d_start < 5)
+		return 0; /* too short */
+	
+	/* length of the parsed string */
+	sublength = pb->dstcall_end_or_ssid - d_start - 3;
+	if (sublength > 3)
+		sublength = 3;
+	
+#ifdef DEBUG_PARSE_APRS
+	if (debug)
+	  printf("\tget_symbol_from_dstcall: %.*s (%d)", (int)(pb->dstcall_end_or_ssid - d_start), d_start, sublength);
+#endif
+	
+	if (strncmp(d_start, "GPS", 3) != 0 && strncmp(d_start, "SPC", 3) != 0 && strncmp(d_start, "SYM", 3) != 0)
+		return 0;
+	
+	// hlog(LOG_DEBUG, "\ttesting %c %c %c", d_start[3], d_start[4], d_start[5]);
+	if (!isalnum(d_start[3]) || !isalnum(d_start[4]))
+		return 0;
+	
+	if (sublength == 3 && !isalnum(d_start[5]))
+		return 0;
+	
+	type = d_start[3];
+	
+	if (sublength == 3) {
+		if (type == 'C' || type == 'E') {
+			if (!isdigit(d_start[4]))
+				return 0;
+			if (!isdigit(d_start[5]))
+				return 0;
+			numberid = (d_start[4] - 48) * 10 + (d_start[5] - 48);
+			
+			*sym_code = numberid + 32;
+			if (type == 'C')
+				*sym_table = '/';
+			else
+				*sym_table = '\\';
+		
+#ifdef DEBUG_PARSE_APRS
+			if (debug)
+			  printf("\tnumeric symbol id in dstcall: %.*s: table %c code %c",
+				(int)(pb->dstcall_end_or_ssid - d_start - 3), d_start + 3, *sym_table, *sym_code);
+#endif
+			return 1;
+		} else {
+			/* secondary symbol table, with overlay
+			 * Check first that we really are in the secondary symbol table
+			 */
+			overlay = d_start[5];
+			if ((type == 'O' || type == 'A' || type == 'N' ||
+				type == 'D' || type == 'S' || type == 'Q')
+				&& isalnum(overlay)) {
+				return get_symbol_from_dstcall_twochar(d_start[3], d_start[4], sym_table, sym_code);
+			}
+			return 0;
+		}
+	} else {
+		// primary or secondary table, no overlay
+		return get_symbol_from_dstcall_twochar(d_start[3], d_start[4], sym_table, sym_code);
+	}
+	
+	return 0;
+}
+
+
+/*
+ *	Parse NMEA position packets.
+ */
+
+static int parse_aprs_nmea(struct pbuf_t *pb, const char *body, const char *body_end)
+{
+	float lat, lng;
+	const char *latp, *lngp;
+	int i, la, lo;
+	char lac, loc;
+	char sym_table, sym_code;
+	
+	if (memcmp(body,"ULT",3) == 0) {
+		/* Ah..  "$ULT..." - that is, Ultimeter 2000 weather instrument */
+		pb->packettype |= T_WX;
+		return 1;
+	}
+	
+	lat  = lng  = 0.0;
+	latp = lngp = NULL;
+	
+	/* NMEA sentences to understand:
+	   $GPGGA  Global Positioning System Fix Data
+	   $GPGLL  Geographic Position, Latitude/Longitude Data
+	   $GPRMC  Remommended Minimum Specific GPS/Transit Data
+	   $GPWPT  Way Point Location ?? (bug in APRS specs ?)
+	   $GPWPL  Waypoint Load (not in APRS specs, but in NMEA specs)
+	   $PNTS   Seen on APRS-IS, private sentense based on NMEA..
+	   $xxTLL  Not seen on radio network, usually $RATLL - Target positions
+	           reported by RAdar.
+	 */
+	 
+	if (memcmp(body, "GPGGA,", 6) == 0) {
+		/* GPGGA,175059,3347.4969,N,11805.7319,W,2,12,1.0,6.8,M,-32.1,M,,*7D
+		//   v=1, looks fine
+		// GPGGA,000000,5132.038,N,11310.221,W,1,09,0.8,940.0,M,-17.7,,
+		//   v=1, timestamp odd, coords look fine
+		// GPGGA,,,,,,0,00,,,,,,,*66
+		//   v=0, invalid
+		// GPGGA,121230,4518.7931,N,07322.3202,W,2,08,1.0,40.0,M,-32.4,M,,*46
+		//   v=2, looks valid ?
+		// GPGGA,193115.00,3302.50182,N,11651.22581,W,1,08,01.6,00465.90,M,-32.891,M,,*5F
+		// $GPGGA,hhmmss.dd,xxmm.dddd,<N|S>,yyymm.dddd,<E|W>,v,
+		//        ss,d.d,h.h,M,g.g,M,a.a,xxxx*hh<CR><LF>
+		*/
+		
+		latp = body+6; // over the keyword
+		while (latp < body_end && *latp != ',')
+			latp++; // scan over the timestamp
+		if (*latp == ',')
+			latp++; // .. and into latitude.
+		lngp = latp;
+		while (lngp < body_end && *lngp != ',')
+			lngp++;
+		if (*lngp == ',')
+			lngp++;
+		if (*lngp != ',')
+			lngp++;
+		if (*lngp == ',')
+			lngp++;
+			
+		/* latp, and lngp  point to start of latitude and longitude substrings
+		// respectively.
+		*/
+	
+	} else if (memcmp(body, "GPGLL,", 6) == 0) {
+		/* $GPGLL,xxmm.dddd,<N|S>,yyymm.dddd,<E|W>,hhmmss.dd,S,M*hh<CR><LF>  */
+		latp = body+6; // over the keyword
+		lngp = latp;
+		while (lngp < body_end && *lngp != ',') // over latitude
+			lngp++;
+		if (*lngp == ',')
+			lngp++; // and lat designator
+		if (*lngp != ',')
+			lngp++; // and lat designator
+		if (*lngp == ',')
+			lngp++;
+		/* latp, and lngp  point to start of latitude and longitude substrings
+		// respectively
+		*/
+	} else if (memcmp(body, "GPRMC,", 6) == 0) {
+		/* $GPRMC,hhmmss.dd,S,xxmm.dddd,<N|S>,yyymm.dddd,<E|W>,s.s,h.h,ddmmyy,d.d, <E|W>,M*hh<CR><LF>
+		// ,S, = Status:  'A' = Valid, 'V' = Invalid
+		// 
+		// GPRMC,175050,A,4117.8935,N,10535.0871,W,0.0,324.3,100208,10.0,E,A*3B
+		// GPRMC,000000,V,0000.0000,0,00000.0000,0,000,000,000000,,*01/It wasn't me :)
+		//    invalid..
+		// GPRMC,000043,V,4411.7761,N,07927.0448,W,0.000,0.0,290697,10.7,W*57
+		// GPRMC,003803,A,3347.1727,N,11812.7184,W,000.0,000.0,140208,013.7,E*67
+		// GPRMC,050058,A,4609.1143,N,12258.8184,W,0.000,0.0,100208,18.0,E*5B
+		*/
+		
+		latp = body+6; // over the keyword
+		while (latp < body_end && *latp != ',')
+			latp++; // scan over the timestamp
+		if (*latp == ',')
+			latp++; // .. and into VALIDITY
+		if (*latp != 'A' && *latp != 'V')
+			return 0; // INVALID !
+		if (*latp != ',')
+			latp++;
+		if (*latp == ',')
+			latp++;
+		
+		/* now it points to latitude substring */
+		lngp = latp;
+		while (lngp < body_end && *lngp != ',')
+			lngp++;
+		
+		if (*lngp == ',')
+			lngp++;
+		if (*lngp != ',')
+			lngp++;
+		if (*lngp == ',')
+			lngp++;
+		
+		/* latp, and lngp  point to start of latitude and longitude substrings
+		// respectively.
+		*/
+		
+	} else if (memcmp(body, "GPWPL,", 6) == 0) {
+		/* $GPWPL,4610.586,N,00607.754,E,4*70
+		// $GPWPL,4610.452,N,00607.759,E,5*74
+		*/
+		latp = body+6;
+		
+	} else if (memcmp(body, "PNTS,1,", 7) == 0) { /* PNTS version 1 */
+		/* $PNTS,1,0,11,01,2002,231932,3539.687,N,13944.480,E,0,000,5,Roppongi UID RELAY,000,1*35
+		// $PNTS,1,0,14,01,2007,131449,3535.182,N,13941.200,E,0,0.0,6,Oota-Ku KissUIDigi,000,1*1D
+		// $PNTS,1,0,17,02,2008,120824,3117.165,N,13036.481,E,49,059,1,Kagoshima,000,1*71
+		// $PNTS,1,0,17,02,2008,120948,3504.283,N,13657.933,E,00,000.0,6,,000,1*36
+		// 
+		// From Alinco EJ-41U Terminal Node Controller manual:
+		// 
+		// 5-4-7 $PNTS
+		// This is a private-sentence based on NMEA-0183.  The data contains date,
+		// time, latitude, longitude, moving speed, direction, altitude plus a short
+		// message, group codes, and icon numbers. The EJ-41U does not analyze this
+		// format but can re-structure it.
+		// The data contains the following information:
+		//  l $PNTS Starts the $PNTS sentence
+		//  l version
+		//  l the registered information. [0]=normal geographical location data.
+		//    This is the only data EJ-41U can re-structure. [s]=Initial position
+		//    for the course setting [E]=ending position for the course setting
+		//    [1]=the course data between initial and ending [P]=the check point
+		//    registration [A]=check data when the automatic position transmission
+		//    is set OFF [R]=check data when the course data or check point data is
+		//    received.
+		//  l dd,mm,yyyy,hhmmss: Date and time indication.
+		//  l Latitude in DMD followed by N or S
+		//  l Longitude in DMD followed by E or W
+		//  l Direction: Shown with the number 360 degrees divided by 64.
+		//    00 stands for true north, 16 for east. Speed in Km/h
+		//  l One of 15 characters [0] to [9], [A] to [E].
+		//    NTSMRK command determines this character when EJ-41U is used.
+		//  l A short message up to 20 bites. Use NTSMSG command to determine this message.
+		//  l A group code: 3 letters with a combination of [0] to [9], [A] to [Z].
+		//    Use NTSGRP command to determine.
+		//  l Status: [1] for usable information, [0] for non-usable information.
+		//  l *hh<CR><LF> the check-sum and end of PNTS sentence.
+		*/
+
+		if (body+55 > body_end) {
+			DEBUG_LOG("body too short");
+			return 0; /* Too short.. */
+		}
+		latp = body+7; /* Over the keyword */
+		/* Accept any registered information code */
+		if (*latp++ == ',') return 0;
+		if (*latp++ != ',') return 0;
+		/* Scan over date+time info */
+		while (*latp != ',' && latp <= body_end) ++latp;
+		if (*latp == ',') ++latp;
+		while (*latp != ',' && latp <= body_end) ++latp;
+		if (*latp == ',') ++latp;
+		while (*latp != ',' && latp <= body_end) ++latp;
+		if (*latp == ',') ++latp;
+		while (*latp != ',' && latp <= body_end) ++latp;
+		if (*latp == ',') ++latp;
+		/* now it points to latitude substring */
+		lngp = latp;
+		while (lngp < body_end && *lngp != ',')
+			lngp++;
+		
+		if (*lngp == ',')
+			lngp++;
+		if (*lngp != ',')
+			lngp++;
+		if (*lngp == ',')
+			lngp++;
+		
+		/* latp, and lngp  point to start of latitude and longitude substrings
+		// respectively.
+		*/
+#if 1
+	} else if (memcmp(body, "GPGSA,", 6) == 0 ||
+		   memcmp(body, "GPVTG,", 6) == 0 ||
+		   memcmp(body, "GPGSV,", 6) == 0) {
+		/* Recognized but ignored */
+		return 1;
+#endif
+	}
+	
+	if (!latp || !lngp) {
+		if (debug)
+			fprintf(stderr, "Unknown NMEA: '%.11s' %.*s", pb->data, (int)(body_end - body), body);
+		return 0; /* Well..  Not NMEA frame */
+	}
+
+	// hlog(LOG_DEBUG, "NMEA parsing: %.*s", (int)(body_end - body), body);
+	// hlog(LOG_DEBUG, "     lat=%.10s   lng=%.10s", latp, lngp);
+
+	i = sscanf(latp, "%2d%f,%c,", &la, &lat, &lac);
+	if (i != 3)
+		return 0; // parse failure
+	
+	i = sscanf(lngp, "%3d%f,%c,", &lo, &lng, &loc);
+	if (i != 3)
+		return 0; // parse failure
+	
+	if (lac != 'N' && lac != 'S' && lac != 'n' && lac != 's')
+		return 0; // bad indicator value
+	if (loc != 'E' && loc != 'W' && loc != 'e' && loc != 'w')
+		return 0; // bad indicator value
+		
+	// hlog(LOG_DEBUG, "   lat: %c %2d %7.4f   lng: %c %2d %7.4f",
+	//                 lac, la, lat, loc, lo, lng);
+
+	lat = (float)la + lat/60.0;
+	lng = (float)lo + lng/60.0;
+	
+	if (lac == 'S' || lac == 's')
+		lat = -lat;
+	if (loc == 'W' || loc == 'w')
+		lng = -lng;
+	
+	pb->packettype |= T_POSITION;
+	
+	// Parse symbol from destination callsign
+	get_symbol_from_dstcall(pb, &sym_table, &sym_code);
+#ifdef DEBUG_PARSE_APRS
+	if (debug) {
+	  printf("\tget_symbol_from_dstcall: %.*s => %c%c",
+		 (int)(pb->dstcall_end_or_ssid - pb->srccall_end-1), pb->srccall_end+1, sym_table, sym_code);
+	}
+#endif
+
+	return pbuf_fill_pos(pb, lat, lng, sym_table, sym_code);
+}
+
+static int parse_aprs_telem(struct pbuf_t *pb, const char *body, const char *body_end)
+{
+	// float lat = 0.0, lng = 0.0;
+
+	DEBUG_LOG("parse_aprs_telem");
+
+	//pbuf_fill_pos(pb, lat, lng, 0, 0);
+	return 1; // okay
+}
+
+/*
+ *	Parse a MIC-E position packet
+ *
+ *	APRS PROTOCOL REFERENCE 1.0.1 Chapter 10, page 42 (52 in PDF)
+ *
+ */
+
+static int parse_aprs_mice(struct pbuf_t *pb, const unsigned char *body, const unsigned char *body_end)
+{
+	float lat = 0.0, lng = 0.0;
+	unsigned int lat_deg = 0, lat_min = 0, lat_min_frag = 0, lng_deg = 0, lng_min = 0, lng_min_frag = 0;
+	const char *d_start;
+	char dstcall[7];
+	char *p;
+	char sym_table, sym_code;
+	int posambiguity = 0;
+	int i;
+	
+        DEBUG_LOG("parse_aprs_mice: %.*s", pb->packet_len-2, pb->data);
+	
+	/* check packet length */
+	if (body_end - body < 8)
+		return 0;
+	
+	/* check that the destination call exists and is of the right size for mic-e */
+	d_start = pb->srccall_end+1;
+	if (pb->dstcall_end_or_ssid - d_start != 6) {
+		DEBUG_LOG(".. bad destcall length! ");
+		return 0; /* eh...? */
+	}
+	
+	/* validate destination call:
+	 * A-K characters are not used in the last 3 characters
+	 * and MNO are never used
+	 */
+ 	if (debug)printf(" destcall='%6.6s'",d_start);
+	for (i = 0; i < 3; i++)
+		if (!((d_start[i] >= '0' && d_start[i] <= '9')
+			|| (d_start[i] >= 'A' && d_start[i] <= 'L')
+			|| (d_start[i] >= 'P' && d_start[i] <= 'Z'))) {
+			DEBUG_LOG(".. bad destcall characters in posits 1..3");
+			return 0;
+		}
+	
+	for (i = 3; i < 6; i++)
+		if (!((d_start[i] >= '0' && d_start[i] <= '9')
+			|| (d_start[i] == 'L')
+			|| (d_start[i] >= 'P' && d_start[i] <= 'Z'))) {
+			DEBUG_LOG(".. bad destcall characters in posits 4..6");
+			return 0;
+		}
+	
+	DEBUG_LOG("\tpassed dstcall format check");
+	
+	/* validate information field (longitude, course, speed and
+	 * symbol table and code are checked). Not bullet proof..
+	 *
+	 *   0          1          23            4          5          6              7
+	 * /^[\x26-\x7f][\x26-\x61][\x1c-\x7f]{2}[\x1c-\x7d][\x1c-\x7f][\x21-\x7b\x7d][\/\\A-Z0-9]/
+	 */
+	if (body[0] < 0x26 || body[0] > 0x7f) {
+		DEBUG_LOG("..bad infofield column 1");
+		return 0;
+	}
+	if (body[1] < 0x26 || body[1] > 0x61) {
+		DEBUG_LOG("..bad infofield column 2");
+		return 0;
+	}
+	if (body[2] < 0x1c || body[2] > 0x7f) {
+		DEBUG_LOG("..bad infofield column 3");
+		return 0;
+	}
+	if (body[3] < 0x1c || body[3] > 0x7f) {
+		DEBUG_LOG("..bad infofield column 4");
+		return 0;
+	}
+	if (body[4] < 0x1c || body[4] > 0x7d) {
+		DEBUG_LOG("..bad infofield column 5");
+		return 0;
+	}
+	if (body[5] < 0x1c || body[5] > 0x7f) {
+		DEBUG_LOG("..bad infofield column 6");
+		return 0;
+	}
+	if ((body[6] < 0x21 || body[6] > 0x7b)
+		&& body[6] != 0x7d) {
+		DEBUG_LOG("..bad infofield column 7");
+		return 0;
+	}
+	if (!valid_sym_table_uncompressed(body[7])) {
+		DEBUG_LOG("..bad symbol table entry on column 8");
+		return 0;
+	}
+	
+	DEBUG_LOG("\tpassed info format check");
+	
+	/* make a local copy, we're going to modify it */
+	strncpy(dstcall, d_start, 6);
+	dstcall[6] = 0;
+	
+	/* First do the destination callsign
+	 * (latitude, message bits, N/S and W/E indicators and long. offset)
+	 *
+	 * Translate the characters to get the latitude
+	 */
+	 
+	//fprintf(stderr, "\tuntranslated dstcall: %s\n", dstcall);
+	for (p = dstcall; *p; p++) {
+		if (*p >= 'A' && *p <= 'J')
+			*p -= 'A' - '0';
+		else if (*p >= 'P' && *p <= 'Y')
+			*p -= 'P' - '0';
+		else if (*p == 'K' || *p == 'L' || *p == 'Z')
+			*p = '_';
+	}
+	//fprintf(stderr, "\ttranslated dstcall: %s\n", dstcall);
+	
+	// position ambiquity is going to get ignored now,
+	// it's not needed in this application.
+
+	if (dstcall[5] == '_') { dstcall[5] = '5'; posambiguity = 1; }
+	if (dstcall[4] == '_') { dstcall[4] = '5'; posambiguity = 2; }
+	if (dstcall[3] == '_') { dstcall[3] = '5'; posambiguity = 3; }
+	if (dstcall[2] == '_') { dstcall[2] = '3'; posambiguity = 4; }
+	if (dstcall[1] == '_' || dstcall[0] == '_') {
+		DEBUG_LOG("..bad pos-ambiguity on destcall");
+		return 0;
+	} // cannot use posamb here
+	
+	// convert to degrees, minutes and decimal degrees,
+	//  and then to a float lat
+
+	if (sscanf(dstcall, "%2u%2u%2u",
+	    &lat_deg, &lat_min, &lat_min_frag) != 3) {
+		DEBUG_LOG("\tsscanf failed");
+		return 0;
+	}
+	lat = (float)lat_deg + (float)lat_min / 60.0 + (float)lat_min_frag / 6000.0;
+	
+	// check the north/south direction and correct the latitude if necessary
+	if (d_start[3] <= 0x4c)
+		lat = 0 - lat;
+	
+	/* Decode the longitude, the first three bytes of the body
+	 * after the data type indicator. First longitude degrees,
+	 * remember the longitude offset.
+	 */
+	lng_deg = body[0] - 28;
+	if (d_start[4] >= 0x50)
+		lng_deg += 100;
+	if (lng_deg >= 180 && lng_deg <= 189)
+		lng_deg -= 80;
+	else if (lng_deg >= 190 && lng_deg <= 199)
+		lng_deg -= 190;
+
+	/* Decode the longitude minutes */
+	lng_min = body[1] - 28;
+	if (lng_min >= 60)
+		lng_min -= 60;
+		
+	/* ... and minute decimals */
+	lng_min_frag = body[2] - 28;
+	
+	/* apply position ambiguity to longitude */
+	switch (posambiguity) {
+	case 0:
+		/* use everything */
+		lng = (float)lng_deg + (float)lng_min / 60.0
+			+ (float)lng_min_frag / 6000.0;
+		break;
+	case 1:
+		/* ignore last number of lng_min_frag */
+		lng = (float)lng_deg + (float)lng_min / 60.0
+			+ (float)(lng_min_frag - lng_min_frag % 10 + 5) / 6000.0;
+		break;
+	case 2:
+		/* ignore lng_min_frag */
+		lng = (float)lng_deg + ((float)lng_min + 0.5) / 60.0;
+		break;
+	case 3:
+		/* ignore lng_min_frag and last number of lng_min */
+		lng = (float)lng_deg + (float)(lng_min - lng_min % 10 + 5) / 60.0;
+		break;
+	case 4:
+		/* minute is unused -> add 0.5 degrees to longitude */
+		lng = (float)lng_deg + 0.5;
+		break;
+	default:
+		DEBUG_LOG(".. posambiguity code BUG!");
+		return 0;
+	}
+	
+	/* check the longitude E/W sign */
+	if (d_start[5] >= 0x50)
+		lng = 0 - lng;
+	
+	/* save the symbol table and code */
+	sym_code = body[6];
+	sym_table = body[7];
+	
+	/* ok, we're done */
+	/*
+	fprintf(stderr, "\tlat %u %u.%u (%.4f) lng %u %u.%u (%.4f)\n",
+	 	lat_deg, lat_min, lat_min_frag, lat,
+	 	lng_deg, lng_min, lng_min_frag, lng);
+	fprintf(stderr, "\tsym '%c' '%c'\n", sym_table, sym_code);
+	*/
+	
+	return pbuf_fill_pos(pb, lat, lng, sym_table, sym_code);
+}
+
+/*
+ *	Parse a compressed APRS position packet
+ *
+ *	APRS PROTOCOL REFERENCE 1.0.1 Chapter 9, page 36 (46 in PDF)
+ *
+ */
+
+static int parse_aprs_compressed(struct pbuf_t *pb, const char *body, const char *body_end)
+{
+	char sym_table, sym_code;
+	int i;
+	int lat1, lat2, lat3, lat4;
+	int lng1, lng2, lng3, lng4;
+	float lat, lng;
+	
+	DEBUG_LOG("parse_aprs_compressed");
+	
+	/* A compressed position is always 13 characters long.
+	 * Make sure we get at least 13 characters and that they are ok.
+	 * Also check the allowed base-91 characters at the same time.
+	 */ 
+	
+	if (body_end - body < 13) {
+		DEBUG_LOG("\ttoo short");
+		return 0; /* too short. */
+	}
+	
+	sym_table = body[0]; /* has been validated before entering this function */
+	sym_code = body[9];
+	
+	/* base-91 check */
+	for (i = 1; i <= 8; i++)
+		if (body[i] < 0x21 || body[i] > 0x7b)
+			return 0;
+	
+	// fprintf(stderr, "\tpassed length and format checks, sym %c%c\n", sym_table, sym_code);
+	
+	/* decode */
+	lat1 = (body[1] - 33);
+	lat2 = (body[2] - 33);
+	lat3 = (body[3] - 33);
+	lat4 = (body[4] - 33);
+
+	lat1 = ((((lat1 * 91) + lat2) * 91) + lat3) * 91 + lat4;
+
+	lng1 = (body[5] - 33);
+	lng2 = (body[6] - 33);
+	lng3 = (body[7] - 33);
+	lng4 = (body[8] - 33);
+
+	lng1 = ((((lng1 * 91) + lng2) * 91) + lng3) * 91 + lng4;
+	
+	/* calculate latitude and longitude */
+	
+	lat =   90.0F - ((float)(lat1) / 380926.0F);
+	lng = -180.0F + ((float)(lng1) / 190463.0F);
+	
+	return pbuf_fill_pos(pb, lat, lng, sym_table, sym_code);
+}
+
+/*
+ *	Parse an uncompressed "normal" APRS packet
+ *
+ *	APRS PROTOCOL REFERENCE 1.0.1 Chapter 8, page 32 (42 in PDF)
+ *
+ */
+
+static int parse_aprs_uncompressed(struct pbuf_t *pb, const char *body, const char *body_end)
+{
+	char posbuf[20];
+	unsigned int lat_deg = 0, lat_min = 0, lat_min_frag = 0, lng_deg = 0, lng_min = 0, lng_min_frag = 0;
+	float lat, lng;
+	char lat_hemi, lng_hemi;
+	char sym_table, sym_code;
+	int issouth = 0;
+	int iswest = 0;
+	
+	DEBUG_LOG("parse_aprs_uncompressed");
+	
+	if (body_end - body < 19) {
+		DEBUG_LOG("\ttoo short");
+		return 0;
+	}
+	
+	/* make a local copy, so we can overwrite it at will. */
+	memcpy(posbuf, body, 19);
+	posbuf[19] = 0;
+	// fprintf(stderr, "\tposbuf: %s\n", posbuf);
+	
+	// position ambiquity is going to get ignored now,
+        // it's not needed in this application.
+
+	/* lat */
+	if (posbuf[2] == ' ') posbuf[2] = '3';
+	if (posbuf[3] == ' ') posbuf[3] = '5';
+	if (posbuf[5] == ' ') posbuf[5] = '5';
+	if (posbuf[6] == ' ') posbuf[6] = '5';
+	/* lng */
+	if (posbuf[12] == ' ') posbuf[12] = '3';
+	if (posbuf[13] == ' ') posbuf[13] = '5';
+	if (posbuf[15] == ' ') posbuf[15] = '5';
+	if (posbuf[16] == ' ') posbuf[16] = '5';
+	
+	// fprintf(stderr, "\tafter filling amb: %s\n", posbuf);
+	/* 3210.70N/13132.15E# */
+	if (sscanf(posbuf, "%2u%2u.%2u%c%c%3u%2u.%2u%c%c",
+	    &lat_deg, &lat_min, &lat_min_frag, &lat_hemi, &sym_table,
+	    &lng_deg, &lng_min, &lng_min_frag, &lng_hemi, &sym_code) != 10) {
+		DEBUG_LOG("\tsscanf failed");
+		return 0;
+	}
+	
+	if (!valid_sym_table_uncompressed(sym_table))
+		sym_table = 0;
+	
+	if (lat_hemi == 'S' || lat_hemi == 's')
+		issouth = 1;
+	else if (lat_hemi != 'N' && lat_hemi != 'n')
+		return 0; /* neither north or south? bail out... */
+	
+	if (lng_hemi == 'W' || lng_hemi == 'w')
+		iswest = 1;
+	else if (lng_hemi != 'E' && lng_hemi != 'e')
+		return 0; /* neither west or east? bail out ... */
+	
+	if (lat_deg > 89 || lng_deg > 179)
+		return 0; /* too large values for lat/lng degrees */
+	
+	lat = (float)lat_deg + (float)lat_min / 60.0 + (float)lat_min_frag / 6000.0;
+	lng = (float)lng_deg + (float)lng_min / 60.0 + (float)lng_min_frag / 6000.0;
+	
+	/* Finally apply south/west indicators */
+	if (issouth)
+		lat = 0.0 - lat;
+	if (iswest)
+		lng = 0.0 - lng;
+	
+	// fprintf(stderr, "\tlat %u %u.%u %c (%.3f) lng %u %u.%u %c (%.3f)\n",
+	// 	lat_deg, lat_min, lat_min_frag, (int)lat_hemi, lat,
+	// 	lng_deg, lng_min, lng_min_frag, (int)lng_hemi, lng);
+	// fprintf(stderr, "\tsym '%c' '%c'\n", sym_table, sym_code);
+
+	return pbuf_fill_pos(pb, lat, lng, sym_table, sym_code);
+}
+
+/*
+ *	Parse an APRS object 
+ *
+ *	APRS PROTOCOL REFERENCE 1.0.1 Chapter 11, page 58 (68 in PDF)
+ *
+ */
+
+static int parse_aprs_object(struct pbuf_t *pb, const char *body, const char *body_end)
+{
+	int i;
+	int namelen = -1;
+	
+	pb->packettype |= T_OBJECT;
+	
+	DEBUG_LOG("parse_aprs_object");
+	
+	/* check that the object name ends with either * or _ */
+	if (*(body + 9) != '*' && *(body + 9) != '_') {
+		DEBUG_LOG("\tinvalid object kill character");
+		return 0;
+	}
+
+	/* check that the timestamp ends with one of the valid timestamp type IDs */
+        char tz_end = body[16];
+        if (tz_end != 'z' && tz_end != 'h' && tz_end != '/') {
+        	DEBUG_LOG("\tinvalid object timestamp character: '%c'", tz_end);
+		return 0;
+	}
+	
+	/* check object's name - scan for non-printable characters and the last
+	 * non-space character
+	 */
+	for (i = 0; i < 9; i++) {
+		if (body[i] < 0x20 || body[i] > 0x7e) {
+			DEBUG_LOG("\tobject name has unprintable characters");
+			return 0; // non-printable
+		}
+		if (body[i] != ' ')
+			namelen = i;
+	}
+	
+	if (namelen < 0) {
+		DEBUG_LOG("\tobject has empty name");
+		return 0;
+	}
+	
+	pb->srcname = body;
+	pb->srcname_len = namelen+1;
+	
+	DEBUG_LOG("object name: '%.*s'\n", pb->srcname_len, pb->srcname);
+	
+	/* Forward the location parsing onwards */
+	if (valid_sym_table_compressed(body[17]))
+		return parse_aprs_compressed(pb, body + 17, body_end);
+	
+	if (body[17] >= '0' && body[17] <= '9')
+		return parse_aprs_uncompressed(pb, body + 17, body_end);
+	
+	DEBUG_LOG("no valid position in object");
+	
+	return 0;
+}
+
+/*
+ *	Parse an APRS item
+ *
+ *	APRS PROTOCOL REFERENCE 1.0.1 Chapter 11, page 59 (69 in PDF)
+ *
+ */
+
+static int parse_aprs_item(struct pbuf_t *pb, const char *body, const char *body_end)
+{
+	int i;
+	
+	pb->packettype |= T_ITEM;
+	
+	DEBUG_LOG("parse_aprs_item");
+	
+	/* check item's name - scan for non-printable characters and the
+	 * ending character ! or _
+	 */
+	for (i = 0; i < 9 && body[i] != '!' && body[i] != '_'; i++) {
+		if (body[i] < 0x20 || body[i] > 0x7e) {
+			DEBUG_LOG("\titem name has unprintable characters");
+			return 0; /* non-printable */
+		}
+	}
+	
+	if (body[i] != '!' && body[i] != '_') {
+		DEBUG_LOG("\titem name ends with neither ! or _");
+		return 0;
+	}
+	
+	if (i < 3 || i > 9) {
+		DEBUG_LOG("\titem name has invalid length");
+		return 0;
+	}
+	
+	pb->srcname = body;
+	pb->srcname_len = i;
+	
+	//fprintf(stderr, "\titem name: '%.*s'\n", pb->srcname_len, pb->srcname);
+	
+	/* Forward the location parsing onwards */
+	i++;
+	if (valid_sym_table_compressed(body[i]))
+		return parse_aprs_compressed(pb, body + i, body_end);
+	
+	if (body[i] >= '0' && body[i] <= '9')
+		return parse_aprs_uncompressed(pb, body + i, body_end);
+	
+	DEBUG_LOG("\tno valid position in item");
+	
+	return 0;
+}
+
+
+#if 0
+int parse_aprs_txgate(struct pbuf_t *pb, int look_inside_3rd_party, historydb_t *historydb)
+{
+	int rc = parse_aprs(pb, look_inside_3rd_party, historydb);
+
+	if (pb->packettype & T_THIRDPARTY) {
+	  // Tx-IGate needs to know from RF received frames, if there is
+	  // source address that arrived from an Tx-IGate...
+
+	  const char *body;
+	  const char *body_end;
+	  const char *pos_start;
+	  const char *info_start = pb->info_start;
+	
+	  
+
+	}
+	return rc;
+}
+#endif
+
+/*
+ *	Try to parse an APRS packet.
+ *	Returns 1 if position was parsed successfully,
+ *	0 if parsing failed.
+ *
+ *	Does also front-end part of the output filter's
+ *	packet type classification job.
+ *
+ * TODO: Recognize TELEM packets in !/=@ packets too!
+ *
+ *	Return 0 for parse failures, 1 for OK.
+ */
+
+int parse_aprs(struct pbuf_t*const pb, historydb_t*const historydb)
+{
+	char packettype, poschar;
+	int paclen;
+	int rc;
+	const char *body;
+	const char *body_end;
+	const char *pos_start;
+	const char *info_start = pb->info_start;
+
+	int look_inside_3rd_party = 1; // Look there once..
+
+	pb->packettype = T_ALL;
+	pb->flags      = 0;
+
+	if (!pb->info_start)
+		return 0;
+
+	if (pb->data[0] == 'C' && /* Perhaps CWOP ? */
+	    pb->data[1] == 'W') {
+		const char *s  = pb->data + 2;
+		const char *pe = pb->data + pb->packet_len;
+		for ( ; *s && s < pe ; ++s ) {
+			int c = *s;
+			if (c < '0' || c > '9')
+				break;
+		}
+		if (*s == '>')
+			pb->packettype |= T_CWOP;
+	}
+
+	/* the following parsing logic has been translated from Ham::APRS::FAP
+	 * Perl module to C
+	 */
+	
+	// ignore the CRLF in the end of the body
+	body_end = pb->data + pb->packet_len; // NOTE! Difference from original aprsc code
+
+	do {
+		// body is right after the packet type character
+		body     = info_start + 1;
+
+		// length of the info field:
+		paclen = body_end - info_start;
+
+		if (paclen < 1) return 0; // consumed all, or empty packet
+
+		// Check the first character of the packet and
+		// determine the packet type
+		packettype = *info_start;
+
+		// Exit this loop unless it is 3rd-party frame
+		if (packettype != '}') break;
+
+		// Look for ':' character separating address block
+		// from 3rd-party body
+		info_start = memchr(body, ':', (int)(body_end - body));
+		if (info_start == NULL) {
+			// Not valid 3rd party frame!
+			return 0;
+		}
+		pb->packettype |= T_THIRDPARTY;
+		if (!look_inside_3rd_party)
+			return 1; // Correct 3rd-party, don't look further.
+
+		// Look once inside the 3rd party frame,
+		// this is used in aprx's tx-igate, which builds
+		// the 3rd-party frame before parsing message-to-be-tx:ed
+		// .. and doing content filters.
+		--look_inside_3rd_party;
+		pb->packettype = 0;
+
+		// Skip over the ':'
+		++info_start;
+		continue;  // and loop..
+
+	} while (1);
+
+	switch (packettype) {
+	/* the following are obsolete mic-e types: 0x1c 0x1d 
+	 * case 0x1c:
+	 * case 0x1d:
+	 */
+	case 0x27: /* ' */
+	case 0x60: /* ` */
+		/* could be mic-e, minimum body length 9 chars */
+		if (paclen >= 9) {
+			pb->packettype |= T_POSITION;
+			rc = parse_aprs_mice(pb,
+                                             (const unsigned char*)body,
+                                             (const unsigned char*)body_end);
+			DEBUG_LOG("\n");
+			return rc;
+		}
+		return 0; // bad
+
+	case '!':
+		if (*body == '!') { /* Ultimeter 2000 - "tnc2addr:!!" */
+			pb->packettype |= T_WX;
+			return 1; // Known Ultimeter format
+		}
+	case '=':
+	case '/':
+	case '@':
+		/* check that we won't run over right away */
+		if (body_end - body < 10)
+			return 0; // bad
+		/* Normal or compressed location packet, with or without
+		 * timestamp, with or without messaging capability
+		 *
+		 * ! and / have messaging, / and @ have a prepended timestamp
+		 */
+		pb->packettype |= T_POSITION;
+		if (packettype == '/' || packettype == '@') {
+			/* With a prepended timestamp, jump over it. */
+			body += 7;
+		}
+		poschar = *body;
+		if (valid_sym_table_compressed(poschar)) { /* [\/\\A-Za-j] */
+		    	/* compressed position packet */
+			rc = 0;
+			if (body_end - body >= 13)
+			  rc = parse_aprs_compressed(pb, body, body_end);
+			DEBUG_LOG("\n");
+			return rc;
+			
+		} else if (poschar >= 0x30 && poschar <= 0x39) { /* [0-9] */
+			/* normal uncompressed position */
+			rc = 0;
+			if (body_end - body >= 19)
+			  rc = parse_aprs_uncompressed(pb, body, body_end);
+			DEBUG_LOG("\n");
+			return rc;
+		}
+		return 0;
+
+	case '$':
+		if (body_end - body > 10) {
+			// Is it OK to declare it as position packet ?
+			rc = parse_aprs_nmea(pb, body, body_end);
+			DEBUG_LOG("\n");
+			return rc;
+		}
+		return 0;
+
+	case ':':
+		pb->packettype |= T_MESSAGE;
+		// quick and loose way to identify NWS and SKYWARN messages
+		// they do apparently originate from "WXSRV", but that is not
+		// guaranteed thing...
+		if (memcmp(body,"NWS-",4) == 0) // as seen on specification
+			pb->packettype |= T_NWS;
+		if (memcmp(body,"NWS_",4) == 0) // as seen on data
+			pb->packettype |= T_NWS;
+		if (memcmp(body,"SKY",3) == 0)  // as seen on specification
+			pb->packettype |= T_NWS;
+
+		// Is it perhaps TELEMETRY related "message" ?
+		if ( body[9] == ':' &&
+		     ( memcmp( body+9, ":PARM.", 6 ) == 0 ||
+		       memcmp( body+9, ":UNIT.", 6 ) == 0 ||
+		       memcmp( body+9, ":EQNS.", 6 ) == 0 ||
+		       memcmp( body+9, ":BITS.", 6 ) == 0    )) {
+			pb->packettype &= ~T_MESSAGE;
+			pb->packettype |=  T_TELEMETRY;
+			// Fall through to recipient location lookup
+		}
+
+		// Or perhaps a DIRECTED QUERY ?
+		if (body[9] == ':' && body[10] == '?') {
+			pb->packettype &= ~T_MESSAGE;
+			pb->packettype |=  T_QUERY;
+			// Fall through to recipient location lookup
+		}
+
+		// Now find out if the message RECIPIENT address is known
+		// to have some location data ?  Because then we can treat
+		// them the same way in filters as we do those with real
+		// positions..
+		{
+			const char *p;
+			int i;
+#ifndef DISABLE_IGATE
+			history_cell_t *history;
+#endif
+			pb->dstname = body;
+			p = body;
+			for (i = 0; i < CALLSIGNLEN_MAX; ++i) {
+				// the recipient address is space padded
+				// to 9 chars, while our historydb is not.
+				if (*p == 0 || *p == ' ' || *p == ':')
+					break;
+			}
+			pb->dstname_len = p - body;
+#ifndef DISABLE_IGATE
+                        if (historydb != NULL) {
+                        	history = historydb_lookup( historydb, pb->dstname, i );
+                                if (history != NULL) {
+					pb->lat     = history->lat;
+                                        pb->lng     = history->lon;
+                                        pb->cos_lat = history->coslat;
+			    
+                                        pb->flags  |= F_HASPOS;
+                                }
+                        }
+#endif
+		}
+		return 1;
+
+	case ';':
+		if (body_end - body > 29) {
+		  rc = parse_aprs_object(pb, body, body_end);
+		  DEBUG_LOG("\n");
+		  return rc;
+		}
+		return 0; // too short
+
+	case '>':
+		pb->packettype |= T_STATUS;
+		return 1; // ok
+
+	case '<':
+		pb->packettype |= T_STATCAPA;
+		return 1; // ok
+
+	case '?':
+		pb->packettype |= T_QUERY;
+		return 1; // ok at igate/digi
+
+	case ')':
+		if (body_end - body > 18) {
+		  rc = parse_aprs_item(pb, body, body_end);
+		  DEBUG_LOG("\n");
+		  return rc;
+		}
+                return 0; // too short
+
+
+	case 'T':
+		if (body_end - body > 18) {
+			pb->packettype |= T_TELEMETRY;
+			rc = parse_aprs_telem(pb, body, body_end);
+			DEBUG_LOG("\n");
+			return rc;
+		}
+		return 0; // too short
+
+	case '#': /* Peet Bros U-II Weather Station */
+	case '*': /* Peet Bros U-I  Weather Station */
+	case '_': /* Weather report without position */
+		pb->packettype |= T_WX;
+		return 1; // good
+
+	case '{':
+		pb->packettype |= T_USERDEF;
+		return 1; // okay at digi?
+
+        // the packettype is never '}'
+        // case '}':
+                // pb->packettype |= T_THIRDPARTY;
+		// return 1; // 3rd-party is okay at digi
+
+	default:
+		break;
+	}
+
+	/* When all else fails, try to look for a !-position that can
+	 * occur anywhere within the 40 first characters according
+	 * to the spec.  (X1J TNC digipeater bugs...)
+	 */
+	pos_start = memchr(body, '!', body_end - body);
+	if ((pos_start) && pos_start - body <= 39) {
+		poschar = *pos_start;
+		if (valid_sym_table_compressed(poschar)) { /* [\/\\A-Za-j] */
+		    	/* compressed position packet */
+			int rc = 0;
+		    	if (body_end - pos_start >= 13)
+			  rc = parse_aprs_compressed(pb, pos_start, body_end);
+			DEBUG_LOG("\n");
+			return rc;
+		} else if (poschar >= 0x30 && poschar <= 0x39) { /* [0-9] */
+			/* normal uncompressed position */
+			int rc = 0;
+			if (body_end - pos_start >= 19)
+			  rc = parse_aprs_uncompressed(pb, pos_start, body_end);
+			DEBUG_LOG("\n");
+			return rc;
+		}
+	}
+	
+	return 0; // bad
+}
+
+/*
+ *      Parse an aprs text message (optional, only done to messages addressed to
+ *      SERVER
+ */
+
+int parse_aprs_message(const struct pbuf_t *pb, struct aprs_message_t * const am)
+{
+        const char *p;
+        
+        memset(am, 0, sizeof(*am));
+        
+        if (!(pb->packettype & T_MESSAGE))
+                return -1;
+                
+        if (pb->info_start[10] != ':')
+                return -2;
+        
+        am->body = pb->info_start + 11;
+        /* -2 for the CRLF already in place */
+        am->body_len = pb->packet_len - 2 - (pb->info_start - pb->data);
+        
+        /* search for { looking backwards from the end of the packet,
+         * it separates the msgid
+         */
+        p = am->body + am->body_len - 1;
+        while (p > am->body && *p != '{')
+                p--;
+        
+        if (*p == '{') {
+                am->msgid = p+1;
+                am->msgid_len = pb->packet_len - 2 - (am->msgid - pb->data);
+                am->body_len = p - am->body;
+        }
+        
+        /* check if this is an ACK */
+        if ((!am->msgid_len) && am->body_len > 3
+            && am->body[0] == 'a' && am->body[1] == 'c' && am->body[2] == 'k') {
+                am->is_ack = 1;
+                am->msgid = am->body + 3;
+                am->msgid_len = am->body_len - 3;
+                am->body_len = 0;
+                return 0;
+        }
+
+        /* check if this is an REJ */
+        if ((!am->msgid_len) && am->body_len > 3
+            && am->body[0] == 'r' && am->body[1] == 'e' && am->body[2] == 'j') {
+                am->is_rej = 1;
+                am->msgid = am->body + 3;
+                am->msgid_len = am->body_len - 3;
+                am->body_len = 0;
+                return 0;
+        }
+        
+        return 0;
+}
diff --git a/pbuf.c b/pbuf.c
new file mode 100644
index 0000000..baee971
--- /dev/null
+++ b/pbuf.c
@@ -0,0 +1,237 @@
+/* **************************************************************** *
+ *                                                                  *
+ *  APRX -- 2nd generation receive-only APRS-i-gate with            *
+ *          minimal requirement of esoteric facilities or           *
+ *          libraries of any kind beyond UNIX system libc.          *
+ *                                                                  *
+ * (c) Matti Aarnio - OH2MQK,  2007-2014                            *
+ *                                                                  *
+ * **************************************************************** */
+
+#define _SVID_SOURCE 1
+
+#include "aprx.h"
+
+/*
+ * - Allocate pbuf
+ * - Free pbuf
+ * - Handle refcount  (get/put)
+ */
+
+#ifndef _FOR_VALGRIND_
+static cellarena_t *pbuf_cells;
+#endif
+
+// int pbuf_size = sizeof(struct pbuf_t); // 152 bytes on i386
+// int pbuf_alignment = __alignof__(struct pbuf_t); // 8 on i386
+
+// 2150 byte pbuf takes in an AX.25 packet of about 1kB in size,
+// and in APRS use there never should be larger than about 512 bytes.
+// A 16 kB arena fits in 7 of these humongous pbufs.
+
+const int pbufcell_size  = sizeof(struct pbuf_t) + 2150;
+const int pbufcell_align = __alignof__(struct pbuf_t);
+
+void pbuf_init(void)
+{
+#ifndef _FOR_VALGRIND_
+	/* A _few_... */
+
+	pbuf_cells = cellinit( "filter",
+			       pbufcell_size,
+			       pbufcell_align,
+			       CELLMALLOC_POLICY_LIFO,
+			       16, // 16 kB at the time
+			       0   // minfree
+			       );
+#endif
+}
+
+static void pbuf_free(struct pbuf_t *pb)
+{
+#ifndef _FOR_VALGRIND_
+	cellfree(pbuf_cells, pb);
+#else
+	free(pb);
+#endif
+	if (debug > 1) printf("pbuf_free(%p)\n",pb);
+}
+
+static struct pbuf_t *pbuf_alloc( const int axlen,
+                                  const int tnc2len )
+{
+	int pblen = sizeof(struct pbuf_t) + axlen + tnc2len + 2;
+
+#ifndef _FOR_VALGRIND_
+	// Picks suitably sized pbuf, and pre-cleans it
+	// before passing to user
+
+	struct pbuf_t *pb;
+	if (pblen > 2150) {
+	  // Outch!
+	  return NULL;
+	}
+	pb = cellmalloc(pbuf_cells);
+	memset(pb, 0, pblen );
+#else
+	// No size limits with valgrind..
+	struct pbuf_t *pb = calloc( 1, pblen );
+#endif
+
+	if (debug > 1) printf("pbuf_alloc(%d,%d) -> %p\n",axlen,tnc2len,pb);
+
+	pb->packet_len = tnc2len;
+	pb->buf_len    = tnc2len;
+	pb->data[tnc2len] = 0;
+        pb->ax25addr = (uint8_t*)pb->data + tnc2len + 1;
+
+
+	return pb;
+}
+
+struct pbuf_t *pbuf_get( struct pbuf_t *pb )
+{
+	// Increments refcount
+	pb->refcount += 1;
+	return pb;
+}
+
+void pbuf_put( struct pbuf_t *pb )
+{
+	// Decrements refcount, if 0 -> free()!
+	pb->refcount -= 1;
+	if (pb->refcount == 0)
+		pbuf_free(pb);
+}
+
+
+static struct pbuf_t *_pbuf_new(const int is_aprs, const int digi_like_aprs, const int axlen, const int tnc2len);
+static struct pbuf_t *_pbuf_new(const int is_aprs, const int digi_like_aprs, const int axlen, const int tnc2len)
+{
+	struct pbuf_t *pb = pbuf_alloc( axlen, tnc2len );
+	if (pb == NULL) return NULL;
+
+	pbuf_get(pb);
+
+	pb->is_aprs        = is_aprs;
+	pb->digi_like_aprs = digi_like_aprs;
+	pb->t              = tick.tv_sec;      // Arrival time
+
+	return pb;
+}
+
+
+// Do the pbuf filling in single location, processes the TNC2 header data
+struct pbuf_t * pbuf_new( const int is_aprs, const int digi_like_aprs,
+                          const int tnc2addrlen, const char *tnc2buf, const int tnc2len,
+                          const int ax25addrlen, const void *ax25buf, const int ax25len )
+{
+	char *p;
+
+	char *src_end; /* pointer to the > after srccall */
+	char *path_start; /* pointer to the start of the path */
+	const char *path_end; /* pointer to the : after the path */
+	const char *packet_end; /* pointer to the end of the packet */
+	const char *info_start; /* pointer to the beginning of the info */
+	const char *info_end; /* end of the info */
+	char *dstcall_end_or_ssid; /* end of dstcall, before SSID ([-:,]) */
+	char *dstcall_end; /* end of dstcall including SSID ([:,]) */
+	char *via_start; /* start of the digipeater path (after dstcall,) */
+	// const char *data;	  /* points to original incoming path/payload separating ':' character */
+	// int datalen;		  /* length of the data block excluding tail \r\n */
+	int pathlen;		  /* length of the path  ==  data-s  */
+        struct pbuf_t *pb;
+
+	/* a packet looks like:
+	 * SRCCALL>DSTCALL,PATH,PATH:INFO\r\n
+	 * (we have normalized the \r\n by now)
+         *
+         * The tnc2addrlen is index of the first ':'.
+	 */
+
+        path_end = tnc2buf + tnc2addrlen;
+        pathlen  = tnc2addrlen;
+	// data     = path_end;            // Begins with ":"
+	// datalen  = tnc2len - pathlen;   // Not including line end \r\n
+
+	packet_end = tnc2buf + tnc2len; // Just to compare against far end..
+
+	/* look for the '>' */
+	src_end = memchr(tnc2buf, '>', pathlen < CALLSIGNLEN_MAX+1 ? pathlen : CALLSIGNLEN_MAX+1);
+	if (!src_end) {
+		return NULL;	// No ">" in packet start..
+        }
+	
+	path_start = src_end+1;
+	if (path_start >= packet_end) {	// We're already at the path end
+		return NULL;
+        }
+	
+	if (src_end - tnc2buf > CALLSIGNLEN_MAX || src_end - tnc2buf < CALLSIGNLEN_MIN) {
+		return NULL; /* too long source callsign */
+        }
+	
+	info_start = path_end+1;	// @":"+1 - first char of the payload
+	if (info_start >= packet_end) {
+		return NULL;
+        }
+	
+	/* see that there is at least some data in the packet */
+	info_end = packet_end;
+	if (info_end <= info_start) {
+		return NULL;
+        }
+	
+	/* look up end of dstcall (excluding SSID - this is the way dupecheck and
+	 * mic-e parser wants it)
+	 */
+
+	dstcall_end = path_start;
+	while (dstcall_end < path_end && *dstcall_end != '-' && *dstcall_end != ',' && *dstcall_end != ':')
+		dstcall_end++;
+	dstcall_end_or_ssid = dstcall_end; // OK, SSID is here (or the dstcall end), go for the real end
+	while (dstcall_end < path_end && *dstcall_end != ',' && *dstcall_end != ':')
+		dstcall_end++;
+	
+	if (dstcall_end - path_start > CALLSIGNLEN_MAX) {
+		return NULL; /* too long for destination callsign */
+        }
+	
+	/* where does the digipeater path start? */
+	via_start = dstcall_end;
+	while (via_start < path_end && (*via_start != ',' && *via_start != ':')) {
+		via_start++;
+        }
+	
+        pb = _pbuf_new( is_aprs, digi_like_aprs, ax25len, tnc2len );
+	if (!pb) {
+          // This should never happen...
+          return NULL;
+	}
+	
+        // copy TNC2 data to its area
+        p = pb->data;
+        memcpy(p, tnc2buf, tnc2len);
+        p += tnc2len;
+
+        // Copy AX.25 data to its area..
+	memcpy(pb->ax25addr, ax25buf, ax25len);
+	pb->ax25addrlen = ax25addrlen;
+	pb->ax25data    = pb->ax25addr + ax25addrlen;
+	pb->ax25datalen = ax25len - ax25addrlen;
+	
+	// How much there really is data?
+	pb->packet_len = tnc2len;
+	
+	packet_end = p; /* for easier overflow checking expressions */
+	/* fill necessary info for parsing and dupe checking in the packet buffer */
+	pb->srcname = pb->data;
+	pb->srcname_len = src_end - tnc2buf;
+	pb->srccall_end = pb->data + (src_end - tnc2buf); // "srccall>.." <-- @'>'
+	pb->dstcall_end_or_ssid = pb->data + (dstcall_end_or_ssid - tnc2buf);
+	pb->dstcall_end = pb->data + (dstcall_end - tnc2buf);
+	pb->dstcall_len = via_start - src_end - 1;
+	pb->info_start  = pb->data + tnc2addrlen + 1;
+
+        return pb;
+}
diff --git a/pbuf.h b/pbuf.h
new file mode 100644
index 0000000..d386910
--- /dev/null
+++ b/pbuf.h
@@ -0,0 +1,125 @@
+/*
+ *	aprsc
+ *
+ *	(c) Heikki Hannikainen, OH7LZB <hessu at hes.iki.fi>
+ *
+ *     This program is licensed under the BSD license, which can be found
+ *     in the file LICENSE.
+ *	
+ */
+
+/* Modified for  APRX by Matti Aarnio, OH2MQK
+ * Altered name from  worker.h  to pbuf.h, and
+ * dropped about 70% of worker.h stuff...
+ */
+
+#ifndef PBUF_H
+#define PBUF_H
+
+/* minimum and maximum length of a callsign on APRS-IS */
+#define CALLSIGNLEN_MIN 3
+#define CALLSIGNLEN_MAX 9
+
+/* packet length limiters and buffer sizes */
+#define PACKETLEN_MIN 10	/* minimum length for a valid APRS-IS packet: "A1A>B1B:\r\n" */
+#define PACKETLEN_MAX 512	/* maximum length for a valid APRS-IS packet (incl. CRLF) */
+
+/*
+ *  Packet length statistics:
+ *
+ *   <=  80:  about  25%
+ *   <=  90:  about  36%
+ *   <= 100:  about  73%
+ *   <= 110:  about  89%
+ *   <= 120:  about  94%
+ *   <= 130:  about  97%
+ *   <= 140:  about  98.7%
+ *   <= 150:  about  99.4%
+ */
+
+#define PACKETLEN_MAX_SMALL  100 
+#define PACKETLEN_MAX_MEDIUM 180 /* about 99.5% are smaller than this */
+#define PACKETLEN_MAX_LARGE  PACKETLEN_MAX
+
+/* number of pbuf_t structures to allocate at a time */
+#define PBUF_ALLOCATE_BUNCH_SMALL  2000 /* grow to 2000 in production use */
+#define PBUF_ALLOCATE_BUNCH_MEDIUM 2000 /* grow to 2000 in production use */
+#define PBUF_ALLOCATE_BUNCH_LARGE    50 /* grow to 50 in production use */
+
+/* a packet buffer */
+/* Type flags -- some can happen in combinations: T_CWOP + T_WX / T_CWOP + T_POSITION ... */
+#define T_POSITION   (1 << 0) // Packet is of position type
+#define T_OBJECT     (1 << 1) // packet is an object
+#define T_ITEM       (1 << 2) // packet is an item
+#define T_MESSAGE    (1 << 3) // packet is a message
+#define T_NWS        (1 << 4) // packet is a NWS message
+#define T_WX         (1 << 5) // packet is WX data
+#define T_TELEMETRY  (1 << 6) // packet is telemetry
+#define T_QUERY      (1 << 7) // packet is a query
+#define T_STATUS     (1 << 8) // packet is status 
+#define T_USERDEF    (1 << 9) // packet is userdefined
+#define T_CWOP       (1 << 10) // packet is recognized as CWOP
+#define T_STATCAPA   (1 << 11) // packet is station capability response
+#define T_THIRDPARTY (1 << 12)
+#define T_ALL	     (1 << 15) // set on _all_ packets
+
+#define F_DUPE    	(1 << 0) // Duplicate of a previously seen packet
+#define F_HASPOS  	(1 << 1) // This packet has valid parsed position
+#define F_HAS_TCPIP	(1 << 2) // There is a TCPIP* in the path
+
+struct pbuf_t {
+	struct pbuf_t *next;
+
+	int16_t	 is_aprs;	// If not, then just digipeated frame..
+	int16_t	 digi_like_aprs;
+	int16_t  source_if_group;
+
+	int16_t  refcount;
+
+	int16_t	 reqcount;      // How many digipeat hops are requested?
+	int16_t	 donecount;	// How many digipeat hops are already done?
+
+	time_t   t;		/* when the packet was received */
+	uint32_t seqnum;	/* ever increasing counter, dupecheck sets */
+	uint16_t packettype;	/* bitmask: one or more of T_* */
+	uint16_t flags;		/* bitmask: one or more of F_* */
+	uint16_t srcname_len;	/* parsed length of source (object, item, srcall) name 3..9 */
+	uint16_t dstcall_len;	/* parsed length of destination callsign *including* SSID */
+	uint16_t dstname_len;   /* parsed length of message destination including SSID */
+	uint16_t entrycall_len;
+	
+	int packet_len;		/* the actual length of the TNC2 packet */
+	int buf_len;		/* the length of this buffer */
+	
+	const char *srccall_end;   /* source callsign with SSID */
+	const char *dstcall_end_or_ssid;   /* end of dest callsign (without SSID) */
+	const char *dstcall_end;   /* end of dest callsign with SSID */
+	const char *qconst_start;  /* "qAX,incomingSSID:"	-- for q and e filters  */
+	const char *info_start;    /* pointer to start of info field */
+	const char *srcname;       /* source's name (either srccall or object/item name) */
+	const char *dstname;       /* message destination callsign */
+	
+	float lat;	/* if the packet is PT_POSITION, latitude and longitude go here */
+	float lng;	/* .. in RADIAN */
+	float cos_lat;	/* cache of COS of LATitude for radial distance filter    */
+
+	char symbol[3]; /* 2(+1) chars of symbol, if any, NUL for not found */
+
+	uint8_t *ax25addr;	// Start of AX.25 address
+	int      ax25addrlen;	// length of AX.25 address
+
+	uint8_t *ax25data;	// Start of AX.25 data after addresses
+	int      ax25datalen;	// length of that data
+
+	char data[1];
+};
+
+/* global packet buffer */
+extern struct pbuf_t  *pbuf_global;
+extern struct pbuf_t  *pbuf_global_last;
+extern struct pbuf_t **pbuf_global_prevp;
+extern struct pbuf_t  *pbuf_global_dupe;
+extern struct pbuf_t  *pbuf_global_dupe_last;
+extern struct pbuf_t **pbuf_global_dupe_prevp;
+
+#endif
diff --git a/rpm/aprx.default b/rpm/aprx.default
new file mode 100644
index 0000000..8fe2c08
--- /dev/null
+++ b/rpm/aprx.default
@@ -0,0 +1,10 @@
+#
+# STARTAPRX: start aprx on boot. Should be set to "yes" once you have
+#            configured aprx.
+#
+STARTAPRX="no"
+
+#
+# Additional options that are passed to the Daemon.
+#
+DAEMON_OPTS=""
diff --git a/rpm/aprx.init b/rpm/aprx.init
new file mode 100755
index 0000000..4ac316c
--- /dev/null
+++ b/rpm/aprx.init
@@ -0,0 +1,84 @@
+#!/bin/bash
+#
+# chkconfig: - 16 84
+# description: Start up a receive only APRS igate
+# processname: aprx
+# config: /etc/sysconfig/aprx
+
+### BEGIN INIT INFO  -- debian style:
+# Provides: aprx
+# Required-Start: $syslog $local_fs
+# Required-Stop:  $syslog $local_fs
+# Default-Stop:   0 1 6
+# Short-Description: start and stop aprx
+# Description: Monitor and gateway radio amateur APRS radio network datagrams
+### END INIT INFO
+
+# source function library
+. /etc/rc.d/init.d/functions
+
+# Check that networking is up.
+[ "${NETWORKING}" = "no" ] && exit 0
+
+# defaults
+
+PATH=/sbin:/bin:/usr/sbin:/usr/bin
+DAEMON=/usr/sbin/aprx
+NAME=aprx
+DESC="aprx igate"
+
+# source the config, if it exists
+if [ -f /etc/sysconfig/aprx ] ; then
+   . /etc/sysconfig/aprx
+fi
+
+test -x $DAEMON || exit 0
+
+if [ "$STARTAPRX" != "yes" ];then
+	echo "Starting of $NAME not enabled in /etc/sysconfig/$NAME."
+	exit 0
+fi
+
+set -e
+
+
+case "$1" in
+  start)
+	echo -n $"Starting aprx server: "
+	$DAEMON
+	disown -ar
+	usleep 500000
+	status $NAME &> /dev/null && echo_success || echo_failure
+	RETVAL=$?
+	[ $RETVAL -eq 0 ] && touch /var/lock/subsys/$NAME
+	echo
+	;;
+  stop)
+	echo -n $"Shutting down aprx server: "
+	killproc $DAEMON
+	RETVAL=$?
+	[ $RETVAL -eq 0 ] && rm -f /var/lock/subsys/$NAME
+	echo_success
+	;;
+  restart|reload)
+        $0 stop
+        $0 start
+	RETVAL=$?
+        ;;
+  condrestart)
+        if [ -f /var/lock/subsys/$NAME ]; then
+                $0 stop
+		$0 start
+        fi
+	RETVAL=$?
+        ;;
+  status)
+        status $NAME
+	RETVAL=$?
+        ;;
+  *)
+	echo $"Usage: $0 {start|stop|restart|reload|condrestart|status}"
+	exit 1
+esac
+
+exit $RETVAL
diff --git a/rpm/aprx.service b/rpm/aprx.service
new file mode 100644
index 0000000..dee7b9b
--- /dev/null
+++ b/rpm/aprx.service
@@ -0,0 +1,11 @@
+[Unit]
+Description=Amateur Radio APRS Gateway & Digipeater
+Documentation=man:aprx(8)
+
+[Service]
+Type=simple
+ExecStart=/usr/sbin/aprx
+# doesn't do any internal reload
+
+[Install]
+WantedBy=multi-user.target
diff --git a/ssl.c b/ssl.c
new file mode 100644
index 0000000..3fa2eaa
--- /dev/null
+++ b/ssl.c
@@ -0,0 +1,920 @@
+
+/*
+ *	This OpenSSL interface code has been proudly copied from
+ *	the excellent NGINX web server.
+ *
+ *	Its license is reproduced here.
+ */
+
+/* 
+ * Copyright (C) 2002-2013 Igor Sysoev
+ * Copyright (C) 2011-2013 Nginx, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ *	OpenSSL thread-safe example code (ssl_thread_* functions) have been
+ *	proudly copied from the excellent CURL package, the original author
+ *	is Jeremy Brown.
+ *
+ *	https://github.com/bagder/curl/blob/master/docs/examples/opensslthreadlock.c
+ *
+ * COPYRIGHT AND PERMISSION NOTICE
+ * Copyright (c) 1996 - 2013, Daniel Stenberg, <daniel at haxx.se>.
+ *
+ * All rights reserved.
+ * 
+ * Permission to use, copy, modify, and distribute this software for any purpose
+ * with or without fee is hereby granted, provided that the above copyright
+ * notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. IN
+ * NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
+ * OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Except as contained in this notice, the name of a copyright holder shall not
+ * be used in advertising or otherwise to promote the sale, use or other dealings
+ * in this Software without prior written authorization of the copyright holder.
+ *	
+ */
+
+#include "config.h"
+#include "ssl.h"
+#include "hlog.h"
+#include "hmalloc.h"
+#include "worker.h"
+
+#ifdef USE_SSL
+
+#include <ctype.h>
+#include <pthread.h>
+#include <openssl/conf.h>
+#include <openssl/ssl.h>
+#include <openssl/err.h>
+
+#define SSL_DEFAULT_CIPHERS     "HIGH:!aNULL:!MD5"
+#define SSL_PROTOCOLS (NGX_SSL_SSLv3|NGX_SSL_TLSv1 |NGX_SSL_TLSv1_1|NGX_SSL_TLSv1_2)
+
+/* ssl error strings */
+#define SSL_ERR_LABELS_COUNT 6
+static const char *ssl_err_labels[][2] = {
+	{ "invalid_err", "Invalid, unknown error" },
+	{ "internal_err", "Internal error" },
+	{ "peer_cert_unverified", "Peer certificate is not valid or not trusted" },
+	{ "no_peer_cert", "Peer did not present a certificate" },
+	{ "cert_no_subj", "Certificate does not contain a Subject field" },
+	{ "cert_no_callsign", "Certificate does not contain a TQSL callsign in CN - not a ham cert" },
+	{ "cert_callsign_mismatch", "Certificate callsign does not match login username" }
+};
+
+/* pthread wrapping for openssl */
+#define MUTEX_TYPE       pthread_mutex_t
+#define MUTEX_SETUP(x)   pthread_mutex_init(&(x), NULL)
+#define MUTEX_CLEANUP(x) pthread_mutex_destroy(&(x))
+#define MUTEX_LOCK(x)    pthread_mutex_lock(&(x))
+#define MUTEX_UNLOCK(x)  pthread_mutex_unlock(&(x))
+#define THREAD_ID        pthread_self(  )
+
+int  ssl_available;
+int  ssl_connection_index;
+int  ssl_server_conf_index;
+int  ssl_session_cache_index;
+
+/* This array will store all of the mutexes available to OpenSSL. */
+static MUTEX_TYPE *mutex_buf= NULL;
+
+static void ssl_thread_locking_function(int mode, int n, const char * file, int line)
+{
+	if (mode & CRYPTO_LOCK)
+		MUTEX_LOCK(mutex_buf[n]);
+	else
+		MUTEX_UNLOCK(mutex_buf[n]);
+}
+
+static unsigned long ssl_thread_id_function(void)
+{
+	return ((unsigned long)THREAD_ID);
+}
+
+static int ssl_thread_setup(void)
+{
+	int i;
+	
+	hlog(LOG_DEBUG, "Creating OpenSSL mutexes (%d)...", CRYPTO_num_locks());
+	
+	mutex_buf = hmalloc(CRYPTO_num_locks() * sizeof(MUTEX_TYPE));
+	
+	for (i = 0;  i < CRYPTO_num_locks();  i++)
+		MUTEX_SETUP(mutex_buf[i]);
+	
+	CRYPTO_set_id_callback(ssl_thread_id_function);
+	CRYPTO_set_locking_callback(ssl_thread_locking_function);
+	
+	return 0;
+}
+
+static int ssl_thread_cleanup(void)
+{
+	int i;
+	
+	if (!mutex_buf)
+		return 0;
+	
+	CRYPTO_set_id_callback(NULL);
+	CRYPTO_set_locking_callback(NULL);
+	
+	for (i = 0;  i < CRYPTO_num_locks(  );  i++)
+		MUTEX_CLEANUP(mutex_buf[i]);
+		
+	hfree(mutex_buf);
+	mutex_buf = NULL;
+	
+	return 0;
+}
+
+/*
+ *	string representations for error codes
+ */
+
+const char *ssl_strerror(int code)
+{
+	code *= -1;
+	
+	if (code >= 0 && code < (sizeof ssl_err_labels / sizeof ssl_err_labels[0]))
+		return ssl_err_labels[code][1];
+		
+	return ssl_err_labels[0][1];
+}
+
+/*
+ *	Clear OpenSSL error queue
+ */
+
+static void ssl_error(int level, const char *msg)
+{
+	unsigned long n;
+	char errstr[512];
+	
+	for ( ;; ) {
+		n = ERR_get_error();
+		
+		if (n == 0)
+			break;
+		
+		ERR_error_string_n(n, errstr, sizeof(errstr));
+		errstr[sizeof(errstr)-1] = 0;
+		
+		hlog(level, "%s (%d): %s", msg, n, errstr);
+	}
+}
+
+static void ssl_clear_error(void)
+{
+	while (ERR_peek_error()) {
+		ssl_error(LOG_INFO, "Ignoring stale SSL error");
+	}
+	
+	ERR_clear_error();
+}
+
+/*
+ *	TrustedQSL custom X.509 certificate objects
+ */
+
+#define TRUSTEDQSL_OID				"1.3.6.1.4.1.12348.1."
+#define TRUSTEDQSL_OID_CALLSIGN			TRUSTEDQSL_OID "1"
+#define TRUSTEDQSL_OID_QSO_NOT_BEFORE		TRUSTEDQSL_OID "2"
+#define TRUSTEDQSL_OID_QSO_NOT_AFTER		TRUSTEDQSL_OID "3"
+#define TRUSTEDQSL_OID_DXCC_ENTITY		TRUSTEDQSL_OID "4"
+#define TRUSTEDQSL_OID_SUPERCEDED_CERT		TRUSTEDQSL_OID "5"
+#define TRUSTEDQSL_OID_CRQ_ISSUER_ORGANIZATION	TRUSTEDQSL_OID "6"
+#define TRUSTEDQSL_OID_CRQ_ISSUER_ORGANIZATIONAL_UNIT TRUSTEDQSL_OID "7"
+
+static const char *tqsl_NIDs[][2] = {
+	{ TRUSTEDQSL_OID_CALLSIGN, "AROcallsign" },
+	{ TRUSTEDQSL_OID_QSO_NOT_BEFORE, "QSONotBeforeDate" },
+	{ TRUSTEDQSL_OID_QSO_NOT_AFTER, "QSONotAfterDate" },
+	{ TRUSTEDQSL_OID_DXCC_ENTITY, "dxccEntity" },
+	{ TRUSTEDQSL_OID_SUPERCEDED_CERT, "supercededCertificate" },
+	{ TRUSTEDQSL_OID_CRQ_ISSUER_ORGANIZATION, "tqslCRQIssuerOrganization" },
+	{ TRUSTEDQSL_OID_CRQ_ISSUER_ORGANIZATIONAL_UNIT, "tqslCRQIssuerOrganizationalUnit" },
+};
+
+static int load_tqsl_custom_objects(void)
+{
+	int i;
+	
+	for (i = 0; i < (sizeof tqsl_NIDs / sizeof tqsl_NIDs[0]); ++i)
+		if (OBJ_create(tqsl_NIDs[i][0], tqsl_NIDs[i][1], NULL) == 0)
+			return -1;
+	
+	return 0;
+}
+
+static void ssl_info_callback(SSL *ssl, int where, int ret)
+{
+	struct client_t *c = SSL_get_ex_data(ssl, ssl_connection_index);
+	
+	if (!c) {
+		hlog(LOG_ERR, "ssl_info_callback: no application data for connection");
+		return;
+	}
+	
+	struct ssl_connection_t *ssl_conn = c->ssl_con;
+	
+	if (!ssl_conn) {
+		hlog(LOG_ERR, "ssl_info_callback: no ssl_conn for connection");
+		return;
+	}
+	
+	if (where & SSL_CB_HANDSHAKE_START) {
+		hlog(LOG_INFO, "%s/%d: SSL handshake start", c->addr_rem, c->fd);
+		if (ssl_conn->handshaked) {
+			ssl_conn->renegotiation = 1;
+		}
+	}
+	
+	if (where & SSL_CB_HANDSHAKE_DONE) {
+		hlog(LOG_INFO, "%s/%d: SSL handshake done", c->addr_rem, c->fd);
+	}
+}
+
+/*
+ *	Initialize SSL
+ */
+
+int ssl_init(void)
+{
+	hlog(LOG_INFO, "Initializing OpenSSL, built against %s ...", OPENSSL_VERSION_TEXT);
+	
+	OPENSSL_config(NULL);
+	
+	SSL_library_init();
+	SSL_load_error_strings();
+	
+	ssl_thread_setup();
+	
+	OpenSSL_add_all_algorithms();
+	
+	load_tqsl_custom_objects();
+	
+#if OPENSSL_VERSION_NUMBER >= 0x0090800fL
+#ifndef SSL_OP_NO_COMPRESSION
+	{
+	/*
+	 * Disable gzip compression in OpenSSL prior to 1.0.0 version,
+	 * this saves about 522K per connection.
+	 */
+	int                  n;
+	STACK_OF(SSL_COMP)  *ssl_comp_methods;
+	
+	ssl_comp_methods = SSL_COMP_get_compression_methods();
+	n = sk_SSL_COMP_num(ssl_comp_methods);
+	
+	while (n--) {
+		(void) sk_SSL_COMP_pop(ssl_comp_methods);
+	}
+	
+	}
+#endif
+#endif
+
+	ssl_connection_index = SSL_get_ex_new_index(0, NULL, NULL, NULL, NULL);
+	
+	if (ssl_connection_index == -1) {
+		ssl_error(LOG_ERR, "SSL_get_ex_new_index for connection");
+		return -1;
+	}
+	
+	ssl_server_conf_index = SSL_CTX_get_ex_new_index(0, NULL, NULL, NULL, NULL);
+	
+	if (ssl_server_conf_index == -1) {
+		ssl_error(LOG_ERR, "SSL_CTX_get_ex_new_index for conf");
+		return -1;
+	}
+	
+	ssl_session_cache_index = SSL_CTX_get_ex_new_index(0, NULL, NULL, NULL, NULL);
+	
+	if (ssl_session_cache_index == -1) {
+		ssl_error(LOG_ERR, "SSL_CTX_get_ex_new_index for session cache");
+		return -1;
+	}
+	
+	ssl_available = 1;
+	
+	return 0;
+}
+
+void ssl_atend(void)
+{
+	ssl_thread_cleanup();
+}
+
+struct ssl_t *ssl_alloc(void)
+{
+	struct ssl_t *ssl;
+	
+	ssl = hmalloc(sizeof(*ssl));
+	memset(ssl, 0, sizeof(*ssl));
+	
+	return ssl;
+}
+
+void ssl_free(struct ssl_t *ssl)
+{
+	if (ssl->ctx)
+	    SSL_CTX_free(ssl->ctx);
+	    
+	hfree(ssl);
+}
+
+int ssl_create(struct ssl_t *ssl, void *data)
+{
+	ssl->ctx = SSL_CTX_new(SSLv23_method());
+	
+	if (ssl->ctx == NULL) {
+		ssl_error(LOG_ERR, "ssl_create SSL_CTX_new failed");
+		return -1;
+	}
+	
+	if (SSL_CTX_set_ex_data(ssl->ctx, ssl_server_conf_index, data) == 0) {
+		ssl_error(LOG_ERR, "ssl_create SSL_CTX_set_ex_data failed");
+		return -1;
+	}
+	
+	/* client side options */
+	
+	SSL_CTX_set_options(ssl->ctx, SSL_OP_MICROSOFT_SESS_ID_BUG);
+	SSL_CTX_set_options(ssl->ctx, SSL_OP_NETSCAPE_CHALLENGE_BUG);
+	
+	/* server side options */
+	
+	SSL_CTX_set_options(ssl->ctx, SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG);
+	SSL_CTX_set_options(ssl->ctx, SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER);
+	
+	/* this option allow a potential SSL 2.0 rollback (CAN-2005-2969) */
+	SSL_CTX_set_options(ssl->ctx, SSL_OP_MSIE_SSLV2_RSA_PADDING);
+	
+	SSL_CTX_set_options(ssl->ctx, SSL_OP_SSLEAY_080_CLIENT_DH_BUG);
+	SSL_CTX_set_options(ssl->ctx, SSL_OP_TLS_D5_BUG);
+	SSL_CTX_set_options(ssl->ctx, SSL_OP_TLS_BLOCK_PADDING_BUG);
+	
+	SSL_CTX_set_options(ssl->ctx, SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS);
+	
+	SSL_CTX_set_options(ssl->ctx, SSL_OP_SINGLE_DH_USE);
+	
+	/* SSL protocols not configurable for now */
+	int protocols = SSL_PROTOCOLS;
+	
+	if (!(protocols & NGX_SSL_SSLv2)) {
+		SSL_CTX_set_options(ssl->ctx, SSL_OP_NO_SSLv2);
+	}
+	if (!(protocols & NGX_SSL_SSLv3)) {
+		SSL_CTX_set_options(ssl->ctx, SSL_OP_NO_SSLv3);
+	}
+	if (!(protocols & NGX_SSL_TLSv1)) {
+		SSL_CTX_set_options(ssl->ctx, SSL_OP_NO_TLSv1);
+	}
+	
+#ifdef SSL_OP_NO_TLSv1_1
+	if (!(protocols & NGX_SSL_TLSv1_1)) {
+		SSL_CTX_set_options(ssl->ctx, SSL_OP_NO_TLSv1_1);
+	}
+#endif
+#ifdef SSL_OP_NO_TLSv1_2
+	if (!(protocols & NGX_SSL_TLSv1_2)) {
+		SSL_CTX_set_options(ssl->ctx, SSL_OP_NO_TLSv1_2);
+	}
+#endif
+
+#ifdef SSL_OP_NO_COMPRESSION
+	SSL_CTX_set_options(ssl->ctx, SSL_OP_NO_COMPRESSION);
+#endif
+
+#ifdef SSL_MODE_RELEASE_BUFFERS
+	SSL_CTX_set_mode(ssl->ctx, SSL_MODE_RELEASE_BUFFERS);
+#endif
+
+	SSL_CTX_set_mode(ssl->ctx, SSL_MODE_ENABLE_PARTIAL_WRITE);
+	
+	SSL_CTX_set_read_ahead(ssl->ctx, 1);
+	
+	SSL_CTX_set_info_callback(ssl->ctx, (void *)ssl_info_callback);
+	
+	if (SSL_CTX_set_cipher_list(ssl->ctx, SSL_DEFAULT_CIPHERS) == 0) {
+		ssl_error(LOG_ERR, "ssl_create SSL_CTX_set_cipher_list failed");
+		return -1;
+	}
+	
+	/* prefer server-selected ciphers */
+	SSL_CTX_set_options(ssl->ctx, SSL_OP_CIPHER_SERVER_PREFERENCE);
+	
+	return 0;
+}
+
+/*
+ *	Load server key and certificate
+ */
+
+int ssl_certificate(struct ssl_t *ssl, const char *certfile, const char *keyfile)
+{
+	if (SSL_CTX_use_certificate_chain_file(ssl->ctx, certfile) == 0) {
+		hlog(LOG_ERR, "Error while loading SSL certificate chain file \"%s\"", certfile);
+		ssl_error(LOG_ERR, "SSL_CTX_use_certificate_chain_file");
+		return -1;
+	}
+	
+	
+	if (SSL_CTX_use_PrivateKey_file(ssl->ctx, keyfile, SSL_FILETYPE_PEM) == 0) {
+		hlog(LOG_ERR, "Error while loading SSL private key file \"%s\"", keyfile);
+		ssl_error(LOG_ERR, "SSL_CTX_use_PrivateKey_file");
+		return -1;
+	}
+	
+	if (!SSL_CTX_check_private_key(ssl->ctx)) {
+		hlog(LOG_ERR, "SSL private key (%s) does not work with this certificate (%s)", keyfile, certfile);
+		ssl_error(LOG_ERR, "SSL_CTX_check_private_key");
+		return -1;
+	}
+	
+	
+	return 0;
+}
+
+static int ssl_verify_callback(int ok, X509_STORE_CTX *x509_store)
+{
+	hlog(LOG_DEBUG, "ssl_verify_callback, ok: %d", ok);
+	
+#if (NGX_DEBUG)
+    char              *subject, *issuer;
+    int                err, depth;
+    X509              *cert;
+    X509_NAME         *sname, *iname;
+    ngx_connection_t  *c;
+    ngx_ssl_conn_t    *ssl_conn;
+
+    ssl_conn = X509_STORE_CTX_get_ex_data(x509_store,
+                                          SSL_get_ex_data_X509_STORE_CTX_idx());
+
+    c = ngx_ssl_get_connection(ssl_conn);
+
+    cert = X509_STORE_CTX_get_current_cert(x509_store);
+    err = X509_STORE_CTX_get_error(x509_store);
+    depth = X509_STORE_CTX_get_error_depth(x509_store);
+
+    sname = X509_get_subject_name(cert);
+    subject = sname ? X509_NAME_oneline(sname, NULL, 0) : "(none)";
+
+    iname = X509_get_issuer_name(cert);
+    issuer = iname ? X509_NAME_oneline(iname, NULL, 0) : "(none)";
+
+    ngx_log_debug5(NGX_LOG_DEBUG_EVENT, c->log, 0,
+                   "verify:%d, error:%d, depth:%d, "
+                   "subject:\"%s\",issuer: \"%s\"",
+                   ok, err, depth, subject, issuer);
+
+    if (sname) {
+        OPENSSL_free(subject);
+    }
+
+    if (iname) {
+        OPENSSL_free(issuer);
+    }
+#endif
+
+    return 1;
+}
+
+
+/*
+ *	Load trusted CA certs for verifying our peers
+ */
+
+int ssl_ca_certificate(struct ssl_t *ssl, const char *cafile, int depth)
+{
+	STACK_OF(X509_NAME)  *list;
+	
+	SSL_CTX_set_verify(ssl->ctx, SSL_VERIFY_PEER, ssl_verify_callback);
+	SSL_CTX_set_verify_depth(ssl->ctx, depth);
+	
+	if (SSL_CTX_load_verify_locations(ssl->ctx, cafile, NULL) == 0) {
+		hlog(LOG_ERR, "Failed to load trusted CA list from \"%s\"", cafile);
+		ssl_error(LOG_ERR, "SSL_CTX_load_verify_locations");
+		return -1;
+	}
+	
+	list = SSL_load_client_CA_file(cafile);
+	
+	if (list == NULL) {
+		hlog(LOG_ERR, "Failed to load client CA file from \"%s\"", cafile);
+		ssl_error(LOG_ERR, "SSL_load_client_CA_file");
+		return -1;
+	}
+	
+	/*
+	 * before 0.9.7h and 0.9.8 SSL_load_client_CA_file()
+	 * always leaved an error in the error queue
+	 */
+	
+	ERR_clear_error();
+	
+	SSL_CTX_set_client_CA_list(ssl->ctx, list);
+	
+	ssl->validate = 1;
+	
+	return 0;
+}
+
+/*
+ *	Create a connect
+ */
+
+int ssl_create_connection(struct ssl_t *ssl, struct client_t *c, int i_am_client)
+{
+	struct ssl_connection_t  *sc;
+	
+	sc = hmalloc(sizeof(*sc));
+	sc->connection = SSL_new(ssl->ctx);
+	
+	if (sc->connection == NULL) {
+		ssl_error(LOG_ERR, "SSL_new failed");
+		hfree(sc);
+		return -1;
+	}
+	
+	if (SSL_set_fd(sc->connection, c->fd) == 0) {
+		ssl_error(LOG_ERR, "SSL_set_fd failed");
+		SSL_free(sc->connection);
+		hfree(sc);
+		return -1;
+	}
+	
+	if (i_am_client) {
+		SSL_set_connect_state(sc->connection);
+	} else {
+		SSL_set_accept_state(sc->connection);
+	}
+	
+	if (SSL_set_ex_data(sc->connection, ssl_connection_index, c) == 0) {
+		ssl_error(LOG_ERR, "SSL_set_ex_data failed");
+		SSL_free(sc->connection);
+		hfree(sc);
+		return -1;
+	}
+	
+	sc->validate = ssl->validate;
+	c->ssl_con = sc;
+	
+	return 0;
+}
+
+void ssl_free_connection(struct client_t *c)
+{
+	if (!c->ssl_con)
+		return;
+		
+	SSL_free(c->ssl_con->connection);
+	hfree(c->ssl_con);
+	c->ssl_con = NULL;
+}
+
+int ssl_cert_callsign_match(const char *subj_call, const char *username)
+{
+	if (subj_call == NULL || username == NULL)
+		return 0;
+	
+	while (*username != '-' && *username != 0 && *subj_call != 0) {
+		if (toupper(*username) != toupper(*subj_call))
+			return 0; /* mismatch */
+		
+		subj_call++;
+		username++;
+	}
+	
+	if (*subj_call != 0)
+		return 0; /* if username is shorter than subject callsign, we fail */
+	
+	if (*username != '-' && *username != 0)
+		return 0; /* if we ran to end of subject callsign but not to end of username or start of SSID, we fail */
+	
+	return 1;
+}
+
+
+/*
+ *	Validate client certificate
+ */
+
+int ssl_validate_peer_cert_phase1(struct client_t *c)
+{
+	X509 *cert;
+	
+	int rc = SSL_get_verify_result(c->ssl_con->connection);
+	
+	if (rc != X509_V_OK) {
+		/* client gave a certificate, but it's not valid */
+		hlog(LOG_DEBUG, "%s/%s: Peer SSL certificate verification error %d: %s",
+			c->addr_rem, c->username, rc, X509_verify_cert_error_string(rc));
+		c->ssl_con->ssl_err_code = rc;
+		return SSL_VALIDATE_CLIENT_CERT_UNVERIFIED;
+	}
+	
+	cert = SSL_get_peer_certificate(c->ssl_con->connection);
+	
+	if (cert == NULL) {
+		/* client did not give a certificate */
+		return SSL_VALIDATE_NO_CLIENT_CERT;
+	}
+	
+	X509_free(cert);
+	
+	return 0;
+}
+
+int ssl_validate_peer_cert_phase2(struct client_t *c)
+{
+	int ret = -1;
+	X509 *cert;
+	X509_NAME *sname, *iname;
+	char *subject, *issuer;
+	char *subj_cn = NULL;
+	char *subj_call = NULL;
+	int nid, idx;
+	X509_NAME_ENTRY *entry;
+	ASN1_STRING *edata;
+	
+	cert = SSL_get_peer_certificate(c->ssl_con->connection);
+	
+	if (cert == NULL) {
+		/* client did not give a certificate */
+		return SSL_VALIDATE_NO_CLIENT_CERT;
+	}
+	
+	/* ok, we have a cert, find subject */
+	sname = X509_get_subject_name(cert);
+	if (!sname) {
+		ret = SSL_VALIDATE_CERT_NO_SUBJECT;
+		goto fail;
+	}
+	subject = X509_NAME_oneline(sname, NULL, 0);
+	
+	/* find tqsl callsign */
+	nid = OBJ_txt2nid("AROcallsign");
+	if (nid == NID_undef) {
+		hlog(LOG_ERR, "OBJ_txt2nid could not find NID for AROcallsign");
+		ret = SSL_VALIDATE_INTERNAL_ERROR;
+		goto fail;
+	}
+	
+	idx = X509_NAME_get_index_by_NID(sname, nid, -1);
+	if (idx == -1) {
+		hlog(LOG_DEBUG, "%s/%s: peer certificate has no callsign: %s", c->addr_rem, c->username, subject);
+		ret = SSL_VALIDATE_CERT_NO_CALLSIGN;
+		goto fail;
+	}
+	
+	entry = X509_NAME_get_entry(sname, idx);
+	if (entry != NULL) {
+		edata = X509_NAME_ENTRY_get_data(entry);
+		if (edata != NULL)
+			ASN1_STRING_to_UTF8((unsigned char **)&subj_call, edata);
+	}
+	
+	/* find CN of subject */
+	idx = X509_NAME_get_index_by_NID(sname, NID_commonName, -1);
+	if (idx == -1) {
+		hlog(LOG_DEBUG, "%s/%s: peer certificate has no CN: %s", c->addr_rem, c->username, subject);
+	} else {
+		entry = X509_NAME_get_entry(sname, idx);
+		if (entry != NULL) {
+			edata = X509_NAME_ENTRY_get_data(entry);
+			if (edata != NULL)
+				ASN1_STRING_to_UTF8((unsigned char **)&subj_cn, edata);
+		}
+	}
+	
+	if (!subj_call) {
+		hlog(LOG_DEBUG, "%s/%s: peer certificate callsign conversion failed: %s", c->addr_rem, c->username, subject);
+		ret = SSL_VALIDATE_CERT_NO_CALLSIGN;
+		goto fail;
+	}
+	
+	if (!ssl_cert_callsign_match(subj_call, c->username)) {
+		ret = SSL_VALIDATE_CERT_CALLSIGN_MISMATCH;
+		goto fail;
+	}
+	
+	/* find issuer */
+	iname = X509_get_issuer_name(cert);
+	issuer = iname ? X509_NAME_oneline(iname, NULL, 0) : "(none)";
+	
+	ret = 0;
+	hlog(LOG_INFO, "%s/%s: Peer validated using SSL certificate: subject '%s' callsign '%s' CN '%s' issuer '%s'",
+		c->addr_rem, c->username, subject, subj_call, (subj_cn) ? subj_cn : "(none)", issuer);
+	
+	/* store copies of cert subject and issuer */
+	strncpy(c->cert_subject, subject, sizeof(c->cert_subject));
+	c->cert_subject[sizeof(c->cert_subject)-1] = 0;
+	strncpy(c->cert_issuer, issuer, sizeof(c->cert_issuer));
+	c->cert_issuer[sizeof(c->cert_issuer)-1] = 0;
+	
+fail:	
+	/* free up whatever we allocated */
+	X509_free(cert);
+	
+	if (subj_call)
+		OPENSSL_free(subj_call);
+	if (subj_cn)
+		OPENSSL_free(subj_cn);
+	
+	return ret;
+}
+
+/*
+ *	Write data to an SSL socket
+ */
+
+int ssl_write(struct worker_t *self, struct client_t *c)
+{
+	int n;
+	int sslerr;
+	int err;
+	int to_write;
+	
+	to_write = c->obuf_end - c->obuf_start;
+	
+	//hlog(LOG_DEBUG, "ssl_write fd %d of %d bytes", c->fd, to_write);
+	ssl_clear_error();
+	
+	n = SSL_write(c->ssl_con->connection, c->obuf + c->obuf_start, to_write);
+	
+	//hlog(LOG_DEBUG, "SSL_write fd %d returned %d", c->fd, n);
+	
+	if (n > 0) {
+		/* ok, we wrote some */
+		c->obuf_start += n;
+		c->obuf_wtime = tick;
+		
+		/* All done ? */
+		if (c->obuf_start >= c->obuf_end) {
+			//hlog(LOG_DEBUG, "ssl_write fd %d (%s) obuf empty", c->fd, c->addr_rem);
+			c->obuf_start = 0;
+			c->obuf_end   = 0;
+			
+			/* tell the poller that we have no outgoing data */
+			xpoll_outgoing(&self->xp, c->xfd, 0);
+			return n;
+		}
+		
+		xpoll_outgoing(&self->xp, c->xfd, 1);
+		
+		return n;
+	}
+	
+	sslerr = SSL_get_error(c->ssl_con->connection, n);
+	err = (sslerr == SSL_ERROR_SYSCALL) ? errno : 0;
+	
+	if (sslerr == SSL_ERROR_WANT_WRITE) {
+		hlog(LOG_INFO, "ssl_write fd %d: SSL_write wants to write again, marking socket for write events", c->fd);
+		
+		/* tell the poller that we have outgoing data */
+		xpoll_outgoing(&self->xp, c->xfd, 1);
+		
+		return 0;
+	}
+	
+	if (sslerr == SSL_ERROR_WANT_READ) {
+		hlog(LOG_INFO, "ssl_write fd %d: SSL_write wants to read, returning 0", c->fd);
+		
+		/* tell the poller that we won't be writing now, until we've read... */
+		xpoll_outgoing(&self->xp, c->xfd, 0);
+		
+		return 0;
+	}
+	
+	if (err) {
+		hlog(LOG_DEBUG, "ssl_write fd %d: I/O syscall error: %s", c->fd, strerror(err));
+	} else {
+		char ebuf[255];
+		
+		ERR_error_string_n(sslerr, ebuf, sizeof(ebuf));
+		hlog(LOG_INFO, "ssl_write fd %d failed with ret %d sslerr %u errno %d: %s (%s)",
+			c->fd, n, sslerr, err, ebuf, ERR_reason_error_string(sslerr));
+	}
+	
+	c->ssl_con->no_wait_shutdown = 1;
+	c->ssl_con->no_send_shutdown = 1;
+	
+	hlog(LOG_DEBUG, "ssl_write fd %d: SSL_write() failed", c->fd);
+	client_close(self, c, err);
+	
+	return -13;
+}
+
+int ssl_writable(struct worker_t *self, struct client_t *c)
+{
+	int to_write;
+	
+	to_write = c->obuf_end - c->obuf_start;
+	
+	//hlog(LOG_DEBUG, "ssl_writable fd %d, %d available for writing", c->fd, to_write);
+	
+	/* SSL_write does not appreciate writing a 0-length buffer */
+	if (to_write == 0) {
+		/* tell the poller that we have no outgoing data */
+		xpoll_outgoing(&self->xp, c->xfd, 0);
+		return 0;
+	}
+	
+	return ssl_write(self, c);
+}
+
+int ssl_readable(struct worker_t *self, struct client_t *c)
+{
+	int r;
+	int sslerr, err;
+	
+	//hlog(LOG_DEBUG, "ssl_readable fd %d", c->fd);
+	
+	ssl_clear_error();
+	
+	r = SSL_read(c->ssl_con->connection, c->ibuf + c->ibuf_end, c->ibuf_size - c->ibuf_end - 1);
+	
+	if (r > 0) {
+		/* we got some data... process */
+		//hlog(LOG_DEBUG, "SSL_read fd %d returned %d bytes of data", c->fd, r);
+		
+		/* TODO: whatever the client_readable does */
+		return client_postread(self, c, r);
+	}
+	
+	sslerr = SSL_get_error(c->ssl_con->connection, r);
+	err = (sslerr == SSL_ERROR_SYSCALL) ? errno : 0;
+	
+	if (sslerr == SSL_ERROR_WANT_READ) {
+		hlog(LOG_DEBUG, "ssl_readable fd %d: SSL_read wants to read again, doing it later", c->fd);
+		
+		if (c->obuf_end - c->obuf_start > 0) {
+			/* tell the poller that we have outgoing data */
+			xpoll_outgoing(&self->xp, c->xfd, 1);
+		}
+		
+		return 0;
+	}
+	
+	if (sslerr == SSL_ERROR_WANT_WRITE) {
+		hlog(LOG_INFO, "ssl_readable fd %d: SSL_read wants to write (peer starts SSL renegotiation?), calling ssl_write", c->fd);
+		return ssl_write(self, c);
+	}
+	
+	c->ssl_con->no_wait_shutdown = 1;
+	c->ssl_con->no_send_shutdown = 1;
+	
+	if (sslerr == SSL_ERROR_ZERO_RETURN || ERR_peek_error() == 0) {
+		hlog(LOG_DEBUG, "ssl_readable fd %d: peer shutdown SSL cleanly", c->fd);
+		client_close(self, c, CLIERR_EOF);
+		return -1;
+	}
+	
+	if (err) {
+		hlog(LOG_DEBUG, "ssl_readable fd %d: I/O syscall error: %s", c->fd, strerror(err));
+	} else {
+		char ebuf[255];
+		
+		ERR_error_string_n(sslerr, ebuf, sizeof(ebuf));
+		hlog(LOG_INFO, "ssl_readable fd %d failed with ret %d sslerr %d errno %d: %s (%s)",
+			c->fd, r, sslerr, err, ebuf, ERR_reason_error_string(sslerr));
+	}
+	
+	client_close(self, c, err);
+	return -1;
+}
+
+
+#endif
+
diff --git a/ssl.h b/ssl.h
new file mode 100644
index 0000000..1ae4dec
--- /dev/null
+++ b/ssl.h
@@ -0,0 +1,102 @@
+
+#include "config.h"
+
+#ifdef HAVE_OPENSSL_SSL_H
+#define USE_SSL
+#endif
+
+#ifndef SSL_H
+#define SSL_H
+
+#ifdef USE_SSL
+
+#include <openssl/ssl.h>
+#include <openssl/err.h>
+#include <openssl/conf.h>
+#include <openssl/engine.h>
+#include <openssl/evp.h>
+
+/* ssl error codes, must match ssl_err_labels order */
+#define SSL_VALIDATE_INTERNAL_ERROR -1
+#define SSL_VALIDATE_CLIENT_CERT_UNVERIFIED -2
+#define SSL_VALIDATE_NO_CLIENT_CERT -3
+#define SSL_VALIDATE_CERT_NO_SUBJECT -4
+#define SSL_VALIDATE_CERT_NO_CALLSIGN -5
+#define SSL_VALIDATE_CERT_CALLSIGN_MISMATCH -6
+
+struct client_t;
+struct worker_t;
+
+struct ssl_t {
+	SSL_CTX *ctx;
+	
+	unsigned	validate;
+};
+
+struct ssl_connection_t {
+	SSL             *connection;
+	
+	unsigned	handshaked:1;
+	
+	unsigned	renegotiation:1;
+	unsigned	buffer:1;
+	unsigned	no_wait_shutdown:1;
+	unsigned	no_send_shutdown:1;
+	
+	unsigned	validate;
+	int		ssl_err_code;
+};
+
+#define NGX_SSL_SSLv2    0x0002
+#define NGX_SSL_SSLv3    0x0004
+#define NGX_SSL_TLSv1    0x0008
+#define NGX_SSL_TLSv1_1  0x0010
+#define NGX_SSL_TLSv1_2  0x0020
+
+
+#define NGX_SSL_BUFFER   1
+#define NGX_SSL_CLIENT   2
+
+#define NGX_SSL_BUFSIZE  16384
+
+/* string representations for error codes */
+extern const char *ssl_strerror(int code);
+
+/* initialize and deinit the library */
+extern int ssl_init(void);
+extern void ssl_atend(void);
+
+/* per-listener structure allocators */
+extern struct ssl_t *ssl_alloc(void);
+extern void ssl_free(struct ssl_t *ssl);
+
+/* create context for listener, load certs */
+extern int ssl_create(struct ssl_t *ssl, void *data);
+extern int ssl_certificate(struct ssl_t *ssl, const char *certfile, const char *keyfile);
+extern int ssl_ca_certificate(struct ssl_t *ssl, const char *cafile, int depth);
+
+/* create / free connection */
+extern int ssl_create_connection(struct ssl_t *ssl, struct client_t *c, int i_am_client);
+extern void ssl_free_connection(struct client_t *c);
+
+/* validate a client certificate */
+extern int ssl_validate_peer_cert_phase1(struct client_t *c);
+extern int ssl_validate_peer_cert_phase2(struct client_t *c);
+
+extern int ssl_write(struct worker_t *self, struct client_t *c);
+extern int ssl_writable(struct worker_t *self, struct client_t *c);
+extern int ssl_readable(struct worker_t *self, struct client_t *c);
+
+
+#else
+
+struct ssl_t {
+};
+
+
+#define ssl_init(...) { }
+#define ssl_atend(...) { }
+
+#endif /* USE_SSL */
+#endif /* SSL_H */
+
diff --git a/svnversion b/svnversion
new file mode 100755
index 0000000..e6d3b81
--- /dev/null
+++ b/svnversion
@@ -0,0 +1,3 @@
+#!/bin/sh
+
+echo 523
diff --git a/svnversion-test.sh b/svnversion-test.sh
new file mode 100644
index 0000000..fdbcca4
--- /dev/null
+++ b/svnversion-test.sh
@@ -0,0 +1,36 @@
+#!/bin/sh
+
+#set -x
+echo "svnversion-test.sh: $*"
+
+SV="$1"
+shift
+
+SVNVERSION=undef
+
+for x in /bin/svnversion /usr/bin/svnversion
+do
+    if [ -x $x ] ; then
+        SVNVERSION="`$x`"
+    fi
+done
+
+if [ "$SVNVERSION" = "undef" -o "$SVNVERSION" = "Unversioned directory" ] ; then
+    if [ -f SVNVERSION ] ; then
+        echo "Can't pull SVNVERSION value from svn storage, pulling from SVNVERSION file.."
+        SVNVERSION="`cat SVNVERSION`"
+    fi
+else
+    echo "$SVNVERSION" > SVNVERSION
+fi
+
+if [ "$SVNVERSION" != "$SV" ] ; then
+    echo "Miss-match of '$SVNVERSION' vs. '$SV' -- aborting now, please rerun the make command."
+    exit 1
+fi
+
+X="`(echo -n $SVNVERSION | tr -d 0-9)`"
+if [ -n "$X" ] ; then
+  echo "Mixed or modified tree: ($SVNVERSION), ARE YOU SURE ??." ; \
+  echo -n "Y/^C ? "; read var ;					    \
+fi
diff --git a/telemetry.c b/telemetry.c
new file mode 100644
index 0000000..b4951f6
--- /dev/null
+++ b/telemetry.c
@@ -0,0 +1,572 @@
+/* **************************************************************** *
+ *                                                                  *
+ *  APRX -- 2nd generation receive-only APRS-i-gate with            *
+ *          minimal requirement of esoteric facilities or           *
+ *          libraries of any kind beyond UNIX system libc.          *
+ *                                                                  *
+ * (c) Matti Aarnio - OH2MQK,  2007-2014                            *
+ *                                                                  *
+ * **************************************************************** */
+
+#include "aprx.h"
+
+#define  telemetry_timescaler 2              // scale to 10 minute sums
+
+static int telemetry_interval = 20 * 60;     // every 20 minutes
+static int telemetry_labelinterval = 120*60; // every 2 hours
+static int telemetry_labelindex = 0;
+
+#if (defined(ERLANGSTORAGE) || (USE_ONE_MINUTE_STORAGE == 1))
+static int telemetry_1min_steps = 20;
+#endif
+#if (defined(ERLANGSTORAGE) || (USE_ONE_MINUTE_STORAGE == 0))
+static int telemetry_10min_steps = 2;
+#endif
+
+static struct timeval telemetry_time;
+static struct timeval telemetry_labeltime;
+static int telemetry_seq;
+static int telemetry_params;
+
+
+struct rftelemetry {
+	struct aprx_interface  *transmitter;
+	struct aprx_interface **sources;
+	int		        source_count;
+	char	               *viapath;
+};
+
+static int                  rftelemetrycount;
+static struct rftelemetry **rftelemetry;
+
+static void rf_telemetry(const struct aprx_interface *sourceaif, const char *beaconaddr,
+			 const const char *buf, const int buflen);
+
+static void telemetry_resettime(void *arg)
+{
+	struct timeval *tv = (struct timeval*)arg;
+	tv_timeradd_seconds( tv, &tick, telemetry_interval );
+}
+
+static void telemetry_resetlabeltime(void *arg)
+{
+	struct timeval *tv = (struct timeval*)arg;
+	tv_timeradd_seconds( tv, &tick, 120 );  // first label 2 minutes from now
+}
+
+
+void telemetry_start()
+{
+	/*
+	 * Initialize the sequence start to be highly likely
+	 * different from previous one...  This really should
+	 * be in some persistent database, but this is reasonable
+	 * compromise.
+	 */
+	telemetry_seq = (time(NULL)) & 255;
+
+	// "tick" is supposedly current time..
+        telemetry_resettime( &telemetry_time );
+        telemetry_resetlabeltime( &telemetry_labeltime );
+
+	if (debug) printf("telemetry_start()\n");
+}
+
+int telemetry_prepoll(struct aprxpolls *app)
+{
+	// Check that time has not jumped too far ahead/back (1.5 telemetry intervals)
+	if (time_reset) {
+        	telemetry_resettime(&telemetry_time);
+                telemetry_resetlabeltime(&telemetry_labeltime);
+        }
+
+        // Normal operational step
+
+        if (tv_timercmp(&app->next_timeout, &telemetry_time) > 0)
+		app->next_timeout = telemetry_time;
+	if (tv_timercmp(&app->next_timeout, &telemetry_labeltime) > 0)
+		app->next_timeout = telemetry_labeltime;
+
+        if (debug>1) printf("telemetry_prepoll()\n");
+
+	return 0;
+}
+
+static void telemetry_datatx(void);
+static void telemetry_labeltx(void);
+
+int telemetry_postpoll(struct aprxpolls *app)
+{
+	if (debug>1) {
+          printf("telemetry_postpoll()  telemetrytime=%ds  labeltime=%ds\n",
+                 tv_timerdelta_millis(&tick, &telemetry_time)/1000,
+                 tv_timerdelta_millis(&tick, &telemetry_labeltime)/1000);
+        }
+        if (tv_timercmp(&telemetry_time, &tick) <= 0) {
+          tv_timeradd_seconds(&telemetry_time, &telemetry_time, telemetry_interval);
+	  telemetry_datatx();
+	}
+
+        if (tv_timercmp(&telemetry_labeltime, &tick) <= 0) {
+	  tv_timeradd_seconds(&telemetry_labeltime, &telemetry_labeltime, telemetry_labelinterval);
+	  telemetry_labeltx();
+	}
+
+	return 0;
+}
+
+static void telemetry_datatx(void)
+{
+	int  i, j, k, t;
+	char buf[200], *s;
+	int  buflen;
+	char beaconaddr[60];
+	int  beaconaddrlen;
+	long erlmax;
+	float erlcapa;
+	float f;
+
+
+	if (debug)
+	  printf("Telemetry Tx run; next one in %.2f minutes\n", (telemetry_interval/60.0));
+
+	// Init these for RF transmission
+	buf[0] = 0x03; // AX.25 Control
+	buf[1] = 0xF0; // AX.25 PID
+
+	++telemetry_seq;
+	telemetry_seq %= 1000;
+	for (i = 0; i < ErlangLinesCount; ++i) {
+		struct erlangline *E = ErlangLines[i];
+		struct aprx_interface *sourceaif = find_interface_by_callsign(E->name);
+		if (!sourceaif || !interface_is_telemetrable(sourceaif))
+		  continue;
+
+		beaconaddrlen = sprintf(beaconaddr, "%s>%s,TCPIP*", E->name, tocall);
+		// First two bytes of BUF are for AX.25 control+PID fields
+		s = buf+2;
+		s += sprintf(s, "T#%03d,", telemetry_seq);
+
+
+		// Raw Rx Erlang - plotting scale factor: 1/200
+		erlmax = 0;
+#if (USE_ONE_MINUTE_DATA == 1)
+		// Find busiest 1 minute
+		k = E->e1_cursor;
+		t = E->e1_max;
+		if (t > telemetry_1min_steps)
+		  t = telemetry_1min_steps;	// Up to 10 of 1 minute samples
+		erlcapa = 1.0 / E->erlang_capa; // 1/capa of 1 minute
+		for (j = 0; j < t; ++j) {
+		  --k;
+		  if (k < 0)
+		    k = E->e1_max - 1;
+		  if (E->e1[k].bytes_rx > erlmax)
+		    erlmax = E->e1[k].bytes_rx;
+		}
+#else
+		// Find busiest 10 minute
+		k = E->e10_cursor;
+		t = E->e10_max;
+		if (t > telemetry_10min_steps)
+		  t = telemetry_10min_steps;	// Up to 1 of 10 minute samples
+		erlcapa = 0.1 / E->erlang_capa; // 1/capa of 10 minute 
+		for (j = 0; j < t; ++j) {
+		  --k;
+		  if (k < 0)
+		    k = E->e10_max - 1;
+		  if (E->e10[k].bytes_rx > erlmax)
+		    erlmax = E->e10[k].bytes_rx;
+		}
+#endif
+		f = (200.0 * erlcapa * erlmax);
+		s += sprintf(s, "%.1f,", f);
+		
+		// Raw Tx Erlang - plotting scale factor: 1/200
+		erlmax = 0;
+#if (USE_ONE_MINUTE_DATA == 1)
+		// Find busiest 1 minute
+		k = E->e1_cursor;
+		t = E->e1_max;
+		if (t > telemetry_1min_steps)
+		  t = telemetry_1min_steps;	// Up to 10 of 1 minute samples
+		erlcapa = 1.0 / E->erlang_capa; // 1/capa of 1 minute
+		for (j = 0; j < t; ++j) {
+		  --k;
+		  if (k < 0)
+		    k = E->e1_max - 1;
+		  if (E->e1[k].bytes_tx > erlmax)
+		    erlmax = E->e1[k].bytes_tx;
+		}
+#else
+		// Find busiest 10 minute
+		k = E->e10_cursor;
+		t = E->e10_max;
+		if (t > telemetry_10min_steps)
+		  t = telemetry_10min_steps;	// Up to 1 of 10 minute samples
+		erlcapa = 0.1 / E->erlang_capa; // 1/capa of 10  minute
+		for (j = 0; j < t; ++j) {
+		  --k;
+		  if (k < 0)
+		    k = E->e10_max - 1;
+		  if (E->e10[k].bytes_tx > erlmax)
+		    erlmax = E->e10[k].bytes_tx;
+		}
+#endif
+		f = (200.0 * erlcapa * erlmax);
+		s += sprintf(s, "%.1f,", f);
+
+		erlmax = 0;
+#if (USE_ONE_MINUTE_DATA == 1)
+		// Sum of 1 minute packet counts
+		k = E->e1_cursor;
+		t = E->e1_max;
+		if (t > telemetry_1min_steps)
+		  t = telemetry_1min_steps;	/* Up to 10 of 1 minute samples */
+		for (j = 0; j < t; ++j) {
+		  --k;
+		  if (k < 0)
+		    k = E->e1_max - 1;
+		  erlmax += E->e1[k].packets_rx;
+		}
+#else
+		// Sum of 10 minute packet counts
+		erlmax = 0;
+		k = E->e10_cursor;
+		t = E->e10_max;
+		if (t > telemetry_10min_steps)
+		  t = telemetry_10min_steps;	// Up to 1 of 10 minute samples
+		for (j = 0; j < t; ++j) {
+		  --k;
+		  if (k < 0)
+		    k = E->e10_max - 1;
+		  erlmax += E->e10[k].packets_rx;
+		}
+#endif
+		f = erlmax / telemetry_timescaler;
+		s += sprintf(s, "%.1f,", f);
+
+		erlmax = 0;
+#if (USE_ONE_MINUTE_DATA == 1)
+		// Sum of 1 minute packet drop counts
+		k = E->e1_cursor;
+		t = E->e1_max;
+		if (t > telemetry_1min_steps)
+		  t = telemetry_1min_steps;	/* Up to 10 of 1 minute samples */
+		for (j = 0; j < t; ++j) {
+		  --k;
+		  if (k < 0)
+		    k = E->e1_max - 1;
+		  erlmax += E->e1[k].packets_rxdrop;
+		}
+#else
+		// Sum of 10 minute packet drop counts
+		k = E->e10_cursor;
+		t = E->e10_max;
+		if (t > telemetry_10min_steps)
+		  t = telemetry_10min_steps;	// Up to 1 of 10 minute samples
+		for (j = 0; j < t; ++j) {
+		  --k;
+		  if (k < 0)
+		    k = E->e10_max - 1;
+		  erlmax += E->e10[k].packets_rxdrop;
+		}
+#endif
+		f = erlmax / telemetry_timescaler;
+		s += sprintf(s, "%.1f,", f);
+
+		erlmax = 0;
+#if (USE_ONE_MINUTE_DATA == 1)
+		// Sum of 1 minute packet tx counts
+		k = E->e1_cursor;
+		t = E->e1_max;
+		if (t > telemetry_1min_steps)
+		  t = telemetry_1min_steps;	/* Up to 10 of 1 minute samples */
+		for (j = 0; j < t; ++j) {
+		  --k;
+		  if (k < 0)
+		    k = E->e1_max - 1;
+		  erlmax += E->e1[k].packets_tx;
+		}
+#else
+		// Sum of 10 minute packet tx counts
+		k = E->e10_cursor;
+		t = E->e10_max;
+		if (t > telemetry_10min_steps)
+		  t = telemetry_10min_steps;	// Up to 1 of 10 minute samples
+		for (j = 0; j < t; ++j) {
+		  --k;
+		  if (k < 0)
+		    k = E->e10_max - 1;
+		  erlmax += E->e10[k].packets_tx;
+		}
+#endif
+		f = erlmax / telemetry_timescaler;
+		s += sprintf(s, "%.1f,", f);
+		
+		/* Tail filler */
+		s += sprintf(s, "00000000");  // FIXME: flag telemetry?
+
+                if (debug>2) printf("%s (to is=%d rf=%d) %s\n",
+                                    beaconaddr, sourceaif->telemeter_to_is,
+                                    sourceaif->telemeter_to_rf,
+                                    buf+2);
+		
+		/* _NO_ ending CRLF, the APRSIS subsystem adds it. */
+		
+		/* Send those (net)beacons.. */
+		buflen = s - buf;
+#ifndef DISABLE_IGATE
+                if (sourceaif->telemeter_to_is) {
+                  aprsis_queue(beaconaddr, beaconaddrlen, 
+                               qTYPE_LOCALGEN, aprsis_login,
+                               buf+2, buflen-2);
+                }
+#endif
+                rf_telemetry(sourceaif, beaconaddr, buf, buflen);
+
+	}
+	++telemetry_params;
+}
+
+// Telemetry Labels are transmitted separately
+static void telemetry_labeltx()
+{
+	int  i;
+	char buf[200], *s;
+	int  buflen;
+	char beaconaddr[60];
+	int  beaconaddrlen;
+
+
+	if (debug)
+	  printf("Telemetry LabelTx run; next one in %.2f minutes\n", (telemetry_labelinterval/60.0));
+
+	// Init these for RF transmission
+	buf[0] = 0x03; // AX.25 Control
+	buf[1] = 0xF0; // AX.25 PID
+
+	++telemetry_seq;
+	telemetry_seq %= 1000;
+	for (i = 0; i < ErlangLinesCount; ++i) {
+		struct erlangline *E = ErlangLines[i];
+		struct aprx_interface *sourceaif = find_interface_by_callsign(E->name);
+		if (!sourceaif || !interface_is_telemetrable(sourceaif))
+		  continue;
+		beaconaddrlen = sprintf(beaconaddr, "%s>%s,TCPIP*", E->name, tocall);
+		// First two bytes of BUF are for AX.25 control+PID fields
+
+		/* Send every 5h20m or thereabouts. */
+
+                switch (telemetry_labelindex) {
+                case 0:
+		  s = buf+2 + sprintf(buf+2,
+				      ":%-9s:PARM.Avg 10m,Avg 10m,RxPkts,IGateDropRx,TxPkts",
+				      E->name);
+                  break;
+                case 1:
+		  s = buf+2 + sprintf(buf+2,
+				      ":%-9s:UNIT.Rx Erlang,Tx Erlang,count/10m,count/10m,count/10m",
+				      E->name);
+                  break;
+                case 2:
+		  
+		  s = buf+2 + sprintf(buf+2,
+				      ":%-9s:EQNS.0,0.005,0,0,0.005,0,0,1,0,0,1,0,0,1,0",
+				      E->name);
+                  break;
+                default:
+                  break;
+                }
+
+                if (debug>2) printf("%s (to is=%d rf=%d) %s\n",
+                                    beaconaddr, sourceaif->telemeter_to_is,
+                                    sourceaif->telemeter_to_rf,
+                                    buf+2);
+
+                buflen = s - buf;
+#ifndef DISABLE_IGATE
+                if (sourceaif->telemeter_to_is) {
+                  aprsis_queue(beaconaddr, beaconaddrlen,
+                               qTYPE_LOCALGEN, aprsis_login,
+                               buf+2, buflen-2);
+                }
+#endif
+                rf_telemetry(sourceaif, beaconaddr, buf, buflen);
+	}
+	++telemetry_params;
+
+	// Switch label-index..
+	++telemetry_labelindex;
+	if (telemetry_labelindex > 2)
+	  telemetry_labelindex = 0;
+}
+
+/*
+ * Transmit telemetry to the RF interface that is being monitored.
+ * Interface 'flags' contain controls on thist.
+ */
+static void rf_telemetry(const struct aprx_interface *sourceaif,
+                         const char *beaconaddr,
+			 const char *buf,
+                         const const int buflen)
+{
+	int i;
+	int t_idx;
+	char *dest;
+
+	if (rftelemetrycount == 0) return; // Nothing to do!
+	if (sourceaif == NULL) return; // Huh? Unknown source..
+
+        if (!sourceaif->telemeter_to_rf) return; // not wanted
+	if (!interface_is_telemetrable(sourceaif)) return; // not possible
+
+
+	// The beaconaddr comes in as:
+	//    "interfacecall>APRXxx,TCPIP*"
+	dest = strchr(beaconaddr, ',');
+	if (dest != NULL) *dest = 0;
+	dest = strchr(beaconaddr, '>');
+	if (dest != NULL) *dest++ = 0;
+	if (dest == NULL) {
+	  // Impossible -- said she...
+	  return;
+	}
+
+	for (t_idx = 0; t_idx < rftelemetrycount; ++t_idx) {
+	  struct rftelemetry *rftlm = rftelemetry[t_idx];
+	  if (rftlm == NULL) break;
+	  for (i = 0; i < rftlm->source_count; ++i) {
+	    if (rftlm->sources[i] == sourceaif) {
+	      // Found telemetry transmitter which wants this source
+
+	      interface_transmit_beacon(rftlm->transmitter,
+					beaconaddr,
+					dest,
+					rftlm->viapath,
+					buf, buflen);
+	    }
+	  }
+	}
+}
+
+int telemetry_config(struct configfile *cf)
+{
+	char *name, *param1;
+	char *str = cf->buf;
+	int   has_fault = 0;
+
+	struct aprx_interface  *aif          = NULL;
+	struct aprx_interface **sources      = NULL;
+	int			source_count = 0;
+	char                   *viapath      = NULL;
+
+	while (readconfigline(cf) != NULL) {
+		if (configline_is_comment(cf))
+			continue;	/* Comment line, or empty line */
+
+		// It can be severely indented...
+		str = config_SKIPSPACE(cf->buf);
+
+		name = str;
+		str = config_SKIPTEXT(str, NULL);
+		str = config_SKIPSPACE(str);
+		config_STRLOWER(name);
+
+		param1 = str;
+		str = config_SKIPTEXT(str, NULL);
+		str = config_SKIPSPACE(str);
+
+		if (strcmp(name, "</telemetry>") == 0)
+		  break;
+
+		if (strcmp(name, "transmit") == 0 ||
+		    strcmp(name, "transmitter") == 0) {
+			if (strcasecmp(param1,"$mycall") == 0)
+				param1 = (char*)mycall;
+
+			aif = find_interface_by_callsign(param1);
+			if (aif != NULL && (!aif->tx_ok)) {
+			  aif = NULL; // Not 
+			  printf("%s:%d ERROR: This transmit interface has no TX-OK TRUE setting: '%s'\n",
+				 cf->name, cf->linenum, param1);
+			  has_fault = 1;
+			} else if (aif == NULL) {
+			  printf("%s:%d ERROR: Unknown interface: '%s'\n",
+				 cf->name, cf->linenum, param1);
+			  has_fault = 1;
+			}
+
+		} else if (strcmp(name, "via") == 0) {
+			if (viapath != NULL) {
+			  printf("%s:%d ERROR: Double definition of 'via'\n",
+				 cf->name, cf->linenum);
+			  has_fault = 1;
+			} else if (*param1 == 0) {
+			  printf("%s:%d ERROR: 'via' keyword without parameter\n",
+				 cf->name, cf->linenum);
+			  has_fault = 1;
+			}
+			if (!has_fault) {
+			  const char *check;
+			  config_STRUPPER(param1);
+			  check = tnc2_verify_callsign_format(param1, 0, 1, param1+strlen(param1));
+			  if (check == NULL) {
+			    has_fault = 1;
+			    printf("%s:%d ERROR: The 'via %s' parameter is not acceptable AX.25 format\n",
+				   cf->name, cf->linenum, param1);
+
+			  }
+			}
+			if (!has_fault) {
+			  // Save it
+			  viapath = strdup(param1);
+			}
+		} else if (strcmp(name, "source") == 0) {
+			struct aprx_interface *source_aif = NULL;
+			if (debug)
+			  printf("%s:%d <telemetry> source = '%s'\n",
+				 cf->name, cf->linenum, param1);
+
+			if (strcasecmp(param1,"$mycall") == 0)
+				param1 = (char*)mycall;
+
+			source_aif = find_interface_by_callsign(param1);
+			if (source_aif == NULL) {
+			  has_fault = 1;
+			  printf("%s:%d ERROR: Digipeater source '%s' not found\n",
+				 cf->name, cf->linenum, param1);
+			} else {
+			  // Collect them all...
+			  sources = realloc(sources, sizeof(void*)*(source_count+3));
+			  sources[source_count++] = source_aif;
+			  sources[source_count+1] = NULL;
+			}
+			if (debug>1)
+			  printf(" .. source_aif = %p\n", source_aif);
+		} else {
+		  printf("%s:%d ERROR: Unknown <telemetry> block keyword '%s'\n",
+			 cf->name, cf->linenum, name);
+		}
+	}
+
+	if (has_fault) {
+	  if (sources != NULL)
+	    free(sources);
+	  if (viapath != NULL)
+	    free(viapath);
+	  printf("ERROR: Failures on defining <telemetry> block parameters\n");
+	  printf("       APRS RF-Telemetry will not be activated.\n");
+	} else {
+	  struct rftelemetry *newrf = calloc(1, sizeof(*newrf));
+	  newrf->transmitter = aif;
+	  newrf->viapath     = viapath;
+	  newrf->sources     = sources;
+	  newrf->source_count = source_count;
+	  rftelemetry = realloc(rftelemetry, sizeof(void*)*(rftelemetrycount+2));
+	  rftelemetry[rftelemetrycount++] = newrf;
+
+	  if (debug) printf("Defined <telemetry> to transmitter %s\n", aif ? aif->callsign : "ALL");
+	}
+	return has_fault;
+}
diff --git a/test.c b/test.c
new file mode 100644
index 0000000..254957d
--- /dev/null
+++ b/test.c
@@ -0,0 +1,21 @@
+#include <stdio.h>
+
+static int aprspass(const char *mycall)
+{
+	int a = 0, h = 29666, c;
+
+	for (; *mycall; ++mycall) {
+		c = 0xFF & *mycall;
+		if (!(('0' <= c && c <= '9') || ('A' <= c && c <= 'Z')))
+			break;
+		h ^= ((0xFF & *mycall) * (a ? 1 : 256));
+		a = !a;
+	}
+	return h;
+}
+
+main()
+{
+	printf("APRSPASS: %d\n", aprspass("OH2MQK-1"));
+	return 0;
+}
diff --git a/timercmp.c b/timercmp.c
new file mode 100644
index 0000000..f03fdda
--- /dev/null
+++ b/timercmp.c
@@ -0,0 +1,157 @@
+/* **************************************************************** *
+ *                                                                  *
+ *  APRX -- 2nd generation receive-only APRS-i-gate with            *
+ *          minimal requirement of esoteric facilities or           *
+ *          libraries of any kind beyond UNIX system libc.          *
+ *                                                                  *
+ * (c) Matti Aarnio - OH2MQK,  2007-2014                            *
+ *                                                                  *
+ * **************************************************************** */
+#include "aprx.h"
+
+/* Bits used only in the main program.. */
+#include <signal.h>
+#ifdef HAVE_SYS_TIME_H
+# include <sys/time.h>
+#endif
+#ifdef HAVE_TIME_H
+# include <time.h>
+#endif
+#include <fcntl.h>
+
+struct timeval now; // public wall clock that can jump around
+struct timeval tick;  // monotonic clock
+
+/*
+ * Calculate difference from now time to target time in milliseconds.
+ */
+int tv_timerdelta_millis(struct timeval *_now, struct timeval *_target)
+{
+	int deltasec  = _target->tv_sec  - _now->tv_sec;
+        int deltausec = _target->tv_usec - _now->tv_usec;
+        while (deltausec < 0) {
+        	deltausec += 1000000;
+                --deltasec;
+        }
+        return deltasec * 1000 + deltausec / 1000;
+}
+
+/*
+ * Add milliseconds to input parameter a returning
+ * the result though parameter ret.
+ */
+void tv_timeradd_millis(struct timeval *ret, struct timeval *a, int millis)
+{
+	if (ret != a) {
+          // Copy if different pointers..
+          *ret = *a;
+        }
+        int usec = (int)(ret->tv_usec) + millis * 1000;
+        if (usec >= 1000000) {
+          int dsec = (usec / 1000000);
+          ret->tv_sec += dsec;
+          usec %= 1000000;
+          // if (debug>3) printf("tv_timeadd_millis() dsec=%d dusec=%d\n",dsec, usec);
+        }
+        ret->tv_usec = usec;
+}
+
+/*
+ * Add seconds to input parameter a returning
+ * the result though parameter ret.
+ */
+void tv_timeradd_seconds(struct timeval *ret, struct timeval *a, int seconds)
+{
+	if (ret != a) {
+          // Copy if different pointers..
+          *ret = *a;
+        }
+        ret->tv_sec += seconds;
+}
+
+
+/*
+ * Comparison returning -1/0/+1 depending on ( a <=> b )
+ *
+ * This handles overflow wraparound of Y2038 issue of 32-bit UNIX time_t.
+ */
+int timecmp(const time_t a, const time_t b)
+{
+	const int i = (int)(a - b);
+        if (i == 0) return 0;
+        if (i > 0) return 1;
+        return -1;
+}
+
+/*
+ * Time compare function returning -1/0/+1 depending
+ * which parameter presents time before the other.
+ * Zero means equals.
+ */
+int tv_timercmp(struct timeval * const a, struct timeval * const b)
+{
+  // if (debug>3) {
+  // int dt_sec  = a->tv_sec - b->tv_sec;
+  // int dt_usec = a->tv_usec - b->tv_usec;
+  // printf("tv_timercmp(%d.%06d <=> %d.%06d) dt=%d:%06d ret= ",
+  // a->tv_sec, a->tv_usec, b->tv_sec, b->tv_usec, dt_sec, dt_usec);
+  // }
+
+	// Time delta calculation to avoid year 2038 issue
+	const int dt = timecmp(a->tv_sec, b->tv_sec);
+        if (dt != 0) {
+          // if (debug>3) printf("%ds\n", dt);
+          return dt;
+        }
+        // tv_usec is always in range 0 .. 999 999
+        if (a->tv_usec < b->tv_usec) {
+          // if (debug>3) printf("-1u\n");
+          return -1;
+        }
+        if (a->tv_usec > b->tv_usec) {
+          // if (debug>3) printf("1u\n");
+          return 1;
+        }
+        // if (debug>3) printf("0\n");
+        return 0; // equals!
+}
+
+/*
+ * Compare *tv with current time value (now), and if the difference
+ * is more than margin seconds, then call resetfunc with resetarg.
+ *
+ * Usually resetarg == tv, but not always.
+ * See 
+ */
+void tv_timerbounds(const char *timername,
+                    struct timeval *tv,
+                    const int margin,
+                    void (*resetfunc)(void*),
+                    void *resetarg)
+{
+	// Check that system time has not jumped too far ahead/back;
+	// that it is within margin seconds to tv.
+
+	struct timeval nowminus;
+	struct timeval nowplus;
+
+        tv_timeradd_seconds(&nowminus, &tick, -margin);
+
+        // If current time MINUS margin is AFTER tv, then reset.
+        if (tv_timercmp(tv, &nowminus) < 0) {
+        	if (debug)
+                	printf("System time has gone too much forwards, Resetting timer '%s'. dt=%d margin=%d\n",
+                               timername,  (int)(tv->tv_sec - nowminus.tv_sec), margin);
+                resetfunc(resetarg);
+        }
+
+        tv_timeradd_seconds(&nowplus,  &tick,  margin);
+
+        // If current time PLUS margin is BEFORE tv, then reset.
+        if (tv_timercmp(&nowplus, tv) < 0) {
+        	if (debug)
+                	printf("System time has gone too much backwards, Resetting timer '%s'. dt=%d margin=%d\n",
+                               timername, (int)(nowplus.tv_sec - tv->tv_sec), margin);
+                resetfunc(resetarg);
+        }
+}
diff --git a/timestamp.c b/timestamp.c
new file mode 100644
index 0000000..eb4e50d
--- /dev/null
+++ b/timestamp.c
@@ -0,0 +1,184 @@
+#include "aprx.h"
+
+/* Time Base Conversion Macros
+ *
+ * The NTP timebase is 00:00 Jan 1 1900.  The local
+ * time base is 00:00 Jan 1 1970.  Convert between
+ * these two by added or substracting 70 years
+ * worth of time.  Note that 17 of these years were
+ * leap years.
+ */
+#define TIME_BASEDIFF           (((70U*365U + 17U) * 24U*3600U))
+#define TIME_NTP_TO_LOCAL(t)    ((t)-TIME_BASEDIFF)
+#define TIME_LOCAL_TO_NTP(t)    ((t)+TIME_BASEDIFF)
+
+typedef struct ntptime {
+	uint32_t seconds;
+	uint32_t fraction;
+} ntptime_t;
+
+uint64_t unix_tv_to_ntp(struct timeval *tv) {
+  // Reciprocal conversion of tv_usec to fractional NTP seconds
+  // Multiply tv_usec by  (2^64)/1_000_000 
+  // GCC optimized this nicely on i386
+  uint64_t fract = 18446744073709ULL * (uint32_t)(tv->tv_usec);
+  // Scale it back by 32 bit positions
+  fract >>= 32;
+  // Straight-forward conversion of tv_sec to NTP seconds
+  uint64_t ntptime = TIME_LOCAL_TO_NTP(tv->tv_sec);
+  ntptime <<= 32;
+  return ntptime + fract;
+}
+
+void unix_tv_to_ntp4(struct timeval *tv, ntptime_t *ntp) {
+  // Reciprocal conversion of tv_usec to fractional NTP seconds
+  // Multiply tv_usec by  ((2^64)/1_000_000) / (2^32)
+  // GCC optimized this nicely on i386, and 64-bit machines
+  uint32_t fract = (18446744073709ULL * (uint32_t)(tv->tv_usec)) >> 32;
+  //
+  //      movl    4(%ebx), %eax
+  //      imull   $4294, %eax, %esi    ;; 32*32->32 --> %esi
+  //      movl    $-140462611, %edi
+  //      mull    %edi                 ;; 32*32->64 --> %edx:eax
+  //      addl    %edx, %esi           ;; sum %esi + %edx
+  //
+  ntp->fraction = fract;
+  // Straight-forward conversion of tv_sec to NTP seconds
+  ntp->seconds  = TIME_LOCAL_TO_NTP(tv->tv_sec);
+}
+
+void unix_tv_to_ntp4a(struct timeval *tv, ntptime_t *ntp) {
+  // Reciprocal conversion of tv_usec to fractional NTP seconds
+  // Multiply tv_usec by  ((2^64)/1_000_000) / (2^32)
+  // GCC optimizes this slightly better for ARM, than ntp4()
+  //  .. for i386 ntp4() and ntp4a() are equal.
+  uint64_t fract = 18446744073709ULL * (uint32_t)(tv->tv_usec);
+  // Scale it back by 32 bit positions
+  fract >>= 32;
+  ntp->fraction = (uint32_t)fract;
+  // Straight-forward conversion of tv_sec to NTP seconds
+  ntp->seconds  = TIME_LOCAL_TO_NTP(tv->tv_sec);
+}
+
+
+uint64_t unix_tv_to_ntp2(struct timeval *tv) {
+  uint64_t tt = TIME_LOCAL_TO_NTP(tv->tv_sec);
+  tt <<= 32;
+  uint64_t tu = tv->tv_usec;
+  tu <<= 32;
+  // Following causes gcc to call __udivdi3() 
+  // on 32-bit machines
+  tu /= 1000000; // Fixed point scaling..
+  return (tt + tu);
+}
+
+// static const double usec2NtpFract = 4294.9672960D; // 2^32 / 1E6
+
+uint64_t unix_tv_to_ntp3(struct timeval *tv) {
+  uint64_t tt = TIME_LOCAL_TO_NTP(tv->tv_sec);
+  tt <<= 32;
+// FP math is bad on embedded systems...
+//  double fract = usec2NtpFract * (uint32_t)tv->tv_usec;
+//  tt += (int64_t)fract;
+  return tt;
+}
+
+
+static const char *BASE64EncodingDictionary =
+  "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+  "abcdefghijklmnopqrstuvwxyz"
+  "0123456789"
+  "+/";
+
+void encode_aprsis_ntptimestamp(uint64_t ntptime, char timestamp[8])
+{
+	int i;
+
+	ntptime >>= 22; // scale to 1/1024 seconds
+	for (i = 6; i >= 0; --i) {
+	    int n = (((int)ntptime) & 0x3F); // lowest 6 bits
+	    // printf("  [n=%d]\n", n);
+	    ntptime >>= 6;
+	    timestamp[i] = BASE64EncodingDictionary[n];
+	}
+	timestamp[7] = 0;
+}
+
+static const int8_t BASE64DecodingDictionary[128] =
+  { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+    -1, -1, -1, -1,  // ' ', '!', '"', '#'
+    -1, -1, -1, -1,  // '$', '%', '&'', '\''
+    -1, -1, -1, 62,  // '(', ')', '*', '+',
+    -1, -1, -1, 63,  // ',', '-', '.', '/'
+    52, 53, 54, 55, 56, 57, 58, 59, 60, 61, // '0' .. '9'
+    -1, -1, -1, -1, -1, -1, // ':', ';', '<', '=', '>', '?'
+    -1,  0,  1,  2,  3,  4,  5,  6, // '@', 'A' .. 'G'
+     7,  8,  9, 10, 11, 12, 13, 14, // 'H' .. 'O'
+    15, 16, 17, 18, 19, 20, 21, 22, // 'P' .. 'W'
+    23, 24, 25, -1, -1, -1, -1, -1, // 'X'..'Z', '[', '\\', ']', '^', '_'
+    -1, 26, 27, 28, 29, 30, 31, 32, // '`', 'a' .. 'g'
+    33, 34, 35, 36, 37, 38, 39, 40, // 'h' .. 'o'
+    41, 42, 43, 44, 45, 46, 47, 48, // 'p' .. 'w'
+    49, 50, 51, -1, -1, -1, -1, -1 }; // 'x'..'z', ...
+
+
+int decode_aprsis_ntptimestamp(char timestamp[8], uint64_t *ntptimep)
+{
+	uint64_t ntptime = 0;
+
+	int i, n;
+	char c;
+
+	for (i = 0; i < 7; ++i) {
+	  c = timestamp[i];
+	  if (c <= 0 || c > 127) return -1; // BARF!
+	  n = BASE64DecodingDictionary[(int)c];
+	  // printf("  [n=%d]\n", n);
+	  if (n < 0) {
+	    // Should not happen!
+	    return -1; // Decode fail!
+	  }
+
+	  ntptime <<= 6;
+	  ntptime |= n;
+	}
+	ntptime <<= 22;
+	*ntptimep = ntptime;
+	return 0; // Decode OK
+}
+
+#ifdef TESTING
+
+int main(int argc, char *argv[]) {
+
+	struct timeval tv;
+	char timestamp[8];
+	uint64_t ntptime;
+	ntptime_t ntp_time;
+
+	// gettimeofday(&tv, NULL);
+
+	// Example time.. (refvalue: NTPseconds!)
+	tv.tv_sec = TIME_NTP_TO_LOCAL(3484745636U); tv.tv_usec = 709603U;
+
+	ntptime = unix_tv_to_ntp(&tv);
+	printf("NTPtime1 = %08x.%08x \n", (uint32_t)(ntptime >> 32), (uint32_t)ntptime);
+	ntptime = unix_tv_to_ntp2(&tv);
+	printf("NTPtime2 = %08x.%08x \n", (uint32_t)(ntptime >> 32), (uint32_t)ntptime);
+	// ntptime = unix_tv_to_ntp3(&tv);
+	// printf("NTPtime3 = %08x.%08x \n", (uint32_t)(ntptime >> 32), (uint32_t)ntptime);
+
+	unix_tv_to_ntp4(&tv, &ntp_time);
+	printf("NTPtime4 = %08x.%08x \n", ntp_time.seconds, ntp_time.fraction);
+
+	encode_aprsis_ntptimestamp( ntptime, timestamp );
+	printf("Timestamp = %s\n", timestamp);
+
+	int rc = decode_aprsis_ntptimestamp( timestamp, &ntptime );
+	printf("Decode rc=%d\n", rc);
+	printf("NTPtime = %08x.%08x \n", (uint32_t)(ntptime >> 32), (uint32_t)ntptime);
+
+	return 0;
+}
+#endif
diff --git a/tt.5383 b/tt.5383
new file mode 100644
index 0000000..06bfe3b
--- /dev/null
+++ b/tt.5383
@@ -0,0 +1,3101 @@
+execve("/bin/svn", ["svn", "--username", "oh2mqk", "commit", "doc/", "-m", "Add note about USB serial ports "...], [/* 59 vars */]) = 0
+brk(0)                                  = 0x7fb0c4d8b000
+mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fb0c41f5000
+access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
+open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
+fstat(3, {st_mode=S_IFREG|0644, st_size=212134, ...}) = 0
+mmap(NULL, 212134, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7fb0c41c1000
+close(3)                                = 0
+open("/lib64/libsvn_client-1.so.0", O_RDONLY|O_CLOEXEC) = 3
+read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\340\0a\2249\0\0\0"..., 832) = 832
+fstat(3, {st_mode=S_IFREG|0755, st_size=421472, ...}) = 0
+mmap(NULL, 2508008, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7fb0c3d72000
+mprotect(0x7fb0c3dd5000, 2093056, PROT_NONE) = 0
+mmap(0x7fb0c3fd4000, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x62000) = 0x7fb0c3fd4000
+close(3)                                = 0
+open("/lib64/libsvn_wc-1.so.0", O_RDONLY|O_CLOEXEC) = 3
+read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\0Z\301f8\0\0\0"..., 832) = 832
+fstat(3, {st_mode=S_IFREG|0755, st_size=741088, ...}) = 0
+mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fb0c41c0000
+mmap(NULL, 2828136, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7fb0c3abf000
+mprotect(0x7fb0c3b6f000, 2093056, PROT_NONE) = 0
+mmap(0x7fb0c3d6e000, 16384, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0xaf000) = 0x7fb0c3d6e000
+close(3)                                = 0
+open("/lib64/libsvn_ra-1.so.0", O_RDONLY|O_CLOEXEC) = 3
+read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\260@ \2259\0\0\0"..., 832) = 832
+fstat(3, {st_mode=S_IFREG|0755, st_size=61752, ...}) = 0
+mmap(NULL, 2151568, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7fb0c38b1000
+mprotect(0x7fb0c38be000, 2093056, PROT_NONE) = 0
+mmap(0x7fb0c3abd000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0xc000) = 0x7fb0c3abd000
+close(3)                                = 0
+open("/lib64/libsvn_diff-1.so.0", O_RDONLY|O_CLOEXEC) = 3
+read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\340=\200f8\0\0\0"..., 832) = 832
+fstat(3, {st_mode=S_IFREG|0755, st_size=89768, ...}) = 0
+mmap(NULL, 2180064, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7fb0c369c000
+mprotect(0x7fb0c36b0000, 2093056, PROT_NONE) = 0
+mmap(0x7fb0c38af000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x13000) = 0x7fb0c38af000
+close(3)                                = 0
+open("/lib64/libsvn_ra_local-1.so.0", O_RDONLY|O_CLOEXEC) = 3
+read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0p4\240l8\0\0\0"..., 832) = 832
+fstat(3, {st_mode=S_IFREG|0755, st_size=44720, ...}) = 0
+mmap(NULL, 2134952, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7fb0c3492000
+mprotect(0x7fb0c349a000, 2097152, PROT_NONE) = 0
+mmap(0x7fb0c369a000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x8000) = 0x7fb0c369a000
+close(3)                                = 0
+open("/lib64/libsvn_repos-1.so.0", O_RDONLY|O_CLOEXEC) = 3
+read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0 \227\300h8\0\0\0"..., 832) = 832
+fstat(3, {st_mode=S_IFREG|0755, st_size=223680, ...}) = 0
+mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fb0c41bf000
+mmap(NULL, 2313200, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7fb0c325d000
+mprotect(0x7fb0c3290000, 2097152, PROT_NONE) = 0
+mmap(0x7fb0c3490000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x33000) = 0x7fb0c3490000
+close(3)                                = 0
+open("/lib64/libsvn_fs-1.so.0", O_RDONLY|O_CLOEXEC) = 3
+read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0p:\0h8\0\0\0"..., 832) = 832
+fstat(3, {st_mode=S_IFREG|0755, st_size=48168, ...}) = 0
+mmap(NULL, 2139032, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7fb0c3052000
+mprotect(0x7fb0c305c000, 2093056, PROT_NONE) = 0
+mmap(0x7fb0c325b000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x9000) = 0x7fb0c325b000
+close(3)                                = 0
+open("/lib64/libsvn_fs_fs-1.so.0", O_RDONLY|O_CLOEXEC) = 3
+read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\20\240 at g8\0\0\0"..., 832) = 832
+fstat(3, {st_mode=S_IFREG|0755, st_size=233360, ...}) = 0
+mmap(NULL, 2322088, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7fb0c2e1b000
+mprotect(0x7fb0c2e51000, 2093056, PROT_NONE) = 0
+mmap(0x7fb0c3050000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x35000) = 0x7fb0c3050000
+close(3)                                = 0
+open("/lib64/libsvn_fs_base-1.so.0", O_RDONLY|O_CLOEXEC) = 3
+read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\360\226 m8\0\0\0"..., 832) = 832
+fstat(3, {st_mode=S_IFREG|0755, st_size=204032, ...}) = 0
+mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fb0c41be000
+mmap(NULL, 2293192, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7fb0c2beb000
+mprotect(0x7fb0c2c1a000, 2093056, PROT_NONE) = 0
+mmap(0x7fb0c2e19000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x2e000) = 0x7fb0c2e19000
+close(3)                                = 0
+open("/lib64/libsvn_fs_util-1.so.0", O_RDONLY|O_CLOEXEC) = 3
+read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\200\f\0g8\0\0\0"..., 832) = 832
+fstat(3, {st_mode=S_IFREG|0755, st_size=14064, ...}) = 0
+mmap(NULL, 2105520, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7fb0c29e8000
+mprotect(0x7fb0c29ea000, 2093056, PROT_NONE) = 0
+mmap(0x7fb0c2be9000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1000) = 0x7fb0c2be9000
+close(3)                                = 0
+open("/lib64/libsvn_ra_svn-1.so.0", O_RDONLY|O_CLOEXEC) = 3
+read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\360u at k8\0\0\0"..., 832) = 832
+fstat(3, {st_mode=S_IFREG|0755, st_size=132640, ...}) = 0
+mmap(NULL, 2222232, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7fb0c27c9000
+mprotect(0x7fb0c27e7000, 2093056, PROT_NONE) = 0
+mmap(0x7fb0c29e6000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1d000) = 0x7fb0c29e6000
+close(3)                                = 0
+open("/lib64/libsasl2.so.3", O_RDONLY|O_CLOEXEC) = 3
+read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0`K\30001\0\0\0"..., 832) = 832
+fstat(3, {st_mode=S_IFREG|0755, st_size=122848, ...}) = 0
+mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fb0c41bd000
+mmap(NULL, 2213960, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7fb0c25ac000
+mprotect(0x7fb0c25c8000, 2093056, PROT_NONE) = 0
+mmap(0x7fb0c27c7000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1b000) = 0x7fb0c27c7000
+close(3)                                = 0
+open("/lib64/libsvn_ra_serf-1.so.0", O_RDONLY|O_CLOEXEC) = 3
+read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0000\225`\2239\0\0\0"..., 832) = 832
+fstat(3, {st_mode=S_IFREG|0755, st_size=203848, ...}) = 0
+mmap(NULL, 2292144, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7fb0c237c000
+mprotect(0x7fb0c23a8000, 2093056, PROT_NONE) = 0
+mmap(0x7fb0c25a7000, 20480, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x2b000) = 0x7fb0c25a7000
+close(3)                                = 0
+open("/lib64/libserf-1.so.0", O_RDONLY|O_CLOEXEC) = 3
+read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0P{\240\2239\0\0\0"..., 832) = 832
+fstat(3, {st_mode=S_IFREG|0755, st_size=115968, ...}) = 0
+mmap(NULL, 2205248, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7fb0c2161000
+mprotect(0x7fb0c217b000, 2093056, PROT_NONE) = 0
+mmap(0x7fb0c237a000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x19000) = 0x7fb0c237a000
+close(3)                                = 0
+open("/lib64/libsvn_delta-1.so.0", O_RDONLY|O_CLOEXEC) = 3
+read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\300<\340k8\0\0\0"..., 832) = 832
+fstat(3, {st_mode=S_IFREG|0755, st_size=85944, ...}) = 0
+mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fb0c41bc000
+mmap(NULL, 2176072, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7fb0c1f4d000
+mprotect(0x7fb0c1f5f000, 2097152, PROT_NONE) = 0
+mmap(0x7fb0c215f000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x12000) = 0x7fb0c215f000
+close(3)                                = 0
+open("/lib64/libsvn_subr-1.so.0", O_RDONLY|O_CLOEXEC) = 3
+read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0000\266\341l8\0\0\0"..., 832) = 832
+fstat(3, {st_mode=S_IFREG|0755, st_size=523360, ...}) = 0
+mmap(NULL, 2611640, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7fb0c1ccf000
+mprotect(0x7fb0c1d48000, 2097152, PROT_NONE) = 0
+mmap(0x7fb0c1f48000, 20480, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x79000) = 0x7fb0c1f48000
+close(3)                                = 0
+open("/lib64/libz.so.1", O_RDONLY|O_CLOEXEC) = 3
+read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\20\"@\r1\0\0\0"..., 832) = 832
+fstat(3, {st_mode=S_IFREG|0755, st_size=92560, ...}) = 0
+mmap(NULL, 2183688, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7fb0c1ab9000
+mprotect(0x7fb0c1ace000, 2093056, PROT_NONE) = 0
+mmap(0x7fb0c1ccd000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x14000) = 0x7fb0c1ccd000
+close(3)                                = 0
+open("/lib64/libsqlite3.so.0", O_RDONLY|O_CLOEXEC) = 3
+read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0000\260\0k8\0\0\0"..., 832) = 832
+fstat(3, {st_mode=S_IFREG|0755, st_size=792288, ...}) = 0
+mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fb0c41bb000
+mmap(NULL, 2873304, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7fb0c17fb000
+mprotect(0x7fb0c18b4000, 2097152, PROT_NONE) = 0
+mmap(0x7fb0c1ab4000, 20480, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0xb9000) = 0x7fb0c1ab4000
+close(3)                                = 0
+open("/lib64/libmagic.so.1", O_RDONLY|O_CLOEXEC) = 3
+read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0`D\340\0321\0\0\0"..., 832) = 832
+fstat(3, {st_mode=S_IFREG|0755, st_size=126128, ...}) = 0
+mmap(NULL, 2217848, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7fb0c15dd000
+mprotect(0x7fb0c15f9000, 2097152, PROT_NONE) = 0
+mmap(0x7fb0c17f9000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1c000) = 0x7fb0c17f9000
+close(3)                                = 0
+open("/lib64/libaprutil-1.so.0", O_RDONLY|O_CLOEXEC) = 3
+read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0@\232\340\0351\0\0\0"..., 832) = 832
+fstat(3, {st_mode=S_IFREG|0755, st_size=173416, ...}) = 0
+mmap(NULL, 2263848, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7fb0c13b4000
+mprotect(0x7fb0c13dc000, 2093056, PROT_NONE) = 0
+mmap(0x7fb0c15db000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x27000) = 0x7fb0c15db000
+close(3)                                = 0
+open("/lib64/libcrypt.so.1", O_RDONLY|O_CLOEXEC) = 3
+read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\320\16\200(1\0\0\0"..., 832) = 832
+fstat(3, {st_mode=S_IFREG|0755, st_size=43848, ...}) = 0
+mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fb0c41ba000
+mmap(NULL, 2318912, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7fb0c117d000
+mprotect(0x7fb0c1185000, 2093056, PROT_NONE) = 0
+mmap(0x7fb0c1384000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x7000) = 0x7fb0c1384000
+mmap(0x7fb0c1386000, 184896, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7fb0c1386000
+close(3)                                = 0
+open("/lib64/libexpat.so.1", O_RDONLY|O_CLOEXEC) = 3
+read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\0>@\0221\0\0\0"..., 832) = 832
+fstat(3, {st_mode=S_IFREG|0755, st_size=175384, ...}) = 0
+mmap(NULL, 2265312, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7fb0c0f53000
+mprotect(0x7fb0c0f7a000, 2097152, PROT_NONE) = 0
+mmap(0x7fb0c117a000, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x27000) = 0x7fb0c117a000
+close(3)                                = 0
+open("/lib64/libdb-5.3.so", O_RDONLY|O_CLOEXEC) = 3
+read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\220\362\"\0341\0\0\0"..., 832) = 832
+fstat(3, {st_mode=S_IFREG|0755, st_size=1840560, ...}) = 0
+mmap(NULL, 3927304, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7fb0c0b94000
+mprotect(0x7fb0c0d49000, 2097152, PROT_NONE) = 0
+mmap(0x7fb0c0f49000, 40960, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1b5000) = 0x7fb0c0f49000
+close(3)                                = 0
+open("/lib64/libapr-1.so.0", O_RDONLY|O_CLOEXEC) = 3
+read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0 \316\240\0361\0\0\0"..., 832) = 832
+fstat(3, {st_mode=S_IFREG|0755, st_size=219224, ...}) = 0
+mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fb0c41b9000
+mmap(NULL, 2309880, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7fb0c0960000
+mprotect(0x7fb0c0992000, 2097152, PROT_NONE) = 0
+mmap(0x7fb0c0b92000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x32000) = 0x7fb0c0b92000
+close(3)                                = 0
+open("/lib64/libpthread.so.0", O_RDONLY|O_CLOEXEC) = 3
+read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\340m\0\r1\0\0\0"..., 832) = 832
+fstat(3, {st_mode=S_IFREG|0755, st_size=150800, ...}) = 0
+mmap(NULL, 2213104, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7fb0c0743000
+mprotect(0x7fb0c075b000, 2093056, PROT_NONE) = 0
+mmap(0x7fb0c095a000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x17000) = 0x7fb0c095a000
+mmap(0x7fb0c095c000, 13552, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7fb0c095c000
+close(3)                                = 0
+open("/lib64/libdl.so.2", O_RDONLY|O_CLOEXEC) = 3
+read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\320\16\300\f1\0\0\0"..., 832) = 832
+fstat(3, {st_mode=S_IFREG|0755, st_size=22440, ...}) = 0
+mmap(NULL, 2109744, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7fb0c053f000
+mprotect(0x7fb0c0542000, 2093056, PROT_NONE) = 0
+mmap(0x7fb0c0741000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x2000) = 0x7fb0c0741000
+close(3)                                = 0
+open("/lib64/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
+read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0p\36B\f1\0\0\0"..., 832) = 832
+fstat(3, {st_mode=S_IFREG|0755, st_size=2100672, ...}) = 0
+mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fb0c41b8000
+mmap(NULL, 3924576, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7fb0c0180000
+mprotect(0x7fb0c0334000, 2097152, PROT_NONE) = 0
+mmap(0x7fb0c0534000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1b4000) = 0x7fb0c0534000
+mmap(0x7fb0c053a000, 16992, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7fb0c053a000
+close(3)                                = 0
+mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fb0c41b7000
+open("/lib64/libresolv.so.2", O_RDONLY|O_CLOEXEC) = 3
+read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0@:\300\0161\0\0\0"..., 832) = 832
+fstat(3, {st_mode=S_IFREG|0755, st_size=113808, ...}) = 0
+mmap(NULL, 2202264, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7fb0bff66000
+mprotect(0x7fb0bff7c000, 2097152, PROT_NONE) = 0
+mmap(0x7fb0c017c000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x16000) = 0x7fb0c017c000
+mmap(0x7fb0c017e000, 6808, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7fb0c017e000
+close(3)                                = 0
+open("/usr/lib64/tls/x86_64/libssl.so.10", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
+stat("/usr/lib64/tls/x86_64", 0x7fff60105170) = -1 ENOENT (No such file or directory)
+open("/usr/lib64/tls/libssl.so.10", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
+stat("/usr/lib64/tls", {st_mode=S_IFDIR|0555, st_size=4096, ...}) = 0
+open("/usr/lib64/x86_64/libssl.so.10", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
+stat("/usr/lib64/x86_64", 0x7fff60105170) = -1 ENOENT (No such file or directory)
+open("/usr/lib64/libssl.so.10", O_RDONLY|O_CLOEXEC) = 3
+read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\300\203\1\0271\0\0\0"..., 832) = 832
+fstat(3, {st_mode=S_IFREG|0755, st_size=446080, ...}) = 0
+mmap(NULL, 2536528, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7fb0bfcfa000
+mprotect(0x7fb0bfd5c000, 2093056, PROT_NONE) = 0
+mmap(0x7fb0bff5b000, 45056, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x61000) = 0x7fb0bff5b000
+close(3)                                = 0
+open("/usr/lib64/tls/libcrypto.so.10", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
+open("/usr/lib64/libcrypto.so.10", O_RDONLY|O_CLOEXEC) = 3
+read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0@\234F\0251\0\0\0"..., 832) = 832
+fstat(3, {st_mode=S_IFREG|0755, st_size=1993248, ...}) = 0
+mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fb0c41b6000
+mmap(NULL, 4091768, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7fb0bf913000
+mprotect(0x7fb0bfad0000, 2093056, PROT_NONE) = 0
+mmap(0x7fb0bfccf000, 159744, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1bc000) = 0x7fb0bfccf000
+mmap(0x7fb0bfcf6000, 16248, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7fb0bfcf6000
+close(3)                                = 0
+open("/usr/lib64/tls/libldap_r-2.4.so.2", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
+open("/usr/lib64/libldap_r-2.4.so.2", O_RDONLY|O_CLOEXEC) = 3
+read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\200\23\241\2229\0\0\0"..., 832) = 832
+fstat(3, {st_mode=S_IFREG|0755, st_size=365848, ...}) = 0
+mmap(NULL, 2465032, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7fb0bf6b9000
+mprotect(0x7fb0bf70e000, 2093056, PROT_NONE) = 0
+mmap(0x7fb0bf90d000, 16384, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x54000) = 0x7fb0bf90d000
+mmap(0x7fb0bf911000, 7432, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7fb0bf911000
+close(3)                                = 0
+open("/usr/lib64/tls/liblber-2.4.so.2", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
+open("/usr/lib64/liblber-2.4.so.2", O_RDONLY|O_CLOEXEC) = 3
+read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\3206\30011\0\0\0"..., 832) = 832
+fstat(3, {st_mode=S_IFREG|0755, st_size=64280, ...}) = 0
+mmap(NULL, 2155848, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7fb0bf4aa000
+mprotect(0x7fb0bf4b8000, 2093056, PROT_NONE) = 0
+mmap(0x7fb0bf6b7000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0xd000) = 0x7fb0bf6b7000
+close(3)                                = 0
+open("/usr/lib64/tls/libgssapi_krb5.so.2", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
+open("/usr/lib64/libgssapi_krb5.so.2", O_RDONLY|O_CLOEXEC) = 3
+read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\20\275@\0261\0\0\0"..., 832) = 832
+fstat(3, {st_mode=S_IFREG|0755, st_size=310624, ...}) = 0
+mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fb0c41b5000
+mmap(NULL, 2398304, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7fb0bf260000
+mprotect(0x7fb0bf2a7000, 2097152, PROT_NONE) = 0
+mmap(0x7fb0bf4a7000, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x47000) = 0x7fb0bf4a7000
+close(3)                                = 0
+open("/usr/lib64/tls/libkrb5.so.3", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
+open("/usr/lib64/libkrb5.so.3", O_RDONLY|O_CLOEXEC) = 3
+read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\240Q\202\0261\0\0\0"..., 832) = 832
+fstat(3, {st_mode=S_IFREG|0755, st_size=929904, ...}) = 0
+mmap(NULL, 3012704, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7fb0bef80000
+mprotect(0x7fb0bf050000, 2093056, PROT_NONE) = 0
+mmap(0x7fb0bf24f000, 69632, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0xcf000) = 0x7fb0bf24f000
+close(3)                                = 0
+open("/usr/lib64/tls/libk5crypto.so.3", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
+open("/usr/lib64/libk5crypto.so.3", O_RDONLY|O_CLOEXEC) = 3
+read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\260H\0\0261\0\0\0"..., 832) = 832
+fstat(3, {st_mode=S_IFREG|0755, st_size=217248, ...}) = 0
+mmap(NULL, 2310640, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7fb0bed4b000
+mprotect(0x7fb0bed7d000, 2093056, PROT_NONE) = 0
+mmap(0x7fb0bef7c000, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x31000) = 0x7fb0bef7c000
+mmap(0x7fb0bef7f000, 496, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7fb0bef7f000
+close(3)                                = 0
+open("/usr/lib64/tls/libcom_err.so.2", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
+open("/usr/lib64/libcom_err.so.2", O_RDONLY|O_CLOEXEC) = 3
+read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0p\25\0\0251\0\0\0"..., 832) = 832
+fstat(3, {st_mode=S_IFREG|0755, st_size=18320, ...}) = 0
+mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fb0c41b4000
+mmap(NULL, 2109928, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7fb0beb47000
+mprotect(0x7fb0beb4a000, 2093056, PROT_NONE) = 0
+mmap(0x7fb0bed49000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x2000) = 0x7fb0bed49000
+close(3)                                = 0
+open("/lib64/libuuid.so.1", O_RDONLY|O_CLOEXEC) = 3
+read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\20\25\300\0201\0\0\0"..., 832) = 832
+fstat(3, {st_mode=S_IFREG|0755, st_size=22624, ...}) = 0
+mmap(NULL, 2113920, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7fb0be942000
+mprotect(0x7fb0be946000, 2093056, PROT_NONE) = 0
+mmap(0x7fb0beb45000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x3000) = 0x7fb0beb45000
+close(3)                                = 0
+open("/lib64/libfreebl3.so", O_RDONLY|O_CLOEXEC) = 3
+read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\200>\200'1\0\0\0"..., 832) = 832
+fstat(3, {st_mode=S_IFREG|0755, st_size=517384, ...}) = 0
+mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fb0c41b3000
+mmap(NULL, 2619232, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7fb0be6c2000
+mprotect(0x7fb0be73c000, 2093056, PROT_NONE) = 0
+mmap(0x7fb0be93b000, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x79000) = 0x7fb0be93b000
+mmap(0x7fb0be93e000, 14176, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7fb0be93e000
+close(3)                                = 0
+open("/usr/lib64/tls/libssl3.so", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
+open("/usr/lib64/libssl3.so", O_RDONLY|O_CLOEXEC) = 3
+read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\220\260`\2219\0\0\0"..., 832) = 832
+fstat(3, {st_mode=S_IFREG|0755, st_size=262984, ...}) = 0
+mmap(NULL, 2351976, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7fb0be483000
+mprotect(0x7fb0be4be000, 2093056, PROT_NONE) = 0
+mmap(0x7fb0be6bd000, 16384, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x3a000) = 0x7fb0be6bd000
+mmap(0x7fb0be6c1000, 872, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7fb0be6c1000
+close(3)                                = 0
+open("/usr/lib64/tls/libsmime3.so", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
+open("/usr/lib64/libsmime3.so", O_RDONLY|O_CLOEXEC) = 3
+read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0`\236\240\2219\0\0\0"..., 832) = 832
+fstat(3, {st_mode=S_IFREG|0755, st_size=192376, ...}) = 0
+mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fb0c41b2000
+mmap(NULL, 2280576, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7fb0be256000
+mprotect(0x7fb0be27f000, 2093056, PROT_NONE) = 0
+mmap(0x7fb0be47e000, 20480, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x28000) = 0x7fb0be47e000
+close(3)                                = 0
+open("/usr/lib64/tls/libnss3.so", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
+open("/usr/lib64/libnss3.so", O_RDONLY|O_CLOEXEC) = 3
+read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\0\232\341\2209\0\0\0"..., 832) = 832
+fstat(3, {st_mode=S_IFREG|0755, st_size=1360352, ...}) = 0
+mmap(NULL, 3434440, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7fb0bdf0f000
+mprotect(0x7fb0be04e000, 2093056, PROT_NONE) = 0
+mmap(0x7fb0be24d000, 32768, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x13e000) = 0x7fb0be24d000
+mmap(0x7fb0be255000, 1992, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7fb0be255000
+close(3)                                = 0
+open("/usr/lib64/tls/libnssutil3.so", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
+open("/usr/lib64/libnssutil3.so", O_RDONLY|O_CLOEXEC) = 3
+read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\20\276 \2219\0\0\0"..., 832) = 832
+fstat(3, {st_mode=S_IFREG|0755, st_size=184296, ...}) = 0
+mmap(NULL, 2275936, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7fb0bdce3000
+mprotect(0x7fb0bdd08000, 2097152, PROT_NONE) = 0
+mmap(0x7fb0bdf08000, 28672, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x25000) = 0x7fb0bdf08000
+close(3)                                = 0
+open("/usr/lib64/tls/libplds4.so", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
+open("/usr/lib64/libplds4.so", O_RDONLY|O_CLOEXEC) = 3
+read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\220\20`\2209\0\0\0"..., 832) = 832
+fstat(3, {st_mode=S_IFREG|0755, st_size=18168, ...}) = 0
+mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fb0c41b1000
+mmap(NULL, 2109800, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7fb0bdadf000
+mprotect(0x7fb0bdae2000, 2093056, PROT_NONE) = 0
+mmap(0x7fb0bdce1000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x2000) = 0x7fb0bdce1000
+close(3)                                = 0
+open("/usr/lib64/tls/libplc4.so", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
+open("/usr/lib64/libplc4.so", O_RDONLY|O_CLOEXEC) = 3
+read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\20\25\240\2209\0\0\0"..., 832) = 832
+fstat(3, {st_mode=S_IFREG|0755, st_size=22272, ...}) = 0
+mmap(NULL, 2113936, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7fb0bd8da000
+mprotect(0x7fb0bd8de000, 2093056, PROT_NONE) = 0
+mmap(0x7fb0bdadd000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x3000) = 0x7fb0bdadd000
+close(3)                                = 0
+open("/usr/lib64/tls/libnspr4.so", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
+open("/usr/lib64/libnspr4.so", O_RDONLY|O_CLOEXEC) = 3
+read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\340\321 \2209\0\0\0"..., 832) = 832
+fstat(3, {st_mode=S_IFREG|0755, st_size=251552, ...}) = 0
+mmap(NULL, 2350496, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7fb0bd69c000
+mprotect(0x7fb0bd6d6000, 2093056, PROT_NONE) = 0
+mmap(0x7fb0bd8d5000, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x39000) = 0x7fb0bd8d5000
+mmap(0x7fb0bd8d8000, 7584, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7fb0bd8d8000
+close(3)                                = 0
+open("/usr/lib64/tls/libkrb5support.so.0", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
+open("/usr/lib64/libkrb5support.so.0", O_RDONLY|O_CLOEXEC) = 3
+read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0 6\300\0261\0\0\0"..., 832) = 832
+fstat(3, {st_mode=S_IFREG|0755, st_size=60896, ...}) = 0
+mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fb0c41b0000
+mmap(NULL, 2152008, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7fb0bd48e000
+mprotect(0x7fb0bd49b000, 2093056, PROT_NONE) = 0
+mmap(0x7fb0bd69a000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0xc000) = 0x7fb0bd69a000
+close(3)                                = 0
+open("/usr/lib64/tls/libkeyutils.so.1", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
+open("/usr/lib64/libkeyutils.so.1", O_RDONLY|O_CLOEXEC) = 3
+read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0p\25\200\0251\0\0\0"..., 832) = 832
+fstat(3, {st_mode=S_IFREG|0755, st_size=17984, ...}) = 0
+mmap(NULL, 2109712, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7fb0bd28a000
+mprotect(0x7fb0bd28d000, 2093056, PROT_NONE) = 0
+mmap(0x7fb0bd48c000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x2000) = 0x7fb0bd48c000
+close(3)                                = 0
+open("/usr/lib64/tls/librt.so.1", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
+open("/usr/lib64/librt.so.1", O_RDONLY|O_CLOEXEC) = 3
+read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\320\"\200\0161\0\0\0"..., 832) = 832
+fstat(3, {st_mode=S_IFREG|0755, st_size=47400, ...}) = 0
+mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fb0c41af000
+mmap(NULL, 2128952, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7fb0bd082000
+mprotect(0x7fb0bd089000, 2093056, PROT_NONE) = 0
+mmap(0x7fb0bd288000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x6000) = 0x7fb0bd288000
+close(3)                                = 0
+open("/usr/lib64/tls/libselinux.so.1", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
+open("/usr/lib64/libselinux.so.1", O_RDONLY|O_CLOEXEC) = 3
+read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\240d@\0161\0\0\0"..., 832) = 832
+fstat(3, {st_mode=S_IFREG|0755, st_size=144952, ...}) = 0
+mmap(NULL, 2242712, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7fb0bce5e000
+mprotect(0x7fb0bce7f000, 2093056, PROT_NONE) = 0
+mmap(0x7fb0bd07e000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x20000) = 0x7fb0bd07e000
+mmap(0x7fb0bd080000, 6296, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7fb0bd080000
+close(3)                                = 0
+open("/usr/lib64/tls/libpcre.so.1", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
+open("/usr/lib64/libpcre.so.1", O_RDONLY|O_CLOEXEC) = 3
+read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0p\27\0\0161\0\0\0"..., 832) = 832
+fstat(3, {st_mode=S_IFREG|0755, st_size=421144, ...}) = 0
+mmap(NULL, 2511368, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7fb0bcbf8000
+mprotect(0x7fb0bcc5d000, 2093056, PROT_NONE) = 0
+mmap(0x7fb0bce5c000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x64000) = 0x7fb0bce5c000
+close(3)                                = 0
+open("/usr/lib64/tls/liblzma.so.5", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
+open("/usr/lib64/liblzma.so.5", O_RDONLY|O_CLOEXEC) = 3
+read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\3400\300\r1\0\0\0"..., 832) = 832
+fstat(3, {st_mode=S_IFREG|0755, st_size=155400, ...}) = 0
+mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fb0c41ae000
+mmap(NULL, 2245240, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7fb0bc9d3000
+mprotect(0x7fb0bc9f7000, 2093056, PROT_NONE) = 0
+mmap(0x7fb0bcbf6000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x23000) = 0x7fb0bcbf6000
+close(3)                                = 0
+mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fb0c41ad000
+mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fb0c41ac000
+mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fb0c41ab000
+mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fb0c41aa000
+mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fb0c41a8000
+arch_prctl(ARCH_SET_FS, 0x7fb0c41a8880) = 0
+mprotect(0x7fb0c0534000, 16384, PROT_READ) = 0
+mprotect(0x7fb0c095a000, 4096, PROT_READ) = 0
+mprotect(0x7fb0bcbf6000, 4096, PROT_READ) = 0
+mprotect(0x7fb0bce5c000, 4096, PROT_READ) = 0
+mprotect(0x7fb0c0741000, 4096, PROT_READ) = 0
+mprotect(0x7fb0bd07e000, 4096, PROT_READ) = 0
+mprotect(0x7fb0bd288000, 4096, PROT_READ) = 0
+mprotect(0x7fb0bd48c000, 4096, PROT_READ) = 0
+mprotect(0x7fb0c017c000, 4096, PROT_READ) = 0
+mprotect(0x7fb0bd69a000, 4096, PROT_READ) = 0
+mprotect(0x7fb0bd8d5000, 4096, PROT_READ) = 0
+mprotect(0x7fb0bdadd000, 4096, PROT_READ) = 0
+mprotect(0x7fb0bdce1000, 4096, PROT_READ) = 0
+mprotect(0x7fb0bdf08000, 24576, PROT_READ) = 0
+mprotect(0x7fb0be24d000, 20480, PROT_READ) = 0
+mprotect(0x7fb0be47e000, 16384, PROT_READ) = 0
+mprotect(0x7fb0c1ccd000, 4096, PROT_READ) = 0
+mprotect(0x7fb0be6bd000, 12288, PROT_READ) = 0
+mprotect(0x7fb0be93b000, 8192, PROT_READ) = 0
+mprotect(0x7fb0beb45000, 4096, PROT_READ) = 0
+mprotect(0x7fb0bed49000, 4096, PROT_READ) = 0
+mprotect(0x7fb0bef7c000, 8192, PROT_READ) = 0
+mprotect(0x7fb0bf24f000, 57344, PROT_READ) = 0
+mprotect(0x7fb0bf4a7000, 4096, PROT_READ) = 0
+mprotect(0x7fb0bf6b7000, 4096, PROT_READ) = 0
+mprotect(0x7fb0c1384000, 4096, PROT_READ) = 0
+mprotect(0x7fb0c27c7000, 4096, PROT_READ) = 0
+mprotect(0x7fb0bf90d000, 8192, PROT_READ) = 0
+mprotect(0x7fb0bfccf000, 110592, PROT_READ) = 0
+mprotect(0x7fb0bff5b000, 16384, PROT_READ) = 0
+mprotect(0x7fb0c0b92000, 4096, PROT_READ) = 0
+mprotect(0x7fb0c0f49000, 28672, PROT_READ) = 0
+mprotect(0x7fb0c117a000, 8192, PROT_READ) = 0
+mprotect(0x7fb0c15db000, 4096, PROT_READ) = 0
+mprotect(0x7fb0c17f9000, 4096, PROT_READ) = 0
+mprotect(0x7fb0c1ab4000, 8192, PROT_READ) = 0
+mprotect(0x7fb0c1f48000, 12288, PROT_READ) = 0
+mprotect(0x7fb0c215f000, 4096, PROT_READ) = 0
+mprotect(0x7fb0c237a000, 4096, PROT_READ) = 0
+mprotect(0x7fb0c25a7000, 16384, PROT_READ) = 0
+mprotect(0x7fb0c29e6000, 4096, PROT_READ) = 0
+mprotect(0x7fb0c2be9000, 4096, PROT_READ) = 0
+mprotect(0x7fb0c2e19000, 4096, PROT_READ) = 0
+mprotect(0x7fb0c3050000, 4096, PROT_READ) = 0
+mprotect(0x7fb0c325b000, 4096, PROT_READ) = 0
+mprotect(0x7fb0c3490000, 4096, PROT_READ) = 0
+mprotect(0x7fb0c369a000, 4096, PROT_READ) = 0
+mprotect(0x7fb0c38af000, 4096, PROT_READ) = 0
+mprotect(0x7fb0c3abd000, 4096, PROT_READ) = 0
+mprotect(0x7fb0c3d6e000, 8192, PROT_READ) = 0
+mprotect(0x7fb0c3fd4000, 4096, PROT_READ) = 0
+mprotect(0x7fb0c4431000, 49152, PROT_READ) = 0
+mprotect(0x7fb0c41f6000, 4096, PROT_READ) = 0
+munmap(0x7fb0c41c1000, 212134)          = 0
+set_tid_address(0x7fb0c41a8b50)         = 5383
+set_robust_list(0x7fb0c41a8b60, 24)     = 0
+rt_sigaction(SIGRTMIN, {0x7fb0c07498c0, [], SA_RESTORER|SA_SIGINFO, 0x7fb0c0752750}, NULL, 8) = 0
+rt_sigaction(SIGRT_1, {0x7fb0c0749950, [], SA_RESTORER|SA_RESTART|SA_SIGINFO, 0x7fb0c0752750}, NULL, 8) = 0
+rt_sigprocmask(SIG_UNBLOCK, [RTMIN RT_1], NULL, 8) = 0
+getrlimit(RLIMIT_STACK, {rlim_cur=8192*1024, rlim_max=RLIM64_INFINITY}) = 0
+statfs("/sys/fs/selinux", 0x7fff60106060) = -1 ENOENT (No such file or directory)
+statfs("/selinux", 0x7fff60106060)      = -1 ENOENT (No such file or directory)
+brk(0)                                  = 0x7fb0c4d8b000
+brk(0x7fb0c4dac000)                     = 0x7fb0c4dac000
+open("/proc/filesystems", O_RDONLY)     = 3
+fstat(3, {st_mode=S_IFREG|0444, st_size=0, ...}) = 0
+mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fb0c41f4000
+read(3, "nodev\tsysfs\nnodev\trootfs\nnodev\tr"..., 1024) = 384
+read(3, "", 1024)                       = 0
+close(3)                                = 0
+munmap(0x7fb0c41f4000, 4096)            = 0
+access("/etc/system-fips", F_OK)        = -1 ENOENT (No such file or directory)
+fstat(0, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 2), ...}) = 0
+fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 2), ...}) = 0
+fstat(2, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 2), ...}) = 0
+open("/usr/lib/locale/locale-archive", O_RDONLY|O_CLOEXEC) = 3
+fstat(3, {st_mode=S_IFREG|0644, st_size=106070960, ...}) = 0
+mmap(NULL, 106070960, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7fb0b64aa000
+close(3)                                = 0
+open("/usr/share/locale/locale.alias", O_RDONLY|O_CLOEXEC) = 3
+fstat(3, {st_mode=S_IFREG|0644, st_size=2492, ...}) = 0
+mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fb0c41f4000
+read(3, "# Locale name alias data base.\n#"..., 4096) = 2492
+read(3, "", 4096)                       = 0
+close(3)                                = 0
+munmap(0x7fb0c41f4000, 4096)            = 0
+open("/usr/lib/locale/A4/LC_PAPER", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
+ioctl(0, SNDCTL_TMR_TIMEBASE or SNDRV_TIMER_IOCTL_NEXT_DEVICE or TCGETS, {B38400 opost isig icanon echo ...}) = 0
+stat("/localhome/mea/.subversion", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
+lstat("/localhome/mea/.subversion/auth", {st_mode=S_IFDIR|0700, st_size=4096, ...}) = 0
+lstat("/localhome/mea/.subversion/auth/svn.simple", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
+lstat("/localhome/mea/.subversion/auth/svn.username", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
+lstat("/localhome/mea/.subversion/auth/svn.ssl.server", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
+lstat("/localhome/mea/.subversion/auth/svn.ssl.client-passphrase", {st_mode=S_IFDIR|0775, st_size=4096, ...}) = 0
+lstat("/localhome/mea/.subversion/README.txt", {st_mode=S_IFREG|0644, st_size=4277, ...}) = 0
+lstat("/localhome/mea/.subversion/servers", {st_mode=S_IFREG|0644, st_size=3270, ...}) = 0
+lstat("/localhome/mea/.subversion/config", {st_mode=S_IFREG|0664, st_size=4749, ...}) = 0
+open("/etc/subversion/servers", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
+open("/localhome/mea/.subversion/servers", O_RDONLY|O_CLOEXEC) = 3
+fcntl(3, F_GETFD)                       = 0x1 (flags FD_CLOEXEC)
+brk(0)                                  = 0x7fb0c4dac000
+brk(0x7fb0c4ddc000)                     = 0x7fb0c4ddc000
+read(3, "### This file specifies server-s"..., 4096) = 3270
+read(3, "", 4096)                       = 0
+read(3, "", 4096)                       = 0
+read(3, "", 4096)                       = 0
+close(3)                                = 0
+open("/etc/subversion/config", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
+open("/localhome/mea/.subversion/config", O_RDONLY|O_CLOEXEC) = 3
+read(3, "### This file configures various"..., 4096) = 4096
+read(3, " is:\n###   file-name-pattern = p"..., 4096) = 653
+read(3, "", 4096)                       = 0
+read(3, "", 4096)                       = 0
+read(3, "", 4096)                       = 0
+close(3)                                = 0
+stat("Add note about USB serial ports benefitting of interface timeout parameter.", 0x7fff60105ca0) = -1 ENOENT (No such file or directory)
+getcwd("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk", 4096) = 77
+rt_sigaction(SIGINT, {0x7fb0c4216ad0, [], SA_RESTORER|SA_INTERRUPT, 0x7fb0c0752750}, {SIG_DFL, [], 0}, 8) = 0
+rt_sigaction(SIGHUP, {0x7fb0c4216ad0, [], SA_RESTORER|SA_INTERRUPT, 0x7fb0c0752750}, {SIG_DFL, [], 0}, 8) = 0
+rt_sigaction(SIGTERM, {0x7fb0c4216ad0, [], SA_RESTORER|SA_INTERRUPT, 0x7fb0c0752750}, {SIG_DFL, [], 0}, 8) = 0
+rt_sigaction(SIGPIPE, {SIG_IGN, [], SA_RESTORER|SA_INTERRUPT, 0x7fb0c0752750}, {SIG_DFL, [], 0}, 8) = 0
+rt_sigaction(SIGXFSZ, {SIG_IGN, [], SA_RESTORER|SA_INTERRUPT, 0x7fb0c0752750}, {SIG_DFL, [], 0}, 8) = 0
+getcwd("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk", 4096) = 77
+getcwd("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk", 4096) = 77
+lstat("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/doc", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
+lstat("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/doc/.svn", 0x7fff60105720) = -1 ENOENT (No such file or directory)
+lstat("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn", {st_mode=S_IFDIR|0755, st_size=43, ...}) = 0
+lstat("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db", {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+stat("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db", {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+open("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db", O_RDWR|O_CLOEXEC) = 3
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+stat("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db", {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+lseek(3, 0, SEEK_SET)                   = 0
+read(3, "SQLite format 3\0\4\0\1\1\0@  \0\0\5\237\0\0\0\241"..., 100) = 100
+brk(0)                                  = 0x7fb0c4ddc000
+brk(0x7fb0c4e09000)                     = 0x7fb0c4e09000
+fcntl(3, F_SETLK, {type=F_RDLCK, whence=SEEK_SET, start=1073741824, len=1}) = 0
+fcntl(3, F_SETLK, {type=F_RDLCK, whence=SEEK_SET, start=1073741826, len=510}) = 0
+fcntl(3, F_SETLK, {type=F_UNLCK, whence=SEEK_SET, start=1073741824, len=1}) = 0
+access("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db-journal", F_OK) = -1 ENOENT (No such file or directory)
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+access("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db-wal", F_OK) = -1 ENOENT (No such file or directory)
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+lseek(3, 0, SEEK_SET)                   = 0
+read(3, "SQLite format 3\0\4\0\1\1\0@  \0\0\5\237\0\0\0\241"..., 1024) = 1024
+lseek(3, 11264, SEEK_SET)               = 11264
+read(3, "\r\0\0\0\t\0x\0\0x\1\25\1J\1\234\1\342\2(\2\242\2\317\0030\0\0\0\0\0\0"..., 1024) = 1024
+lseek(3, 14336, SEEK_SET)               = 14336
+read(3, "\r\3+\0\3\0\204\0\0\204\0\265\2\364\3+\3\227\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 1024) = 1024
+lseek(3, 19456, SEEK_SET)               = 19456
+read(3, "\r\0\0\0\5\0017\0\0017\2D\2m\2\354\3\321\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 1024) = 1024
+lseek(3, 25600, SEEK_SET)               = 25600
+read(3, "\r\3\230\0\2\0\233\0\0\233\3m\3\230\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 1024) = 1024
+lseek(3, 27648, SEEK_SET)               = 27648
+read(3, "\r\0\0\0\4\0\335\0\0\335\1\347\2L\3&\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 1024) = 1024
+lseek(3, 28672, SEEK_SET)               = 28672
+read(3, "\r\0\0\0\2\0\330\0\0\330\2'\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 1024) = 1024
+lseek(3, 33792, SEEK_SET)               = 33792
+read(3, "\r\2\234\0\6\0E\0\2i\3\n\2\2\1\250\0\374\0E\0\0\0\0\0\0\0\0\0\0\0\0"..., 1024) = 1024
+fcntl(3, F_SETLK, {type=F_UNLCK, whence=SEEK_SET, start=0, len=0}) = 0
+fcntl(3, F_SETLK, {type=F_RDLCK, whence=SEEK_SET, start=1073741824, len=1}) = 0
+fcntl(3, F_SETLK, {type=F_RDLCK, whence=SEEK_SET, start=1073741826, len=510}) = 0
+fcntl(3, F_SETLK, {type=F_UNLCK, whence=SEEK_SET, start=1073741824, len=1}) = 0
+access("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db-journal", F_OK) = -1 ENOENT (No such file or directory)
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+lseek(3, 24, SEEK_SET)                  = 24
+read(3, "\0\0\5\237\0\0\0\241\0\0\0v\0\0\0\1", 16) = 16
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+access("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db-wal", F_OK) = -1 ENOENT (No such file or directory)
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+lseek(3, 8192, SEEK_SET)                = 8192
+read(3, "\n\0\0\0\1\3\374\0\3\374\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 1024) = 1024
+fcntl(3, F_SETLK, {type=F_UNLCK, whence=SEEK_SET, start=0, len=0}) = 0
+fcntl(3, F_SETLK, {type=F_RDLCK, whence=SEEK_SET, start=1073741824, len=1}) = 0
+fcntl(3, F_SETLK, {type=F_RDLCK, whence=SEEK_SET, start=1073741826, len=510}) = 0
+fcntl(3, F_SETLK, {type=F_UNLCK, whence=SEEK_SET, start=1073741824, len=1}) = 0
+access("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db-journal", F_OK) = -1 ENOENT (No such file or directory)
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+lseek(3, 24, SEEK_SET)                  = 24
+read(3, "\0\0\5\237\0\0\0\241\0\0\0v\0\0\0\1", 16) = 16
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+access("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db-wal", F_OK) = -1 ENOENT (No such file or directory)
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+fcntl(3, F_SETLK, {type=F_UNLCK, whence=SEEK_SET, start=0, len=0}) = 0
+fcntl(3, F_SETLK, {type=F_RDLCK, whence=SEEK_SET, start=1073741824, len=1}) = 0
+fcntl(3, F_SETLK, {type=F_RDLCK, whence=SEEK_SET, start=1073741826, len=510}) = 0
+fcntl(3, F_SETLK, {type=F_UNLCK, whence=SEEK_SET, start=1073741824, len=1}) = 0
+access("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db-journal", F_OK) = -1 ENOENT (No such file or directory)
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+lseek(3, 24, SEEK_SET)                  = 24
+read(3, "\0\0\5\237\0\0\0\241\0\0\0v\0\0\0\1", 16) = 16
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+access("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db-wal", F_OK) = -1 ENOENT (No such file or directory)
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+lseek(3, 20480, SEEK_SET)               = 20480
+read(3, "\r\0\0\0\0\4\0\0\2\230\2\230\2\230\2\230\2\230\2\230\2\230\2\230\2\230\1\232\1\232\1\232"..., 1024) = 1024
+fcntl(3, F_SETLK, {type=F_UNLCK, whence=SEEK_SET, start=0, len=0}) = 0
+fcntl(3, F_SETLK, {type=F_RDLCK, whence=SEEK_SET, start=1073741824, len=1}) = 0
+fcntl(3, F_SETLK, {type=F_RDLCK, whence=SEEK_SET, start=1073741826, len=510}) = 0
+fcntl(3, F_SETLK, {type=F_UNLCK, whence=SEEK_SET, start=1073741824, len=1}) = 0
+access("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db-journal", F_OK) = -1 ENOENT (No such file or directory)
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+lseek(3, 24, SEEK_SET)                  = 24
+read(3, "\0\0\5\237\0\0\0\241\0\0\0v\0\0\0\1", 16) = 16
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+access("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db-wal", F_OK) = -1 ENOENT (No such file or directory)
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+lseek(3, 24576, SEEK_SET)               = 24576
+read(3, "\2\0\0\0\2\3\315\0\0\0\0y\3\342\3\315\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 1024) = 1024
+lseek(3, 53248, SEEK_SET)               = 53248
+read(3, "\n\3\226\0\35\0012\2\1d\1|\1\233\0012\1\304\1\333\1\356\2\0\2\33\1\260\2B\2M"..., 1024) = 1024
+lseek(3, 23552, SEEK_SET)               = 23552
+read(3, "\5\3~\0$\3\25\f\0\0\0\241\3\265\3\260\3L\3X\3\246\3\241\3\234\3\227\3\222\3\210"..., 1024) = 1024
+lseek(3, 148480, SEEK_SET)              = 148480
+read(3, "\r\0\0\0\2\2\202\0\2\202\3\17\3\17\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 1024) = 1024
+lseek(3, 52224, SEEK_SET)               = 52224
+read(3, "\n\2\240\0%\1+\0\1G\1O\1`\1o\1~\1\221\1\241\1\257\1\275\1\327\1\343\1\362"..., 1024) = 1024
+lseek(3, 163840, SEEK_SET)              = 163840
+read(3, "\r\3(\0\2\1\301\0\1\301\2\244\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 1024) = 1024
+fcntl(3, F_SETLK, {type=F_UNLCK, whence=SEEK_SET, start=0, len=0}) = 0
+getcwd("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk", 4096) = 77
+fcntl(3, F_SETLK, {type=F_RDLCK, whence=SEEK_SET, start=1073741824, len=1}) = 0
+fcntl(3, F_SETLK, {type=F_RDLCK, whence=SEEK_SET, start=1073741826, len=510}) = 0
+fcntl(3, F_SETLK, {type=F_UNLCK, whence=SEEK_SET, start=1073741824, len=1}) = 0
+access("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db-journal", F_OK) = -1 ENOENT (No such file or directory)
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+lseek(3, 24, SEEK_SET)                  = 24
+read(3, "\0\0\5\237\0\0\0\241\0\0\0v\0\0\0\1", 16) = 16
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+access("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db-wal", F_OK) = -1 ENOENT (No such file or directory)
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+lseek(3, 22528, SEEK_SET)               = 22528
+read(3, "\n\0\0\0\0\4\0\0\3\373\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 1024) = 1024
+fcntl(3, F_SETLK, {type=F_WRLCK, whence=SEEK_SET, start=1073741825, len=1}) = 0
+lseek(3, 21504, SEEK_SET)               = 21504
+read(3, "\r\0\0\0\0\4\0\0\3\371\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 1024) = 1024
+stat("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db", {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+stat("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db", {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+open("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db-journal", O_RDWR|O_CREAT|O_CLOEXEC, 0644) = 4
+fstat(4, {st_mode=S_IFREG|0644, st_size=0, ...}) = 0
+geteuid()                               = 530
+fstat(4, {st_mode=S_IFREG|0644, st_size=0, ...}) = 0
+open("/dev/urandom", O_RDONLY|O_CLOEXEC) = 5
+read(5, "!?\\6X$\260\376\v\3335\213\17H\267\303\0076eP\206\3N\264\320\311K\335\241vF\331"..., 256) = 256
+close(5)                                = 0
+lseek(4, 0, SEEK_SET)                   = 0
+write(4, "\331\325\5\371 \241c\327\377\377\377\377\224\337\311\2\0\0\0\241\0\0\2\0\0\0\4\0\0\0\0\0"..., 512) = 512
+lseek(4, 512, SEEK_SET)                 = 512
+write(4, "\0\0\0\27", 4)                = 4
+lseek(4, 516, SEEK_SET)                 = 516
+write(4, "\n\0\0\0\0\4\0\0\3\373\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 1024) = 1024
+lseek(4, 1540, SEEK_SET)                = 1540
+write(4, "\224\337\311\2", 4)           = 4
+lseek(4, 1544, SEEK_SET)                = 1544
+write(4, "\0\0\0\26", 4)                = 4
+lseek(4, 1548, SEEK_SET)                = 1548
+write(4, "\r\0\0\0\0\4\0\0\3\371\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 1024) = 1024
+lseek(4, 2572, SEEK_SET)                = 2572
+write(4, "\224\337\311\2", 4)           = 4
+fcntl(3, F_SETLK, {type=F_WRLCK, whence=SEEK_SET, start=1073741824, len=1}) = 0
+fcntl(3, F_SETLK, {type=F_WRLCK, whence=SEEK_SET, start=1073741826, len=510}) = 0
+lseek(4, 2576, SEEK_SET)                = 2576
+write(4, "\0\0\0\1", 4)                 = 4
+lseek(4, 2580, SEEK_SET)                = 2580
+write(4, "SQLite format 3\0\4\0\1\1\0@  \0\0\5\237\0\0\0\241"..., 1024) = 1024
+lseek(4, 3604, SEEK_SET)                = 3604
+write(4, "\224\337\311\2", 4)           = 4
+lseek(3, 0, SEEK_SET)                   = 0
+write(3, "SQLite format 3\0\4\0\1\1\0@  \0\0\5\240\0\0\0\241"..., 1024) = 1024
+lseek(3, 21504, SEEK_SET)               = 21504
+write(3, "\r\0\0\0\1\3\371\0\3\371\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 1024) = 1024
+lseek(3, 22528, SEEK_SET)               = 22528
+write(3, "\n\0\0\0\1\3\373\0\3\373\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 1024) = 1024
+close(4)                                = 0
+unlink("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db-journal") = 0
+fcntl(3, F_SETLK, {type=F_RDLCK, whence=SEEK_SET, start=1073741826, len=510}) = 0
+fcntl(3, F_SETLK, {type=F_UNLCK, whence=SEEK_SET, start=1073741824, len=2}) = 0
+fcntl(3, F_SETLK, {type=F_UNLCK, whence=SEEK_SET, start=0, len=0}) = 0
+getcwd("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk", 4096) = 77
+fcntl(3, F_SETLK, {type=F_RDLCK, whence=SEEK_SET, start=1073741824, len=1}) = 0
+fcntl(3, F_SETLK, {type=F_RDLCK, whence=SEEK_SET, start=1073741826, len=510}) = 0
+fcntl(3, F_SETLK, {type=F_UNLCK, whence=SEEK_SET, start=1073741824, len=1}) = 0
+access("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db-journal", F_OK) = -1 ENOENT (No such file or directory)
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+lseek(3, 24, SEEK_SET)                  = 24
+read(3, "\0\0\5\240\0\0\0\241\0\0\0v\0\0\0\1", 16) = 16
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+access("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db-wal", F_OK) = -1 ENOENT (No such file or directory)
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+lseek(3, 13312, SEEK_SET)               = 13312
+read(3, "\n\0\0\0\0\4\0\0\3\365\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 1024) = 1024
+fcntl(3, F_SETLK, {type=F_UNLCK, whence=SEEK_SET, start=0, len=0}) = 0
+fcntl(3, F_SETLK, {type=F_RDLCK, whence=SEEK_SET, start=1073741824, len=1}) = 0
+fcntl(3, F_SETLK, {type=F_RDLCK, whence=SEEK_SET, start=1073741826, len=510}) = 0
+fcntl(3, F_SETLK, {type=F_UNLCK, whence=SEEK_SET, start=1073741824, len=1}) = 0
+access("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db-journal", F_OK) = -1 ENOENT (No such file or directory)
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+lseek(3, 24, SEEK_SET)                  = 24
+read(3, "\0\0\5\240\0\0\0\241\0\0\0v\0\0\0\1", 16) = 16
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+access("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db-wal", F_OK) = -1 ENOENT (No such file or directory)
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+fcntl(3, F_SETLK, {type=F_UNLCK, whence=SEEK_SET, start=0, len=0}) = 0
+fcntl(3, F_SETLK, {type=F_RDLCK, whence=SEEK_SET, start=1073741824, len=1}) = 0
+fcntl(3, F_SETLK, {type=F_RDLCK, whence=SEEK_SET, start=1073741826, len=510}) = 0
+fcntl(3, F_SETLK, {type=F_UNLCK, whence=SEEK_SET, start=1073741824, len=1}) = 0
+access("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db-journal", F_OK) = -1 ENOENT (No such file or directory)
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+lseek(3, 24, SEEK_SET)                  = 24
+read(3, "\0\0\5\240\0\0\0\241\0\0\0v\0\0\0\1", 16) = 16
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+access("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db-wal", F_OK) = -1 ENOENT (No such file or directory)
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+lseek(3, 18432, SEEK_SET)               = 18432
+read(3, "\n\0\0\0\0\4\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 1024) = 1024
+fcntl(3, F_SETLK, {type=F_UNLCK, whence=SEEK_SET, start=0, len=0}) = 0
+fcntl(3, F_SETLK, {type=F_RDLCK, whence=SEEK_SET, start=1073741824, len=1}) = 0
+fcntl(3, F_SETLK, {type=F_RDLCK, whence=SEEK_SET, start=1073741826, len=510}) = 0
+fcntl(3, F_SETLK, {type=F_UNLCK, whence=SEEK_SET, start=1073741824, len=1}) = 0
+access("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db-journal", F_OK) = -1 ENOENT (No such file or directory)
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+lseek(3, 24, SEEK_SET)                  = 24
+read(3, "\0\0\5\240\0\0\0\241\0\0\0v\0\0\0\1", 16) = 16
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+access("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db-wal", F_OK) = -1 ENOENT (No such file or directory)
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+lseek(3, 1024, SEEK_SET)                = 1024
+read(3, "\r\0\0\0\1\3\273\0\3\273\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 1024) = 1024
+fcntl(3, F_SETLK, {type=F_UNLCK, whence=SEEK_SET, start=0, len=0}) = 0
+brk(0)                                  = 0x7fb0c4e09000
+brk(0x7fb0c4e2a000)                     = 0x7fb0c4e2a000
+brk(0)                                  = 0x7fb0c4e2a000
+brk(0)                                  = 0x7fb0c4e2a000
+brk(0x7fb0c4e29000)                     = 0x7fb0c4e29000
+brk(0)                                  = 0x7fb0c4e29000
+fcntl(3, F_SETLK, {type=F_RDLCK, whence=SEEK_SET, start=1073741824, len=1}) = 0
+fcntl(3, F_SETLK, {type=F_RDLCK, whence=SEEK_SET, start=1073741826, len=510}) = 0
+fcntl(3, F_SETLK, {type=F_UNLCK, whence=SEEK_SET, start=1073741824, len=1}) = 0
+access("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db-journal", F_OK) = -1 ENOENT (No such file or directory)
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+lseek(3, 24, SEEK_SET)                  = 24
+read(3, "\0\0\5\240\0\0\0\241\0\0\0v\0\0\0\1", 16) = 16
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+access("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db-wal", F_OK) = -1 ENOENT (No such file or directory)
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+fcntl(3, F_SETLK, {type=F_UNLCK, whence=SEEK_SET, start=0, len=0}) = 0
+fcntl(3, F_SETLK, {type=F_RDLCK, whence=SEEK_SET, start=1073741824, len=1}) = 0
+fcntl(3, F_SETLK, {type=F_RDLCK, whence=SEEK_SET, start=1073741826, len=510}) = 0
+fcntl(3, F_SETLK, {type=F_UNLCK, whence=SEEK_SET, start=1073741824, len=1}) = 0
+access("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db-journal", F_OK) = -1 ENOENT (No such file or directory)
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+lseek(3, 24, SEEK_SET)                  = 24
+read(3, "\0\0\5\240\0\0\0\241\0\0\0v\0\0\0\1", 16) = 16
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+access("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db-wal", F_OK) = -1 ENOENT (No such file or directory)
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+lseek(3, 32768, SEEK_SET)               = 32768
+read(3, "\n\0\0\0\0\4\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 1024) = 1024
+fcntl(3, F_SETLK, {type=F_UNLCK, whence=SEEK_SET, start=0, len=0}) = 0
+lstat("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/doc", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
+openat(AT_FDCWD, "/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/doc", O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC) = 4
+getdents(4, /* 8 entries */, 32768)     = 328
+lstat("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/doc/.", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
+lstat("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/doc/..", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
+lstat("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/doc/aprx-manual-pics.odp", {st_mode=S_IFREG|0664, st_size=12644, ...}) = 0
+lstat("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/doc/aprx-manual.odt", {st_mode=S_IFREG|0664, st_size=197896, ...}) = 0
+lstat("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/doc/aprx-requirement-specification.odt", {st_mode=S_IFREG|0644, st_size=34162, ...}) = 0
+lstat("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/doc/aprx-manual.pdf", {st_mode=S_IFREG|0664, st_size=438348, ...}) = 0
+lstat("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/doc/aprx-requirement-specification.pdf", {st_mode=S_IFREG|0644, st_size=175248, ...}) = 0
+lstat("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/doc/.~lock.aprx-manual.odt#", {st_mode=S_IFREG|0664, st_size=95, ...}) = 0
+getdents(4, /* 0 entries */, 32768)     = 0
+close(4)                                = 0
+fcntl(3, F_SETLK, {type=F_RDLCK, whence=SEEK_SET, start=1073741824, len=1}) = 0
+fcntl(3, F_SETLK, {type=F_RDLCK, whence=SEEK_SET, start=1073741826, len=510}) = 0
+fcntl(3, F_SETLK, {type=F_UNLCK, whence=SEEK_SET, start=1073741824, len=1}) = 0
+access("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db-journal", F_OK) = -1 ENOENT (No such file or directory)
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+lseek(3, 24, SEEK_SET)                  = 24
+read(3, "\0\0\5\240\0\0\0\241\0\0\0v\0\0\0\1", 16) = 16
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+access("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db-wal", F_OK) = -1 ENOENT (No such file or directory)
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+lseek(3, 26624, SEEK_SET)               = 26624
+read(3, "\2\3\360\0\2\3\277\0\0\0\0t\3\277\3\322\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 1024) = 1024
+lseek(3, 117760, SEEK_SET)              = 117760
+read(3, "\n\0\0\0\21\1\265\0\1\265\1\316\1\360\2\n\2-\2L\2k\2\234\2\315\2\357\3\16\0030"..., 1024) = 1024
+lseek(3, 68608, SEEK_SET)               = 68608
+read(3, "\r\0\0\0\4\0\23\0\2\273\2\"\1\2\0\23\0\0\0\201lO\31\t+\10\35\t7\2\31\0"..., 1024) = 1024
+lseek(3, 105472, SEEK_SET)              = 105472
+read(3, "\r\0\0\0\3\0\311\0\0\311\1\341\2\350\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 1024) = 1024
+lseek(3, 64512, SEEK_SET)               = 64512
+read(3, "\r\0\0\0\3\0e\0\0e\2\250\1P\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 1024) = 1024
+lseek(3, 15360, SEEK_SET)               = 15360
+read(3, "\n\0\0\0\0\4\0\0\3\364\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 1024) = 1024
+fcntl(3, F_SETLK, {type=F_UNLCK, whence=SEEK_SET, start=0, len=0}) = 0
+fcntl(3, F_SETLK, {type=F_RDLCK, whence=SEEK_SET, start=1073741824, len=1}) = 0
+fcntl(3, F_SETLK, {type=F_RDLCK, whence=SEEK_SET, start=1073741826, len=510}) = 0
+fcntl(3, F_SETLK, {type=F_UNLCK, whence=SEEK_SET, start=1073741824, len=1}) = 0
+access("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db-journal", F_OK) = -1 ENOENT (No such file or directory)
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+lseek(3, 24, SEEK_SET)                  = 24
+read(3, "\0\0\5\240\0\0\0\241\0\0\0v\0\0\0\1", 16) = 16
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+access("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db-wal", F_OK) = -1 ENOENT (No such file or directory)
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+fcntl(3, F_SETLK, {type=F_UNLCK, whence=SEEK_SET, start=0, len=0}) = 0
+lstat("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/doc/aprx-manual.odt", {st_mode=S_IFREG|0664, st_size=197896, ...}) = 0
+fcntl(3, F_SETLK, {type=F_RDLCK, whence=SEEK_SET, start=1073741824, len=1}) = 0
+fcntl(3, F_SETLK, {type=F_RDLCK, whence=SEEK_SET, start=1073741826, len=510}) = 0
+fcntl(3, F_SETLK, {type=F_UNLCK, whence=SEEK_SET, start=1073741824, len=1}) = 0
+access("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db-journal", F_OK) = -1 ENOENT (No such file or directory)
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+lseek(3, 24, SEEK_SET)                  = 24
+read(3, "\0\0\5\240\0\0\0\241\0\0\0v\0\0\0\1", 16) = 16
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+access("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db-wal", F_OK) = -1 ENOENT (No such file or directory)
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+fcntl(3, F_SETLK, {type=F_UNLCK, whence=SEEK_SET, start=0, len=0}) = 0
+lstat("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/doc/aprx-manual.odt", {st_mode=S_IFREG|0664, st_size=197896, ...}) = 0
+fcntl(3, F_SETLK, {type=F_RDLCK, whence=SEEK_SET, start=1073741824, len=1}) = 0
+fcntl(3, F_SETLK, {type=F_RDLCK, whence=SEEK_SET, start=1073741826, len=510}) = 0
+fcntl(3, F_SETLK, {type=F_UNLCK, whence=SEEK_SET, start=1073741824, len=1}) = 0
+access("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db-journal", F_OK) = -1 ENOENT (No such file or directory)
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+lseek(3, 24, SEEK_SET)                  = 24
+read(3, "\0\0\5\240\0\0\0\241\0\0\0v\0\0\0\1", 16) = 16
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+access("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db-wal", F_OK) = -1 ENOENT (No such file or directory)
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+lseek(3, 10240, SEEK_SET)               = 10240
+read(3, "\2\0\0\0\1\3\310\0\0\0\0\213\3\310\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 1024) = 1024
+lseek(3, 140288, SEEK_SET)              = 140288
+read(3, "\2\1\325\0\f\1-\2\0\0\0|\2B\2\n\2\352\1-\2z\1e\2\263\3\311\3X\3!"..., 1024) = 1024
+lseek(3, 88064, SEEK_SET)               = 88064
+read(3, "\n\0\0\0\16\1/\0\1/\1b\1\225\1\311\1\375\0020\2c\2\227\2\312\2\376\0031\3e"..., 1024) = 1024
+lseek(3, 9216, SEEK_SET)                = 9216
+read(3, "\5\0\0\0&\3(\0\0\0\0\240\3\373\3\366\3\361\3\354\3\347\3\342\3\335\3\330\3\323\3\316"..., 1024) = 1024
+lseek(3, 150528, SEEK_SET)              = 150528
+read(3, "\r\0\0\0\n\0F\0\3\241\3A\2\341\2\202\2\"\1\303\1d\1\5\0\245\0F\0\0\0\0"..., 1024) = 1024
+open("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/pristine/5b/5b78dd1d69e60a7ae82aec254bcc346289c7895d.svn-base", O_RDONLY|O_CLOEXEC) = 4
+fcntl(3, F_SETLK, {type=F_UNLCK, whence=SEEK_SET, start=0, len=0}) = 0
+fcntl(3, F_SETLK, {type=F_RDLCK, whence=SEEK_SET, start=1073741824, len=1}) = 0
+fcntl(3, F_SETLK, {type=F_RDLCK, whence=SEEK_SET, start=1073741826, len=510}) = 0
+fcntl(3, F_SETLK, {type=F_UNLCK, whence=SEEK_SET, start=1073741824, len=1}) = 0
+access("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db-journal", F_OK) = -1 ENOENT (No such file or directory)
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+lseek(3, 24, SEEK_SET)                  = 24
+read(3, "\0\0\5\240\0\0\0\241\0\0\0v\0\0\0\1", 16) = 16
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+access("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db-wal", F_OK) = -1 ENOENT (No such file or directory)
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+fcntl(3, F_SETLK, {type=F_UNLCK, whence=SEEK_SET, start=0, len=0}) = 0
+close(4)                                = 0
+fcntl(3, F_SETLK, {type=F_RDLCK, whence=SEEK_SET, start=1073741824, len=1}) = 0
+fcntl(3, F_SETLK, {type=F_RDLCK, whence=SEEK_SET, start=1073741826, len=510}) = 0
+fcntl(3, F_SETLK, {type=F_UNLCK, whence=SEEK_SET, start=1073741824, len=1}) = 0
+access("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db-journal", F_OK) = -1 ENOENT (No such file or directory)
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+lseek(3, 24, SEEK_SET)                  = 24
+read(3, "\0\0\5\240\0\0\0\241\0\0\0v\0\0\0\1", 16) = 16
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+access("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db-wal", F_OK) = -1 ENOENT (No such file or directory)
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+fcntl(3, F_SETLK, {type=F_UNLCK, whence=SEEK_SET, start=0, len=0}) = 0
+lstat("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/doc/aprx-manual.pdf", {st_mode=S_IFREG|0664, st_size=438348, ...}) = 0
+fcntl(3, F_SETLK, {type=F_RDLCK, whence=SEEK_SET, start=1073741824, len=1}) = 0
+fcntl(3, F_SETLK, {type=F_RDLCK, whence=SEEK_SET, start=1073741826, len=510}) = 0
+fcntl(3, F_SETLK, {type=F_UNLCK, whence=SEEK_SET, start=1073741824, len=1}) = 0
+access("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db-journal", F_OK) = -1 ENOENT (No such file or directory)
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+lseek(3, 24, SEEK_SET)                  = 24
+read(3, "\0\0\5\240\0\0\0\241\0\0\0v\0\0\0\1", 16) = 16
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+access("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db-wal", F_OK) = -1 ENOENT (No such file or directory)
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+fcntl(3, F_SETLK, {type=F_UNLCK, whence=SEEK_SET, start=0, len=0}) = 0
+lstat("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/doc/aprx-manual.pdf", {st_mode=S_IFREG|0664, st_size=438348, ...}) = 0
+fcntl(3, F_SETLK, {type=F_RDLCK, whence=SEEK_SET, start=1073741824, len=1}) = 0
+fcntl(3, F_SETLK, {type=F_RDLCK, whence=SEEK_SET, start=1073741826, len=510}) = 0
+fcntl(3, F_SETLK, {type=F_UNLCK, whence=SEEK_SET, start=1073741824, len=1}) = 0
+access("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db-journal", F_OK) = -1 ENOENT (No such file or directory)
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+lseek(3, 24, SEEK_SET)                  = 24
+read(3, "\0\0\5\240\0\0\0\241\0\0\0v\0\0\0\1", 16) = 16
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+access("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db-wal", F_OK) = -1 ENOENT (No such file or directory)
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+lseek(3, 98304, SEEK_SET)               = 98304
+read(3, "\n\0\0\0\17\0\367\0\1+\1_\1\223\1\307\1\373\2.\2b\2\226\2\311\2\374\0\367\0030"..., 1024) = 1024
+lseek(3, 145408, SEEK_SET)              = 145408
+read(3, "\r\0\0\0\n\0F\0\3\241\3A\2\342\2\203\2#\1\303\1d\1\5\0\246\0F\0\0\0\0"..., 1024) = 1024
+open("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/pristine/80/801e13de8f6f628e0af791392a3cdbe991e46277.svn-base", O_RDONLY|O_CLOEXEC) = 4
+fcntl(3, F_SETLK, {type=F_UNLCK, whence=SEEK_SET, start=0, len=0}) = 0
+fcntl(3, F_SETLK, {type=F_RDLCK, whence=SEEK_SET, start=1073741824, len=1}) = 0
+fcntl(3, F_SETLK, {type=F_RDLCK, whence=SEEK_SET, start=1073741826, len=510}) = 0
+fcntl(3, F_SETLK, {type=F_UNLCK, whence=SEEK_SET, start=1073741824, len=1}) = 0
+access("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db-journal", F_OK) = -1 ENOENT (No such file or directory)
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+lseek(3, 24, SEEK_SET)                  = 24
+read(3, "\0\0\5\240\0\0\0\241\0\0\0v\0\0\0\1", 16) = 16
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+access("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db-wal", F_OK) = -1 ENOENT (No such file or directory)
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+fcntl(3, F_SETLK, {type=F_UNLCK, whence=SEEK_SET, start=0, len=0}) = 0
+close(4)                                = 0
+fcntl(3, F_SETLK, {type=F_RDLCK, whence=SEEK_SET, start=1073741824, len=1}) = 0
+fcntl(3, F_SETLK, {type=F_RDLCK, whence=SEEK_SET, start=1073741826, len=510}) = 0
+fcntl(3, F_SETLK, {type=F_UNLCK, whence=SEEK_SET, start=1073741824, len=1}) = 0
+access("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db-journal", F_OK) = -1 ENOENT (No such file or directory)
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+lseek(3, 24, SEEK_SET)                  = 24
+read(3, "\0\0\5\240\0\0\0\241\0\0\0v\0\0\0\1", 16) = 16
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+access("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db-wal", F_OK) = -1 ENOENT (No such file or directory)
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+fcntl(3, F_SETLK, {type=F_UNLCK, whence=SEEK_SET, start=0, len=0}) = 0
+fcntl(3, F_SETLK, {type=F_RDLCK, whence=SEEK_SET, start=1073741824, len=1}) = 0
+fcntl(3, F_SETLK, {type=F_RDLCK, whence=SEEK_SET, start=1073741826, len=510}) = 0
+fcntl(3, F_SETLK, {type=F_UNLCK, whence=SEEK_SET, start=1073741824, len=1}) = 0
+access("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db-journal", F_OK) = -1 ENOENT (No such file or directory)
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+lseek(3, 24, SEEK_SET)                  = 24
+read(3, "\0\0\5\240\0\0\0\241\0\0\0v\0\0\0\1", 16) = 16
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+access("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db-wal", F_OK) = -1 ENOENT (No such file or directory)
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+fcntl(3, F_SETLK, {type=F_UNLCK, whence=SEEK_SET, start=0, len=0}) = 0
+fcntl(3, F_SETLK, {type=F_RDLCK, whence=SEEK_SET, start=1073741824, len=1}) = 0
+fcntl(3, F_SETLK, {type=F_RDLCK, whence=SEEK_SET, start=1073741826, len=510}) = 0
+fcntl(3, F_SETLK, {type=F_UNLCK, whence=SEEK_SET, start=1073741824, len=1}) = 0
+access("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db-journal", F_OK) = -1 ENOENT (No such file or directory)
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+lseek(3, 24, SEEK_SET)                  = 24
+read(3, "\0\0\5\240\0\0\0\241\0\0\0v\0\0\0\1", 16) = 16
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+access("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db-wal", F_OK) = -1 ENOENT (No such file or directory)
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+fcntl(3, F_SETLK, {type=F_UNLCK, whence=SEEK_SET, start=0, len=0}) = 0
+epoll_create1(EPOLL_CLOEXEC)            = 4
+socket(PF_NETLINK, SOCK_RAW, 0)         = 5
+bind(5, {sa_family=AF_NETLINK, pid=0, groups=00000000}, 12) = 0
+getsockname(5, {sa_family=AF_NETLINK, pid=5383, groups=00000000}, [12]) = 0
+sendto(5, "\24\0\0\0\26\0\1\3(#0S\0\0\0\0\0\0\0\0", 20, 0, {sa_family=AF_NETLINK, pid=0, groups=00000000}, 12) = 20
+recvmsg(5, {msg_name(12)={sa_family=AF_NETLINK, pid=0, groups=00000000}, msg_iov(1)=[{"D\0\0\0\24\0\2\0(#0S\7\25\0\0\2\10\200\376\1\0\0\0\10\0\1\0\177\0\0\1"..., 4096}], msg_controllen=0, msg_flags=0}, 0) = 148
+recvmsg(5, {msg_name(12)={sa_family=AF_NETLINK, pid=0, groups=00000000}, msg_iov(1)=[{"H\0\0\0\24\0\2\0(#0S\7\25\0\0\n\200\200\376\1\0\0\0\24\0\1\0\0\0\0\0"..., 4096}], msg_controllen=0, msg_flags=0}, 0) = 216
+recvmsg(5, {msg_name(12)={sa_family=AF_NETLINK, pid=0, groups=00000000}, msg_iov(1)=[{"\24\0\0\0\3\0\2\0(#0S\7\25\0\0\0\0\0\0", 4096}], msg_controllen=0, msg_flags=0}, 0) = 20
+socket(PF_LOCAL, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0) = 6
+connect(6, {sa_family=AF_LOCAL, sun_path="/var/run/nscd/socket"}, 110) = -1 ENOENT (No such file or directory)
+close(6)                                = 0
+close(5)                                = 0
+socket(PF_LOCAL, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0) = 5
+connect(5, {sa_family=AF_LOCAL, sun_path="/var/run/nscd/socket"}, 110) = -1 ENOENT (No such file or directory)
+close(5)                                = 0
+open("/etc/nsswitch.conf", O_RDONLY|O_CLOEXEC) = 5
+fstat(5, {st_mode=S_IFREG|0644, st_size=1751, ...}) = 0
+mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fb0c41f4000
+read(5, "#\n# /etc/nsswitch.conf\n#\n# An ex"..., 4096) = 1751
+read(5, "", 4096)                       = 0
+close(5)                                = 0
+munmap(0x7fb0c41f4000, 4096)            = 0
+open("/etc/host.conf", O_RDONLY|O_CLOEXEC) = 5
+fstat(5, {st_mode=S_IFREG|0644, st_size=9, ...}) = 0
+mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fb0c41f4000
+read(5, "multi on\n", 4096)             = 9
+read(5, "", 4096)                       = 0
+close(5)                                = 0
+munmap(0x7fb0c41f4000, 4096)            = 0
+futex(0x7fb0c053d3d0, FUTEX_WAKE_PRIVATE, 2147483647) = 0
+open("/etc/resolv.conf", O_RDONLY|O_CLOEXEC) = 5
+fstat(5, {st_mode=S_IFREG|0644, st_size=94, ...}) = 0
+mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fb0c41f4000
+read(5, "# Generated by NetworkManager\nse"..., 4096) = 94
+read(5, "", 4096)                       = 0
+close(5)                                = 0
+munmap(0x7fb0c41f4000, 4096)            = 0
+open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 5
+fstat(5, {st_mode=S_IFREG|0644, st_size=212134, ...}) = 0
+mmap(NULL, 212134, PROT_READ, MAP_PRIVATE, 5, 0) = 0x7fb0c41c1000
+close(5)                                = 0
+open("/lib64/libnss_files.so.2", O_RDONLY|O_CLOEXEC) = 5
+read(5, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0@\"\0\0\0\0\0\0"..., 832) = 832
+fstat(5, {st_mode=S_IFREG|0755, st_size=57976, ...}) = 0
+mmap(NULL, 2144360, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 5, 0) = 0x7fb0b629e000
+mprotect(0x7fb0b62a9000, 2093056, PROT_NONE) = 0
+mmap(0x7fb0b64a8000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 5, 0xa000) = 0x7fb0b64a8000
+close(5)                                = 0
+mprotect(0x7fb0b64a8000, 4096, PROT_READ) = 0
+munmap(0x7fb0c41c1000, 212134)          = 0
+open("/etc/hosts", O_RDONLY|O_CLOEXEC)  = 5
+fstat(5, {st_mode=S_IFREG|0644, st_size=210, ...}) = 0
+mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fb0c41f4000
+read(5, "127.0.0.1   localhost localhost."..., 4096) = 210
+read(5, "", 4096)                       = 0
+close(5)                                = 0
+munmap(0x7fb0c41f4000, 4096)            = 0
+open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 5
+fstat(5, {st_mode=S_IFREG|0644, st_size=212134, ...}) = 0
+mmap(NULL, 212134, PROT_READ, MAP_PRIVATE, 5, 0) = 0x7fb0c41c1000
+close(5)                                = 0
+open("/lib64/libnss_dns.so.2", O_RDONLY|O_CLOEXEC) = 5
+read(5, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\0\21\0\0\0\0\0\0"..., 832) = 832
+fstat(5, {st_mode=S_IFREG|0755, st_size=27512, ...}) = 0
+mmap(NULL, 2117888, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 5, 0) = 0x7fb0b6098000
+mprotect(0x7fb0b609d000, 2093056, PROT_NONE) = 0
+mmap(0x7fb0b629c000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 5, 0x4000) = 0x7fb0b629c000
+close(5)                                = 0
+mprotect(0x7fb0b629c000, 4096, PROT_READ) = 0
+munmap(0x7fb0c41c1000, 212134)          = 0
+socket(PF_INET, SOCK_DGRAM|SOCK_NONBLOCK, IPPROTO_IP) = 5
+connect(5, {sa_family=AF_INET, sin_port=htons(53), sin_addr=inet_addr("10.10.10.53")}, 16) = 0
+poll([{fd=5, events=POLLOUT}], 1, 0)    = 1 ([{fd=5, revents=POLLOUT}])
+sendmmsg(5, {{{msg_name(0)=NULL, msg_iov(1)=[{"\36\326\1\0\0\1\0\0\0\0\0\0\4repo\3ham\2fi\0\0\1\0\1", 29}], msg_controllen=0, msg_flags=0}, 29}, {{msg_name(0)=NULL, msg_iov(1)=[{"\2125\1\0\0\1\0\0\0\0\0\0\4repo\3ham\2fi\0\0\34\0\1", 29}], msg_controllen=0, msg_flags=0}, 29}}, 2, MSG_NOSIGNAL) = 2
+poll([{fd=5, events=POLLIN}], 1, 5000)  = 1 ([{fd=5, revents=POLLIN}])
+ioctl(5, FIONREAD, [508])               = 0
+recvfrom(5, "\36\326\201\200\0\1\0\1\0\r\0\f\4repo\3ham\2fi\0\0\1\0\1\300\f\0"..., 2048, 0, {sa_family=AF_INET, sin_port=htons(53), sin_addr=inet_addr("10.10.10.53")}, [16]) = 508
+poll([{fd=5, events=POLLIN}], 1, 4998)  = 1 ([{fd=5, revents=POLLIN}])
+ioctl(5, FIONREAD, [99])                = 0
+recvfrom(5, "\2125\201\200\0\1\0\0\0\1\0\0\4repo\3ham\2fi\0\0\34\0\1\300\21\0"..., 1540, 0, {sa_family=AF_INET, sin_port=htons(53), sin_addr=inet_addr("10.10.10.53")}, [16]) = 99
+close(5)                                = 0
+brk(0)                                  = 0x7fb0c4e29000
+brk(0x7fb0c4e4b000)                     = 0x7fb0c4e4b000
+socket(PF_INET, SOCK_STREAM|SOCK_CLOEXEC, IPPROTO_TCP) = 5
+fcntl(5, F_GETFL)                       = 0x2 (flags O_RDWR)
+fcntl(5, F_SETFL, O_RDWR|O_NONBLOCK)    = 0
+setsockopt(5, SOL_TCP, TCP_NODELAY, [1], 4) = 0
+connect(5, {sa_family=AF_INET, sin_port=htons(80), sin_addr=inet_addr("193.19.136.46")}, 16) = -1 EINPROGRESS (Operation now in progress)
+epoll_ctl(4, EPOLL_CTL_DEL, 5, {0, {u32=0, u64=0}}) = -1 ENOENT (No such file or directory)
+epoll_ctl(4, EPOLL_CTL_ADD, 5, {EPOLLIN|EPOLLOUT, {u32=3303153608, u64=140397194125256}}) = 0
+epoll_wait(4, {{EPOLLOUT, {u32=3303153608, u64=140397194125256}}}, 16, 500) = 1
+writev(5, [{"OPTIONS /svn/aprx/trunk/doc HTTP"..., 38}, {"Host", 4}, {": ", 2}, {"repo.ham.fi", 11}, {"\r\n", 2}, {"User-Agent", 10}, {": ", 2}, {"SVN/1.8.8 (x86_64-redhat-linux-g"..., 46}, {"\r\n", 2}, {"Content-Type", 12}, {": ", 2}, {"text/xml", 8}, {"\r\n", 2}, {"Connection", 10}, {": ", 2}, {"keep-alive", 10}, {"\r\n", 2}, {"Accept-Encoding", 15}, {": ", 2}, {"gzip", 4}, {"\r\n", 2}, {"DAV", 3}, {": ", 2}, {"http://subversion.tigris.org/xml"..., 48}, {"\r\n", 2}, {"DAV", 3}, {": ",  [...]
+epoll_ctl(4, EPOLL_CTL_DEL, 5, {0, {u32=0, u64=0}}) = 0
+epoll_ctl(4, EPOLL_CTL_ADD, 5, {EPOLLIN, {u32=3303153656, u64=140397194125304}}) = 0
+epoll_wait(4, {{EPOLLIN, {u32=3303153656, u64=140397194125304}}}, 16, 500) = 1
+read(5, "HTTP/1.1 200 OK\r\nDate: Mon, 24 M"..., 8000) = 860
+brk(0)                                  = 0x7fb0c4e4b000
+brk(0x7fb0c4e6c000)                     = 0x7fb0c4e6c000
+epoll_ctl(4, EPOLL_CTL_DEL, 5, {0, {u32=0, u64=0}}) = 0
+epoll_ctl(4, EPOLL_CTL_ADD, 5, {EPOLLIN|EPOLLOUT, {u32=3303153608, u64=140397194125256}}) = 0
+epoll_wait(4, {{EPOLLOUT, {u32=3303153608, u64=140397194125256}}}, 16, 500) = 1
+writev(5, [{"OPTIONS /svn/aprx/trunk/doc HTTP"..., 38}, {"Host", 4}, {": ", 2}, {"repo.ham.fi", 11}, {"\r\n", 2}, {"User-Agent", 10}, {": ", 2}, {"SVN/1.8.8 (x86_64-redhat-linux-g"..., 46}, {"\r\n", 2}, {"Accept-Encoding", 15}, {": ", 2}, {"gzip", 4}, {"\r\n", 2}, {"DAV", 3}, {": ", 2}, {"http://subversion.tigris.org/xml"..., 48}, {"\r\n", 2}, {"DAV", 3}, {": ", 2}, {"http://subversion.tigris.org/xml"..., 52}, {"\r\n", 2}, {"DAV", 3}, {": ", 2}, {"http://subversion.tigris.org/xml"..., 55 [...]
+epoll_ctl(4, EPOLL_CTL_DEL, 5, {0, {u32=0, u64=0}}) = 0
+epoll_ctl(4, EPOLL_CTL_ADD, 5, {EPOLLIN, {u32=3303153656, u64=140397194125304}}) = 0
+epoll_wait(4, {{EPOLLIN, {u32=3303153656, u64=140397194125304}}}, 16, 500) = 1
+read(5, "HTTP/1.1 200 OK\r\nDate: Mon, 24 M"..., 8000) = 754
+epoll_ctl(4, EPOLL_CTL_DEL, 5, {0, {u32=0, u64=0}}) = 0
+epoll_ctl(4, EPOLL_CTL_ADD, 5, {EPOLLIN|EPOLLOUT, {u32=3303153608, u64=140397194125256}}) = 0
+epoll_wait(4, {{EPOLLOUT, {u32=3303153608, u64=140397194125256}}}, 16, 500) = 1
+writev(5, [{"PROPFIND /svn/aprx/trunk/doc HTT"..., 39}, {"Host", 4}, {": ", 2}, {"repo.ham.fi", 11}, {"\r\n", 2}, {"User-Agent", 10}, {": ", 2}, {"SVN/1.8.8 (x86_64-redhat-linux-g"..., 46}, {"\r\n", 2}, {"Content-Type", 12}, {": ", 2}, {"text/xml", 8}, {"\r\n", 2}, {"Accept-Encoding", 15}, {": ", 2}, {"gzip", 4}, {"\r\n", 2}, {"DAV", 3}, {": ", 2}, {"http://subversion.tigris.org/xml"..., 48}, {"\r\n", 2}, {"DAV", 3}, {": ", 2}, {"http://subversion.tigris.org/xml"..., 52}, {"\r\n", 2}, {" [...]
+epoll_ctl(4, EPOLL_CTL_DEL, 5, {0, {u32=0, u64=0}}) = 0
+epoll_ctl(4, EPOLL_CTL_ADD, 5, {EPOLLIN, {u32=3303153656, u64=140397194125304}}) = 0
+epoll_wait(4, {{EPOLLIN, {u32=3303153656, u64=140397194125304}}}, 16, 500) = 1
+read(5, "HTTP/1.1 207 Multi-Status\r\nDate:"..., 8000) = 554
+stat("/dev/random", {st_mode=S_IFCHR|0666, st_rdev=makedev(1, 8), ...}) = 0
+open("/dev/urandom", O_RDONLY|O_CLOEXEC) = 6
+fcntl(6, F_GETFD)                       = 0x1 (flags FD_CLOEXEC)
+fcntl(6, F_SETFD, FD_CLOEXEC)           = 0
+getuid()                                = 530
+getppid()                               = 5378
+read(6, "\264C8\327\255\304#\352\0163g\0\370\27\351\255", 16) = 16
+close(6)                                = 0
+gettid()                                = 5383
+epoll_ctl(4, EPOLL_CTL_DEL, 5, {0, {u32=0, u64=0}}) = 0
+epoll_ctl(4, EPOLL_CTL_ADD, 5, {EPOLLIN|EPOLLOUT, {u32=3303153608, u64=140397194125256}}) = 0
+epoll_wait(4, {{EPOLLOUT, {u32=3303153608, u64=140397194125256}}}, 16, 500) = 1
+writev(5, [{"MKACTIVITY /svn/aprx/!svn/act/9c"..., 77}, {"Host", 4}, {": ", 2}, {"repo.ham.fi", 11}, {"\r\n", 2}, {"User-Agent", 10}, {": ", 2}, {"SVN/1.8.8 (x86_64-redhat-linux-g"..., 46}, {"\r\n", 2}, {"Accept-Encoding", 15}, {": ", 2}, {"gzip", 4}, {"\r\n", 2}, {"DAV", 3}, {": ", 2}, {"http://subversion.tigris.org/xml"..., 48}, {"\r\n", 2}, {"DAV", 3}, {": ", 2}, {"http://subversion.tigris.org/xml"..., 52}, {"\r\n", 2}, {"DAV", 3}, {": ", 2}, {"http://subversion.tigris.org/xml"..., 55 [...]
+epoll_ctl(4, EPOLL_CTL_DEL, 5, {0, {u32=0, u64=0}}) = 0
+epoll_ctl(4, EPOLL_CTL_ADD, 5, {EPOLLIN, {u32=3303153656, u64=140397194125304}}) = 0
+epoll_wait(4, {{EPOLLIN, {u32=3303153656, u64=140397194125304}}}, 16, 500) = 1
+read(5, "HTTP/1.1 401 Authorization Requi"..., 8000) = 600
+lstat("/localhome/mea/.subversion/auth/svn.simple/5ab2e05495eafc7b602c32da117c5d46", 0x7fff601051f0) = -1 ENOENT (No such file or directory)
+open("/dev/tty", O_RDWR|O_CLOEXEC)      = 6
+ioctl(6, SNDCTL_TMR_TIMEBASE or SNDRV_TIMER_IOCTL_NEXT_DEVICE or TCGETS, {B38400 opost isig icanon echo ...}) = 0
+ioctl(6, SNDCTL_TMR_CONTINUE or SNDRV_TIMER_IOCTL_GPARAMS or TCSETSF, {B38400 opost -isig -icanon -echo ...}) = 0
+write(6, "Authentication realm: <http://re"..., 68) = 68
+ioctl(6, SNDCTL_TMR_START or SNDRV_TIMER_IOCTL_TREAD or TCSETS, {B38400 opost isig icanon echo ...}) = 0
+ioctl(6, SNDCTL_TMR_TIMEBASE or SNDRV_TIMER_IOCTL_NEXT_DEVICE or TCGETS, {B38400 opost isig icanon echo ...}) = 0
+close(6)                                = 0
+open("/dev/tty", O_RDWR|O_CLOEXEC)      = 6
+ioctl(6, SNDCTL_TMR_TIMEBASE or SNDRV_TIMER_IOCTL_NEXT_DEVICE or TCGETS, {B38400 opost isig icanon echo ...}) = 0
+ioctl(6, SNDCTL_TMR_CONTINUE or SNDRV_TIMER_IOCTL_GPARAMS or TCSETSF, {B38400 opost -isig -icanon -echo ...}) = 0
+write(6, "Password for 'oh2mqk': ", 23) = 23
+read(6, "r", 1)                         = 1
+write(6, "*", 1)                        = 1
+read(6, "i", 1)                         = 1
+write(6, "*", 1)                        = 1
+read(6, "f", 1)                         = 1
+write(6, "*", 1)                        = 1
+read(6, "r", 1)                         = 1
+write(6, "*", 1)                        = 1
+read(6, "a", 1)                         = 1
+write(6, "*", 1)                        = 1
+read(6, "f", 1)                         = 1
+write(6, "*", 1)                        = 1
+read(6, "2", 1)                         = 1
+write(6, "*", 1)                        = 1
+read(6, "2", 1)                         = 1
+write(6, "*", 1)                        = 1
+read(6, "\n", 1)                        = 1
+write(6, "\n", 1)                       = 1
+write(6, "\n", 1)                       = 1
+ioctl(6, SNDCTL_TMR_START or SNDRV_TIMER_IOCTL_TREAD or TCSETS, {B38400 opost isig icanon echo ...}) = 0
+ioctl(6, SNDCTL_TMR_TIMEBASE or SNDRV_TIMER_IOCTL_NEXT_DEVICE or TCGETS, {B38400 opost isig icanon echo ...}) = 0
+close(6)                                = 0
+epoll_ctl(4, EPOLL_CTL_DEL, 5, {0, {u32=0, u64=0}}) = 0
+epoll_ctl(4, EPOLL_CTL_ADD, 5, {EPOLLIN|EPOLLOUT, {u32=3303153608, u64=140397194125256}}) = 0
+epoll_wait(4, {{EPOLLIN|EPOLLOUT, {u32=3303153608, u64=140397194125256}}}, 16, 500) = 1
+read(5, "", 8000)                       = 0
+epoll_ctl(4, EPOLL_CTL_DEL, 5, {0, {u32=0, u64=0}}) = 0
+close(5)                                = 0
+socket(PF_INET, SOCK_STREAM|SOCK_CLOEXEC, IPPROTO_TCP) = 5
+fcntl(5, F_GETFL)                       = 0x2 (flags O_RDWR)
+fcntl(5, F_SETFL, O_RDWR|O_NONBLOCK)    = 0
+setsockopt(5, SOL_TCP, TCP_NODELAY, [1], 4) = 0
+connect(5, {sa_family=AF_INET, sin_port=htons(80), sin_addr=inet_addr("193.19.136.46")}, 16) = -1 EINPROGRESS (Operation now in progress)
+epoll_ctl(4, EPOLL_CTL_DEL, 5, {0, {u32=0, u64=0}}) = -1 ENOENT (No such file or directory)
+epoll_ctl(4, EPOLL_CTL_ADD, 5, {EPOLLIN|EPOLLOUT, {u32=3303153656, u64=140397194125304}}) = 0
+epoll_wait(4, {{EPOLLOUT, {u32=3303153656, u64=140397194125304}}}, 16, 500) = 1
+writev(5, [{"MKACTIVITY /svn/aprx/!svn/act/9c"..., 77}, {"Host", 4}, {": ", 2}, {"repo.ham.fi", 11}, {"\r\n", 2}, {"Authorization", 13}, {": ", 2}, {"Basic b2gybXFrOnJpZnJhZjIy", 26}, {"\r\n", 2}, {"User-Agent", 10}, {": ", 2}, {"SVN/1.8.8 (x86_64-redhat-linux-g"..., 46}, {"\r\n", 2}, {"Accept-Encoding", 15}, {": ", 2}, {"gzip", 4}, {"\r\n", 2}, {"DAV", 3}, {": ", 2}, {"http://subversion.tigris.org/xml"..., 48}, {"\r\n", 2}, {"DAV", 3}, {": ", 2}, {"http://subversion.tigris.org/xml"...,  [...]
+epoll_ctl(4, EPOLL_CTL_DEL, 5, {0, {u32=0, u64=0}}) = 0
+epoll_ctl(4, EPOLL_CTL_ADD, 5, {EPOLLIN, {u32=3303153608, u64=140397194125256}}) = 0
+epoll_wait(4, {{EPOLLIN, {u32=3303153608, u64=140397194125256}}}, 16, 500) = 1
+read(5, "HTTP/1.1 201 Created\r\nDate: Mon,"..., 8000) = 550
+open("/dev/tty", O_RDWR|O_CLOEXEC)      = 6
+ioctl(6, SNDCTL_TMR_TIMEBASE or SNDRV_TIMER_IOCTL_NEXT_DEVICE or TCGETS, {B38400 opost isig icanon echo ...}) = 0
+ioctl(6, SNDCTL_TMR_CONTINUE or SNDRV_TIMER_IOCTL_GPARAMS or TCSETSF, {B38400 opost -isig -icanon -echo ...}) = 0
+write(6, "\n-------------------------------"..., 607) = 607
+ioctl(6, SNDCTL_TMR_START or SNDRV_TIMER_IOCTL_TREAD or TCSETS, {B38400 opost isig icanon echo ...}) = 0
+ioctl(6, SNDCTL_TMR_TIMEBASE or SNDRV_TIMER_IOCTL_NEXT_DEVICE or TCGETS, {B38400 opost isig icanon echo ...}) = 0
+close(6)                                = 0
+open("/dev/tty", O_RDWR|O_CLOEXEC)      = 6
+ioctl(6, SNDCTL_TMR_TIMEBASE or SNDRV_TIMER_IOCTL_NEXT_DEVICE or TCGETS, {B38400 opost isig icanon echo ...}) = 0
+ioctl(6, SNDCTL_TMR_CONTINUE or SNDRV_TIMER_IOCTL_GPARAMS or TCSETSF, {B38400 opost -isig -icanon -echo ...}) = 0
+write(6, "Store password unencrypted (yes/"..., 37) = 37
+read(6, "r", 1)                         = 1
+write(6, "r", 1)                        = 1
+read(6, "a", 1)                         = 1
+write(6, "a", 1)                        = 1
+read(6, "\27", 1)                       = 1
+write(6, "\7", 1)                       = 1
+read(6, "\25", 1)                       = 1
+write(6, "\7", 1)                       = 1
+read(6, "\177", 1)                      = 1
+write(6, "\10", 1)                      = 1
+write(6, " ", 1)                        = 1
+write(6, "\10", 1)                      = 1
+read(6, "\177", 1)                      = 1
+write(6, "\10", 1)                      = 1
+write(6, " ", 1)                        = 1
+write(6, "\10", 1)                      = 1
+read(6, "\177", 1)                      = 1
+read(6, "\177", 1)                      = 1
+read(6, "e", 1)                         = 1
+write(6, "e", 1)                        = 1
+read(6, "\177", 1)                      = 1
+write(6, "\10", 1)                      = 1
+write(6, " ", 1)                        = 1
+write(6, "\10", 1)                      = 1
+read(6, "\177", 1)                      = 1
+read(6, "y", 1)                         = 1
+write(6, "y", 1)                        = 1
+read(6, "e", 1)                         = 1
+write(6, "e", 1)                        = 1
+read(6, "s", 1)                         = 1
+write(6, "s", 1)                        = 1
+read(6, "\177", 1)                      = 1
+write(6, "\10", 1)                      = 1
+write(6, " ", 1)                        = 1
+write(6, "\10", 1)                      = 1
+read(6, "\177", 1)                      = 1
+write(6, "\10", 1)                      = 1
+write(6, " ", 1)                        = 1
+write(6, "\10", 1)                      = 1
+read(6, "\177", 1)                      = 1
+write(6, "\10", 1)                      = 1
+write(6, " ", 1)                        = 1
+write(6, "\10", 1)                      = 1
+read(6, "\177", 1)                      = 1
+read(6, "\177", 1)                      = 1
+read(6, "n", 1)                         = 1
+write(6, "n", 1)                        = 1
+read(6, "o", 1)                         = 1
+write(6, "o", 1)                        = 1
+read(6, "\177", 1)                      = 1
+write(6, "\10", 1)                      = 1
+write(6, " ", 1)                        = 1
+write(6, "\10", 1)                      = 1
+read(6, "\177", 1)                      = 1
+write(6, "\10", 1)                      = 1
+write(6, " ", 1)                        = 1
+write(6, "\10", 1)                      = 1
+read(6, "\177", 1)                      = 1
+read(6, "\177", 1)                      = 1
+read(6, "y", 1)                         = 1
+write(6, "y", 1)                        = 1
+read(6, "e", 1)                         = 1
+write(6, "e", 1)                        = 1
+read(6, "s", 1)                         = 1
+write(6, "s", 1)                        = 1
+read(6, "\n", 1)                        = 1
+write(6, "\n", 1)                       = 1
+ioctl(6, SNDCTL_TMR_START or SNDRV_TIMER_IOCTL_TREAD or TCSETS, {B38400 opost isig icanon echo ...}) = 0
+ioctl(6, SNDCTL_TMR_TIMEBASE or SNDRV_TIMER_IOCTL_NEXT_DEVICE or TCGETS, {B38400 opost isig icanon echo ...}) = 0
+close(6)                                = 0
+open("/localhome/mea/.subversion/auth/svn.simple/5ab2e05495eafc7b602c32da117c5d46", O_WRONLY|O_CREAT|O_TRUNC|O_CLOEXEC, 0666) = 6
+write(6, "K 8\npasstype\nV 6\nsimple\nK 8\npass"..., 150) = 150
+close(6)                                = 0
+epoll_ctl(4, EPOLL_CTL_DEL, 5, {0, {u32=0, u64=0}}) = 0
+epoll_ctl(4, EPOLL_CTL_ADD, 5, {EPOLLIN|EPOLLOUT, {u32=3303153656, u64=140397194125304}}) = 0
+epoll_wait(4, {{EPOLLIN|EPOLLOUT, {u32=3303153656, u64=140397194125304}}}, 16, 500) = 1
+read(5, "", 8000)                       = 0
+epoll_ctl(4, EPOLL_CTL_DEL, 5, {0, {u32=0, u64=0}}) = 0
+close(5)                                = 0
+socket(PF_INET, SOCK_STREAM|SOCK_CLOEXEC, IPPROTO_TCP) = 5
+fcntl(5, F_GETFL)                       = 0x2 (flags O_RDWR)
+fcntl(5, F_SETFL, O_RDWR|O_NONBLOCK)    = 0
+setsockopt(5, SOL_TCP, TCP_NODELAY, [1], 4) = 0
+connect(5, {sa_family=AF_INET, sin_port=htons(80), sin_addr=inet_addr("193.19.136.46")}, 16) = -1 EINPROGRESS (Operation now in progress)
+epoll_ctl(4, EPOLL_CTL_DEL, 5, {0, {u32=0, u64=0}}) = -1 ENOENT (No such file or directory)
+epoll_ctl(4, EPOLL_CTL_ADD, 5, {EPOLLIN|EPOLLOUT, {u32=3303153608, u64=140397194125256}}) = 0
+epoll_wait(4, {{EPOLLOUT, {u32=3303153608, u64=140397194125256}}}, 16, 500) = 1
+writev(5, [{"PROPFIND /svn/aprx/trunk/doc HTT"..., 39}, {"Host", 4}, {": ", 2}, {"repo.ham.fi", 11}, {"\r\n", 2}, {"Authorization", 13}, {": ", 2}, {"Basic b2gybXFrOnJpZnJhZjIy", 26}, {"\r\n", 2}, {"User-Agent", 10}, {": ", 2}, {"SVN/1.8.8 (x86_64-redhat-linux-g"..., 46}, {"\r\n", 2}, {"Content-Type", 12}, {": ", 2}, {"text/xml", 8}, {"\r\n", 2}, {"Accept-Encoding", 15}, {": ", 2}, {"gzip", 4}, {"\r\n", 2}, {"DAV", 3}, {": ", 2}, {"http://subversion.tigris.org/xml"..., 48}, {"\r\n", 2},  [...]
+epoll_ctl(4, EPOLL_CTL_DEL, 5, {0, {u32=0, u64=0}}) = 0
+epoll_ctl(4, EPOLL_CTL_ADD, 5, {EPOLLIN, {u32=3303153656, u64=140397194125304}}) = 0
+epoll_wait(4, {{EPOLLIN, {u32=3303153656, u64=140397194125304}}}, 16, 500) = 1
+read(5, "HTTP/1.1 207 Multi-Status\r\nDate:"..., 8000) = 443
+epoll_ctl(4, EPOLL_CTL_DEL, 5, {0, {u32=0, u64=0}}) = 0
+epoll_ctl(4, EPOLL_CTL_ADD, 5, {EPOLLIN|EPOLLOUT, {u32=3303153608, u64=140397194125256}}) = 0
+epoll_wait(4, {{EPOLLOUT, {u32=3303153608, u64=140397194125256}}}, 16, 500) = 1
+writev(5, [{"CHECKOUT /svn/aprx/!svn/vcc/defa"..., 46}, {"Host", 4}, {": ", 2}, {"repo.ham.fi", 11}, {"\r\n", 2}, {"Authorization", 13}, {": ", 2}, {"Basic b2gybXFrOnJpZnJhZjIy", 26}, {"\r\n", 2}, {"User-Agent", 10}, {": ", 2}, {"SVN/1.8.8 (x86_64-redhat-linux-g"..., 46}, {"\r\n", 2}, {"Content-Type", 12}, {": ", 2}, {"text/xml", 8}, {"\r\n", 2}, {"Accept-Encoding", 15}, {": ", 2}, {"gzip", 4}, {"\r\n", 2}, {"DAV", 3}, {": ", 2}, {"http://subversion.tigris.org/xml"..., 48}, {"\r\n", 2},  [...]
+epoll_wait(4, {{EPOLLOUT, {u32=3303153608, u64=140397194125256}}}, 16, 500) = 1
+epoll_ctl(4, EPOLL_CTL_DEL, 5, {0, {u32=0, u64=0}}) = 0
+epoll_ctl(4, EPOLL_CTL_ADD, 5, {EPOLLIN, {u32=3303153656, u64=140397194125304}}) = 0
+epoll_wait(4, {{EPOLLIN, {u32=3303153656, u64=140397194125304}}}, 16, 500) = 1
+read(5, "HTTP/1.1 201 Created\r\nDate: Mon,"..., 8000) = 566
+epoll_ctl(4, EPOLL_CTL_DEL, 5, {0, {u32=0, u64=0}}) = 0
+epoll_ctl(4, EPOLL_CTL_ADD, 5, {EPOLLIN|EPOLLOUT, {u32=3303153608, u64=140397194125256}}) = 0
+epoll_wait(4, {{EPOLLOUT, {u32=3303153608, u64=140397194125256}}}, 16, 500) = 1
+writev(5, [{"PROPPATCH /svn/aprx/!svn/wbl/9ce"..., 80}, {"Host", 4}, {": ", 2}, {"repo.ham.fi", 11}, {"\r\n", 2}, {"Authorization", 13}, {": ", 2}, {"Basic b2gybXFrOnJpZnJhZjIy", 26}, {"\r\n", 2}, {"User-Agent", 10}, {": ", 2}, {"SVN/1.8.8 (x86_64-redhat-linux-g"..., 46}, {"\r\n", 2}, {"Accept-Encoding", 15}, {": ", 2}, {"gzip", 4}, {"\r\n", 2}, {"DAV", 3}, {": ", 2}, {"http://subversion.tigris.org/xml"..., 48}, {"\r\n", 2}, {"DAV", 3}, {": ", 2}, {"http://subversion.tigris.org/xml"...,  [...]
+epoll_ctl(4, EPOLL_CTL_DEL, 5, {0, {u32=0, u64=0}}) = 0
+epoll_ctl(4, EPOLL_CTL_ADD, 5, {EPOLLIN, {u32=3303153656, u64=140397194125304}}) = 0
+epoll_wait(4, {{EPOLLIN, {u32=3303153656, u64=140397194125304}}}, 16, 500) = 1
+read(5, "HTTP/1.1 207 Multi-Status\r\nDate:"..., 8000) = 464
+fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 2), ...}) = 0
+mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fb0c41f4000
+write(1, "Sending        doc/aprx-manual.o"..., 35) = 35
+lstat("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/doc/aprx-manual.odt", {st_mode=S_IFREG|0664, st_size=197896, ...}) = 0
+fcntl(3, F_SETLK, {type=F_RDLCK, whence=SEEK_SET, start=1073741824, len=1}) = 0
+fcntl(3, F_SETLK, {type=F_RDLCK, whence=SEEK_SET, start=1073741826, len=510}) = 0
+fcntl(3, F_SETLK, {type=F_UNLCK, whence=SEEK_SET, start=1073741824, len=1}) = 0
+access("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db-journal", F_OK) = -1 ENOENT (No such file or directory)
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+lseek(3, 24, SEEK_SET)                  = 24
+read(3, "\0\0\5\240\0\0\0\241\0\0\0v\0\0\0\1", 16) = 16
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+access("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db-wal", F_OK) = -1 ENOENT (No such file or directory)
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+fcntl(3, F_SETLK, {type=F_UNLCK, whence=SEEK_SET, start=0, len=0}) = 0
+epoll_ctl(4, EPOLL_CTL_DEL, 5, {0, {u32=0, u64=0}}) = 0
+epoll_ctl(4, EPOLL_CTL_ADD, 5, {EPOLLIN|EPOLLOUT, {u32=3303153608, u64=140397194125256}}) = 0
+epoll_wait(4, {{EPOLLOUT, {u32=3303153608, u64=140397194125256}}}, 16, 500) = 1
+writev(5, [{"CHECKOUT /svn/aprx/!svn/ver/574/"..., 68}, {"Host", 4}, {": ", 2}, {"repo.ham.fi", 11}, {"\r\n", 2}, {"Authorization", 13}, {": ", 2}, {"Basic b2gybXFrOnJpZnJhZjIy", 26}, {"\r\n", 2}, {"User-Agent", 10}, {": ", 2}, {"SVN/1.8.8 (x86_64-redhat-linux-g"..., 46}, {"\r\n", 2}, {"Content-Type", 12}, {": ", 2}, {"text/xml", 8}, {"\r\n", 2}, {"Accept-Encoding", 15}, {": ", 2}, {"gzip", 4}, {"\r\n", 2}, {"DAV", 3}, {": ", 2}, {"http://subversion.tigris.org/xml"..., 48}, {"\r\n", 2},  [...]
+epoll_ctl(4, EPOLL_CTL_DEL, 5, {0, {u32=0, u64=0}}) = 0
+epoll_ctl(4, EPOLL_CTL_ADD, 5, {EPOLLIN, {u32=3303153656, u64=140397194125304}}) = 0
+epoll_wait(4, {{EPOLLIN, {u32=3303153656, u64=140397194125304}}}, 16, 500) = 1
+read(5, "HTTP/1.1 201 Created\r\nDate: Mon,"..., 8000) = 602
+write(1, "Sending        doc/aprx-manual.p"..., 35) = 35
+lstat("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/doc/aprx-manual.pdf", {st_mode=S_IFREG|0664, st_size=438348, ...}) = 0
+fcntl(3, F_SETLK, {type=F_RDLCK, whence=SEEK_SET, start=1073741824, len=1}) = 0
+fcntl(3, F_SETLK, {type=F_RDLCK, whence=SEEK_SET, start=1073741826, len=510}) = 0
+fcntl(3, F_SETLK, {type=F_UNLCK, whence=SEEK_SET, start=1073741824, len=1}) = 0
+access("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db-journal", F_OK) = -1 ENOENT (No such file or directory)
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+lseek(3, 24, SEEK_SET)                  = 24
+read(3, "\0\0\5\240\0\0\0\241\0\0\0v\0\0\0\1", 16) = 16
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+access("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db-wal", F_OK) = -1 ENOENT (No such file or directory)
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+fcntl(3, F_SETLK, {type=F_UNLCK, whence=SEEK_SET, start=0, len=0}) = 0
+epoll_ctl(4, EPOLL_CTL_DEL, 5, {0, {u32=0, u64=0}}) = 0
+epoll_ctl(4, EPOLL_CTL_ADD, 5, {EPOLLIN|EPOLLOUT, {u32=3303153608, u64=140397194125256}}) = 0
+epoll_wait(4, {{EPOLLOUT, {u32=3303153608, u64=140397194125256}}}, 16, 500) = 1
+writev(5, [{"CHECKOUT /svn/aprx/!svn/ver/569/"..., 68}, {"Host", 4}, {": ", 2}, {"repo.ham.fi", 11}, {"\r\n", 2}, {"Authorization", 13}, {": ", 2}, {"Basic b2gybXFrOnJpZnJhZjIy", 26}, {"\r\n", 2}, {"User-Agent", 10}, {": ", 2}, {"SVN/1.8.8 (x86_64-redhat-linux-g"..., 46}, {"\r\n", 2}, {"Content-Type", 12}, {": ", 2}, {"text/xml", 8}, {"\r\n", 2}, {"Accept-Encoding", 15}, {": ", 2}, {"gzip", 4}, {"\r\n", 2}, {"DAV", 3}, {": ", 2}, {"http://subversion.tigris.org/xml"..., 48}, {"\r\n", 2},  [...]
+epoll_ctl(4, EPOLL_CTL_DEL, 5, {0, {u32=0, u64=0}}) = 0
+epoll_ctl(4, EPOLL_CTL_ADD, 5, {EPOLLIN, {u32=3303153656, u64=140397194125304}}) = 0
+epoll_wait(4, {{EPOLLIN, {u32=3303153656, u64=140397194125304}}}, 16, 500) = 1
+read(5, "HTTP/1.1 201 Created\r\nDate: Mon,"..., 8000) = 602
+write(1, "Transmitting file data .", 24) = 24
+lstat("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/doc/aprx-manual.odt", {st_mode=S_IFREG|0664, st_size=197896, ...}) = 0
+fcntl(3, F_SETLK, {type=F_RDLCK, whence=SEEK_SET, start=1073741824, len=1}) = 0
+fcntl(3, F_SETLK, {type=F_RDLCK, whence=SEEK_SET, start=1073741826, len=510}) = 0
+fcntl(3, F_SETLK, {type=F_UNLCK, whence=SEEK_SET, start=1073741824, len=1}) = 0
+access("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db-journal", F_OK) = -1 ENOENT (No such file or directory)
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+lseek(3, 24, SEEK_SET)                  = 24
+read(3, "\0\0\5\240\0\0\0\241\0\0\0v\0\0\0\1", 16) = 16
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+access("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db-wal", F_OK) = -1 ENOENT (No such file or directory)
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+fcntl(3, F_SETLK, {type=F_UNLCK, whence=SEEK_SET, start=0, len=0}) = 0
+open("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/doc/aprx-manual.odt", O_RDONLY|O_CLOEXEC) = 6
+open("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/tmp/svn-VYI0r2", O_RDWR|O_CREAT|O_EXCL, 0600) = 7
+fcntl(7, F_GETFD)                       = 0
+fcntl(7, F_SETFD, FD_CLOEXEC)           = 0
+open("/tmp/apr-tmp.fOowVz", O_RDWR|O_CREAT|O_EXCL, 0600) = 8
+fcntl(8, F_GETFD)                       = 0
+fcntl(8, F_SETFD, FD_CLOEXEC)           = 0
+write(8, "!", 1)                        = 1
+close(8)                                = 0
+unlink("/tmp/apr-tmp.fOowVz")           = 0
+open("/tmp/svn-0c067acf.tmp", O_RDWR|O_CREAT|O_EXCL|O_CLOEXEC, 0666) = 8
+fstat(8, {st_mode=S_IFREG|0664, st_size=0, ...}) = 0
+close(8)                                = 0
+unlink("/tmp/svn-0c067acf.tmp")         = 0
+fstat(7, {st_mode=S_IFREG|0600, st_size=0, ...}) = 0
+chmod("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/tmp/svn-VYI0r2", 0664) = 0
+fcntl(3, F_SETLK, {type=F_RDLCK, whence=SEEK_SET, start=1073741824, len=1}) = 0
+fcntl(3, F_SETLK, {type=F_RDLCK, whence=SEEK_SET, start=1073741826, len=510}) = 0
+fcntl(3, F_SETLK, {type=F_UNLCK, whence=SEEK_SET, start=1073741824, len=1}) = 0
+access("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db-journal", F_OK) = -1 ENOENT (No such file or directory)
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+lseek(3, 24, SEEK_SET)                  = 24
+read(3, "\0\0\5\240\0\0\0\241\0\0\0v\0\0\0\1", 16) = 16
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+access("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db-wal", F_OK) = -1 ENOENT (No such file or directory)
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+fcntl(3, F_SETLK, {type=F_UNLCK, whence=SEEK_SET, start=0, len=0}) = 0
+fcntl(3, F_SETLK, {type=F_RDLCK, whence=SEEK_SET, start=1073741824, len=1}) = 0
+fcntl(3, F_SETLK, {type=F_RDLCK, whence=SEEK_SET, start=1073741826, len=510}) = 0
+fcntl(3, F_SETLK, {type=F_UNLCK, whence=SEEK_SET, start=1073741824, len=1}) = 0
+access("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db-journal", F_OK) = -1 ENOENT (No such file or directory)
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+lseek(3, 24, SEEK_SET)                  = 24
+read(3, "\0\0\5\240\0\0\0\241\0\0\0v\0\0\0\1", 16) = 16
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+access("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db-wal", F_OK) = -1 ENOENT (No such file or directory)
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+open("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/pristine/5b/5b78dd1d69e60a7ae82aec254bcc346289c7895d.svn-base", O_RDONLY|O_CLOEXEC) = 8
+fcntl(3, F_SETLK, {type=F_UNLCK, whence=SEEK_SET, start=0, len=0}) = 0
+fcntl(3, F_SETLK, {type=F_RDLCK, whence=SEEK_SET, start=1073741824, len=1}) = 0
+fcntl(3, F_SETLK, {type=F_RDLCK, whence=SEEK_SET, start=1073741826, len=510}) = 0
+fcntl(3, F_SETLK, {type=F_UNLCK, whence=SEEK_SET, start=1073741824, len=1}) = 0
+access("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db-journal", F_OK) = -1 ENOENT (No such file or directory)
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+lseek(3, 24, SEEK_SET)                  = 24
+read(3, "\0\0\5\240\0\0\0\241\0\0\0v\0\0\0\1", 16) = 16
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+access("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db-wal", F_OK) = -1 ENOENT (No such file or directory)
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+fcntl(3, F_SETLK, {type=F_UNLCK, whence=SEEK_SET, start=0, len=0}) = 0
+fcntl(3, F_SETLK, {type=F_RDLCK, whence=SEEK_SET, start=1073741824, len=1}) = 0
+fcntl(3, F_SETLK, {type=F_RDLCK, whence=SEEK_SET, start=1073741826, len=510}) = 0
+fcntl(3, F_SETLK, {type=F_UNLCK, whence=SEEK_SET, start=1073741824, len=1}) = 0
+access("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db-journal", F_OK) = -1 ENOENT (No such file or directory)
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+lseek(3, 24, SEEK_SET)                  = 24
+read(3, "\0\0\5\240\0\0\0\241\0\0\0v\0\0\0\1", 16) = 16
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+access("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db-wal", F_OK) = -1 ENOENT (No such file or directory)
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+fcntl(3, F_SETLK, {type=F_UNLCK, whence=SEEK_SET, start=0, len=0}) = 0
+open("/tmp/svn-4fJ8w7", O_RDWR|O_CREAT|O_EXCL, 0600) = 9
+fcntl(9, F_GETFD)                       = 0
+fcntl(9, F_SETFD, FD_CLOEXEC)           = 0
+mmap(NULL, 212992, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fb0c4174000
+read(8, "PK\3\4\24\0\0\10\0\0\271dhD^\3062\f'\0\0\0'\0\0\0\10\0\0\0mi"..., 4096) = 4096
+read(8, "\26\256\3365\36\v\34\303:\343=\342\234x j\204\33Vt\21yb\202X\n\353\242#\377\177\34"..., 4096) = 4096
+read(8, "5\270\233\351M\206\346\245\324\370\374\271\277s-v_U\236:\331\3044\345\312-'\263W\35O\235"..., 4096) = 4096
+read(8, "\272\263\245\347\367\302\2075\374\202\374N?\247\25\300\1&\302\200\250\231_iM\337\343 E\317\264\320"..., 4096) = 4096
+read(8, ";\222\352\271\212.\22\3657\17h\233\27\317\267y\227\v\243n\260\34\315\260\370\353\306!\270\240B\316"..., 4096) = 4096
+read(8, "\357\253}U\35\250\3728+\354nxh]dk\364j|s\242\222\2609\336\236\343\315*k\355\220"..., 4096) = 4096
+read(8, "} \362]Ws\33\25{\372\23z\t\201\4\237~\370\362\356g\205'\325\346\"\30/\277&Rl"..., 4096) = 4096
+read(8, "^]\251]GY\313=a\240\277\31\277\350\232\256\16\6\23]-\350\10\23\267\300\2o\266\364=\27"..., 4096) = 4096
+read(8, "\203\224\4\362E9\225\264g\257\245K\253\204\21~\320\r\204\356\233X\235\341b\\\0\5^R3\6"..., 4096) = 4096
+read(8, "\330\3734\273\326`\213m7M\215\331\334R\313\203\272\237\344\224\273\233\336\356\203j\236D\320\276fr"..., 4096) = 4096
+read(8, "\212\302Y\345\3216Lcd\230#k`\33p)\230\243\241Y\26h\374\336\264\32\35m4\271\362\335"..., 4096) = 4096
+read(8, "G\200\342K\240\245\316%\326{U~f4<%%\333\336<\225\351\360\224\325\251\353*\335\221\266\32"..., 4096) = 4096
+read(8, "\27\362\254U\345\232\212\340L\241\31'\361&\232+\366S\265\204\345,D^\222\325\261\341\2439\221~"..., 4096) = 4096
+read(8, "i\301\363\16\213\304\23\nm\251'Y\372\322\0u\364\247<\301U\267\325A\35(\260\22i3\16\225"..., 4096) = 4096
+read(8, "A\343F\35\324 at 7\352P\220Ckj\177\261\350\356\222?\334\342\244a\277\4}\215\213\211\24\232q"..., 4096) = 4096
+read(8, "*l\243\263\7\222v\314\33\3\364\264\251)\0074\313-\243\316<\31\357\223-y\16\300\2353}\225"..., 4096) = 4096
+read(8, "\314\365\1\374\222\316L\326\315\0\373\374\3\355\200\317\255[[\3047\7\230<\6\16p\213\2q\377\313"..., 4096) = 4096
+read(8, "\253\5\f\23hE\255\361\246v)O\316\336\207l\36\367\257\3237\\\235\206.\10\212\"\227\363\343\311"..., 4096) = 4096
+read(8, "\326\237\320\354\332\377\325\24\374\316\25\2473\205\234\206\267\341\252\261\332\241\354\321\341\365\370\233\352\315\315\344"..., 4096) = 4096
+read(8, "\214\316\307\346\364d\223N\225\343\227\365\31$m0\307\310(T\355S\342\27\246\2$\211.k\245n"..., 4096) = 4096
+read(8, "\301\30w+\246\257\227ivVF\233\374v'\5\201d\345\237bZ\323N.C\226=\252f&p"..., 4096) = 4096
+read(8, "V\246A\366\6\206\v\323\325\362\267\254(\377u\\\334\210$\216\330\212;\240\231\21/A\313\375#~"..., 4096) = 4096
+read(8, "&\177\325\232\357X\204\223H\237(Jy\347\274\27T\275\355\27i\257b\35\33\27\217\277g\266\347\274"..., 4096) = 4096
+read(8, "Eg\264[\\<?<\266R\311\244\305J\246\215\"\374y\372\0\216\233\270Dt\355\301\377\346\211!"..., 4096) = 4096
+read(8, "\6C#\260!\343\34\344l\257\304\263E\16\326\27\205?\242d\240\275\261B\17Ik\330\0!\f@"..., 4096) = 4096
+read(6, "PK\3\4\24\0\0\10\0\0\360axD^\3062\f'\0\0\0'\0\0\0\10\0\0\0mi"..., 4096) = 4096
+read(6, "\350\305\345\33_GTU\377|\203\225\344\344\344\204B\373A\21\233\364\330\244\322J\360\206t\302\237v"..., 4096) = 4096
+read(6, "\34\316f\263\234U\304\337Q\230\3019\317d\261K+\336\311\347<\223\v\315 at y'\237\363L\26\32"..., 4096) = 4096
+read(6, "\27\17\321\36\314\242\213\207h\23\222\321\305C\264\7\337\350\342!Z\205z\224\214\207\230u\361\20\r\303"..., 4096) = 4096
+read(6, "\326\252\234\370@\373#{\274\367\3\233\364\365\264;\35U\327C^\346\20\357\207\37\t=\310\216\256\34"..., 4096) = 4096
+read(6, "Qx\320\26<\260E\264\200\2\364\302\335# \346h>\24\200\223\260\26\336#!\266\4\360\347\24\330"..., 4096) = 4096
+read(6, "Y\16f\211\1\362\242\364\v(\361\274\370\261G\"\27}\3006\337\234(l\235\3057*\177+T~"..., 4096) = 4096
+read(6, "\201\205\37\340\265\245Dm \3366b\323\0025\346,?%\376\262\372]PJXSN\356t\34{"..., 4096) = 4096
+read(6, "\35\204T\20\4\377\366\351z\306\334\217n3<\334\34\351\241\207\252C\221\f\213\3618AG\"\256\4"..., 4096) = 4096
+read(6, "\0103\\\275s\304\274C\5s0\366\7\327\224\20\3k\310\224\220\365%r\356F,3I\237'\211"..., 4096) = 4096
+read(6, "p\256\24\230\203\354\275\306\1b0\201\202\251\23\35f\333\216\341\7\2V2\305\352\310!E\347\211\327"..., 4096) = 4096
+read(6, "\204\311\212\307^\"2\2752\310\255AO\337\304\370\262\232H\336et\343\23q\300\375\220\0027\30\212"..., 4096) = 4096
+read(6, "N\260\372\330<ez\31#\366\225\337\30D\323Y\200\364r\211X\202\201\317Yw\357\375\313\0\r\265"..., 4096) = 4096
+read(6, "w\27p\16=<\305\21*_i5A\357\340\361\f\205\16\230\352'U\302/\223W\200t\301\373\224"..., 4096) = 4096
+read(6, "x\224)\247d\260\261\351aW'J\234F&\26\345.\236\237\237\377\376m\332\365?\317\371\36t\223"..., 4096) = 4096
+read(6, "\3639\314~\213\353\0\243\321\22\305g\246\373\34\330\25\377\374iz\332k\332T\351t\354<\302\314\252"..., 4096) = 4096
+read(6, "kjs?\374P\234\25T\270\6\303*\351ur\2\335\3161\37Q\352\263\37\370\246\215J\253\304\366"..., 4096) = 4096
+read(6, "\377yDq\265{\23\233i.k\226^\216\f\243\211)QQk\341r\364\204\247\2333\275\334\207v"..., 4096) = 4096
+read(6, ".\270\327\327\320\210\302eb\3543\236r\346g\302Zm\333\227\272\324pS\213\336\203\206*5U\346"..., 4096) = 4096
+read(6, "V9l\344\370\247\3217\220)\1\200\t\347\3412\275\255\274\345\242e\235O\334\242\251gH\302eF"..., 4096) = 4096
+read(6, "\226\16\267\33\275m\347\356\334\267o1A\3.\351erJ\252\357\266\35\356\256\263B.]puv"..., 4096) = 4096
+read(6, "/\300\0160\5\354\0S\300\16\365\2\366c\1\0\0\0\350%\0\0\0\0\275\4\0\0\0\240\227\0"..., 4096) = 4096
+read(6, "\341CmF\30\231[\f\263\265\213\210\214\244n\363q\2342\315\310\334\302q\3124\352\306\37\372\n\266"..., 4096) = 4096
+read(6, "\311\272\215>\3222RQQ\271\34x~\213\317\206\305\313V\304F\204\23B\250\377\377\265\320\236]b"..., 4096) = 4096
+read(6, "\214\355\321\313\214\376\312\312nd\350\275{eee\1\27\2\355\306\214Ul;\260\233b\357\201\203\273"..., 4096) = 4096
+write(7, "PK\3\4\24\0\0\10\0\0\360axD^\3062\f'\0\0\0'\0\0\0\10\0\0\0mi"..., 4096) = 4096
+write(7, "\350\305\345\33_GTU\377|\203\225\344\344\344\204B\373A\21\233\364\330\244\322J\360\206t\302\237v"..., 4096) = 4096
+write(7, "\34\316f\263\234U\304\337Q\230\3019\317d\261K+\336\311\347<\223\v\315 at y'\237\363L\26\32"..., 4096) = 4096
+write(7, "\27\17\321\36\314\242\213\207h\23\222\321\305C\264\7\337\350\342!Z\205z\224\214\207\230u\361\20\r\303"..., 4096) = 4096
+write(7, "\326\252\234\370@\373#{\274\367\3\233\364\365\264;\35U\327C^\346\20\357\207\37\t=\310\216\256\34"..., 4096) = 4096
+write(7, "Qx\320\26<\260E\264\200\2\364\302\335# \346h>\24\200\223\260\26\336#!\266\4\360\347\24\330"..., 4096) = 4096
+write(7, "Y\16f\211\1\362\242\364\v(\361\274\370\261G\"\27}\3006\337\234(l\235\3057*\177+T~"..., 4096) = 4096
+write(7, "\201\205\37\340\265\245Dm \3366b\323\0025\346,?%\376\262\372]PJXSN\356t\34{"..., 4096) = 4096
+write(7, "\35\204T\20\4\377\366\351z\306\334\217n3<\334\34\351\241\207\252C\221\f\213\3618AG\"\256\4"..., 4096) = 4096
+write(7, "\0103\\\275s\304\274C\5s0\366\7\327\224\20\3k\310\224\220\365%r\356F,3I\237'\211"..., 4096) = 4096
+write(7, "p\256\24\230\203\354\275\306\1b0\201\202\251\23\35f\333\216\341\7\2V2\305\352\310!E\347\211\327"..., 4096) = 4096
+write(7, "\204\311\212\307^\"2\2752\310\255AO\337\304\370\262\232H\336et\343\23q\300\375\220\0027\30\212"..., 4096) = 4096
+write(7, "N\260\372\330<ez\31#\366\225\337\30D\323Y\200\364r\211X\202\201\317Yw\357\375\313\0\r\265"..., 4096) = 4096
+write(7, "w\27p\16=<\305\21*_i5A\357\340\361\f\205\16\230\352'U\302/\223W\200t\301\373\224"..., 4096) = 4096
+write(7, "x\224)\247d\260\261\351aW'J\234F&\26\345.\236\237\237\377\376m\332\365?\317\371\36t\223"..., 4096) = 4096
+write(7, "\3639\314~\213\353\0\243\321\22\305g\246\373\34\330\25\377\374iz\332k\332T\351t\354<\302\314\252"..., 4096) = 4096
+write(7, "kjs?\374P\234\25T\270\6\303*\351ur\2\335\3161\37Q\352\263\37\370\246\215J\253\304\366"..., 4096) = 4096
+write(7, "\377yDq\265{\23\233i.k\226^\216\f\243\211)QQk\341r\364\204\247\2333\275\334\207v"..., 4096) = 4096
+write(7, ".\270\327\327\320\210\302eb\3543\236r\346g\302Zm\333\227\272\324pS\213\336\203\206*5U\346"..., 4096) = 4096
+write(7, "V9l\344\370\247\3217\220)\1\200\t\347\3412\275\255\274\345\242e\235O\334\242\251gH\302eF"..., 4096) = 4096
+write(7, "\226\16\267\33\275m\347\356\334\267o1A\3.\351erJ\252\357\266\35\356\256\263B.]puv"..., 4096) = 4096
+write(7, "/\300\0160\5\354\0S\300\16\365\2\366c\1\0\0\0\350%\0\0\0\0\275\4\0\0\0\240\227\0"..., 4096) = 4096
+write(7, "\341CmF\30\231[\f\263\265\213\210\214\244n\363q\2342\315\310\334\302q\3124\352\306\37\372\n\266"..., 4096) = 4096
+write(7, "\311\272\215>\3222RQQ\271\34x~\213\317\206\305\313V\304F\204\23B\250\377\377\265\320\236]b"..., 4096) = 4096
+mmap(NULL, 139264, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fb0c41d2000
+write(9, "SVN\0\0\206\240\0\206\240\0\6\206\237v\n\0\200\206\237v\360axD^\3062\f'\0\0"..., 4096) = 4096
+write(9, "a\200\267{e\231\231\231\330c\205\350\305\345\33_GTU\377|\203\225\344\344\344\204B\373A\21\233"..., 4096) = 4096
+write(9, "\216f'\336Q\230\3019\317d\323\34\316f\263\234U\304\337Q\230\3019\317d\261K+\336\311\347<"..., 4096) = 4096
+write(9, "<D{p\210.\36\242M\350D\27\17\321\36\314\242\213\207h\23\222\321\305C\264\7\337\350\342!Z"..., 4096) = 4096
+write(9, "32@\232\33\23}`\216M0\326\252\234\370@\373#{\274\367\3\233\364\365\264;\35U\327C^"..., 4096) = 4096
+write(9, "\370\22\210\4v\204\30\214pY\335Qx\320\26<\260E\264\200\2\364\302\335# \346h>\24\200\223"..., 4096) = 4096
+write(9, "+\v\343\220\365Dh\341\212\257lY\16f\211\1\362\242\364\v(\361\274\370\261G\"\27}\3006\337"..., 4096) = 4096
+write(9, "\0234\34C\326\310\256\245\353\254\251\201\205\37\340\265\245Dm \3366b\323\0025\346,?%\376\262"..., 4096) = 4096
+write(9, "L\365\312\221/\214\310\273$Pl\35\204T\20\4\377\366\351z\306\334\217n3<\334\34\351\241\207\252"..., 4096) = 4096
+write(9, "\276y\v\270\267\204%\253c7\24\0103\\\275s\304\274C\5s0\366\7\327\224\20\3k\310\224\220"..., 4096) = 4096
+write(9, "l\35y\24\224\207\301\223o\323\270p\256\24\230\203\354\275\306\1b0\201\202\251\23\35f\333\216\341\7"..., 4096) = 4096
+write(9, "\315\22\27\24\362!\235\307\341D\324\204\311\212\307^\"2\2752\310\255AO\337\304\370\262\232H\336e"..., 4096) = 4096
+write(9, "\244\2\217\337|P8\212\2517\271N\260\372\330<ez\31#\366\225\337\30D\323Y\200\364r\211X"..., 4096) = 4096
+write(9, "\362\374\20\371.9?\7\23\337\vw\27p\16=<\305\21*_i5A\357\340\361\f\205\16\230\352"..., 4096) = 4096
+write(9, "-\321\245\314k\27\317f\177\373:x\224)\247d\260\261\351aW'J\234F&\26\345.\236\237\237"..., 4096) = 4096
+write(9, "?3\333IOwO7\27\346>\3639\314~\213\353\0\243\321\22\305g\246\373\34\330\25\377\374iz"..., 4096) = 4096
+write(9, "PkQ\364m8\347\0g%\250kjs?\374P\234\25T\270\6\303*\351ur\2\335\3161\37"..., 4096) = 4096
+write(9, "\355\362\350\356m\17WG\232$\212\377yDq\265{\23\233i.k\226^\216\f\243\211)QQk"..., 4096) = 4096
+write(9, "\301\262\364\0364\214\302er|\5.\270\327\327\320\210\302eb\3543\236r\346g\302Zm\333\227\272"..., 4096) = 4096
+write(9, "\221\325\226\346\226\310\243~\251g\342V9l\344\370\247\3217\220)\1\200\t\347\3412\275\255\274\345\242"..., 4096) = 4096
+write(9, "\24!\32E,n\342\323\244\5\213\226\16\267\33\275m\347\356\334\267o1A\3.\351erJ\252\357"..., 4096) = 4096
+write(9, "\205\220a?6!9[\336lW/\300\0160\5\354\0S\300\16\365\2\366c\1\0\0\0\350%\0"..., 4096) = 4096
+write(9, "V\346Y\242*p\356~\237Ga\341CmF\30\231[\f\263\265\213\210\214\244n\363q\2342\315\310"..., 4096) = 4096
+write(9, "\333\350\323\333\334,\354^\250\251\211\311\272\215>\3222RQQ\271\34x~\213\317\206\305\313V\304F"..., 4096) = 4096
+write(9, "K\206p\v\332\16\217\302\302\355\306\214\355\321\313\214\376\312\312nd\350\275{eee\1\27\2\355\306"..., 4096) = 4096
+read(8, "\237\225\0323\353\223\331j\271H~\220\343\355\232\334>\335h&\270\240 v\21\26s)\274\250\270X"..., 4096) = 4096
+read(8, "\5\2I\224\264\21\374\355B2\312\243\363\vY1Fqh\30-nL\257\214\250\322\236\5\277\315\252"..., 4096) = 4096
+read(8, "G\255\333\6\376\322\333i_\330d\252\22\23\36|\214\326\267\31\321\267\262l\323\214\277\220\272m\211\24"..., 4096) = 4096
+read(8, "\222\2403\212\347-\315\201\371tr\277\315\3275pn\356W\24C\351+\210\327h\365\16\21G\321V"..., 4096) = 4096
+read(8, "_K\212?\373;\277T\244\325\370\312w\265A)gQ:h\31\265_:\"|T\251\276\343\n!"..., 4096) = 4096
+read(8, "\256I\362d\264\352\t\266_\247i0n\222\1&\2253\261p\374,g+2\0\325\7{\322*r"..., 4096) = 4096
+read(8, "\252\361\324\2248\336\240Gf%\246\360&\312\266\t\230\377\273\215\216n\2\206\254\251\201\301\322\3104\225"..., 4096) = 4096
+read(8, "M\264\26\266\216 \344\21\16~\216\205Q\317\361\313;\316\36\2428\2711\27c\235K\240\213b\337s"..., 4096) = 4096
+read(8, "\340\v\277\334R<\312:\231h\347Ru\234\247E\214sl\343\207\307j\253\274\323/\233\255{X\213"..., 4096) = 4096
+read(8, "\310\235?\254\306\365\254.~\275\337\224V\2777\300\312\n\250{\330\203#\277\243\35\341\227H\244\215H"..., 4096) = 4096
+read(8, "\263\353\311\306\351%\341\275\317\312\337X\255hZP\246\22P\200\343\354\3\241e\266\24\322\376\251\225?"..., 4096) = 4096
+read(8, "4\331\313\37\263\265J\233\303!2\242\336D\\&\337\331f\373\213`\264\324\215\304\v6'\353^^"..., 4096) = 4096
+read(8, "t\216\276\245P\224c\333 at J<\17\313O\26\23\22\366\0W\307\271\24\313n*\345k\254\246\211\216"..., 4096) = 4096
+read(8, "\265\205d\267\263\324{\354\362\273\v71\251\342\247\367\376&\215,\275\7\216:\317\276z\362I\362g"..., 4096) = 4096
+read(8, "s?{\2731\315?\37\221\224\2220c\215Y\25\362O\240%wl\365\375\262cx\10;\f\3550"..., 4096) = 4096
+read(8, "\0314MiT\374z\3127z:C\317\356\200\36 \353\231\254D|\353\210\260\360\240G\330\373d="..., 4096) = 4096
+read(8, "\335RR\337\"r\342x\220\221U\375H\315J\213\303k-\2518\244\4\vcZ\207\234\327q\270,"..., 4096) = 4096
+read(8, "\223\315x8=?\377\325\374\321>\16\16\316G\v\213\1}\264C\321\354\274<\361\233\344\314\202\2I"..., 4096) = 4096
+read(8, "o\275\226\201\201\301\24\243h\24\317\1\17U\220\2\333\373\344\203G\r\350J\3\32\275\335\17\214C?"..., 4096) = 4096
+read(8, "\355]X\10\313\3qc\2}K\310\235\35\236\266'W\322\341\334$.\322\332y.~w\33\306\26"..., 4096) = 4096
+read(8, "7.pngPK\1\2\24\0\24\0\10\10\10\0\271dhD\306\266\377\31\220.\0\0R2\0"..., 4096) = 1052
+read(8, "", 4096)                       = 0
+read(8, "", 4096)                       = 0
+read(6, "\270\3g\2\351\3\352\177\316\333\274\243\1\227\3o\334)*\376(\346\225\346\274\315\353\360\177m\350\203"..., 4096) = 4096
+read(6, "a\320M\275\344x(}\24K.\226C/\215p\374\22?\241\20\7\203\35\277\274u\373\266\320{4"..., 4096) = 4096
+read(6, "\364Je\345\33\201\301\314\275\344+\313\227\350\27t\34~\316?\27\366V\204\273\227\17\375Q`\330\244"..., 4096) = 4096
+read(6, "\26\316\5r\2632<]\34:w\356l}\304QH$\27\tU\27\302:\325U\225\17n\335P\36"..., 4096) = 4096
+read(6, "\245\254\305\334\"\341\376\227\317\333\37\22\222?p[\304\304\304\244\345B\374\305x\235\345\313\247\261\237s"..., 4096) = 4096
+read(6, "\227\16\222\2\350\350ke-\356]\241\242\243\224DG\251vdG\201 \10\302%\2654\332\327\312:"..., 4096) = 4096
+read(6, "~~\376\314\2313e[\376T,\322\3668w\356\\\247N\235\f\r\r\tc\fq\200i\246\350\326"..., 4096) = 4096
+read(6, ")Q{\301?\223\3736Kg\240>\257\326\231\372\3441,7\355\365\3537`\20\275\222U\16\367T"..., 4096) = 4096
+read(6, "f\326\223\307\260\335\177\324k\304\330\361\344J\272A\356\0iY\220\332\302\274w\f\244\226\33\36\"\210"..., 4096) = 4096
+read(6, "\355+7\234G\272\2<\220Z\30\02200\342#\303\26,3\254\251\372\331Wr\300\322\225\246\0205"..., 4096) = 4096
+read(6, "\266\251\273/\236=!KR\\\324\322\r\333\7\217\32\313\254\360s\301\247%\366\26d\200g\226\274L"..., 4096) = 4096
+read(6, "\23\35f\325u\247\324\t\0\305EE'\217\36\214\16\373\317L}\261\341\301\373\267\271\221\277Y\352."..., 4096) = 4096
+read(6, "\230\233\363\232\272\\\302\262i\223\236=\274O=\312<\7\213\363\311X'\374}\375}<Y7q\331"..., 4096) = 4096
+read(6, "\323\fM%\353\32\242\262\3615\0\0\360\27\302%\0\10\30\27\237\220:\227\351\247\245\3156\352Pc"..., 4096) = 4096
+read(6, "\306\326\265\226/\315UzV\365\234\234\317\377\271|\331\323\7QU\333\2326\213\265\220\364\242\240\273/"..., 4096) = 4096
+read(6, ">\351,,,L^5\326\317T\315\2773\363\356\375\260Y\355t\4%\355\360\341\310e\250\337\331\223"..., 4096) = 4096
+read(6, "\245\327\t\247\313\27\375M\226\256\"\205\302\325\227\322\316\375\222\243;w\276\276\331b\266JH\16 \253"..., 4096) = 4096
+read(6, "\222\226\362\356o\207}\302\302m\26X\256\33=iZ\273v\355\237>\210:w\362HB\354K?\367"..., 4096) = 4096
+read(6, "\321\262\231dC\267\2\0@\264\224\224U|\377Q\336\320\255h\202\204\2267\3304\373s\317v\341\257"..., 4096) = 4096
+read(6, "`\324\255\372\361 \352_\3\0\324\37\217+\371\230\352\177\372\243\250\335\307/)\361\266\327\276\235\2572"..., 4096) = 4096
+read(6, "s\363\332\3A\221\324\10P\2]5s\25\202x\343>\346\276ep\234\260\341\177\304\235:\233\205\271"..., 4096) = 4096
+read(6, "K\0h:\250H1c\336R\353\371\313\204\263\306\327Y/\311\343B3\3\256\257\346\345\262\337\377W"..., 4096) = 4096
+read(6, "\251\276\300\332\326O\1K{O2\262\16/\331 \235\16!?;\360A.UNe\210$ZB%"..., 4096) = 4096
+read(6, "\0\0\0\0\0\0\0\0\0\0\17\263\1\0Pictures/100000000"..., 4096) = 1288
+read(6, "", 4096)                       = 0
+read(6, "", 4096)                       = 0
+write(7, "\214\355\321\313\214\376\312\312nd\350\275{eee\1\27\2\355\306\214Ul;\260\233b\357\201\203\273"..., 4096) = 4096
+write(7, "\270\3g\2\351\3\352\177\316\333\274\243\1\227\3o\334)*\376(\346\225\346\274\315\353\360\177m\350\203"..., 4096) = 4096
+write(7, "a\320M\275\344x(}\24K.\226C/\215p\374\22?\241\20\7\203\35\277\274u\373\266\320{4"..., 4096) = 4096
+write(7, "\364Je\345\33\201\301\314\275\344+\313\227\350\27t\34~\316?\27\366V\204\273\227\17\375Q`\330\244"..., 4096) = 4096
+write(7, "\26\316\5r\2632<]\34:w\356l}\304QH$\27\tU\27\302:\325U\225\17n\335P\36"..., 4096) = 4096
+write(7, "\245\254\305\334\"\341\376\227\317\333\37\22\222?p[\304\304\304\244\345B\374\305x\235\345\313\247\261\237s"..., 4096) = 4096
+write(7, "\227\16\222\2\350\350ke-\356]\241\242\243\224DG\251vdG\201 \10\302%\2654\332\327\312:"..., 4096) = 4096
+write(7, "~~\376\314\2313e[\376T,\322\3668w\356\\\247N\235\f\r\r\tc\fq\200i\246\350\326"..., 4096) = 4096
+write(7, ")Q{\301?\223\3736Kg\240>\257\326\231\372\3441,7\355\365\3537`\20\275\222U\16\367T"..., 4096) = 4096
+write(7, "f\326\223\307\260\335\177\324k\304\330\361\344J\272A\356\0iY\220\332\302\274w\f\244\226\33\36\"\210"..., 4096) = 4096
+write(7, "\355+7\234G\272\2<\220Z\30\02200\342#\303\26,3\254\251\372\331Wr\300\322\225\246\0205"..., 4096) = 4096
+write(7, "\266\251\273/\236=!KR\\\324\322\r\333\7\217\32\313\254\360s\301\247%\366\26d\200g\226\274L"..., 4096) = 4096
+write(7, "\23\35f\325u\247\324\t\0\305EE'\217\36\214\16\373\317L}\261\341\301\373\267\271\221\277Y\352."..., 4096) = 4096
+write(7, "\230\233\363\232\272\\\302\262i\223\236=\274O=\312<\7\213\363\311X'\374}\375}<Y7q\331"..., 4096) = 4096
+write(7, "\323\fM%\353\32\242\262\3615\0\0\360\27\302%\0\10\30\27\237\220:\227\351\247\245\3156\352Pc"..., 4096) = 4096
+write(7, "\306\326\265\226/\315UzV\365\234\234\317\377\271|\331\323\7QU\333\2326\213\265\220\364\242\240\273/"..., 4096) = 4096
+write(7, ">\351,,,L^5\326\317T\315\2773\363\356\375\260Y\355t\4%\355\360\341\310e\250\337\331\223"..., 4096) = 4096
+write(7, "\245\327\t\247\313\27\375M\226\256\"\205\302\325\227\322\316\375\222\243;w\276\276\331b\266JH\16 \253"..., 4096) = 4096
+write(7, "\222\226\362\356o\207}\302\302m\26X\256\33=iZ\273v\355\237>\210:w\362HB\354K?\367"..., 4096) = 4096
+write(7, "\321\262\231dC\267\2\0@\264\224\224U|\377Q\336\320\255h\202\204\2267\3304\373s\317v\341\257"..., 4096) = 4096
+write(7, "`\324\255\372\361 \352_\3\0\324\37\217+\371\230\352\177\372\243\250\335\307/)\361\266\327\276\235\2572"..., 4096) = 4096
+write(7, "s\363\332\3A\221\324\10P\2]5s\25\202x\343>\346\276ep\234\260\341\177\304\235:\233\205\271"..., 4096) = 4096
+write(7, "K\0h:\250H1c\336R\353\371\313\204\263\306\327Y/\311\343B3\3\256\257\346\345\262\337\377W"..., 4096) = 4096
+write(7, "\251\276\300\332\326O\1K{O2\262\16/\331 \235\16!?;\360A.UNe\210$ZB%"..., 4096) = 4096
+write(9, "\277+7\17\371\5e\275\310\241\334\206\240\0\205\210\34\205\352\10\r\205\347N\200\205\321\30\0\202:\204"..., 4096) = 4096
+write(9, "\35\277\223\21hkk[\266l\331\363\317?oee\365\312+\257\344\347\347\313D\240c\16\352DC"..., 4096) = 4096
+write(9, "\205\32U\273\21.f\320u>Z\260p\377\201\203\255\255\255\337n\337\21\277p\261T*\365\237\370f"..., 4096) = 4096
+write(9, "d\232\307\320\242\202\32\275\32Y\271\205\220\303H;\0m\0\341: \247v\35>\371\373\32\3\217S"..., 4096) = 4096
+write(9, "\v\261%Tc8\215\323\21tw\232\205M\325\205\21\221\371\37\21y\327\256]|n\221mjkk"..., 4096) = 4096
+write(9, " \10\202 \10\371\240&C\20\4A\20\4!\37\324d\10\202 \10\202 \344#UZQ\213\223\306"..., 4096) = 4096
+write(9, "\230:{\36UM\343BLd\372\213\224\342\242\2\325\336\32\377\2318y\336\202%\304\2114\2\221\366"..., 4096) = 4096
+write(9, "\330Bg\27(y9\331\311\367n\335\276r\1\4\250\357\16\327\352\252*\3026\33A\20\4\21$b"..., 4096) = 4096
+write(9, "\260\277\224\264\333\331\10KS\375\350\260\240\351\32\363\225&N\341\225\267\10-2\244A d\205\371\271"..., 4096) = 4096
+write(9, "\343\270\235\365\311\360X\362\31\3478\34\354N\356\266V\377\273\177g\343\236?\377\363\373?W{g-"..., 4096) = 4096
+write(9, "\241j\267\242\312\213\v\v\311\250\274q\351\334\237?\177R\345w\257_&K\372\223G\314\17\220\310P"..., 4096) = 4096
+write(9, "\264g\231i\317.\236\213\361<\34\306\374\236%.<\304\327sS\351\217\37\324\335W\31\351d\271\236"..., 4096) = 4096
+write(9, "`<JZZ\242\3374\n\f[7`\240'\210\25d\217\372\21\211_\340\2\0\360\317\267\257_\316"..., 4096) = 4096
+write(9, "-vG\230\345\332#\307\234\275\34u\353r\310\375[\327\263>e|\371\234UYY\321EAIN"..., 4096) = 4096
+write(9, "\255g\37\241\252a\325\330\257\t\306*\361M\325\0\302\343\246\316d+\37?u&\211nO\356\336\256"..., 4096) = 4096
+write(9, "\267\356!\371i\371\246?\355\266\254\371k\327\226\243~\241\324\230S\274\336:\265\25^t\225\354\254\217"..., 4096) = 4096
+write(9, "\214P\365\230\300z\363\26M\236eH\357\317\310X\5\235u\377\226\373u\356\342\25\346\253\326S%d"..., 4096) = 4096
+write(9, "\257S\236G\35~\2338EA\271k\2756**Z\365FZT\370=,\340\334\322u[\307O\233"..., 4096) = 4096
+write(9, "6\10\227\0\0\0\0@\233f\371Ee\25\r\335\10q#%\301h\323BJ\10+\372R\\\206w"..., 4096) = 4096
+write(9, "r\232\355o\177\307\236\177\371\354\211\247\313v\207-{Y_\212\16\t\270s\355\312\3737\331\16[\367"..., 4096) = 4096
+write(9, "\324\357\330\360\361\223\250\221eD\220\3603%\245\270\250\320m\363\332\212\362\362%\353\266\222\10\265`\365"..., 4096) = 4096
+write(9, "m\247\230['\304\305\204\371\35{\226\374h\357\206\225\307\335\367\370F_\23D\313\2330\341w\3\6"..., 4096) = 4096
+write(9, "\262\342\35u\0344\266\3444\276\313\203\0f\7\307\241d\255\203h\37\5\25\257:\253\237\2U\\\322"..., 4096) = 4096
+read(6, "", 4096)                       = 0
+close(8)                                = 0
+write(7, "\0\0\0\0\0\0\0\0\0\0\17\263\1\0Pictures/100000000"..., 1288) = 1288
+close(7)                                = 0
+close(6)                                = 0
+fcntl(3, F_SETLK, {type=F_RDLCK, whence=SEEK_SET, start=1073741824, len=1}) = 0
+fcntl(3, F_SETLK, {type=F_RDLCK, whence=SEEK_SET, start=1073741826, len=510}) = 0
+fcntl(3, F_SETLK, {type=F_UNLCK, whence=SEEK_SET, start=1073741824, len=1}) = 0
+access("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db-journal", F_OK) = -1 ENOENT (No such file or directory)
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+lseek(3, 24, SEEK_SET)                  = 24
+read(3, "\0\0\5\240\0\0\0\241\0\0\0v\0\0\0\1", 16) = 16
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+access("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db-wal", F_OK) = -1 ENOENT (No such file or directory)
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+fcntl(3, F_SETLK, {type=F_WRLCK, whence=SEEK_SET, start=1073741825, len=1}) = 0
+lseek(3, 125952, SEEK_SET)              = 125952
+read(3, "\n\0\0\0\20\0\303\0\1\307\1\373\2.\2b\2\226\1\223\0\367\0\303\2\312\2\375\0031\1+"..., 1024) = 1024
+rename("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/tmp/svn-VYI0r2", "/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/pristine/89/89fca0c3d11ef3e57ccef84637945108c9785928.svn-base") = 0
+stat("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/pristine/89/89fca0c3d11ef3e57ccef84637945108c9785928.svn-base", {st_mode=S_IFREG|0664, st_size=197896, ...}) = 0
+lseek(3, 162816, SEEK_SET)              = 162816
+read(3, "\r\0\0\0\3\2\342\0\3\241\3B\2\342\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 1024) = 1024
+lseek(3, 54272, SEEK_SET)               = 54272
+read(3, "\2\1\370\0\21\0L\3\0\0\0\215\2S\0\253\0|\1\311\1\231\3p\1j\3\320\0\333\3A"..., 1024) = 1024
+lseek(3, 102400, SEEK_SET)              = 102400
+read(3, "\n\0\0\0\23\0\302\0\0\302\0\356\1\32\1E\1q\1\235\1\311\1\365\2 \2L\2x\2\244"..., 1024) = 1024
+stat("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db", {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+stat("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db", {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+open("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db-journal", O_RDWR|O_CREAT|O_CLOEXEC, 0644) = 6
+fstat(6, {st_mode=S_IFREG|0644, st_size=0, ...}) = 0
+geteuid()                               = 530
+fstat(6, {st_mode=S_IFREG|0644, st_size=0, ...}) = 0
+lseek(6, 0, SEEK_SET)                   = 0
+write(6, "\331\325\5\371 \241c\327\377\377\377\377\0265o\343\0\0\0\241\0\0\2\0\0\0\4\0\0\0\0\0"..., 512) = 512
+lseek(6, 512, SEEK_SET)                 = 512
+write(6, "\0\0\0e", 4)                  = 4
+lseek(6, 516, SEEK_SET)                 = 516
+write(6, "\n\0\0\0\23\0\302\0\0\302\0\356\1\32\1E\1q\1\235\1\311\1\365\2 \2L\2x\2\244"..., 1024) = 1024
+lseek(6, 1540, SEEK_SET)                = 1540
+write(6, "\0265p\344", 4)               = 4
+lseek(6, 1544, SEEK_SET)                = 1544
+write(6, "\0\0\0|", 4)                  = 4
+lseek(6, 1548, SEEK_SET)                = 1548
+write(6, "\n\0\0\0\20\0\303\0\1\307\1\373\2.\2b\2\226\1\223\0\367\0\303\2\312\2\375\0031\1+"..., 1024) = 1024
+lseek(6, 2572, SEEK_SET)                = 2572
+write(6, "\0265p\353", 4)               = 4
+lseek(6, 2576, SEEK_SET)                = 2576
+write(6, "\0\0\0\240", 4)               = 4
+lseek(6, 2580, SEEK_SET)                = 2580
+write(6, "\r\0\0\0\3\2\342\0\3\241\3B\2\342\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 1024) = 1024
+lseek(6, 3604, SEEK_SET)                = 3604
+write(6, "\0265p\27", 4)                = 4
+fcntl(3, F_SETLK, {type=F_WRLCK, whence=SEEK_SET, start=1073741824, len=1}) = 0
+fcntl(3, F_SETLK, {type=F_WRLCK, whence=SEEK_SET, start=1073741826, len=510}) = 0
+lseek(6, 3608, SEEK_SET)                = 3608
+write(6, "\0\0\0\1", 4)                 = 4
+lseek(6, 3612, SEEK_SET)                = 3612
+write(6, "SQLite format 3\0\4\0\1\1\0@  \0\0\5\240\0\0\0\241"..., 1024) = 1024
+lseek(6, 4636, SEEK_SET)                = 4636
+write(6, "\0265o\343", 4)               = 4
+lseek(3, 0, SEEK_SET)                   = 0
+write(3, "SQLite format 3\0\4\0\1\1\0@  \0\0\5\241\0\0\0\241"..., 1024) = 1024
+lseek(3, 102400, SEEK_SET)              = 102400
+write(3, "\n\0\0\0\24\0\226\0\0\302\0\356\1\32\1E\1q\1\235\1\311\1\365\2 \2L\0\226\2x"..., 1024) = 1024
+lseek(3, 125952, SEEK_SET)              = 125952
+write(3, "\n\0\0\0\21\0\217\0\0\217\1\307\1\373\2.\2b\2\226\1\223\0\367\0\303\2\312\2\375\0031"..., 1024) = 1024
+lseek(3, 162816, SEEK_SET)              = 162816
+write(3, "\r\0\0\0\4\2\202\0\3\241\3B\2\342\2\202\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 1024) = 1024
+close(6)                                = 0
+unlink("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db-journal") = 0
+fcntl(3, F_SETLK, {type=F_RDLCK, whence=SEEK_SET, start=1073741826, len=510}) = 0
+fcntl(3, F_SETLK, {type=F_UNLCK, whence=SEEK_SET, start=1073741824, len=2}) = 0
+fcntl(3, F_SETLK, {type=F_UNLCK, whence=SEEK_SET, start=0, len=0}) = 0
+epoll_ctl(4, EPOLL_CTL_DEL, 5, {0, {u32=0, u64=0}}) = 0
+epoll_ctl(4, EPOLL_CTL_ADD, 5, {EPOLLIN|EPOLLOUT, {u32=3303153608, u64=140397194125256}}) = 0
+epoll_wait(4, {{EPOLLOUT, {u32=3303153608, u64=140397194125256}}}, 16, 500) = 1
+write(9, "\0\0\0\0\0\0005#\2\0Pictures/1000000000000"..., 1011) = 1011
+lseek(9, 0, SEEK_SET)                   = 0
+stat("/tmp/svn-4fJ8w7", {st_mode=S_IFREG|0600, st_size=197619, ...}) = 0
+mmap(NULL, 197619, PROT_READ, MAP_SHARED, 9, 0) = 0x7fb0c4143000
+writev(5, [{"PUT /svn/aprx/!svn/wrk/9ce1e70b-"..., 96}, {"Host", 4}, {": ", 2}, {"repo.ham.fi", 11}, {"\r\n", 2}, {"Authorization", 13}, {": ", 2}, {"Basic b2gybXFrOnJpZnJhZjIy", 26}, {"\r\n", 2}, {"User-Agent", 10}, {": ", 2}, {"SVN/1.8.8 (x86_64-redhat-linux-g"..., 46}, {"\r\n", 2}, {"Content-Type", 12}, {": ", 2}, {"application/vnd.svn-svndiff", 27}, {"\r\n", 2}, {"Accept-Encoding", 15}, {": ", 2}, {"gzip", 4}, {"\r\n", 2}, {"DAV", 3}, {": ", 2}, {"http://subversion.tigris.org/xml"... [...]
+writev(5, [{"\206\7\3553V\314\234\370\370\336\235\372r\362%\223%\243W\361W\311\237>d\320\355\317}\373WU"..., 128757}, {"\r\n", 2}, {"0\r\n\r\n", 5}], 3) = -1 EAGAIN (Resource temporarily unavailable)
+epoll_wait(4, {{EPOLLOUT, {u32=3303153608, u64=140397194125256}}}, 16, 500) = 1
+writev(5, [{"\206\7\3553V\314\234\370\370\336\235\372r\362%\223%\243W\361W\311\237>d\320\355\317}\373WU"..., 128757}, {"\r\n", 2}, {"0\r\n\r\n", 5}], 3) = 128764
+epoll_ctl(4, EPOLL_CTL_DEL, 5, {0, {u32=0, u64=0}}) = 0
+epoll_ctl(4, EPOLL_CTL_ADD, 5, {EPOLLIN, {u32=3303153656, u64=140397194125304}}) = 0
+epoll_wait(4, {}, 16, 500)              = 0
+epoll_wait(4, {{EPOLLIN, {u32=3303153656, u64=140397194125304}}}, 16, 500) = 1
+read(5, "HTTP/1.1 204 No Content\r\nDate: M"..., 8000) = 106
+munmap(0x7fb0c4143000, 197619)          = 0
+close(9)                                = 0
+write(1, ".", 1)                        = 1
+lstat("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/doc/aprx-manual.pdf", {st_mode=S_IFREG|0664, st_size=438348, ...}) = 0
+fcntl(3, F_SETLK, {type=F_RDLCK, whence=SEEK_SET, start=1073741824, len=1}) = 0
+fcntl(3, F_SETLK, {type=F_RDLCK, whence=SEEK_SET, start=1073741826, len=510}) = 0
+fcntl(3, F_SETLK, {type=F_UNLCK, whence=SEEK_SET, start=1073741824, len=1}) = 0
+access("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db-journal", F_OK) = -1 ENOENT (No such file or directory)
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+lseek(3, 24, SEEK_SET)                  = 24
+read(3, "\0\0\5\241\0\0\0\241\0\0\0v\0\0\0\1", 16) = 16
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+access("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db-wal", F_OK) = -1 ENOENT (No such file or directory)
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+fcntl(3, F_SETLK, {type=F_UNLCK, whence=SEEK_SET, start=0, len=0}) = 0
+open("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/doc/aprx-manual.pdf", O_RDONLY|O_CLOEXEC) = 6
+open("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/tmp/svn-2LgtUH", O_RDWR|O_CREAT|O_EXCL, 0600) = 7
+fcntl(7, F_GETFD)                       = 0
+fcntl(7, F_SETFD, FD_CLOEXEC)           = 0
+fstat(7, {st_mode=S_IFREG|0600, st_size=0, ...}) = 0
+chmod("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/tmp/svn-2LgtUH", 0664) = 0
+fcntl(3, F_SETLK, {type=F_RDLCK, whence=SEEK_SET, start=1073741824, len=1}) = 0
+fcntl(3, F_SETLK, {type=F_RDLCK, whence=SEEK_SET, start=1073741826, len=510}) = 0
+fcntl(3, F_SETLK, {type=F_UNLCK, whence=SEEK_SET, start=1073741824, len=1}) = 0
+access("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db-journal", F_OK) = -1 ENOENT (No such file or directory)
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+lseek(3, 24, SEEK_SET)                  = 24
+read(3, "\0\0\5\241\0\0\0\241\0\0\0v\0\0\0\1", 16) = 16
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+access("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db-wal", F_OK) = -1 ENOENT (No such file or directory)
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+fcntl(3, F_SETLK, {type=F_UNLCK, whence=SEEK_SET, start=0, len=0}) = 0
+fcntl(3, F_SETLK, {type=F_RDLCK, whence=SEEK_SET, start=1073741824, len=1}) = 0
+fcntl(3, F_SETLK, {type=F_RDLCK, whence=SEEK_SET, start=1073741826, len=510}) = 0
+fcntl(3, F_SETLK, {type=F_UNLCK, whence=SEEK_SET, start=1073741824, len=1}) = 0
+access("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db-journal", F_OK) = -1 ENOENT (No such file or directory)
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+lseek(3, 24, SEEK_SET)                  = 24
+read(3, "\0\0\5\241\0\0\0\241\0\0\0v\0\0\0\1", 16) = 16
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+access("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db-wal", F_OK) = -1 ENOENT (No such file or directory)
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+open("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/pristine/80/801e13de8f6f628e0af791392a3cdbe991e46277.svn-base", O_RDONLY|O_CLOEXEC) = 8
+fcntl(3, F_SETLK, {type=F_UNLCK, whence=SEEK_SET, start=0, len=0}) = 0
+fcntl(3, F_SETLK, {type=F_RDLCK, whence=SEEK_SET, start=1073741824, len=1}) = 0
+fcntl(3, F_SETLK, {type=F_RDLCK, whence=SEEK_SET, start=1073741826, len=510}) = 0
+fcntl(3, F_SETLK, {type=F_UNLCK, whence=SEEK_SET, start=1073741824, len=1}) = 0
+access("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db-journal", F_OK) = -1 ENOENT (No such file or directory)
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+lseek(3, 24, SEEK_SET)                  = 24
+read(3, "\0\0\5\241\0\0\0\241\0\0\0v\0\0\0\1", 16) = 16
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+access("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db-wal", F_OK) = -1 ENOENT (No such file or directory)
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+fcntl(3, F_SETLK, {type=F_UNLCK, whence=SEEK_SET, start=0, len=0}) = 0
+fcntl(3, F_SETLK, {type=F_RDLCK, whence=SEEK_SET, start=1073741824, len=1}) = 0
+fcntl(3, F_SETLK, {type=F_RDLCK, whence=SEEK_SET, start=1073741826, len=510}) = 0
+fcntl(3, F_SETLK, {type=F_UNLCK, whence=SEEK_SET, start=1073741824, len=1}) = 0
+access("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db-journal", F_OK) = -1 ENOENT (No such file or directory)
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+lseek(3, 24, SEEK_SET)                  = 24
+read(3, "\0\0\5\241\0\0\0\241\0\0\0v\0\0\0\1", 16) = 16
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+access("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db-wal", F_OK) = -1 ENOENT (No such file or directory)
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+fcntl(3, F_SETLK, {type=F_UNLCK, whence=SEEK_SET, start=0, len=0}) = 0
+open("/tmp/svn-S2P1pi", O_RDWR|O_CREAT|O_EXCL, 0600) = 9
+fcntl(9, F_GETFD)                       = 0
+fcntl(9, F_SETFD, FD_CLOEXEC)           = 0
+read(8, "%PDF-1.4\n%\303\244\303\274\303\266\303\237\n2 0 obj\n<</Le"..., 4096) = 4096
+read(8, "0\223\34\366\25\351NH\7\365\275?\371O(o\231\375\305PiNo\300\\[qBR *\34"..., 4096) = 4096
+read(8, "A\222S\1M&\325\32\21\240\33!\223\3115\23\22\4o\2624>\203\20\253\311\371\0004\305\320\31"..., 4096) = 4096
+read(8, "BB\345\326U\33wX\266o(\376\\9vPf\367^\371o\257+\252>S\361\305W5\327\276"..., 4096) = 4096
+read(8, "\273\310\226\224\27\26\331R-#\357/\274<\355xy\266\264l9z\353'\345\250\263\331\271\223\32\232"..., 4096) = 4096
+read(8, "\31\335z\312\0263\266i\234\fu\345'g\312\17\325\324\315\245\316\320]\277\253|\330\263\317I\177Y"..., 4096) = 4096
+read(8, "\266\37<\361\366\226\242'G\215\r\16\t\221\233RZ\267\251\274|\307\343\201\320\304\32>:\227l\t"..., 4096) = 4096
+read(8, "\277\277\243\304E\217\f\331\22\0\0\370+W\37\337rg\325\351Q\23\246FEGKf\213\210\214\32"..., 4096) = 4096
+read(8, "O]\3\322\206S\n\215Y\36\2579\23\274\245q\344\243\336r\375\266\342\266Sf\355\233B\312\362\202"..., 4096) = 4096
+read(8, "\351ZC\313\217\24\27\36|G\337\fe\330\272\357h\243u\26G\372\177|\217\4Jw\241X\247\274"..., 4096) = 4096
+read(8, "\22r(xK\0\0\0\n\201\267\204\340-!\207\202\267\4\0\0\240\20xK\10\336\22r(xK"..., 4096) = 4096
+read(8, "\265\214\10$\256\305 U\305\324R\263\4>b\325\24\"6\346\230\222\324\2\373\345\303\327\224!\21\5"..., 4096) = 4096
+read(8, "\370\211\354\316\212\212\211\315\330\224\235_Y_v\371n\365\315\207\205g\256c\16\360\336\324Y\255\221\334"..., 4096) = 4096
+read(8, "^i\356\331\246\277Z\221\325X\256\244\225\306X\t=\311`D& \fLD`:\2&\256\245\273"..., 4096) = 4096
+read(8, "@\17XK\210d\234h\220\214qH\260\26\222\201\310\222\10Q1m\304\223\346\326\222\343^\336\336\21"..., 4096) = 4096
+read(8, "p0\224\10\26|\33>*\235,-Ru\343+R2u\301R\207(K#\271(=!\271\217\273"..., 4096) = 4096
+read(8, "-o\225/I\324M\364\345PJ\225o\202YJ\"Y\342(y?\0342\340\374\374\265\356x\203'"..., 4096) = 4096
+read(8, "\245\342\345;(\306\365\305\263{\256\353q\t\3725\343eZ&J\246\207P\223\205>5\213\246\1~"..., 4096) = 4096
+read(8, "\202\202\203\333'\245d<?2{\326\202\375\225\347\34\365wc\277\270=\2417\306\353L\17e\240}"..., 4096) = 4096
+read(8, "ELXx8\255[fv.\367\2133\r\352\312s\323\223*DP\371`z*\5\246\247\357\226w"..., 4096) = 4096
+read(8, "\347\32-0=\16\305K4.\241\25;9\322Y~\325'\333\345\277\337\256\310\371\275\357\340a\324\262"..., 4096) = 4096
+read(8, "^\267Q\357\236x4ta\f\270A\10]F\22B\27\27!t\231V\6\200.\341e\365\235\357\17"..., 4096) = 4096
+read(8, "\21\22\232@\227`J\350K\253+]*S\fK[\256\275\373\203\305~QB6l\300\331\300\204."..., 4096) = 4096
+read(8, "]i\332\\J\320m\350\274\300\f\360\241\264\r\t\303C\227\336a -\240>u\262\233c\200-\204"..., 4096) = 4096
+read(8, "\17u?\37\354\210[\213\5K\200[\2\0\0\0\300V\250\352\226G\217\36\225\251\224\2\226\271\345\371"..., 4096) = 4096
+read(6, "%PDF-1.4\n%\303\244\303\274\303\266\303\237\n2 0 obj\n<</Le"..., 4096) = 4096
+read(6, "\344\226\5r\10\344]\362\367#\225VK%\331~\231\261\372y\314@\341\356\351E\313W\245\252\222\324"..., 4096) = 4096
+read(6, "\334\267l\331\270\361F\f-\345\233ap\254\2279\222\375H\36\322Y u\34\337\254<\316\212ep"..., 4096) = 4096
+read(6, "=~\307\375\262\310\226\36)\262e\300\26\331R\203!\352\376\"[R^XdK\177*\262\245G\212"..., 4096) = 4096
+read(6, "\215\221\214\241\351\246\374c\312\255^r\206M\265\34{m\377\341\207\37<\362\217c\375\\\30L}R"..., 4096) = 4096
+read(6, "\361\3253X~\220-\345]\325\366\203'\236\177q\201\262C\204<b\352M\362O\321\275\357\300\240\372"..., 4096) = 4096
+read(6, "\34\233\375%\277\311\325\232\353?h\246\252\272\362\255\301ly\270\356\236fZe7\37\231\263\\\216\210"..., 4096) = 4096
+read(6, "\314B\266\4\0\0\200Y\310\226\0\0\0000\v\331\22\0\0\0f![\2\0\0\300,dK\0\0"..., 4096) = 4096
+read(6, ";\246\247';\342\216\342B\tn\n\336\222\303;G\23\377\226\27zK\231\337D\4\334\377\340j\225"..., 4096) = 4096
+read(6, "W^\32;qJ\367^\211!\241\226\204\244~\354f\221d\2014F'\17L\243a:\274C\304\340"..., 4096) = 4096
+read(6, "Q$<\350\245/\264\20E\273\240b\216\221\31/\275\370\361\205.E\266\263\304\27\376\20I\244\265B"..., 4096) = 4096
+read(6, "\255\2640\355\322\317\277\264/KW\337z\324\321\317\237\33\6\272w\245Z0\246\245\20\256\317\264\2a"..., 4096) = 4096
+read(6, "aZ\262MN\374R\263\302z-\312'L\231aj\231\300|\276u\327\341\332K\230iW\337|H"..., 4096) = 4096
+read(6, "\310\v\221\314\223\204Hf\212\20\311l+\17F2P\306\354EPa\372\342\34\231&\31s\26\v&"..., 4096) = 4096
+read(6, "\213\342\213 \331\337\376\3667\375F\2372\270\3\354\327_\177M\16\316z \31L\240dE\21/o"..., 4096) = 4096
+read(6, "D2\333\312\236HFTTs)}\312\254\300\240\347\251\353\374\3\2\3233g\26\237\276\302=\253\6"..., 4096) = 4096
+read(6, "\330\f\327\311~\326\25:\"\224w=S\263\5n1\236\213\"\353,\376\217W\27\0254y\217\352?"..., 4096) = 4096
+read(6, "\262m\227Rw\357\361\313\23\247\312L\365\312\364\327\344M\317\3259\300\364\0\0\0\0`L\0241\275"..., 4096) = 4096
+read(6, "\v\275\246\310\2344\255mb\22\271A\277!\303\227\257^\317-\264\344\354\2151\223s\273\244\367\244E"..., 4096) = 4096
+read(6, "\305\27\307\33\356\221E\364\31\364\34\275\0a\37\305.\\\361W\366\215D\r\352\312\303\nq\343\231A"..., 4096) = 4096
+read(6, "\355\211I\2063\367\244H\223\31\244'\33/]8\365\203\355\251\213\327f8\233\236.\203\357i\2147"..., 4096) = 4096
+read(6, "\360\227\24\226\7\275\265\352}x\267\377\213#(\377\312\277\177B*\216\34;\376\243\375\205\324\35\274J"..., 4096) = 4096
+read(6, "\241\v\305\226\7AW\355\335\37,\366_\226e\307^p6\3503\332;\202\256\262\353-$\3638e"..., 4096) = 4096
+read(6, "h 57 0 R\n/Filter/FlateDecode/Col"..., 4096) = 4096
+read(6, "aC18h\\\307-Wn\330\254\354\233\242\376\341\217A!\241\16\372vk\202[\32`\256[\322"..., 4096) = 4096
+write(7, "%PDF-1.4\n%\303\244\303\274\303\266\303\237\n2 0 obj\n<</Le"..., 4096) = 4096
+write(7, "\344\226\5r\10\344]\362\367#\225VK%\331~\231\261\372y\314@\341\356\351E\313W\245\252\222\324"..., 4096) = 4096
+write(7, "\334\267l\331\270\361F\f-\345\233ap\254\2279\222\375H\36\322Y u\34\337\254<\316\212ep"..., 4096) = 4096
+write(7, "=~\307\375\262\310\226\36)\262e\300\26\331R\203!\352\376\"[R^XdK\177*\262\245G\212"..., 4096) = 4096
+write(7, "\215\221\214\241\351\246\374c\312\255^r\206M\265\34{m\377\341\207\37<\362\217c\375\\\30L}R"..., 4096) = 4096
+write(7, "\361\3253X~\220-\345]\325\366\203'\236\177q\201\262C\204<b\352M\362O\321\275\357\300\240\372"..., 4096) = 4096
+write(7, "\34\233\375%\277\311\325\232\353?h\246\252\272\362\255\301ly\270\356\236fZe7\37\231\263\\\216\210"..., 4096) = 4096
+write(7, "\314B\266\4\0\0\200Y\310\226\0\0\0000\v\331\22\0\0\0f![\2\0\0\300,dK\0\0"..., 4096) = 4096
+write(7, ";\246\247';\342\216\342B\tn\n\336\222\303;G\23\377\226\27zK\231\337D\4\334\377\340j\225"..., 4096) = 4096
+write(7, "W^\32;qJ\367^\211!\241\226\204\244~\354f\221d\2014F'\17L\243a:\274C\304\340"..., 4096) = 4096
+write(7, "Q$<\350\245/\264\20E\273\240b\216\221\31/\275\370\361\205.E\266\263\304\27\376\20I\244\265B"..., 4096) = 4096
+write(7, "\255\2640\355\322\317\277\264/KW\337z\324\321\317\237\33\6\272w\245Z0\246\245\20\256\317\264\2a"..., 4096) = 4096
+write(7, "aZ\262MN\374R\263\302z-\312'L\231aj\231\300|\276u\327\341\332K\230iW\337|H"..., 4096) = 4096
+write(7, "\310\v\221\314\223\204Hf\212\20\311l+\17F2P\306\354EPa\372\342\34\231&\31s\26\v&"..., 4096) = 4096
+write(7, "\213\342\213 \331\337\376\3667\375F\2372\270\3\354\327_\177M\16\316z \31L\240dE\21/o"..., 4096) = 4096
+write(7, "D2\333\312\236HFTTs)}\312\254\300\240\347\251\353\374\3\2\3233g\26\237\276\302=\253\6"..., 4096) = 4096
+write(7, "\330\f\327\311~\326\25:\"\224w=S\263\5n1\236\213\"\353,\376\217W\27\0254y\217\352?"..., 4096) = 4096
+write(7, "\262m\227Rw\357\361\313\23\247\312L\365\312\364\327\344M\317\3259\300\364\0\0\0\0`L\0241\275"..., 4096) = 4096
+write(7, "\v\275\246\310\2344\255mb\22\271A\277!\303\227\257^\317-\264\344\354\2151\223s\273\244\367\244E"..., 4096) = 4096
+write(7, "\305\27\307\33\356\221E\364\31\364\34\275\0a\37\305.\\\361W\366\215D\r\352\312\303\nq\343\231A"..., 4096) = 4096
+write(7, "\355\211I\2063\367\244H\223\31\244'\33/]8\365\203\355\251\213\327f8\233\236.\203\357i\2147"..., 4096) = 4096
+write(7, "\360\227\24\226\7\275\265\352}x\267\377\213#(\377\312\277\177B*\216\34;\376\243\375\205\324\35\274J"..., 4096) = 4096
+write(7, "\241\v\305\226\7AW\355\335\37,\366_\226e\307^p6\3503\332;\202\256\262\353-$\3638e"..., 4096) = 4096
+write(7, "h 57 0 R\n/Filter/FlateDecode/Col"..., 4096) = 4096
+write(9, "SVN\0\0\206\240\0\206\240\0H\201\3418\0I\0\200\312\n\0\201\362`\321\0\200\236}\0\253"..., 4096) = 4096
+write(9, "\330\321\336\335`\f\343\245\17\271=\30\310!\344\226\5r\10\344]\362\367#\225VK%\331~\231\261"..., 4096) = 4096
+write(9, "\205j\324\250\234\244Ug\344\240PR-4\334\267l\331\270\361F\f-\345\233ap\254\2279\222\375"..., 4096) = 4096
+write(9, "\253\260\10\354\344%\261\220$\0014#\250\321\0\2157\32m5\242\334\234\245q\26;m\177\"\0r"..., 4096) = 4096
+write(9, "u\302\214k<7f\206=,\247f(\320\354\251\263\21c;\233\325\315\233\347\216r\1774\246\330\17"..., 4096) = 4096
+write(9, "\37\31S\246cp\324\36yN\325\2315n\244\344H\250%\242}\352\1\324\377\345\251=l\334W\235"..., 4096) = 4096
+write(9, "W\357\3705\\\266\200\225\267\3[\207\2723h\2\3068\277\347\377\0\3{\6\264\213\231\201\375\2023"..., 4096) = 4096
+read(8, "\267\34?i\332\276\323\225F\347*\330}X\250\366\341\336?\330\374Y\230\212s\270%7\n\207DM"..., 4096) = 4096
+read(8, "\270\364\312\275I\2632c\23\222h\233C\302\302\373'\17]U\260\215\33:I\251h\351\226\302\17\342"..., 4096) = 4096
+read(8, "\240\37N\334\267c\347\332[\340\226\34f\271\245\30\17\17\217\311\351s\313\232[\r\353[\260_\354\307"..., 4096) = 4096
+read(8, "\2520\\\232\251\376A\\^y\353)\375\3373\272w\303\243\27\251\31YA!\241\264L\241\346\316\23"..., 4096) = 4096
+read(8, "<\261\200B\35\r\2616\302I\321\232cF^\220\22%\371\353\270$I\0\376\305$\254j&/`"..., 4096) = 4096
+read(8, "G\21\340r)Y2\207U\21_v,\255\307\362\254\351\307Ku\237yd\\6\207{1Y\272#"..., 4096) = 4096
+read(8, "\272H\325\337^\243\313\"\365\202Z\271\357Vo/\265\241p\r\224\32\206\263\213\353s`\265\tX\326"..., 4096) = 4096
+read(8, "\343\303-\216DC\"]\271\261\25T\4\23\250\341\30\276\222 \205\355,\6\251a$h\4\225;u"..., 4096) = 4096
+read(8, "S;q4\307\221c\227\243^\272\200\205gB\326G\n\262r\234\351NG\222\242\357H+\227\240T"..., 4096) = 4096
+read(8, "5\277\353\225\264h\216\311-5\212U\n1\226E\1\2232\277j\v\204$\320\253\4\204!Of\221"..., 4096) = 4096
+read(8, "p\0T\331\307\271\325\3715\31\247\323\353\31x]h\1\303\215\0007`w\301 B\351\361\215\366\212"..., 4096) = 4096
+read(8, "|\r\334\222\6\314\2?\274\315\"\264\224o\6\307\225\335\332p\315cQ<\224\21\20\225\24\327\22\232"..., 4096) = 4096
+read(8, ":\202\262ERV\272~\2\362\241\310\306L\324\312\222gf\242\1\26o\234\252\02169\236\355O\301"..., 4096) = 4096
+read(8, "$\374Y\334\333\225\371 $\17N\336(\242\37E\357\376\220]\\\336\262\236\314-\254\31`\226\332\t"..., 4096) = 4096
+read(8, "\341S\t\31/K\265ms\261N{\20\215\201\16f\331r\310sk\213T\325n&\224m\224\305+"..., 4096) = 4096
+read(8, "\275\17\321T/\t\320\373\275\35\322\373:g\262\306w\220\265\245\367\25~\244\352\251\32\250\37\227A\347"..., 4096) = 4096
+read(8, "n\332vrj3?\v6qM\274\24\4f?(\324o\301M\351@\334\213\343&:\276\242\315\245"..., 4096) = 4096
+read(8, "\324\230\330I\233\315\256\357\244M\244\361mw\216\264\\H\336\3033\313A\244R\211Xb\266\21\3678"..., 4096) = 4096
+read(8, "u\231\211*\3671\322\361\261\215\200\344z<CI\243f\361\305\2S\337\260\26z\326\366\235\331\n\32"..., 4096) = 4096
+read(8, " obj\n<</Length 2233 0 R/Filter/F"..., 4096) = 4096
+read(8, "\260\3648\222\203\33\246fw\370\n\311\323\r\346@\324C\236\270\10\275\02227\345\360\217\vy\n\213"..., 4096) = 4096
+read(8, "y%?\310\20\334\265\252'T\233\333\203\331C\303\355\201\212\351[\326\4\364@\33\253\20&\373^\227"..., 4096) = 4096
+read(8, "Q\311\242\302J\32\243v\321\367\250~\274\347Bh\372\210\340\361U\320\206\235\245P>\264\252\37\253\7"..., 4096) = 4096
+read(8, "\302g\vrTu9bh0\v9\252\23\362\303\322\vG\314e\264\4D1\212\205N\2\2\221\302"..., 4096) = 4096
+read(8, "\227+\323\204[\374\2563\276\t\353\5:X\320\201ut\0F\25U\301\206\211\337\205\365\255\337B)"..., 4096) = 4096
+read(6, "\337U\270N\274`\367aa\277|\270\367\17\26/\231\225\10?R\267[\323\262\246b\264A\32]\313"..., 4096) = 4096
+read(6, "\242\34*\241\00347cVn>\225/\310}\227\23375#\313\324\306\323v\322\326Ft\375\3070"..., 4096) = 4096
+read(6, "\272~QM3\0335}\373\321\22\v6{\317\251\n\2327\274sW\213\267\312p\tV\6n\311\241"..., 4096) = 4096
+read(6, "\346F%q\375\7p#S5\265\367\233\370\2425\353\271Y6\356< T;Y\177c\374\244i="..., 4096) = 4096
+read(6, "c\34\205\2234\276J\37e\230\376\4\316)\2\370\374\"\257\257o\213\277Z\227\36=\223xl\322\352"..., 4096) = 4096
+read(6, "\204\263\262\240\266\230\22\327\234@\1\262\0\202\365\33\267\326\3!l\5\371\n\236\16\200\2248\24\334\263"..., 4096) = 4096
+read(6, "\365y\1\201\357^\377a*\f\254C\36PU\3407\241TBGZ\305\322\250A\n\3l\325=\\"..., 4096) = 4096
+read(6, "\1T>\220\360\304\4Fh\372\363\250X\336G=*R\327=\253\217\v\307KA\315e\10\334\274O"..., 4096) = 4096
+read(6, ":\351\303\257_\377=\250\203J\237\374\352O\346\2608}Z\16\277\374\370\365\227\337\35\376\363\245N\253"..., 4096) = 4096
+read(6, "9\346\tA>/y\262w\210\310\321\336J\341\247\257\254\374\240\355 \3\310\7\235\341\233}1\200,"..., 4096) = 4096
+read(6, "R\371*\333\217L\377f?M\365\25\246\321\266\362n\270s\321q\342x\317P\353QB\21%\30\266"..., 4096) = 4096
+read(6, "ter/FlateDecode>>\nstream\nx\234\255ZM\2173"..., 4096) = 4096
+read(6, "\353\t\231\220\376\2\10D\217\337\206\300\16\215\37\f\1\303\361\213\20\330\221\21\221\323\214\357q\22%\303"..., 4096) = 4096
+read(6, "\327\364'6\274\326\322\347\276!\212\217=\277u\276\357\231:\257\3452G\323Hb\203\324\24+\241\256"..., 4096) = 4096
+read(6, "\36GT\315SA\341\362\320<\215\3356\327r\2\303\300\230\207\f\322\4i\306fu\250\1\n\tz"..., 4096) = 4096
+read(6, "+\315\222\2715Z\177\250\2\27\323Ac\243\202!\5\325\347\356\221bcS}*\207\25\337\263\266\323"..., 4096) = 4096
+read(6, "Fz\356\202\254s\27\331n&\24\317\331\323\212C\n\215\313\350\25&9\4\20/\310s\302\342v\265"..., 4096) = 4096
+read(6, "\260\333\3714MZ\273]x\303\361\10\20\2029\0341\344\216\303-\333\312I\265\33\265%\252\315y\31"..., 4096) = 4096
+read(6, "\351\224\255\306\252\234\255\353Y\204~Q5t\277\177d\206\315)hc\0262\301\37\6\262\r\205\367\341"..., 4096) = 4096
+read(6, "\243\374&\245\255\342\342d\323\353\225\30\335\327\251Z\311\36\264\5q6\321\352'\212\203\23\256\224\233\344"..., 4096) = 4096
+read(6, "\26\315\333?e\21\33\4\340\323\177\"^*\334\227\351?^\221\350\343\nendstream"..., 4096) = 4096
+read(6, "Filter/FlateDecode>>\nstream\nx\234\255Y"..., 4096) = 4096
+read(6, "\277\276|Z\251\326\312\36\355\206j\346$3)\225\33 \252\2e\">\333\23\231F\223-\235{J"..., 4096) = 4096
+read(6, "lter/FlateDecode>>\nstream\nx\234\255X\313\252"..., 4096) = 4096
+read(6, "5\nendobj\n\n158 0 obj\n<</Length 15"..., 4096) = 4096
+write(7, "aC18h\\\307-Wn\330\254\354\233\242\376\341\217A!\241\16\372vk\202[\32`\256[\322"..., 4096) = 4096
+write(7, "\337U\270N\274`\367aa\277|\270\367\17\26/\231\225\10?R\267[\323\262\246b\264A\32]\313"..., 4096) = 4096
+write(7, "\242\34*\241\00347cVn>\225/\310}\227\23375#\313\324\306\323v\322\326Ft\375\3070"..., 4096) = 4096
+write(7, "\272~QM3\0335}\373\321\22\v6{\317\251\n\2327\274sW\213\267\312p\tV\6n\311\241"..., 4096) = 4096
+write(7, "\346F%q\375\7p#S5\265\367\233\370\2425\353\271Y6\356< T;Y\177c\374\244i="..., 4096) = 4096
+write(7, "c\34\205\2234\276J\37e\230\376\4\316)\2\370\374\"\257\257o\213\277Z\227\36=\223xl\322\352"..., 4096) = 4096
+write(7, "\204\263\262\240\266\230\22\327\234@\1\262\0\202\365\33\267\326\3!l\5\371\n\236\16\200\2248\24\334\263"..., 4096) = 4096
+write(7, "\365y\1\201\357^\377a*\f\254C\36PU\3407\241TBGZ\305\322\250A\n\3l\325=\\"..., 4096) = 4096
+write(7, "\1T>\220\360\304\4Fh\372\363\250X\336G=*R\327=\253\217\v\307KA\315e\10\334\274O"..., 4096) = 4096
+write(7, ":\351\303\257_\377=\250\203J\237\374\352O\346\2608}Z\16\277\374\370\365\227\337\35\376\363\245N\253"..., 4096) = 4096
+write(7, "9\346\tA>/y\262w\210\310\321\336J\341\247\257\254\374\240\355 \3\310\7\235\341\233}1\200,"..., 4096) = 4096
+write(7, "R\371*\333\217L\377f?M\365\25\246\321\266\362n\270s\321q\342x\317P\353QB\21%\30\266"..., 4096) = 4096
+write(7, "ter/FlateDecode>>\nstream\nx\234\255ZM\2173"..., 4096) = 4096
+write(7, "\353\t\231\220\376\2\10D\217\337\206\300\16\215\37\f\1\303\361\213\20\330\221\21\221\323\214\357q\22%\303"..., 4096) = 4096
+write(7, "\327\364'6\274\326\322\347\276!\212\217=\277u\276\357\231:\257\3452G\323Hb\203\324\24+\241\256"..., 4096) = 4096
+write(7, "\36GT\315SA\341\362\320<\215\3356\327r\2\303\300\230\207\f\322\4i\306fu\250\1\n\tz"..., 4096) = 4096
+write(7, "+\315\222\2715Z\177\250\2\27\323Ac\243\202!\5\325\347\356\221bcS}*\207\25\337\263\266\323"..., 4096) = 4096
+write(7, "Fz\356\202\254s\27\331n&\24\317\331\323\212C\n\215\313\350\25&9\4\20/\310s\302\342v\265"..., 4096) = 4096
+write(7, "\260\333\3714MZ\273]x\303\361\10\20\2029\0341\344\216\303-\333\312I\265\33\265%\252\315y\31"..., 4096) = 4096
+write(7, "\351\224\255\306\252\234\255\353Y\204~Q5t\277\177d\206\315)hc\0262\301\37\6\262\r\205\367\341"..., 4096) = 4096
+write(7, "\243\374&\245\255\342\342d\323\353\225\30\335\327\251Z\311\36\264\5q6\321\352'\212\203\23\256\224\233\344"..., 4096) = 4096
+write(7, "\26\315\333?e\21\33\4\340\323\177\"^*\334\227\351?^\221\350\343\nendstream"..., 4096) = 4096
+write(7, "Filter/FlateDecode>>\nstream\nx\234\255Y"..., 4096) = 4096
+write(7, "\277\276|Z\251\326\312\36\355\206j\346$3)\225\33 \252\2e\">\333\23\231F\223-\235{J"..., 4096) = 4096
+write(7, "lter/FlateDecode>>\nstream\nx\234\255X\313\252"..., 4096) = 4096
+write(9, "\336\370\244A\2127B\r\372\0371\277\372\325\257V\256\\\231\233\233\253\331\32\t\362\207\213\327Z\24\274"..., 4096) = 4096
+write(9, "%\vB\253\363\324\325`\300Q\3\215;\21m\244\365\203\210\346\226e\3\23\22\201,\347_\333\262C"..., 4096) = 4096
+write(9, "&\27\23\273\v\2\335\5\223\36Lg\25\3\301\357\347\35\\Nc\5\207\\\316\17~T9B\v;"..., 4096) = 4096
+write(9, "]\333kU\376`\227e\261\313\222\26\261u\2\36\232z\255\241\225\24\254\36\253$\325=N\353j\275"..., 4096) = 4096
+write(9, "\35i\37\254\307\264&\214\337\303\2\177\234s\242d\207\305\325^\366'\305\325\314\201\376\266lw\202\241"..., 4096) = 4096
+write(9, "\0\202\3525\n\212\10\325-\334X\371\306\35\347L\300UG\234\307\23\231\205gc\250\302\224\v\216\0"..., 4096) = 4096
+write(9, "A\356\214\21\215\316\r\32yld%\30\3322\"\23\224\205\22\31%\310!GK\333\306\20Q\205;"..., 4096) = 4096
+write(9, "\31\373lQ\365\234\274z\366\206\365b\323y\336\305\234{\244\331A\367\255m\272z\244\365\226v`\207"..., 4096) = 4096
+write(9, "\3~\216;\373\217+\0K\334\24\301\362\371\310*a\3008\251Zb\364\227\26\270Hh\311\266\351e"..., 4096) = 4096
+write(9, "@\362Z\273i+!\274\215\324\v$\231[s\300\235\230\303\333\222f%\35?\307\226\207l\34h\267"..., 4096) = 4096
+write(9, "5\370\325Wo\304\275Y\216\203ra\177\23F\r\377\262}!\212\202\3508\177\rPb\303\2366C"..., 4096) = 4096
+write(9, "/\346q3dw\342*?nAA\303\263\363\202d\271\326L|r\36E\271\254\315#\231\250\"5"..., 4096) = 4096
+write(9, "a<\246\327T\372\223\352IR?yi\334\273\327%\3330\356_\32w\372/M\337_\2326;\207"..., 4096) = 4096
+write(9, "\316\5\205E\7\271b\267\344\25l\365x\254\6m*\246,\236\26\212\320\365\365\254eW\223-4\344"..., 4096) = 4096
+write(9, "{\3\227\313\32\276P\301\210\232\33F\32\350\214\252\305Q8\36\267\35\215\225\342\242\25~\267\"\333u"..., 4096) = 4096
+write(9, "l\321\275n/\277\375\372\355\317\177x\371\27}\7\377~\373\307\267\373\367o\336\271\327\370\262\256\361\345"..., 4096) = 4096
+write(9, "\316\310\207#\315\265\257\273\235\304\375\361\31\2221\354\214s%(\222\373\334[rg\331\25w0;\343"..., 4096) = 4096
+write(9, "\324\236\304\0-\343T&\275&\371B\206\203\34>;\201\223{\23WzV\205\262\f\234\315Y\21o"..., 4096) = 4096
+write(9, "U3\3525\311R\262\304\5\ntYX\244\354\364\334\330(\233>\232\322\324\230\315\236El\355-M"..., 4096) = 4096
+write(9, "m\24<\2671:\305\323\250\"K\232\16\222O0\343\34r3\346H\227\221l\v\207\270\222\205Z\22"..., 4096) = 4096
+write(9, "\311A\2250St\232\\\n\25Uc,Q\311U\202\271TJ\214\33\372z\232\n\226$L_Hm"..., 4096) = 4096
+read(8, "\256\272$\244g\214.5aa\320/-Z\247F~z\f\7\264\2329\v\237\f\304\270J\214\340\313"..., 4096) = 4096
+read(8, "\317\257r\1T\272\332J8\264\3203\230u\241E9\303i`c\341a\200\200\6\235y\200\20\"\216"..., 4096) = 4096
+read(8, "\343\220\261B9%\316r\364t\234\310\306z\301\33\317\246\313\302\2426\352\212\3613\217\312\262b\271r"..., 4096) = 4096
+read(8, "\26\217(\373\231\360\2707{T\254\200\202\240\21\234\25\353\206{\245\viq\356\226\34\v\34\370\212\34"..., 4096) = 4096
+read(8, "\34\343Wz\304\364\323sS\30\307\243\t\372bt\260\300\350c\26\320'C!\351!b\245]\243\246"..., 4096) = 4096
+read(8, "\333+B\306+%\177\313\263U(\301)\244h\ng\215\302\r\334|\324m\240\205\3\21E\30\274\231"..., 4096) = 4096
+read(8, "\257\335\235\211\26v\222\314\23X\332\4\231,\33K\260\351\237\315\265\234\212k\234\21\216\255\370\177\235\354"..., 4096) = 4096
+read(8, "|\361\366\326\362\251s\26\272UODr\352\306\245q\372\275\f\30\34\274\354\346\376\3\30439kJ"..., 4096) = 4096
+read(8, "\216\213\362\232_YSS\223\271j\371\306r1\366\310\321\177=\375UUU\205\270c\212A\273L\7"..., 4096) = 4096
+read(8, "xS\226F\10!\361\0026\264\356\355-'?\377\\\330\226\3414\273D\244\244l3\362 \247\375\n"..., 4096) = 4096
+read(8, "L\267X?\4k\227\321<aun\374E\277o\244]\6^\10\3552g\241]\352\254%\26)t"..., 4096) = 4096
+read(8, "200000d>\320.\31\30\30\30\30\30R\6M\273\314\26\365\352\325\313v\25\10!\204\220"..., 4096) = 4096
+read(8, "\332`Vu\365\325W\243&\35:tx\374\361\307\341\5w\335u\27\246\264b\251x\215\342\234s\316"..., 4096) = 4096
+read(8, "\320\236\276X\241\255u\215\253\344u;\17&'\353_~En\362\307e_\272?{\371\212|z\365"..., 4096) = 4096
+read(8, "\v\356\222\336'<\371\336K\353\241\301G\17\35\341\361\342\36\243\303\212\315\257\371\310-\237\34\342\302."..., 4096) = 4096
+read(8, "\264\\\276S\371P*\226\305\"\210Sc\361\344\202\6\321E\364\215\270\20\2\6 at G\36&|#\332"..., 4096) = 4096
+read(8, "\261\376wMg1\301{\325&\265\305\2446uP\334\232\31\237Y\233e\206\377\357\v\35\2427\311\301"..., 4096) = 4096
+read(8, "GU)q7=JS\215\30\377\235\v\277\342\2\237\363\271\250o{\360_z\260\313\343\362\224\25\314"..., 4096) = 4096
+read(8, "\320q\374N\177\177\354o\313\210\5\6\260\347d\207\203\356(\352\333:\303B=\24\204\201\30\216\374\247"..., 4096) = 4096
+read(8, "\225\314$\355M\"[\23\367'\222m\232;5d\207zNM\352I\33\31$L:h5e\303\7"..., 4096) = 4096
+read(8, "\16\263<\346yf\213r\37pH\267\2362B\261\311\22\334\245?\254'H\217\365\372\244\270\250\221x"..., 4096) = 4096
+read(8, "`H'[W\241D>\221$\322m\225\214\34j\37]\20\344\226\344`\242\304dJJ\2455\25x"..., 4096) = 4096
+read(8, "m\323m\250\2334\326\3759e\313\262\\\345\313\335n\225\245\276\375\357\336K\305\226\343\251\371Y\217s"..., 4096) = 4096
+read(8, "$\360+\326\360+\337b\345j\177\200u}\371\261g_\317\232\37{\366\261g\327-kY\325\322\261"..., 4096) = 4096
+read(8, "\322\6\337\237\206\357\331\360\335V\370\316>\370\366a\370g\33\276\205\340\337\332\7\217?6\240<\276\17"..., 4096) = 4096
+read(6, "/\31`}8\272\327\f\340\344s\232\301g\256\332-\1sY6z&\32\245\252$\300UI\234J"..., 4096) = 4096
+read(6, ":\0\360%\0\232\306\366\307\341?\233s\2705\nendstream\nendobj"..., 4096) = 4096
+read(6, "\24[O\31\177F\335\222\262\361\210\24\2067L\360\210O\3E\256,7\250G\213\224\271L\360\223\372"..., 4096) = 4096
+read(6, "\231\213 \215N\213Yfi_\224)N.\272P\253w\315j\"\364<\314\n\r\351\212T^\274U"..., 4096) = 4096
+read(6, "\326>\20\25\21\234\21\210\210\263\306\\\302\262\345\257\2127\3130\205\304\271\217\277\216[\2319g\366}"..., 4096) = 4096
+read(6, "\21\251\252\252B\3341\305\240]\272\340\330Ek\376'\273\\h\201\31\370b\203\332t\"\"\262\317\17"..., 4096) = 4096
+read(6, "\25\2112`\342\257\330\234\375~\231\242(\267Z\2515q+\23\22=?\363\5\375}W\357\221\343\305"..., 4096) = 4096
+read(6, "\250`\355R\7\235y\267\316\322\240\210\224]\6\270b\272y\24:x#\303v\31\257\336,p\326\224"..., 4096) = 4096
+read(6, "M5Ep,*e\255\324z*\312|\370\221G\314\327\333\325[I\271G\350\237-\27\0o\270\271"..., 4096) = 4096
+read(6, "c\335\307\36{\314\242C\343\306\215\277\365\255oa_\314\265\322,?\20\5\314)\370i\236\23\245\265"..., 4096) = 4096
+read(6, "$\20)\34\277\5\341\255\34\377\225q+V\375\365\3320\232D\6.\360\232\323\203\262\313&\371\3150"..., 4096) = 4096
+read(6, "\17\260i\17\266\273\t\350\7X\215\1x^\334\362\212|\360\331{\377E|\317\205kK}w\213\201"..., 4096) = 4096
+read(6, "\213\233~*,\374\307\241^\237\7B<\331!\4;<\177\37~\232q@\32\236\337\177\235\0\201\316"..., 4096) = 4096
+read(6, "f\252pD+\233\231\257]\360\207\317u\310Q\373R\314\342\2341\271*\254\242\252\3519\265\270[\30"..., 4096) = 4096
+read(6, "6l\2164+\233\227Ade\223\22i\206MM0`\303\306i\10OC\277\r}\376\265J\337\f"..., 4096) = 4096
+read(6, "4\211n\225\325\340\255@\325\373\321\0264I\212Q;\372#\32\303?\2079\324pz\374T\250\266\263"..., 4096) = 4096
+read(6, "\373\237\34\335y:\231\341tZ5y\232(\265:\371\267r\26\320o\4O\371\232\234\352m\255\313-"..., 4096) = 4096
+read(6, "\203\r\32\203&\205\373\204\7Ts\2117 ..R\245q\221\202\236\23B%\5u\2450X|c"..., 4096) = 4096
+read(6, "\343\23\235\207\357\272\vU9\32\243\5\255\35\321^Ggct\0\22!\232\230\206\204\340\270`AU"..., 4096) = 4096
+read(6, "\327\272k\273\203\301\241x\213]\257c\276\374\331\324\273O\217\327\317~v\327C\357=>^\273\347\241"..., 4096) = 4096
+read(6, "\3057=\344\235L\375\3623j\203^\313\202\201Uk\264,W\320\332\331\0371\344\34595\350\374\352"..., 4096) = 4096
+read(6, "\340,\327\302\334\203\322qZ\356A\f3|\234\207\263Hx\231\223\2\257\20^K\310\327ip17"..., 4096) = 4096
+read(6, "\375\1L,\4\10\246\26\346\347\3+\305\3630O\346\367+\357\225w\363\201\364\v\4Q\312\260p>"..., 4096) = 4096
+read(6, "\321\232\307\326{z\2264&3\23\227\206/q\2\332,x\361\336\343\233\6\16\365\26\206?\3300\342"..., 4096) = 4096
+read(6, "w\274(Y\23\274Lce\262\225Y\35\214\345\321P\34\223\253\306\335\270\206\343M5\2475,\240\301"..., 4096) = 4096
+write(7, "5\nendobj\n\n158 0 obj\n<</Length 15"..., 4096) = 4096
+write(7, "/\31`}8\272\327\f\340\344s\232\301g\256\332-\1sY6z&\32\245\252$\300UI\234J"..., 4096) = 4096
+write(7, ":\0\360%\0\232\306\366\307\341?\233s\2705\nendstream\nendobj"..., 4096) = 4096
+write(7, "\24[O\31\177F\335\222\262\361\210\24\2067L\360\210O\3E\256,7\250G\213\224\271L\360\223\372"..., 4096) = 4096
+write(7, "\231\213 \215N\213Yfi_\224)N.\272P\253w\315j\"\364<\314\n\r\351\212T^\274U"..., 4096) = 4096
+write(7, "\326>\20\25\21\234\21\210\210\263\306\\\302\262\345\257\2127\3130\205\304\271\217\277\216[\2319g\366}"..., 4096) = 4096
+write(7, "\21\251\252\252B\3341\305\240]\272\340\330Ek\376'\273\\h\201\31\370b\203\332t\"\"\262\317\17"..., 4096) = 4096
+write(7, "\25\2112`\342\257\330\234\375~\231\242(\267Z\2515q+\23\22=?\363\5\375}W\357\221\343\305"..., 4096) = 4096
+write(7, "\250`\355R\7\235y\267\316\322\240\210\224]\6\270b\272y\24:x#\303v\31\257\336,p\326\224"..., 4096) = 4096
+write(7, "M5Ep,*e\255\324z*\312|\370\221G\314\327\333\325[I\271G\350\237-\27\0o\270\271"..., 4096) = 4096
+write(7, "c\335\307\36{\314\242C\343\306\215\277\365\255oa_\314\265\322,?\20\5\314)\370i\236\23\245\265"..., 4096) = 4096
+write(7, "$\20)\34\277\5\341\255\34\377\225q+V\375\365\3320\232D\6.\360\232\323\203\262\313&\371\3150"..., 4096) = 4096
+write(7, "\17\260i\17\266\273\t\350\7X\215\1x^\334\362\212|\360\331{\377E|\317\205kK}w\213\201"..., 4096) = 4096
+write(7, "\213\233~*,\374\307\241^\237\7B<\331!\4;<\177\37~\232q@\32\236\337\177\235\0\201\316"..., 4096) = 4096
+write(7, "f\252pD+\233\231\257]\360\207\317u\310Q\373R\314\342\2341\271*\254\242\252\3519\265\270[\30"..., 4096) = 4096
+write(7, "6l\2164+\233\227Ade\223\22i\206MM0`\303\306i\10OC\277\r}\376\265J\337\f"..., 4096) = 4096
+write(7, "4\211n\225\325\340\255@\325\373\321\0264I\212Q;\372#\32\303?\2079\324pz\374T\250\266\263"..., 4096) = 4096
+write(7, "\373\237\34\335y:\231\341tZ5y\232(\265:\371\267r\26\320o\4O\371\232\234\352m\255\313-"..., 4096) = 4096
+write(7, "\203\r\32\203&\205\373\204\7Ts\2117 ..R\245q\221\202\236\23B%\5u\2450X|c"..., 4096) = 4096
+write(7, "\343\23\235\207\357\272\vU9\32\243\5\255\35\321^Ggct\0\22!\232\230\206\204\340\270`AU"..., 4096) = 4096
+write(7, "\327\272k\273\203\301\241x\213]\257c\276\374\331\324\273O\217\327\317~v\327C\357=>^\273\347\241"..., 4096) = 4096
+write(7, "\3057=\344\235L\375\3623j\203^\313\202\201Uk\264,W\320\332\331\0371\344\34595\350\374\352"..., 4096) = 4096
+write(7, "\340,\327\302\334\203\322qZ\356A\f3|\234\207\263Hx\231\223\2\257\20^K\310\327ip17"..., 4096) = 4096
+write(7, "\375\1L,\4\10\246\26\346\347\3+\305\3630O\346\367+\357\225w\363\201\364\v\4Q\312\260p>"..., 4096) = 4096
+write(7, "\321\232\307\326{z\2264&3\23\227\206/q\2\332,x\361\336\343\233\6\16\365\26\206?\3300\342"..., 4096) = 4096
+mmap(NULL, 139264, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fb0c4152000
+write(9, "*\343:\347\363\222\313SJx'\27\215\247FY\323\273\214Z\263\342\227\21\235\373\0o\246\377\254\36"..., 4096) = 4096
+write(9, "\320\333\302\v=\224\336\272\273\320C\241{\351\337\257\244\371\360\330\361\204\335\22H\34\217Fz$=#"..., 4096) = 4096
+write(9, "3e\367\262\357V\323\236X\2301\346hSUL&\v\207\246\340\36\26\203\177\336\3\f\354V\232\226"..., 4096) = 4096
+write(9, "6\341\25\225\274\212\212WlM\230\345\31o\213A\305$G\325\362\20\271\367\31}\331\231\233E\366="..., 4096) = 4096
+write(9, "\323\201)\320E\341\314d\36\303Le\2\277\3601\214\344\334\361\350\325\326\3640\360\223g\300|fs"..., 4096) = 4096
+write(9, "\302\322\307u}A\331\210\303\7\243\331\224`\215\225v\1&r\3370\260\243\304\222\242\255\2056._"..., 4096) = 4096
+write(9, "j\n\n209 0 obj\n1357\nendobj\n\n211 0 "..., 4096) = 4096
+write(9, "\341%\353\225\270\223\260'\324+\361\223\330+\361J\257$\216\263W\3425}\301q\364J|\276^I"..., 4096) = 4096
+write(9, "\303\366\1\334\231\234P\223#P\333<\343\264\225\334k\3109\354\3375\317\210\2B\310\211\234\266sz"..., 4096) = 4096
+write(9, "tc\\Ib?e\202\252L\243`0T\3755\23\314\200F\324c\312\6 at K\20p_\367R\31"..., 4096) = 4096
+write(9, "uTo\1\223Q\231\247j\30X\223F\222\204\337\274\373\275\31\326'`\351\374\206t\265\305Q\210\261"..., 4096) = 4096
+write(9, "e[C\363\32qdR\354\23\247&\372\6\6w\364Ml\23\307\206n~\276id\363\340D\337\324"..., 4096) = 4096
+write(9, "W\277\267\253w\363Pmf \351\27\2649\256\260\375\252f\274C\256t3HrIM\241F\32b"..., 4096) = 4096
+write(9, "\255\3\225\375EE\346\nKQsc\203;\3675\360\256g\324j\r\272\377vw\201;G\5,\224"..., 4096) = 4096
+write(9, "N\306\351,\312\236\327\251\213\346\2113C\332T4S\203\372b$}\242\343\365\304\312\361\36^\ta"..., 4096) = 4096
+write(9, "\256\233\234(\227\272;[\332\373\232\7:c\33\245\251yi\\Z\230\33\237\230\334;>w\2554\275"..., 4096) = 4096
+write(9, "sq\\e\325\357\355\354[\23\262\365X\373p\246\255\261wZ\35!\3372\354\340e\316\316\376el"..., 4096) = 4096
+write(9, "\266\356\260\3626+\230\325]v\215GC5\252\200\33\25H\237\336\321h6\253\343\3\"\247V\274&"..., 4096) = 4096
+read(8, "\264A\270\204\374\252\312\17_\10{f9T\351W\253\241\210/\r\3664\207\214\327\247~s\23\253\342"..., 4096) = 4096
+read(8, "/a\37\210>\360!\277Cps\216M\5*\201\17\361M|\214_\340q\332A\342\37ss\372\21"..., 4096) = 4096
+read(8, "\211\213\257_\314J+\307Ka\374\214:\244\201\375K\341|OFuz\240\232\351\270\365\205[V\227"..., 4096) = 4096
+read(8, "\3265%[\353\266vne\267\254u\271\23\303K\356\315\303Q\3670vl\1\271\331<\220\0351\17"..., 4096) = 4096
+read(8, "#\306\327ew\267\361\242,\27y\\x\t\351\205\264\244x\26\255\205\222\342B\352L\327Su\346,"..., 4096) = 4096
+read(8, "D\213\305\266\335v\330F\317\332\300m\v\330\216\332\270\230T\377Y,\26U\375\330\333\27\213\200$\251"..., 4096) = 4096
+read(8, "\3660/\177\221\31\7$\327\223\353\313\355\311\35\316\335\221{$We\317\275\234K\323\226\237\326\202G"..., 4096) = 4096
+read(8, "xX\317\2627+;M\375X\224\3765J=\21\256\r\3433\210|\357W\270]\250\244\256U\3328"..., 4096) = 4096
+read(8, "$\272\300\320b\216\26_\224\361\331_V\\\304\264<\250w\353\323\335zw\r\21ci\370\301\3300"..., 4096) = 4096
+read(8, "\302H\203\214\204\3210 l\220\334)\343M2\31\317\341\26(\332I\31\201\5^\325\320\370\221F\303"..., 4096) = 4096
+read(8, "SnZ.\323\340\35\361\222}\342\254H\312E\274/\t\317\332\360*}\227\236\34R\343\260zH\275"..., 4096) = 4096
+read(8, "00 600 600 600 600 600 600 600 6"..., 4096) = 4096
+read(8, "\312\355\315:\222E}\26599\26\347\"U\270\326\350\6\267{A\355}*\230Q\1Q\201J\265\272"..., 4096) = 4096
+read(8, "8\17\177\204m\367\220i\371\376^\327N\327\235.n\255\rZ\235\220CA\225`M\240\32'\323\311"..., 4096) = 4096
+read(8, "\30\357\33\214h\2356\220A\302v\301\21+\211D\320\347*\v\226\241p\24\321\274\35\243\27\36\231Z"..., 4096) = 4096
+read(8, "\247c>\355\n<e\306\277\253\265\\\326\274\0p\n\236\204\330\242F\226\305\26=E\236$\224{\330"..., 4096) = 4096
+read(8, "\264\254\274\242rb\244\252Z\2354yJMm\335\324h\375\264\206[\246\317\230\3318k\366\234\246\346"..., 4096) = 4096
+read(8, "*qm\246\306\0249\30nD1L~\221i!f&O\250\334\3653\335\204\306\3705\261B\361\371"..., 4096) = 4096
+read(8, "\3529\250\344 \333\10\rh>\302\254\213p\rn\3028\33\227`,R\274\231G\310,\3\33\223a"..., 4096) = 4096
+read(8, "P\36V\236RN)\\\267\2\271J\231\322\242\20'#\201?)\360\276\2O)?S\360\1\5\6"..., 4096) = 4096
+read(8, "\303e\226\215\271\215:9\255\360\312\353U\330\331\275\33\235\333\2569\304\27_\225xv\204\317\242)\4"..., 4096) = 4096
+read(8, "\2778\320q\177\320\327\326\256\311\231\315\263\345\34\207#_\256\366\266\310\236&m\256\\\356o\266\311\305"..., 4096) = 4096
+read(8, "\203\0258\262\263\202\365\356\360\320wt\5\305\32\f\210\3\2211\252=\235\343\305\22\3\3758Dc5"..., 4096) = 4096
+read(8, "\254\252n\3277\314-G^\333\275\357\255\7V\256\30\330\273R\327>\370\322\351\320\334\360\220\266\351\276"..., 4096) = 4096
+read(8, "oX\327\323\247\v\375VU1\375\324\255S\301[+V\337\366\340\201\351x\372\331\3576\337\273c\250"..., 4096) = 4096
+read(6, "\316\304WX\324\250\340\267\211\300\200\350A\366M@\255\330\354+\301j8F\244]\344\16Gjag"..., 4096) = 4096
+read(6, "G\217<w\3669\345\24\200\3769\235\336o8\0368N\217q\21\232\223H-\336\315xs\344\0>"..., 4096) = 4096
+read(6, "]\374\226\2576s8w\366\224\2\236\17\326\314\316\35\235@\353\262ut\36\227\306MG\331\264\206{"..., 4096) = 4096
+read(6, "\"\240$y\221\362\10vE@\214\300\317?\211|\35\301\335\24\300\35\210\274\34y3\302\323\344\351W"..., 4096) = 4096
+read(6, "\3467\327\16\236\333\35\232\26v\325\336yl\305m\303\375\223G\217\36\2331\270\2642\330\334\3270\265"..., 4096) = 4096
+read(6, "\3469\273\327\314M\33\235\217\233C\233\37{u\305\363\243_\34o\305oh]\24\234\333?\275\244\250"..., 4096) = 4096
+read(6, "A\337\3002\277\246)\3124\7\305\275\24S\266k\207p\360\305T\272\300\354\266.\260\347gL\f6"..., 4096) = 4096
+read(6, "\216\277\3025\364s\232'\353u\332\206\363\322\347s=~\251\257!\263\252\347C\273\274\356\346\307\363R"..., 4096) = 4096
+read(6, "\32\247\344\3620\317\214\37C9,#\273\237G\326\26xa\36\22D\203\214\230eD\220\241\214i\347"..., 4096) = 4096
+read(6, "%\222m\352\00147b\"\3768\332v\314Y\205=\7\357\317m*\317E\225`\357\233\375\207\321\343"..., 4096) = 4096
+read(6, "\374\340\343\317\36\376\333\373\277\230\234\371\315\7\37\355?\360\321\7\277\336\211c\373p\354\235\322\330+\304"..., 4096) = 4096
+read(6, "W\311:\371\36y\355\352x\201\207j(\2\31\371'\330F~L\336#o\220W\310\303\357\233W\20"..., 4096) = 4096
+read(6, "z\347\342\227N\356Y\253]\30s%\376J\373o\377\206Z\356C\271\\F;\253$~\362T \272"..., 4096) = 4096
+read(6, "\201\35\364\215\355>\312\306\215\233\2731_0\202^X\24\24\5S\320\273u\236Z\363\334\216\20\372\252"..., 4096) = 4096
+read(6, "^\22\341q\225F\303s\327\370\342\272A\347V\244\327W\27\210Bny\205e\16c(\201\tF\v"..., 4096) = 4096
+read(6, "\364\334:\26]\300\203ES\233\211\236t\210*\213(\2524\372d}\216\276\217-#\361{D\10\210"..., 4096) = 4096
+read(6, "\0\275!\351y?|I\251\364\200\37v\372a\243\37j\375P\344\207\17\375\360\242\37\36S*\210\345"..., 4096) = 4096
+read(6, "+\271\323\10\235\306\1#5\32u#\211b\354\275\205!\26\337\34R\2\234CW\313g\277\315\21_"..., 4096) = 4096
+read(6, "48>>\nstream\nx\234\325\274\7x\33\307\2650:3\273\213^\26\215\0\t\202"..., 4096) = 4096
+read(6, "G\36\31\34<>Z\261~\223\252\376\326U\345\313\217\276\17\263\337\7\374\264R\344c\237\220$\223Q"..., 4096) = 4096
+read(6, "*\225\354\10\r\335p2\213\270G)\306e6\323\355t\300\230\207\356\276\350\304\220\r/n\31P<"..., 4096) = 4096
+read(6, "\244\362\254\330\323\25\330\262<\277a\342\276\245\366\232\206\305\331\331~\343=I+\n<\3\231I\371&"..., 4096) = 4096
+read(6, "M>{\337;c\357\354z\207\351{k\354\255]o1\347\277\205\277\31N\267\217\237\303\216s\371\347"..., 4096) = 4096
+read(6, "0 0 595 842]/Annots[\n304 0 R 324"..., 4096) = 4096
+read(6, "0 R/MediaBox[0 0 595 842]/Group<"..., 4096) = 4096
+write(7, "w\274(Y\23\274Lce\262\225Y\35\214\345\321P\34\223\253\306\335\270\206\343M5\2475,\240\301"..., 4096) = 4096
+write(7, "\316\304WX\324\250\340\267\211\300\200\350A\366M@\255\330\354+\301j8F\244]\344\16Gjag"..., 4096) = 4096
+write(7, "G\217<w\3669\345\24\200\3769\235\336o8\0368N\217q\21\232\223H-\336\315xs\344\0>"..., 4096) = 4096
+write(7, "]\374\226\2576s8w\366\224\2\236\17\326\314\316\35\235@\353\262ut\36\227\306MG\331\264\206{"..., 4096) = 4096
+write(7, "\"\240$y\221\362\10vE@\214\300\317?\211|\35\301\335\24\300\35\210\274\34y3\302\323\344\351W"..., 4096) = 4096
+write(7, "\3467\327\16\236\333\35\232\26v\325\336yl\305m\303\375\223G\217\36\2331\270\2642\330\334\3270\265"..., 4096) = 4096
+write(7, "\3469\273\327\314M\33\235\217\233C\233\37{u\305\363\243_\34o\305oh]\24\234\333?\275\244\250"..., 4096) = 4096
+write(7, "A\337\3002\277\246)\3124\7\305\275\24S\266k\207p\360\305T\272\300\354\266.\260\347gL\f6"..., 4096) = 4096
+write(7, "\216\277\3025\364s\232'\353u\332\206\363\322\347s=~\251\257!\263\252\347C\273\274\356\346\307\363R"..., 4096) = 4096
+write(7, "\32\247\344\3620\317\214\37C9,#\273\237G\326\26xa\36\22D\203\214\230eD\220\241\214i\347"..., 4096) = 4096
+write(7, "%\222m\352\00147b\"\3768\332v\314Y\205=\7\357\317m*\317E\225`\357\233\375\207\321\343"..., 4096) = 4096
+write(7, "\374\340\343\317\36\376\333\373\277\230\234\371\315\7\37\355?\360\321\7\277\336\211c\373p\354\235\322\330+\304"..., 4096) = 4096
+write(7, "W\311:\371\36y\355\352x\201\207j(\2\31\371'\330F~L\336#o\220W\310\303\357\233W\20"..., 4096) = 4096
+write(7, "z\347\342\227N\356Y\253]\30s%\376J\373o\377\206Z\356C\271\\F;\253$~\362T \272"..., 4096) = 4096
+write(7, "\201\35\364\215\355>\312\306\215\233\2731_0\202^X\24\24\5S\320\273u\236Z\363\334\216\20\372\252"..., 4096) = 4096
+write(7, "^\22\341q\225F\303s\327\370\342\272A\347V\244\327W\27\210Bny\205e\16c(\201\tF\v"..., 4096) = 4096
+write(7, "\364\334:\26]\300\203ES\233\211\236t\210*\213(\2524\372d}\216\276\217-#\361{D\10\210"..., 4096) = 4096
+write(7, "\0\275!\351y?|I\251\364\200\37v\372a\243\37j\375P\344\207\17\375\360\242\37\36S*\210\345"..., 4096) = 4096
+write(7, "+\271\323\10\235\306\1#5\32u#\211b\354\275\205!\26\337\34R\2\234CW\313g\277\315\21_"..., 4096) = 4096
+write(7, "48>>\nstream\nx\234\325\274\7x\33\307\2650:3\273\213^\26\215\0\t\202"..., 4096) = 4096
+write(7, "G\36\31\34<>Z\261~\223\252\376\326U\345\313\217\276\17\263\337\7\374\264R\344c\237\220$\223Q"..., 4096) = 4096
+write(7, "*\225\354\10\r\335p2\213\270G)\306e6\323\355t\300\230\207\356\276\350\304\220\r/n\31P<"..., 4096) = 4096
+write(7, "\244\362\254\330\323\25\330\262<\277a\342\276\245\366\232\206\305\331\331~\343=I+\n<\3\231I\371&"..., 4096) = 4096
+write(7, "M>{\337;c\357\354z\207\351{k\354\255]o1\347\277\205\277\31N\267\217\237\303\216s\371\347"..., 4096) = 4096
+write(7, "0 0 595 842]/Annots[\n304 0 R 324"..., 4096) = 4096
+write(9, "M\347B\24\0278\264\10\31[\200\360<\25jU\240\342\2\24\354\24\f\24(Q\230\302\350\232f\214"..., 4096) = 4096
+write(9, "4<\355Q\253\305\353\17KG6\36\345i\327|\221G\361\250E\177\2744\371\r\305\242Y\203\367\212"..., 4096) = 4096
+write(9, "W\254:\314\264\244\35t\200\356\340f 7\252Rse\273b\307v\2737\301]w\206\351O2R"..., 4096) = 4096
+write(9, "C\v\257\304\306\224t\n\230\374\377\4\30:\222\256\340C\337U\"\202(\32*-_0\311\367\302U"..., 4096) = 4096
+write(9, "\226x\353\274K\275\33\275\333\275OzOz_\367~\344\375\302\233\360\6\273b/\33\261c\357\177\34"..., 4096) = 4096
+write(9, "\3704\315U\370\230f\214?\20\341i\21\366\211PNiq\201\10`\24a\377\n\261_\334%>+"..., 4096) = 4096
+write(9, "\2161\313\243\333\f\373\242\331D:e\334\367\257\227\6'\255\373.\221A\6r0J!g\310\30\337"..., 4096) = 4096
+write(9, "\32@\364\316\315\5\\\216\300\334\300\334\340\374\342\336\215.\207\3015wZ\243\231\233\252G\f\223\326n"..., 4096) = 4096
+write(9, "\246I\37\303?s~\373J\231\17\274\337\300D)\363\255$\211\n78\313BD\351\24E\204\203\37"..., 4096) = 4096
+write(9, "\27\4X\2\361\232\375p\3l\350\336;1\320\256'\240>\374\203\205;\245\27\267!\2\331\302\203\330"..., 4096) = 4096
+write(9, "A\367l \323\216\244\326\210[\324\272 at S \321~\245q\261\221\2666Bc at m\367\7[\2024"..., 4096) = 4096
+write(9, "/aP\22\355\25]|\22\265\206\26\10v\27\325\351\202\263\357\275'm\22H\347\306/d\7\321\336"..., 4096) = 4096
+write(9, "\312\231,\254%G\345?\352H,\335\272\26207\237\344+f*y\257\333]\317\17\305c|w4"..., 4096) = 4096
+write(9, "\225\345\343\312g\200\345\207\315\36s\246\307\354YD\335S\31\360\340\324fa\345\337\236X\304\277\311\214"..., 4096) = 4096
+write(9, "\323`\214\315\27\223\331b2\233M\354`\203d\252h\364\2332\235\6\31\302\5f\247H4\215\351&"..., 4096) = 4096
+write(9, "\6\266\205\332\2501.3\21\213\211\271B\315\234\206\253\247\200.\7H\32\7\316B7\372v\32\r5"..., 4096) = 4096
+write(9, "\375\223m--\326 at 1k\353\32l\353o>w\2\6\240\377sS\35\3127Q\246\337B{_\305"..., 4096) = 4096
+write(9, "\32]\326\266\354g\313\376\260\354?\227\t\17.\3\373\322\214\274Z\373\322T\367\377\323\262\331\3534\f"..., 4096) = 4096
+write(9, "jS}\276\224\313*.3f,*\261\367\17z\33\v\223\342\266\202\330\357\231g\250\245\200Q\35\350"..., 4096) = 4096
+write(9, "\267\271\300\261/\376x\354\30\253\216\307\264\243\235l\n\333\204\n\300:?&\324\354\310\237\315'\303~"..., 4096) = 4096
+write(9, "\331tj\223\4\316R\236\307\22\205J\262\356M|\207\241\250\322\237\22l^\22L\361W\372\f\321\333"..., 4096) = 4096
+write(9, "\271\320^\0003\242\20\313C\276\277y\347?\36\365\377\f\0221\230\257\25G\231\22\307\216\365\34\21\307"..., 4096) = 4096
+write(9, "aBox[0 0 595 842]/Group<</S/Tran"..., 4096) = 4096
+write(9, "[\n293 0 R 294 0 R 295 0 R ]\n/Gro"..., 4096) = 4096
+read(8, "\331\261c\7\260\4\26\331\201\3570\204a\314\311\252\16\347\303k\32\360\225[J\306\342\250ZX\315\204"..., 4096) = 4096
+read(8, "S/Transparency/CS/DeviceRGB/I tr"..., 4096) = 4096
+read(8, "32\n/Group<</S/Transparency/CS/De"..., 4096) = 4096
+read(8, "ources 3772 0 R/MediaBox[0 0 595"..., 4096) = 4096
+read(8, "ructElem\n/S/Standard\n/P 4 0 R\n/P"..., 4096) = 4096
+read(8, "lem\n/S/Standard\n/P 4 0 R\n/Pg 34 "..., 4096) = 4096
+read(8, "</Type/StructElem\n/S/Span\n/P 84 "..., 4096) = 4096
+read(8, "ctElem\n/S/TOCI\n/P 91 0 R\n/Pg 86 "..., 4096) = 4096
+read(8, "bj\n<</Type/StructElem\n/S/Content"..., 4096) = 4096
+read(8, "tructElem\n/S/Link\n/P 181 0 R\n/Pg"..., 4096) = 4096
+read(8, "\n<</Type/StructElem\n/S/Link\n/P 2"..., 4096) = 4096
+read(8, "dobj\n\n240 0 obj\n<</Type/StructEl"..., 4096) = 4096
+read(8, "ent/Block\n/StartIndent 56.6\n>>\ne"..., 4096) = 4096
+read(8, "ype/OBJR/Obj 3665 0 R>>\nendobj\n\n"..., 4096) = 4096
+read(8, "endobj\n\n4035 0 obj\n<</Type/OBJR/"..., 4096) = 4096
+read(8, " 367 0 R\n/Pg 272 0 R\n/A 4058 0 R"..., 4096) = 4096
+read(8, "ign/Justify\n>>\nendobj\n\n398 0 obj"..., 4096) = 4096
+read(8, "93 0 R\n/A 4098 0 R\n>>\nendobj\n\n40"..., 4096) = 4096
+read(8, " R\n/A 4121 0 R\n/K[5 ]\n>>\nendobj\n"..., 4096) = 4096
+read(8, "\n>>\nendobj\n\n4137 0 obj\n<</O/Layo"..., 4096) = 4096
+read(8, "nt/Block\n/SpaceBefore 11.3\n/Text"..., 4096) = 4096
+read(8, "xt#20body\n/P 4 0 R\n/Pg 493 0 R\n/"..., 4096) = 4096
+read(8, "/SpaceBefore 11.3\n/TextAlign/Jus"..., 4096) = 4096
+read(8, "ctElem\n/S/Text#20body\n/P 4 0 R\n/"..., 4096) = 4096
+read(8, "obj\n<</Type/StructElem\n/S/Span\n/"..., 4096) = 4096
+read(6, "95 842]/Group<</S/Transparency/C"..., 4096) = 4096
+read(6, "0 R/XYZ 103.4 255.9 0]\n/5F5FRefH"..., 4096) = 4096
+read(6, "st[178 0 R/XYZ 99.3 459.2 0]>>\ne"..., 4096) = 4096
+read(6, "293.1 538.8 306.9]/Dest[97 0 R/X"..., 4096) = 4096
+read(6, "<</Type/Action/S/URI/URI(http://"..., 4096) = 4096
+read(6, "ype/Catalog/Pages 327 0 R\n/Dests"..., 4096) = 4096
+read(6, "9380 00000 n \n0000215587 00000 n"..., 4096) = 4096
+read(6, " ]\n/DocChecksum /A9128BDB763FCCD"..., 4096) = 76
+read(6, "", 4096)                       = 0
+read(6, "", 4096)                       = 0
+write(7, "0 R/MediaBox[0 0 595 842]/Group<"..., 4096) = 4096
+write(7, "95 842]/Group<</S/Transparency/C"..., 4096) = 4096
+write(7, "0 R/XYZ 103.4 255.9 0]\n/5F5FRefH"..., 4096) = 4096
+write(7, "st[178 0 R/XYZ 99.3 459.2 0]>>\ne"..., 4096) = 4096
+write(7, "293.1 538.8 306.9]/Dest[97 0 R/X"..., 4096) = 4096
+write(7, "<</Type/Action/S/URI/URI(http://"..., 4096) = 4096
+write(7, "ype/Catalog/Pages 327 0 R\n/Dests"..., 4096) = 4096
+write(7, "9380 00000 n \n0000215587 00000 n"..., 4096) = 4096
+write(9, "0 595 842]/Group<</S/Transparenc"..., 4096) = 4096
+write(9, "0]\n/5F5FRefHeading5F5F154955F187"..., 4096) = 4096
+write(9, "ink/Border[0 0 0]/Rect[70.2 481."..., 4096) = 4096
+write(9, "/Type/Annot/Subtype/Link/Border["..., 4096) = 4096
+write(9, "419.2]/A<</Type/Action/S/URI/URI"..., 4096) = 4096
+write(9, "t[64 0 R/XYZ 73.7 96.6 0]>>\nendo"..., 4096) = 4096
+write(9, " n \n0000210521 00000 n \n00002124"..., 4096) = 4096
+read(8, "an\n/P 674 0 R\n/Pg 611 0 R\n/Lang("..., 4096) = 4096
+read(8, "t/Block\n/SpaceBefore 11.3\n/Start"..., 4096) = 4096
+read(8, "/Span\n/P 735 0 R\n/Pg 683 0 R\n/La"..., 4096) = 4096
+read(8, "\n>>\nendobj\n\n770 0 obj\n<</Type/St"..., 4096) = 4096
+read(8, "8 0 R ]\n>>\nendobj\n\n800 0 obj\n<</"..., 4096) = 4096
+read(8, "<</Type/StructElem\n/S/verbatim\n/"..., 4096) = 4096
+read(8, ")\n/K[18 ]\n>>\nendobj\n\n869 0 obj\n<"..., 4096) = 4096
+read(8, "m\n/P 4 0 R\n/Pg 889 0 R\n/A 4358 0"..., 4096) = 4096
+read(8, "batim\n/P 4 0 R\n/Pg 889 0 R\n/A 43"..., 4096) = 4096
+read(8, "72 0 R ]\n>>\nendobj\n\n970 0 obj\n<<"..., 4096) = 4096
+read(8, "obj\n\n1004 0 obj\n<</Type/StructEl"..., 4096) = 4096
+read(8, "19 0 obj\n<</O/Layout\n/Placement/"..., 4096) = 4096
+read(8, "t 36\n/TextAlign/Justify\n>>\nendob"..., 4096) = 4096
+read(8, "ype/StructElem\n/S/Span\n/P 1097 0"..., 4096) = 4096
+read(8, "\n/Placement/Block\n/TextAlign/Jus"..., 4096) = 4096
+read(8, "7 0 R\n>>\nendobj\n\n4478 0 obj\n<</O"..., 4096) = 4096
+read(8, "ctElem\n/S/Text#20body\n/P 4 0 R\n/"..., 4096) = 4096
+read(8, "86 0 R\n/K[1222 0 R ]\n>>\nendobj\n\n"..., 4096) = 4096
+read(8, "bj\n\n4521 0 obj\n<</O/Layout\n/Plac"..., 4096) = 4096
+read(8, "3 0 R\n/A 4536 0 R\n/K[21 1284 0 R"..., 4096) = 4096
+read(8, " 1311 0 R 1312 0 R 1313 0 R 1314"..., 4096) = 4096
+read(8, "\n>>\nendobj\n\n4570 0 obj\n<</O/Layo"..., 4096) = 4096
+read(8, "\n1383 0 obj\n<</Type/StructElem\n/"..., 4096) = 4096
+read(8, "Type/StructElem\n/S/Text#20body\n/"..., 4096) = 4096
+read(8, "e 11.3\n>>\nendobj\n\n1444 0 obj\n<</"..., 4096) = 4096
+read(6, "", 4096)                       = 0
+read(8, "/Layout\n/Placement/Block\n/SpaceB"..., 4096) = 4096
+read(8, "obj\n<</Type/StructElem\n/S/Span\n/"..., 4096) = 4096
+read(8, "1483 0 R\n/A 4649 0 R\n/K[38 ]\n>>\n"..., 4096) = 4096
+read(8, "tructElem\n/S/Span\n/P 1577 0 R\n/P"..., 4096) = 4096
+read(8, "\n1607 0 obj\n<</Type/StructElem\n/"..., 4096) = 4096
+read(8, "ore 11.3\n/TextAlign/Justify\n>>\ne"..., 4096) = 4096
+read(8, "673 0 obj\n<</Type/StructElem\n/S/"..., 4096) = 4096
+read(8, "0 R\n/Pg 1699 0 R\n/A 4723 0 R\n/K["..., 4096) = 4096
+read(8, "/S/Span\n/P 1736 0 R\n/Pg 1699 0 R"..., 4096) = 4096
+read(8, " 0 R ]\n>>\nendobj\n\n1769 0 obj\n<</"..., 4096) = 4096
+read(8, " R\n/K[4 ]\n>>\nendobj\n\n4772 0 obj\n"..., 4096) = 4096
+read(8, "tElem\n/S/LBody\n/P 1829 0 R\n/Pg 1"..., 4096) = 4096
+read(8, "0 R\n/K[1860 0 R ]\n>>\nendobj\n\n186"..., 4096) = 4096
+read(8, "R\n/Lang(zxx)\n/K[28 ]\n>>\nendobj\n\n"..., 4096) = 4096
+read(8, "lem\n/S/Span\n/P 1931 0 R\n/Pg 1846"..., 4096) = 4096
+read(8, "stify\n>>\nendobj\n\n1964 0 obj\n<</T"..., 4096) = 4096
+read(8, "R 1980 0 R 1983 0 R 1986 0 R 198"..., 4096) = 4096
+read(8, "/Block\n>>\nendobj\n\n2020 0 obj\n<</"..., 4096) = 4096
+read(8, "uctElem\n/S/Span\n/P 2055 0 R\n/Pg "..., 4096) = 4096
+read(8, "\n/S/verbatim\n/P 4 0 R\n/Pg 2078 0"..., 4096) = 4096
+read(8, "</O/Layout\n/Placement/Block\n/Spa"..., 4096) = 4096
+read(8, "Align/Justify\n>>\nendobj\n\n2145 0 "..., 4096) = 4096
+read(8, "ent/Block\n/SpaceBefore 11.3\n>>\ne"..., 4096) = 4096
+read(8, " 0 R\n/A 4972 0 R\n/K[29 2207 0 R "..., 4096) = 4096
+read(8, "Elem\n/S/verbatim\n/P 4 0 R\n/Pg 22"..., 4096) = 4096
+read(8, "\n\n2274 0 obj\n<</Type/StructElem\n"..., 4096) = 4096
+read(8, "Pg 2231 0 R\n/A 5017 0 R\n/K[45 23"..., 4096) = 4096
+read(8, "lem\n/S/LBody\n/P 2334 0 R\n/Pg 232"..., 4096) = 4096
+read(8, "/K[2371 0 R ]\n>>\nendobj\n\n2377 0 "..., 4096) = 4096
+read(8, "/A 5060 0 R\n/K[37 ]\n>>\nendobj\n\n2"..., 4096) = 4096
+read(8, "endobj\n\n2442 0 obj\n<</Type/Struc"..., 4096) = 4096
+read(8, " 0 R ]\n>>\nendobj\n\n2468 0 obj\n<</"..., 4096) = 4096
+read(8, "n/Justify\n>>\nendobj\n\n2504 0 obj\n"..., 4096) = 4096
+read(8, "gn/Justify\n>>\nendobj\n\n2527 0 obj"..., 4096) = 4096
+read(8, "ify\n>>\nendobj\n\n2553 0 obj\n<</Typ"..., 4096) = 4096
+read(8, "0body\n/P 2584 0 R\n/Pg 2565 0 R\n/"..., 4096) = 4096
+read(8, "Indent 36\n/TextAlign/Justify\n>>\n"..., 4096) = 4096
+read(8, "obj\n\n2648 0 obj\n<</Type/StructEl"..., 4096) = 4096
+read(8, "t/Block\n/SpaceBefore 11.3\n/TextA"..., 4096) = 4096
+read(8, "\n>>\nendobj\n\n5233 0 obj\n<</O/Layo"..., 4096) = 4096
+read(8, ">>\nendobj\n\n2741 0 obj\n<</Type/St"..., 4096) = 4096
+read(8, "j\n<</Type/StructElem\n/S/Text#20b"..., 4096) = 4096
+read(8, "/verbatim\n/P 4 0 R\n/Pg 2796 0 R\n"..., 4096) = 4096
+read(8, "R\n/A 5297 0 R\n>>\nendobj\n\n5298 0 "..., 4096) = 4096
+read(8, " 2830 0 R\n/A 5313 0 R\n/K[2865 0 "..., 4096) = 4096
+read(8, "g 2830 0 R\n/A 5325 0 R\n/K[24 ]\n>"..., 4096) = 4096
+read(8, "\n/Pg 2897 0 R\n/Lang(zxx)\n/K[16 ]"..., 4096) = 4096
+read(8, "\nendobj\n\n2965 0 obj\n<</Type/Stru"..., 4096) = 4096
+read(8, "endobj\n\n5374 0 obj\n<</O/Layout\n/"..., 4096) = 4096
+read(8, "lem\n/S/Text#20body\n/P 4 0 R\n/Pg "..., 4096) = 4096
+read(8, "R\n/Pg 3024 0 R\n/A 5414 0 R\n/K[30"..., 4096) = 4096
+read(8, "\nendobj\n\n5433 0 obj\n<</O/Layout\n"..., 4096) = 4096
+read(8, "\n\n5454 0 obj\n<</O/Layout\n/Placem"..., 4096) = 4096
+read(8, " obj\n<</O/Layout\n/Placement/Bloc"..., 4096) = 4096
+read(8, " 5485 0 R\n/K[3176 0 R 3177 0 R ]"..., 4096) = 4096
+read(8, "21 0 R\n/A 5499 0 R\n/K[3209 0 R ]"..., 4096) = 4096
+read(8, "<</O/Layout\n/Placement/Block\n/Te"..., 4096) = 4096
+read(8, "ify\n>>\nendobj\n\n3268 0 obj\n<</Typ"..., 4096) = 4096
+read(8, "ructElem\n/S/Text#20body\n/P 4 0 R"..., 4096) = 4096
+read(8, "Justify\n>>\nendobj\n\n3332 0 obj\n<<"..., 4096) = 4096
+read(8, "t/Block\n/SpaceBefore 11.3\n>>\nend"..., 4096) = 4096
+read(8, "/Text#20body\n/P 4 0 R\n/Pg 3388 0"..., 4096) = 4096
+read(8, "33 0 obj\n<</O/Layout\n/Placement/"..., 4096) = 4096
+read(8, "\n\n3453 0 obj\n<</Type/StructElem\n"..., 4096) = 4096
+read(8, "<</O/Layout\n/Placement/Block\n/Sp"..., 4096) = 4096
+read(8, "pe/StructElem\n/S/Text#20body\n/P "..., 4096) = 4096
+read(8, "ut\n/Placement/Block\n/TextAlign/J"..., 4096) = 4096
+read(8, "<</Type/StructElem\n/S/Span\n/P 35"..., 4096) = 4096
+read(8, "ck\n/SpaceBefore 11.3\n/TextAlign/"..., 4096) = 4096
+read(8, "R 1078 0 R 1081 0 R 1082 0 R 108"..., 4096) = 4096
+read(8, " 2228 0 R 2230 0 R 2234 0 R 2236"..., 4096) = 4096
+read(8, "3220 0 R 3221 0 R 3222 0 R 3223 "..., 4096) = 4096
+read(8, " 434 0 R 433 0 R 439 0 R 447 0 R"..., 4096) = 4096
+read(8, " 0 R 1403 0 R 1405 0 R\n1406 0 R "..., 4096) = 4096
+read(8, "47 0 R 2149 0 R 2151 0 R 2153 0 "..., 4096) = 4096
+read(8, " R 2965 0 R 2967 0 R 2969 0 R\n29"..., 4096) = 4096
+read(8, "76 314 0 R\n177 317 0 R\n178 318 0"..., 4096) = 4096
+read(8, " obj\n<</Type/Annot/Subtype/Link/"..., 4096) = 4096
+read(8, "ink/Border[0 0 0]/Rect[56 715.9 "..., 4096) = 4096
+read(8, "8 0 obj\n<</Type/Annot/Subtype/Li"..., 4096) = 4096
+read(8, "ndobj\n\n3715 0 obj\n<</Type/Annot/"..., 4096) = 4096
+read(8, "0441541 00000 n \n0000441675 0000"..., 4096) = 4096
+read(8, "\n0000469005 00000 n \n0000468893 "..., 4096) = 4096
+read(8, "0 n \n0000496829 00000 n \n0000497"..., 4096) = 4096
+read(8, "00000 n \n0000522719 00000 n \n000"..., 4096) = 4096
+read(8, "766 00000 n \n0000548419 00000 n "..., 4096) = 4096
+read(8, "0574989 00000 n \n0000574733 0000"..., 4096) = 4096
+read(8, "\n0000601375 00000 n \n0000601467 "..., 4096) = 4096
+read(8, "0 n \n0000627289 00000 n \n0000627"..., 4096) = 4096
+read(8, "00000 n \n0000653206 00000 n \n000"..., 4096) = 4096
+read(8, "783 00000 n \n0000679694 00000 n "..., 4096) = 4096
+read(8, "0706504 00000 n \n0000706341 0000"..., 4096) = 4096
+read(8, "\n0000732171 00000 n \n0000732561 "..., 4096) = 4096
+read(8, "0 n \n0000760566 00000 n \n0000760"..., 4096) = 4096
+read(8, "00000 n \n0000787452 00000 n \n000"..., 4096) = 4096
+read(8, "753 00000 n \n0000813918 00000 n "..., 4096) = 4096
+read(8, "0840635 00000 n \n0000840820 0000"..., 4096) = 4096
+read(8, "\n0000867968 00000 n \n0000868263 "..., 4096) = 4096
+read(8, "0 n \n0000929507 00000 n \n0000929"..., 4096) = 4096
+read(8, "00000 n \n0000432015 00000 n \n000"..., 4096) = 4096
+read(8, "222 00000 n \n0000467486 00000 n "..., 4096) = 4096
+read(8, "0512314 00000 n \n0000512564 0000"..., 4096) = 4096
+read(8, "\n0000565053 00000 n \n0000565326 "..., 4096) = 4096
+read(8, "0 n \n0000623533 00000 n \n0000623"..., 4096) = 4096
+read(8, "00000 n \n0000682257 00000 n \n000"..., 4096) = 4096
+read(8, "308 00000 n \n0000733768 00000 n "..., 4096) = 4096
+read(8, "0782730 00000 n \n0000782993 0000"..., 4096) = 4096
+read(8, "\n0000830956 00000 n \n0000831219 "..., 4096) = 4096
+read(8, "0 n \n0000876188 00000 n \n0000876"..., 4096) = 1946
+read(8, "", 4096)                       = 0
+read(8, "", 4096)                       = 0
+close(8)                                = 0
+write(7, " ]\n/DocChecksum /A9128BDB763FCCD"..., 76) = 76
+close(7)                                = 0
+close(6)                                = 0
+fcntl(3, F_SETLK, {type=F_RDLCK, whence=SEEK_SET, start=1073741824, len=1}) = 0
+fcntl(3, F_SETLK, {type=F_RDLCK, whence=SEEK_SET, start=1073741826, len=510}) = 0
+fcntl(3, F_SETLK, {type=F_UNLCK, whence=SEEK_SET, start=1073741824, len=1}) = 0
+access("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db-journal", F_OK) = -1 ENOENT (No such file or directory)
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+lseek(3, 24, SEEK_SET)                  = 24
+read(3, "\0\0\5\241\0\0\0\241\0\0\0v\0\0\0\1", 16) = 16
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+access("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db-wal", F_OK) = -1 ENOENT (No such file or directory)
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+fcntl(3, F_SETLK, {type=F_WRLCK, whence=SEEK_SET, start=1073741825, len=1}) = 0
+lseek(3, 141312, SEEK_SET)              = 141312
+read(3, "\2\0\0\0\n\1\322\0\0\0\0b\2y\2A\2\t\2\260\2\350\3X\1\322\3 \3\220\3\310"..., 1024) = 1024
+lseek(3, 103424, SEEK_SET)              = 103424
+read(3, "\n\0\0\0\22\0]\0\0\371\1-\1a\1\224\1\310\1\373\2/\0]\2c\2\227\2\313\2\377"..., 1024) = 1024
+rename("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/tmp/svn-2LgtUH", "/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/pristine/e9/e98ce4d859b08fcc744bd1f50aef6dd6f418493f.svn-base") = 0
+stat("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/pristine/e9/e98ce4d859b08fcc744bd1f50aef6dd6f418493f.svn-base", {st_mode=S_IFREG|0664, st_size=438348, ...}) = 0
+lseek(3, 114688, SEEK_SET)              = 114688
+read(3, "\n\0\0\0\26\0>\0\0>\0i\0\225\0\301\0\355\1\31\1D\1o\1\233\1\307\1\363\2\37"..., 1024) = 1024
+stat("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db", {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+stat("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db", {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+open("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db-journal", O_RDWR|O_CREAT|O_CLOEXEC, 0644) = 6
+fstat(6, {st_mode=S_IFREG|0644, st_size=0, ...}) = 0
+geteuid()                               = 530
+fstat(6, {st_mode=S_IFREG|0644, st_size=0, ...}) = 0
+lseek(6, 0, SEEK_SET)                   = 0
+write(6, "\331\325\5\371 \241c\327\377\377\377\377\267[\205\232\0\0\0\241\0\0\2\0\0\0\4\0\0\0\0\0"..., 512) = 512
+lseek(6, 512, SEEK_SET)                 = 512
+write(6, "\0\0\0006", 4)                = 4
+lseek(6, 516, SEEK_SET)                 = 516
+write(6, "\2\1\370\0\21\0L\3\0\0\0\215\2S\0\253\0|\1\311\1\231\3p\1j\3\320\0\333\3A"..., 1024) = 1024
+lseek(6, 1540, SEEK_SET)                = 1540
+write(6, "\267[\206g", 4)               = 4
+lseek(3, 115712, SEEK_SET)              = 115712
+read(3, "\n\0\0\0\25\0l\0\0l\0\230\0\303\0\357\1\33\1G\1s\1\237\1\312\1\366\2!\2M"..., 1024) = 1024
+lseek(3, 113664, SEEK_SET)              = 113664
+read(3, "\n\0\0\0\26\0D\0\0D\0p\0\234\0\310\0\363\1\37\1J\1v\1\241\1\314\1\370\2$"..., 1024) = 1024
+lseek(6, 1544, SEEK_SET)                = 1544
+write(6, "\0\0\0p", 4)                  = 4
+lseek(6, 1548, SEEK_SET)                = 1548
+write(6, "\n\0\0\0\26\0D\0\0D\0p\0\234\0\310\0\363\1\37\1J\1v\1\241\1\314\1\370\2$"..., 1024) = 1024
+lseek(6, 2572, SEEK_SET)                = 2572
+write(6, "\267[\206\315", 4)            = 4
+lseek(6, 2576, SEEK_SET)                = 2576
+write(6, "\0\0\0q", 4)                  = 4
+lseek(6, 2580, SEEK_SET)                = 2580
+write(6, "\n\0\0\0\26\0>\0\0>\0i\0\225\0\301\0\355\1\31\1D\1o\1\233\1\307\1\363\2\37"..., 1024) = 1024
+lseek(6, 3604, SEEK_SET)                = 3604
+write(6, "\267[\206\250", 4)            = 4
+lseek(6, 3608, SEEK_SET)                = 3608
+write(6, "\0\0\0r", 4)                  = 4
+lseek(6, 3612, SEEK_SET)                = 3612
+write(6, "\n\0\0\0\25\0l\0\0l\0\230\0\303\0\357\1\33\1G\1s\1\237\1\312\1\366\2!\2M"..., 1024) = 1024
+lseek(6, 4636, SEEK_SET)                = 4636
+write(6, "\267[\206\203", 4)            = 4
+lseek(6, 4640, SEEK_SET)                = 4640
+write(6, "\0\0\0\213", 4)               = 4
+lseek(6, 4644, SEEK_SET)                = 4644
+write(6, "\2\0\0\0\n\1\322\0\0\0\0b\2y\2A\2\t\2\260\2\350\3X\1\322\3 \3\220\3\310"..., 1024) = 1024
+lseek(6, 5668, SEEK_SET)                = 5668
+write(6, "\267[\206\2", 4)              = 4
+lseek(3, 136192, SEEK_SET)              = 136192
+read(3, "\n\0\0\0\f\1\222\0\2.\2b\1\372\2\226\2\311\1\222\1\306\2\375\0031\3e\3\231\3\315"..., 1024) = 1024
+lseek(3, 160768, SEEK_SET)              = 160768
+read(3, "\n\0\0\0\n\1\374\0\0020\2c\2\226\2\312\2\375\1\374\0030\3d\3\230\3\314\0\0\0\0"..., 1024) = 1024
+lseek(6, 5672, SEEK_SET)                = 5672
+write(6, "\0\0\0\236", 4)               = 4
+lseek(6, 5676, SEEK_SET)                = 5676
+write(6, "\n\0\0\0\n\1\374\0\0020\2c\2\226\2\312\2\375\1\374\0030\3d\3\230\3\314\0\0\0\0"..., 1024) = 1024
+lseek(6, 6700, SEEK_SET)                = 6700
+write(6, "\267[\206\1", 4)              = 4
+lseek(6, 6704, SEEK_SET)                = 6704
+write(6, "\0\0\0f", 4)                  = 4
+lseek(6, 6708, SEEK_SET)                = 6708
+write(6, "\n\0\0\0\22\0]\0\0\371\1-\1a\1\224\1\310\1\373\2/\0]\2c\2\227\2\313\2\377"..., 1024) = 1024
+lseek(6, 7732, SEEK_SET)                = 7732
+write(6, "\267[\207\5", 4)              = 4
+lseek(6, 7736, SEEK_SET)                = 7736
+write(6, "\0\0\0\206", 4)               = 4
+lseek(6, 7740, SEEK_SET)                = 7740
+write(6, "\n\0\0\0\f\1\222\0\2.\2b\1\372\2\226\2\311\1\222\1\306\2\375\0031\3e\3\231\3\315"..., 1024) = 1024
+lseek(6, 8764, SEEK_SET)                = 8764
+write(6, "\267[\206\230", 4)            = 4
+lseek(6, 8768, SEEK_SET)                = 8768
+write(6, "\0\0\0\240", 4)               = 4
+lseek(6, 8772, SEEK_SET)                = 8772
+write(6, "\r\0\0\0\4\2\202\0\3\241\3B\2\342\2\202\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 1024) = 1024
+lseek(6, 9796, SEEK_SET)                = 9796
+write(6, "\267[\205\316", 4)            = 4
+fcntl(3, F_SETLK, {type=F_WRLCK, whence=SEEK_SET, start=1073741824, len=1}) = 0
+fcntl(3, F_SETLK, {type=F_WRLCK, whence=SEEK_SET, start=1073741826, len=510}) = 0
+lseek(6, 9800, SEEK_SET)                = 9800
+write(6, "\0\0\0\1", 4)                 = 4
+lseek(6, 9804, SEEK_SET)                = 9804
+write(6, "SQLite format 3\0\4\0\1\1\0@  \0\0\5\241\0\0\0\241"..., 1024) = 1024
+lseek(6, 10828, SEEK_SET)               = 10828
+write(6, "\267[\205\232", 4)            = 4
+lseek(3, 0, SEEK_SET)                   = 0
+write(3, "SQLite format 3\0\4\0\1\1\0@  \0\0\5\242\0\0\0\241"..., 1024) = 1024
+lseek(3, 54272, SEEK_SET)               = 54272
+write(3, "\2\1\370\0\21\0L\3\0\0\0\215\2S\0\253\0|\1\311\1\231\3p\1j\3\320\0\333\3A"..., 1024) = 1024
+lseek(3, 103424, SEEK_SET)              = 103424
+write(3, "\n\0\0\0\20\0\306\0\0\306\0\371\1,\1`\1\223\1\306\1\372\2.\2b\2\226\2\312\2\376"..., 1024) = 1024
+lseek(3, 113664, SEEK_SET)              = 113664
+write(3, "\n\0\0\0\26\0D\0\0D\0p\0\234\0\310\0\363\1\37\1J\1v\1\241\1\314\1\370\2$"..., 1024) = 1024
+lseek(3, 114688, SEEK_SET)              = 114688
+write(3, "\n\0\0\0\26\0>\0\0>\0i\0\225\0\301\0\355\1\31\1D\1o\1\233\1\307\1\363\2\37"..., 1024) = 1024
+lseek(3, 115712, SEEK_SET)              = 115712
+write(3, "\n\0\0\0\26\0@\0\0@\0l\0\230\0\303\0\357\1\33\1G\1s\1\237\1\312\1\366\2!"..., 1024) = 1024
+lseek(3, 136192, SEEK_SET)              = 136192
+write(3, "\n\0\0\0\16\1+\0\1+\1_\1\223\1\307\1\373\2/\2b\2\225\2\311\2\374\0030\3d"..., 1024) = 1024
+lseek(3, 141312, SEEK_SET)              = 141312
+write(3, "\2\0\0\0\n\1\322\0\0\0\0b\2y\2A\2\t\2\260\2\350\3X\1\322\3 \3\220\3\310"..., 1024) = 1024
+lseek(3, 160768, SEEK_SET)              = 160768
+write(3, "\n\0\0\0\v\1\306\0\1\306\1\372\2.\2a\2\225\2\311\2\375\0031\3e\3\231\3\315\0\0"..., 1024) = 1024
+lseek(3, 162816, SEEK_SET)              = 162816
+write(3, "\r\0\0\0\5\2\"\0\3\241\3B\2\342\2\202\2\"\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 1024) = 1024
+close(6)                                = 0
+unlink("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db-journal") = 0
+fcntl(3, F_SETLK, {type=F_RDLCK, whence=SEEK_SET, start=1073741826, len=510}) = 0
+fcntl(3, F_SETLK, {type=F_UNLCK, whence=SEEK_SET, start=1073741824, len=2}) = 0
+fcntl(3, F_SETLK, {type=F_UNLCK, whence=SEEK_SET, start=0, len=0}) = 0
+epoll_ctl(4, EPOLL_CTL_DEL, 5, {0, {u32=0, u64=0}}) = 0
+epoll_ctl(4, EPOLL_CTL_ADD, 5, {EPOLLIN|EPOLLOUT, {u32=3303153608, u64=140397194125256}}) = 0
+epoll_wait(4, {{EPOLLOUT, {u32=3303153608, u64=140397194125256}}}, 16, 500) = 1
+write(9, "0000 n \n0000430066 00000 n \n0000"..., 246) = 246
+lseek(9, 0, SEEK_SET)                   = 0
+stat("/tmp/svn-S2P1pi", {st_mode=S_IFREG|0600, st_size=315638, ...}) = 0
+mmap(NULL, 315638, PROT_READ, MAP_SHARED, 9, 0) = 0x7fb0c4104000
+writev(5, [{"PUT /svn/aprx/!svn/wrk/9ce1e70b-"..., 96}, {"Host", 4}, {": ", 2}, {"repo.ham.fi", 11}, {"\r\n", 2}, {"Authorization", 13}, {": ", 2}, {"Basic b2gybXFrOnJpZnJhZjIy", 26}, {"\r\n", 2}, {"User-Agent", 10}, {": ", 2}, {"SVN/1.8.8 (x86_64-redhat-linux-g"..., 46}, {"\r\n", 2}, {"Content-Type", 12}, {": ", 2}, {"application/vnd.svn-svndiff", 27}, {"\r\n", 2}, {"Accept-Encoding", 15}, {": ", 2}, {"gzip", 4}, {"\r\n", 2}, {"DAV", 3}, {": ", 2}, {"http://subversion.tigris.org/xml"... [...]
+writev(5, [{"\242\5\36\341\313\222\"\237\0053\204\364\f\243\265\0\271\22\2304D\376dVK\206\261\n\370\275+v"..., 94736}, {"\r\n", 2}, {"0\r\n\r\n", 5}], 3) = -1 EAGAIN (Resource temporarily unavailable)
+epoll_wait(4, {{EPOLLOUT, {u32=3303153608, u64=140397194125256}}}, 16, 500) = 1
+writev(5, [{"\242\5\36\341\313\222\"\237\0053\204\364\f\243\265\0\271\22\2304D\376dVK\206\261\n\370\275+v"..., 94736}, {"\r\n", 2}, {"0\r\n\r\n", 5}], 3) = 86880
+writev(5, [{"00000000 65535 f \n0000399797 000"..., 7856}, {"\r\n", 2}, {"0\r\n\r\n", 5}], 3) = -1 EAGAIN (Resource temporarily unavailable)
+epoll_wait(4, {{EPOLLOUT, {u32=3303153608, u64=140397194125256}}}, 16, 500) = 1
+writev(5, [{"00000000 65535 f \n0000399797 000"..., 7856}, {"\r\n", 2}, {"0\r\n\r\n", 5}], 3) = 7863
+epoll_ctl(4, EPOLL_CTL_DEL, 5, {0, {u32=0, u64=0}}) = 0
+epoll_ctl(4, EPOLL_CTL_ADD, 5, {EPOLLIN, {u32=3303153656, u64=140397194125304}}) = 0
+epoll_wait(4, {{EPOLLIN, {u32=3303153656, u64=140397194125304}}}, 16, 500) = 1
+read(5, "HTTP/1.1 204 No Content\r\nDate: M"..., 8000) = 106
+munmap(0x7fb0c4104000, 315638)          = 0
+close(9)                                = 0
+epoll_ctl(4, EPOLL_CTL_DEL, 5, {0, {u32=0, u64=0}}) = 0
+epoll_ctl(4, EPOLL_CTL_ADD, 5, {EPOLLIN|EPOLLOUT, {u32=3303153608, u64=140397194125256}}) = 0
+epoll_wait(4, {{EPOLLOUT, {u32=3303153608, u64=140397194125256}}}, 16, 500) = 1
+writev(5, [{"MERGE /svn/aprx/trunk/doc HTTP/1"..., 36}, {"Host", 4}, {": ", 2}, {"repo.ham.fi", 11}, {"\r\n", 2}, {"Authorization", 13}, {": ", 2}, {"Basic b2gybXFrOnJpZnJhZjIy", 26}, {"\r\n", 2}, {"User-Agent", 10}, {": ", 2}, {"SVN/1.8.8 (x86_64-redhat-linux-g"..., 46}, {"\r\n", 2}, {"Accept-Encoding", 15}, {": ", 2}, {"gzip", 4}, {"\r\n", 2}, {"DAV", 3}, {": ", 2}, {"http://subversion.tigris.org/xml"..., 48}, {"\r\n", 2}, {"DAV", 3}, {": ", 2}, {"http://subversion.tigris.org/xml"...,  [...]
+writev(5, [{"2b\r\n", 4}, {"</", 2}, {"D:creator-displayname", 21}, {">", 1}, {"</", 2}, {"D:prop", 6}, {">", 1}, {"</", 2}, {"D:merge", 7}, {">", 1}, {"\r\n", 2}, {"0\r\n\r\n", 5}], 12) = 54
+epoll_ctl(4, EPOLL_CTL_DEL, 5, {0, {u32=0, u64=0}}) = 0
+epoll_ctl(4, EPOLL_CTL_ADD, 5, {EPOLLIN, {u32=3303153656, u64=140397194125304}}) = 0
+epoll_wait(4, {{EPOLLIN, {u32=3303153656, u64=140397194125304}}}, 16, 500) = 1
+read(5, "HTTP/1.1 200 OK\r\nDate: Mon, 24 M"..., 8000) = 542
+brk(0)                                  = 0x7fb0c4e6c000
+brk(0x7fb0c4e8d000)                     = 0x7fb0c4e8d000
+brk(0)                                  = 0x7fb0c4e8d000
+brk(0)                                  = 0x7fb0c4e8d000
+brk(0x7fb0c4e85000)                     = 0x7fb0c4e85000
+brk(0)                                  = 0x7fb0c4e85000
+write(1, "\nCommitted revision 590.\n", 25) = 25
+epoll_ctl(4, EPOLL_CTL_DEL, 5, {0, {u32=0, u64=0}}) = 0
+epoll_ctl(4, EPOLL_CTL_ADD, 5, {EPOLLIN|EPOLLOUT, {u32=3303153608, u64=140397194125256}}) = 0
+epoll_wait(4, {{EPOLLOUT, {u32=3303153608, u64=140397194125256}}}, 16, 500) = 1
+writev(5, [{"DELETE /svn/aprx/!svn/act/9ce1e7"..., 73}, {"Host", 4}, {": ", 2}, {"repo.ham.fi", 11}, {"\r\n", 2}, {"Authorization", 13}, {": ", 2}, {"Basic b2gybXFrOnJpZnJhZjIy", 26}, {"\r\n", 2}, {"User-Agent", 10}, {": ", 2}, {"SVN/1.8.8 (x86_64-redhat-linux-g"..., 46}, {"\r\n", 2}, {"Accept-Encoding", 15}, {": ", 2}, {"gzip", 4}, {"\r\n", 2}, {"DAV", 3}, {": ", 2}, {"http://subversion.tigris.org/xml"..., 48}, {"\r\n", 2}, {"DAV", 3}, {": ", 2}, {"http://subversion.tigris.org/xml"...,  [...]
+epoll_ctl(4, EPOLL_CTL_DEL, 5, {0, {u32=0, u64=0}}) = 0
+epoll_ctl(4, EPOLL_CTL_ADD, 5, {EPOLLIN, {u32=3303153656, u64=140397194125304}}) = 0
+epoll_wait(4, {{EPOLLIN, {u32=3303153656, u64=140397194125304}}}, 16, 500) = 1
+read(5, "HTTP/1.1 204 No Content\r\nDate: M"..., 8000) = 106
+unlink("/tmp/svn-S2P1pi")               = 0
+unlink("/tmp/svn-4fJ8w7")               = 0
+lstat("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/doc/aprx-manual.odt", {st_mode=S_IFREG|0664, st_size=197896, ...}) = 0
+fcntl(3, F_SETLK, {type=F_RDLCK, whence=SEEK_SET, start=1073741824, len=1}) = 0
+fcntl(3, F_SETLK, {type=F_RDLCK, whence=SEEK_SET, start=1073741826, len=510}) = 0
+fcntl(3, F_SETLK, {type=F_UNLCK, whence=SEEK_SET, start=1073741824, len=1}) = 0
+access("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db-journal", F_OK) = -1 ENOENT (No such file or directory)
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+lseek(3, 24, SEEK_SET)                  = 24
+read(3, "\0\0\5\242\0\0\0\241\0\0\0v\0\0\0\1", 16) = 16
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+access("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db-wal", F_OK) = -1 ENOENT (No such file or directory)
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+fcntl(3, F_SETLK, {type=F_UNLCK, whence=SEEK_SET, start=0, len=0}) = 0
+fcntl(3, F_SETLK, {type=F_RDLCK, whence=SEEK_SET, start=1073741824, len=1}) = 0
+fcntl(3, F_SETLK, {type=F_RDLCK, whence=SEEK_SET, start=1073741826, len=510}) = 0
+fcntl(3, F_SETLK, {type=F_UNLCK, whence=SEEK_SET, start=1073741824, len=1}) = 0
+access("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db-journal", F_OK) = -1 ENOENT (No such file or directory)
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+lseek(3, 24, SEEK_SET)                  = 24
+read(3, "\0\0\5\242\0\0\0\241\0\0\0v\0\0\0\1", 16) = 16
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+access("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db-wal", F_OK) = -1 ENOENT (No such file or directory)
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+fcntl(3, F_SETLK, {type=F_WRLCK, whence=SEEK_SET, start=1073741825, len=1}) = 0
+stat("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db", {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+stat("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db", {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+open("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db-journal", O_RDWR|O_CREAT|O_CLOEXEC, 0644) = 6
+fstat(6, {st_mode=S_IFREG|0644, st_size=0, ...}) = 0
+geteuid()                               = 530
+fstat(6, {st_mode=S_IFREG|0644, st_size=0, ...}) = 0
+lseek(6, 0, SEEK_SET)                   = 0
+write(6, "\331\325\5\371 \241c\327\377\377\377\377\3200\257Y\0\0\0\241\0\0\2\0\0\0\4\0\0\0\0\0"..., 512) = 512
+lseek(6, 512, SEEK_SET)                 = 512
+write(6, "\0\0\0t", 4)                  = 4
+lseek(6, 516, SEEK_SET)                 = 516
+write(6, "\n\0\0\0\21\1\265\0\1\265\1\316\1\360\2\n\2-\2L\2k\2\234\2\315\2\357\3\16\0030"..., 1024) = 1024
+lseek(6, 1540, SEEK_SET)                = 1540
+write(6, "\3200\257\323", 4)            = 4
+lseek(3, 101376, SEEK_SET)              = 101376
+read(3, "\n\0035\0`\1\30\0\3\371\3\362\3\353\3\344\3\335\3\326\3\317\3\310\3\301\3\272\3\263\3\254"..., 1024) = 1024
+lseek(6, 1544, SEEK_SET)                = 1544
+write(6, "\0\0\0d", 4)                  = 4
+lseek(6, 1548, SEEK_SET)                = 1548
+write(6, "\n\0035\0`\1\30\0\3\371\3\362\3\353\3\344\3\335\3\326\3\317\3\310\3\301\3\272\3\263\3\254"..., 1024) = 1024
+lseek(6, 2572, SEEK_SET)                = 2572
+write(6, "\3200\257p", 4)               = 4
+lseek(6, 2576, SEEK_SET)                = 2576
+write(6, "\0\0\0005", 4)                = 4
+lseek(6, 2580, SEEK_SET)                = 2580
+write(6, "\n\3\226\0\35\0012\2\1d\1|\1\233\0012\1\304\1\333\1\356\2\0\2\33\1\260\2B\2M"..., 1024) = 1024
+lseek(6, 3604, SEEK_SET)                = 3604
+write(6, "\3200\260:", 4)               = 4
+lseek(6, 3608, SEEK_SET)                = 3608
+write(6, "\0\0\0h", 4)                  = 4
+lseek(6, 3612, SEEK_SET)                = 3612
+write(6, "\r\0\0\0\3\0\311\0\0\311\1\341\2\350\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 1024) = 1024
+lseek(6, 4636, SEEK_SET)                = 4636
+write(6, "\3200\2602", 4)               = 4
+lseek(6, 4640, SEEK_SET)                = 4640
+write(6, "\0\0\0\224", 4)               = 4
+lseek(6, 4644, SEEK_SET)                = 4644
+write(6, "\r\0\0\0\n\0F\0\3\241\3A\2\341\2\202\2\"\1\303\1d\1\5\0\245\0F\0\0\0\0"..., 1024) = 1024
+lseek(6, 5668, SEEK_SET)                = 5668
+write(6, "\3200\260h", 4)               = 4
+lseek(6, 5672, SEEK_SET)                = 5672
+write(6, "\0\0\0\241", 4)               = 4
+lseek(6, 5676, SEEK_SET)                = 5676
+write(6, "\r\3(\0\2\1\301\0\1\301\2\244\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 1024) = 1024
+lseek(6, 6700, SEEK_SET)                = 6700
+write(6, "\3200\257\313", 4)            = 4
+lseek(6, 6704, SEEK_SET)                = 6704
+write(6, "\0\0\0\240", 4)               = 4
+lseek(6, 6708, SEEK_SET)                = 6708
+write(6, "\r\0\0\0\5\2\"\0\3\241\3B\2\342\2\202\2\"\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 1024) = 1024
+lseek(6, 7732, SEEK_SET)                = 7732
+write(6, "\3200\257\304", 4)            = 4
+lseek(3, 3072, SEEK_SET)                = 3072
+read(3, "\r\0\0\0\3\3\325\0\3\361\3\346\3\325\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 1024) = 1024
+lseek(6, 7736, SEEK_SET)                = 7736
+write(6, "\0\0\0\25", 4)                = 4
+lseek(6, 7740, SEEK_SET)                = 7740
+write(6, "\r\0\0\0\0\4\0\0\2\230\2\230\2\230\2\230\2\230\2\230\2\230\2\230\2\230\1\232\1\232\1\232"..., 1024) = 1024
+lseek(6, 8764, SEEK_SET)                = 8764
+write(6, "\3200\257[", 4)               = 4
+lseek(6, 8768, SEEK_SET)                = 8768
+write(6, "\0\0\0\4", 4)                 = 4
+lseek(6, 8772, SEEK_SET)                = 8772
+write(6, "\r\0\0\0\3\3\325\0\3\361\3\346\3\325\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 1024) = 1024
+lseek(6, 9796, SEEK_SET)                = 9796
+write(6, "\3200\257Y", 4)               = 4
+fcntl(3, F_SETLK, {type=F_WRLCK, whence=SEEK_SET, start=1073741824, len=1}) = 0
+fcntl(3, F_SETLK, {type=F_WRLCK, whence=SEEK_SET, start=1073741826, len=510}) = 0
+lseek(6, 9800, SEEK_SET)                = 9800
+write(6, "\0\0\0\1", 4)                 = 4
+lseek(6, 9804, SEEK_SET)                = 9804
+write(6, "SQLite format 3\0\4\0\1\1\0@  \0\0\5\242\0\0\0\241"..., 1024) = 1024
+lseek(6, 10828, SEEK_SET)               = 10828
+write(6, "\3200\257Y", 4)               = 4
+lseek(3, 0, SEEK_SET)                   = 0
+write(3, "SQLite format 3\0\4\0\1\1\0@  \0\0\5\243\0\0\0\241"..., 1024) = 1024
+lseek(3, 3072, SEEK_SET)                = 3072
+write(3, "\r\0\0\0\3\3\325\0\3\361\3\346\3\325\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 1024) = 1024
+lseek(3, 20480, SEEK_SET)               = 20480
+write(3, "\r\0\0\0\1\3\331\0\3\331\2\230\2\230\2\230\2\230\2\230\2\230\2\230\2\230\1\232\1\232\1\232"..., 1024) = 1024
+lseek(3, 53248, SEEK_SET)               = 53248
+write(3, "\n\3\226\0\35\0012\2\1d\1|\1\233\0012\1\304\1\333\1\356\2\0\2\33\1\260\2B\2M"..., 1024) = 1024
+lseek(3, 101376, SEEK_SET)              = 101376
+write(3, "\n\0035\0`\1\30\0\3\371\3\362\3\353\3\344\3\335\3\326\3\317\3\310\3\301\3\272\3\263\3\254"..., 1024) = 1024
+lseek(3, 105472, SEEK_SET)              = 105472
+write(3, "\r\2\350\0\2\0\311\0\0\311\1\341\2\350\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 1024) = 1024
+lseek(3, 117760, SEEK_SET)              = 117760
+write(3, "\n\0\0\0\21\1\265\0\1\265\1\316\1\360\2\n\2-\2L\2k\2\234\2\315\2\357\3\16\0030"..., 1024) = 1024
+lseek(3, 150528, SEEK_SET)              = 150528
+write(3, "\r\0\0\0\n\0F\0\3\241\3A\2\341\2\202\2\"\1\303\1d\1\5\0\245\0F\0\0\0\0"..., 1024) = 1024
+lseek(3, 162816, SEEK_SET)              = 162816
+write(3, "\r\0\0\0\5\2\"\0\3\241\3B\2\342\2\202\2\"\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 1024) = 1024
+lseek(3, 163840, SEEK_SET)              = 163840
+write(3, "\r\3(\0\3\0\264\0\1\301\2\244\0\264\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 1024) = 1024
+close(6)                                = 0
+unlink("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db-journal") = 0
+fcntl(3, F_SETLK, {type=F_RDLCK, whence=SEEK_SET, start=1073741826, len=510}) = 0
+fcntl(3, F_SETLK, {type=F_UNLCK, whence=SEEK_SET, start=1073741824, len=2}) = 0
+fcntl(3, F_SETLK, {type=F_UNLCK, whence=SEEK_SET, start=0, len=0}) = 0
+lstat("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/doc/aprx-manual.pdf", {st_mode=S_IFREG|0664, st_size=438348, ...}) = 0
+fcntl(3, F_SETLK, {type=F_RDLCK, whence=SEEK_SET, start=1073741824, len=1}) = 0
+fcntl(3, F_SETLK, {type=F_RDLCK, whence=SEEK_SET, start=1073741826, len=510}) = 0
+fcntl(3, F_SETLK, {type=F_UNLCK, whence=SEEK_SET, start=1073741824, len=1}) = 0
+access("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db-journal", F_OK) = -1 ENOENT (No such file or directory)
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+lseek(3, 24, SEEK_SET)                  = 24
+read(3, "\0\0\5\243\0\0\0\241\0\0\0v\0\0\0\1", 16) = 16
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+access("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db-wal", F_OK) = -1 ENOENT (No such file or directory)
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+fcntl(3, F_SETLK, {type=F_UNLCK, whence=SEEK_SET, start=0, len=0}) = 0
+fcntl(3, F_SETLK, {type=F_RDLCK, whence=SEEK_SET, start=1073741824, len=1}) = 0
+fcntl(3, F_SETLK, {type=F_RDLCK, whence=SEEK_SET, start=1073741826, len=510}) = 0
+fcntl(3, F_SETLK, {type=F_UNLCK, whence=SEEK_SET, start=1073741824, len=1}) = 0
+access("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db-journal", F_OK) = -1 ENOENT (No such file or directory)
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+lseek(3, 24, SEEK_SET)                  = 24
+read(3, "\0\0\5\243\0\0\0\241\0\0\0v\0\0\0\1", 16) = 16
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+access("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db-wal", F_OK) = -1 ENOENT (No such file or directory)
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+fcntl(3, F_SETLK, {type=F_WRLCK, whence=SEEK_SET, start=1073741825, len=1}) = 0
+stat("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db", {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+stat("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db", {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+open("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db-journal", O_RDWR|O_CREAT|O_CLOEXEC, 0644) = 6
+fstat(6, {st_mode=S_IFREG|0644, st_size=0, ...}) = 0
+geteuid()                               = 530
+fstat(6, {st_mode=S_IFREG|0644, st_size=0, ...}) = 0
+lseek(6, 0, SEEK_SET)                   = 0
+write(6, "\331\325\5\371 \241c\327\377\377\377\377{)\253\354\0\0\0\241\0\0\2\0\0\0\4\0\0\0\0\0"..., 512) = 512
+lseek(6, 512, SEEK_SET)                 = 512
+write(6, "\0\0\0t", 4)                  = 4
+lseek(6, 516, SEEK_SET)                 = 516
+write(6, "\n\0\0\0\21\1\265\0\1\265\1\316\1\360\2\n\2-\2L\2k\2\234\2\315\2\357\3\16\0030"..., 1024) = 1024
+lseek(6, 1540, SEEK_SET)                = 1540
+write(6, "{)\254f", 4)                  = 4
+lseek(6, 1544, SEEK_SET)                = 1544
+write(6, "\0\0\0d", 4)                  = 4
+lseek(6, 1548, SEEK_SET)                = 1548
+write(6, "\n\0035\0`\1\30\0\3\371\3\362\3\353\3\344\3\335\3\326\3\317\3\310\3\301\3\272\3\263\3\254"..., 1024) = 1024
+lseek(6, 2572, SEEK_SET)                = 2572
+write(6, "{)\254\3", 4)                 = 4
+lseek(6, 2576, SEEK_SET)                = 2576
+write(6, "\0\0\0005", 4)                = 4
+lseek(6, 2580, SEEK_SET)                = 2580
+write(6, "\n\3\226\0\35\0012\2\1d\1|\1\233\0012\1\304\1\333\1\356\2\0\2\33\1\260\2B\2M"..., 1024) = 1024
+lseek(6, 3604, SEEK_SET)                = 3604
+write(6, "{)\254\315", 4)               = 4
+lseek(6, 3608, SEEK_SET)                = 3608
+write(6, "\0\0\0h", 4)                  = 4
+lseek(6, 3612, SEEK_SET)                = 3612
+write(6, "\r\2\350\0\2\0\311\0\0\311\1\341\2\350\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 1024) = 1024
+lseek(6, 4636, SEEK_SET)                = 4636
+write(6, "{)\254S", 4)                  = 4
+lseek(6, 4640, SEEK_SET)                = 4640
+write(6, "\0\0\0\30", 4)                = 4
+lseek(6, 4644, SEEK_SET)                = 4644
+write(6, "\5\3~\0$\3\25\f\0\0\0\241\3\265\3\260\3L\3X\3\246\3\241\3\234\3\227\3\222\3\210"..., 1024) = 1024
+lseek(6, 5668, SEEK_SET)                = 5668
+write(6, "{)\254\26", 4)                = 4
+lseek(3, 139264, SEEK_SET)              = 139264
+read(3, "\r\2i\0\2\1\237\0\1\237\0030\0039\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 1024) = 1024
+lseek(6, 5672, SEEK_SET)                = 5672
+write(6, "\0\0\0\211", 4)               = 4
+lseek(6, 5676, SEEK_SET)                = 5676
+write(6, "\r\2i\0\2\1\237\0\1\237\0030\0039\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 1024) = 1024
+lseek(6, 6700, SEEK_SET)                = 6700
+write(6, "{)\254\2", 4)                 = 4
+lseek(6, 6704, SEEK_SET)                = 6704
+write(6, "\0\0\0\1", 4)                 = 4
+lseek(6, 6708, SEEK_SET)                = 6708
+write(6, "SQLite format 3\0\4\0\1\1\0@  \0\0\5\243\0\0\0\241"..., 1024) = 1024
+lseek(6, 7732, SEEK_SET)                = 7732
+write(6, "{)\253\354", 4)               = 4
+lseek(6, 7736, SEEK_SET)                = 7736
+write(6, "\0\0\0\222", 4)               = 4
+lseek(6, 7740, SEEK_SET)                = 7740
+write(6, "\r\0\0\0\2\2\202\0\2\202\3\17\3\17\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 1024) = 1024
+lseek(6, 8764, SEEK_SET)                = 8764
+write(6, "{)\254\32", 4)                = 4
+lseek(3, 119808, SEEK_SET)              = 119808
+read(3, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 1024) = 1024
+lseek(6, 8768, SEEK_SET)                = 8768
+write(6, "\0\0\0v", 4)                  = 4
+lseek(6, 8772, SEEK_SET)                = 8772
+write(6, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 1024) = 1024
+lseek(6, 9796, SEEK_SET)                = 9796
+write(6, "{)\253\354", 4)               = 4
+lseek(6, 9800, SEEK_SET)                = 9800
+write(6, "\0\0\0\217", 4)               = 4
+lseek(6, 9804, SEEK_SET)                = 9804
+write(6, "\r\0\0\0\n\0F\0\3\241\3A\2\342\2\203\2#\1\303\1d\1\5\0\246\0F\0\0\0\0"..., 1024) = 1024
+lseek(6, 10828, SEEK_SET)               = 10828
+write(6, "{)\254\372", 4)               = 4
+lseek(6, 10832, SEEK_SET)               = 10832
+write(6, "\0\0\0\241", 4)               = 4
+lseek(6, 10836, SEEK_SET)               = 10836
+write(6, "\r\3(\0\3\0\264\0\1\301\2\244\0\264\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 1024) = 1024
+lseek(6, 11860, SEEK_SET)               = 11860
+write(6, "{)\254\376", 4)               = 4
+lseek(6, 11864, SEEK_SET)               = 11864
+write(6, "\0\0\0\240", 4)               = 4
+lseek(6, 11868, SEEK_SET)               = 11868
+write(6, "\r\0\0\0\5\2\"\0\3\241\3B\2\342\2\202\2\"\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 1024) = 1024
+lseek(6, 12892, SEEK_SET)               = 12892
+write(6, "{)\254W", 4)                  = 4
+lseek(6, 12896, SEEK_SET)               = 12896
+write(6, "\0\0\0\25", 4)                = 4
+lseek(6, 12900, SEEK_SET)               = 12900
+write(6, "\r\0\0\0\1\3\331\0\3\331\2\230\2\230\2\230\2\230\2\230\2\230\2\230\2\230\1\232\1\232\1\232"..., 1024) = 1024
+lseek(6, 13924, SEEK_SET)               = 13924
+write(6, "{)\253\356", 4)               = 4
+lseek(6, 13928, SEEK_SET)               = 13928
+write(6, "\0\0\0\4", 4)                 = 4
+lseek(6, 13932, SEEK_SET)               = 13932
+write(6, "\r\0\0\0\3\3\325\0\3\361\3\346\3\325\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 1024) = 1024
+lseek(6, 14956, SEEK_SET)               = 14956
+write(6, "{)\253\354", 4)               = 4
+fcntl(3, F_SETLK, {type=F_WRLCK, whence=SEEK_SET, start=1073741824, len=1}) = 0
+fcntl(3, F_SETLK, {type=F_WRLCK, whence=SEEK_SET, start=1073741826, len=510}) = 0
+lseek(3, 0, SEEK_SET)                   = 0
+write(3, "SQLite format 3\0\4\0\1\1\0@  \0\0\5\244\0\0\0\241"..., 1024) = 1024
+lseek(3, 3072, SEEK_SET)                = 3072
+write(3, "\r\0\0\0\3\3\325\0\3\361\3\346\3\325\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 1024) = 1024
+lseek(3, 20480, SEEK_SET)               = 20480
+write(3, "\r\0\0\0\2\3\262\0\3\331\3\262\2\230\2\230\2\230\2\230\2\230\2\230\2\230\1\232\1\232\1\232"..., 1024) = 1024
+lseek(3, 23552, SEEK_SET)               = 23552
+write(3, "\5\3~\0#\3\25\f\0\0\0\241\3\265\3\260\3L\3X\3\246\3\241\3\234\3\227\3\222\3\210"..., 1024) = 1024
+lseek(3, 53248, SEEK_SET)               = 53248
+write(3, "\n\3\226\0\35\0012\2\1d\1|\1\233\0012\1\304\1\333\1\356\2\0\2\33\1\260\2B\2M"..., 1024) = 1024
+lseek(3, 101376, SEEK_SET)              = 101376
+write(3, "\n\0035\0`\1\30\0\3\371\3\362\3\353\3\344\3\335\3\326\3\317\3\310\3\301\3\272\3\263\3\254"..., 1024) = 1024
+lseek(3, 105472, SEEK_SET)              = 105472
+write(3, "\r\0\0\0\3\1_\0\1_\2)\2\371\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 1024) = 1024
+lseek(3, 117760, SEEK_SET)              = 117760
+write(3, "\n\0\0\0\21\1\265\0\1\265\1\316\1\360\2\n\2-\2L\2k\2\234\2\315\2\357\3\16\0030"..., 1024) = 1024
+lseek(3, 119808, SEEK_SET)              = 119808
+write(3, "\0\0\0\0\0\0\0\1\0\0\0\222\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 1024) = 1024
+lseek(3, 139264, SEEK_SET)              = 139264
+write(3, "\r\0\0\0\2\2\202\0\2\202\3\17\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 1024) = 1024
+lseek(3, 145408, SEEK_SET)              = 145408
+write(3, "\r\0\0\0\n\0F\0\3\241\3A\2\342\2\203\2#\1\303\1d\1\5\0\246\0F\0\0\0\0"..., 1024) = 1024
+lseek(3, 148480, SEEK_SET)              = 148480
+write(3, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 1024) = 1024
+lseek(3, 162816, SEEK_SET)              = 162816
+write(3, "\r\0\0\0\5\2\"\0\3\241\3B\2\342\2\202\2\"\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 1024) = 1024
+lseek(3, 163840, SEEK_SET)              = 163840
+write(3, "\r\0\0\0\4\0\177\0\3\35\2\231\1\214\0\177\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 1024) = 1024
+close(6)                                = 0
+unlink("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db-journal") = 0
+fcntl(3, F_SETLK, {type=F_RDLCK, whence=SEEK_SET, start=1073741826, len=510}) = 0
+fcntl(3, F_SETLK, {type=F_UNLCK, whence=SEEK_SET, start=1073741824, len=2}) = 0
+fcntl(3, F_SETLK, {type=F_UNLCK, whence=SEEK_SET, start=0, len=0}) = 0
+fcntl(3, F_SETLK, {type=F_RDLCK, whence=SEEK_SET, start=1073741824, len=1}) = 0
+fcntl(3, F_SETLK, {type=F_RDLCK, whence=SEEK_SET, start=1073741826, len=510}) = 0
+fcntl(3, F_SETLK, {type=F_UNLCK, whence=SEEK_SET, start=1073741824, len=1}) = 0
+access("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db-journal", F_OK) = -1 ENOENT (No such file or directory)
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+lseek(3, 24, SEEK_SET)                  = 24
+read(3, "\0\0\5\244\0\0\0\241\0\0\0v\0\0\0\2", 16) = 16
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+access("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db-wal", F_OK) = -1 ENOENT (No such file or directory)
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+fcntl(3, F_SETLK, {type=F_UNLCK, whence=SEEK_SET, start=0, len=0}) = 0
+lstat("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/doc/aprx-manual.odt", {st_mode=S_IFREG|0664, st_size=197896, ...}) = 0
+fcntl(3, F_SETLK, {type=F_RDLCK, whence=SEEK_SET, start=1073741824, len=1}) = 0
+fcntl(3, F_SETLK, {type=F_RDLCK, whence=SEEK_SET, start=1073741826, len=510}) = 0
+fcntl(3, F_SETLK, {type=F_UNLCK, whence=SEEK_SET, start=1073741824, len=1}) = 0
+access("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db-journal", F_OK) = -1 ENOENT (No such file or directory)
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+lseek(3, 24, SEEK_SET)                  = 24
+read(3, "\0\0\5\244\0\0\0\241\0\0\0v\0\0\0\2", 16) = 16
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+access("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db-wal", F_OK) = -1 ENOENT (No such file or directory)
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+fcntl(3, F_SETLK, {type=F_UNLCK, whence=SEEK_SET, start=0, len=0}) = 0
+fcntl(3, F_SETLK, {type=F_RDLCK, whence=SEEK_SET, start=1073741824, len=1}) = 0
+fcntl(3, F_SETLK, {type=F_RDLCK, whence=SEEK_SET, start=1073741826, len=510}) = 0
+fcntl(3, F_SETLK, {type=F_UNLCK, whence=SEEK_SET, start=1073741824, len=1}) = 0
+access("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db-journal", F_OK) = -1 ENOENT (No such file or directory)
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+lseek(3, 24, SEEK_SET)                  = 24
+read(3, "\0\0\5\244\0\0\0\241\0\0\0v\0\0\0\2", 16) = 16
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+access("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db-wal", F_OK) = -1 ENOENT (No such file or directory)
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+fcntl(3, F_SETLK, {type=F_UNLCK, whence=SEEK_SET, start=0, len=0}) = 0
+fcntl(3, F_SETLK, {type=F_RDLCK, whence=SEEK_SET, start=1073741824, len=1}) = 0
+fcntl(3, F_SETLK, {type=F_RDLCK, whence=SEEK_SET, start=1073741826, len=510}) = 0
+fcntl(3, F_SETLK, {type=F_UNLCK, whence=SEEK_SET, start=1073741824, len=1}) = 0
+access("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db-journal", F_OK) = -1 ENOENT (No such file or directory)
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+lseek(3, 24, SEEK_SET)                  = 24
+read(3, "\0\0\5\244\0\0\0\241\0\0\0v\0\0\0\2", 16) = 16
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+access("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db-wal", F_OK) = -1 ENOENT (No such file or directory)
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+fcntl(3, F_SETLK, {type=F_UNLCK, whence=SEEK_SET, start=0, len=0}) = 0
+fcntl(3, F_SETLK, {type=F_RDLCK, whence=SEEK_SET, start=1073741824, len=1}) = 0
+fcntl(3, F_SETLK, {type=F_RDLCK, whence=SEEK_SET, start=1073741826, len=510}) = 0
+fcntl(3, F_SETLK, {type=F_UNLCK, whence=SEEK_SET, start=1073741824, len=1}) = 0
+access("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db-journal", F_OK) = -1 ENOENT (No such file or directory)
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+lseek(3, 24, SEEK_SET)                  = 24
+read(3, "\0\0\5\244\0\0\0\241\0\0\0v\0\0\0\2", 16) = 16
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+access("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db-wal", F_OK) = -1 ENOENT (No such file or directory)
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+fcntl(3, F_SETLK, {type=F_UNLCK, whence=SEEK_SET, start=0, len=0}) = 0
+lstat("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/doc/aprx-manual.odt", {st_mode=S_IFREG|0664, st_size=197896, ...}) = 0
+lstat("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/doc/aprx-manual.odt", {st_mode=S_IFREG|0664, st_size=197896, ...}) = 0
+lstat("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/doc/aprx-manual.odt", {st_mode=S_IFREG|0664, st_size=197896, ...}) = 0
+fcntl(3, F_SETLK, {type=F_RDLCK, whence=SEEK_SET, start=1073741824, len=1}) = 0
+fcntl(3, F_SETLK, {type=F_RDLCK, whence=SEEK_SET, start=1073741826, len=510}) = 0
+fcntl(3, F_SETLK, {type=F_UNLCK, whence=SEEK_SET, start=1073741824, len=1}) = 0
+access("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db-journal", F_OK) = -1 ENOENT (No such file or directory)
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+lseek(3, 24, SEEK_SET)                  = 24
+read(3, "\0\0\5\244\0\0\0\241\0\0\0v\0\0\0\2", 16) = 16
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+access("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db-wal", F_OK) = -1 ENOENT (No such file or directory)
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+fcntl(3, F_SETLK, {type=F_WRLCK, whence=SEEK_SET, start=1073741825, len=1}) = 0
+stat("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db", {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+stat("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db", {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+open("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db-journal", O_RDWR|O_CREAT|O_CLOEXEC, 0644) = 6
+fstat(6, {st_mode=S_IFREG|0644, st_size=0, ...}) = 0
+geteuid()                               = 530
+fstat(6, {st_mode=S_IFREG|0644, st_size=0, ...}) = 0
+lseek(6, 0, SEEK_SET)                   = 0
+write(6, "\331\325\5\371 \241c\327\377\377\377\377h\201\256\326\0\0\0\241\0\0\2\0\0\0\4\0\0\0\0\0"..., 512) = 512
+lseek(6, 512, SEEK_SET)                 = 512
+write(6, "\0\0\0\241", 4)               = 4
+lseek(6, 516, SEEK_SET)                 = 516
+write(6, "\r\0\0\0\4\0\177\0\3\35\2\231\1\214\0\177\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 1024) = 1024
+lseek(6, 1540, SEEK_SET)                = 1540
+write(6, "h\201\257{", 4)               = 4
+fcntl(3, F_SETLK, {type=F_WRLCK, whence=SEEK_SET, start=1073741824, len=1}) = 0
+fcntl(3, F_SETLK, {type=F_WRLCK, whence=SEEK_SET, start=1073741826, len=510}) = 0
+lseek(6, 1544, SEEK_SET)                = 1544
+write(6, "\0\0\0\1", 4)                 = 4
+lseek(6, 1548, SEEK_SET)                = 1548
+write(6, "SQLite format 3\0\4\0\1\1\0@  \0\0\5\244\0\0\0\241"..., 1024) = 1024
+lseek(6, 2572, SEEK_SET)                = 2572
+write(6, "h\201\256\326", 4)            = 4
+lseek(3, 0, SEEK_SET)                   = 0
+write(3, "SQLite format 3\0\4\0\1\1\0@  \0\0\5\245\0\0\0\241"..., 1024) = 1024
+lseek(3, 163840, SEEK_SET)              = 163840
+write(3, "\r\0\0\0\4\0t\0\3\35\2\231\0t\1\214\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 1024) = 1024
+close(6)                                = 0
+unlink("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db-journal") = 0
+fcntl(3, F_SETLK, {type=F_RDLCK, whence=SEEK_SET, start=1073741826, len=510}) = 0
+fcntl(3, F_SETLK, {type=F_UNLCK, whence=SEEK_SET, start=1073741824, len=2}) = 0
+fcntl(3, F_SETLK, {type=F_UNLCK, whence=SEEK_SET, start=0, len=0}) = 0
+fcntl(3, F_SETLK, {type=F_RDLCK, whence=SEEK_SET, start=1073741824, len=1}) = 0
+fcntl(3, F_SETLK, {type=F_RDLCK, whence=SEEK_SET, start=1073741826, len=510}) = 0
+fcntl(3, F_SETLK, {type=F_UNLCK, whence=SEEK_SET, start=1073741824, len=1}) = 0
+access("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db-journal", F_OK) = -1 ENOENT (No such file or directory)
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+lseek(3, 24, SEEK_SET)                  = 24
+read(3, "\0\0\5\245\0\0\0\241\0\0\0v\0\0\0\2", 16) = 16
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+access("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db-wal", F_OK) = -1 ENOENT (No such file or directory)
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+fcntl(3, F_SETLK, {type=F_WRLCK, whence=SEEK_SET, start=1073741825, len=1}) = 0
+stat("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db", {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+stat("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db", {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+open("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db-journal", O_RDWR|O_CREAT|O_CLOEXEC, 0644) = 6
+fstat(6, {st_mode=S_IFREG|0644, st_size=0, ...}) = 0
+geteuid()                               = 530
+fstat(6, {st_mode=S_IFREG|0644, st_size=0, ...}) = 0
+lseek(6, 0, SEEK_SET)                   = 0
+write(6, "\331\325\5\371 \241c\327\377\377\377\377\360IZ\206\0\0\0\241\0\0\2\0\0\0\4\0\0\0\0\0"..., 512) = 512
+lseek(6, 512, SEEK_SET)                 = 512
+write(6, "\0\0\0\25", 4)                = 4
+lseek(6, 516, SEEK_SET)                 = 516
+write(6, "\r\0\0\0\2\3\262\0\3\331\3\262\2\230\2\230\2\230\2\230\2\230\2\230\2\230\1\232\1\232\1\232"..., 1024) = 1024
+lseek(6, 1540, SEEK_SET)                = 1540
+write(6, "\360IZ\210", 4)               = 4
+fcntl(3, F_SETLK, {type=F_WRLCK, whence=SEEK_SET, start=1073741824, len=1}) = 0
+fcntl(3, F_SETLK, {type=F_WRLCK, whence=SEEK_SET, start=1073741826, len=510}) = 0
+lseek(6, 1544, SEEK_SET)                = 1544
+write(6, "\0\0\0\1", 4)                 = 4
+lseek(6, 1548, SEEK_SET)                = 1548
+write(6, "SQLite format 3\0\4\0\1\1\0@  \0\0\5\245\0\0\0\241"..., 1024) = 1024
+lseek(6, 2572, SEEK_SET)                = 2572
+write(6, "\360IZ\206", 4)               = 4
+lseek(3, 0, SEEK_SET)                   = 0
+write(3, "SQLite format 3\0\4\0\1\1\0@  \0\0\5\246\0\0\0\241"..., 1024) = 1024
+lseek(3, 20480, SEEK_SET)               = 20480
+write(3, "\r\3\331\0\1\3\262\0\3\262\3\262\2\230\2\230\2\230\2\230\2\230\2\230\2\230\1\232\1\232\1\232"..., 1024) = 1024
+close(6)                                = 0
+unlink("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db-journal") = 0
+fcntl(3, F_SETLK, {type=F_RDLCK, whence=SEEK_SET, start=1073741826, len=510}) = 0
+fcntl(3, F_SETLK, {type=F_UNLCK, whence=SEEK_SET, start=1073741824, len=2}) = 0
+fcntl(3, F_SETLK, {type=F_UNLCK, whence=SEEK_SET, start=0, len=0}) = 0
+lstat("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/doc/aprx-manual.pdf", {st_mode=S_IFREG|0664, st_size=438348, ...}) = 0
+fcntl(3, F_SETLK, {type=F_RDLCK, whence=SEEK_SET, start=1073741824, len=1}) = 0
+fcntl(3, F_SETLK, {type=F_RDLCK, whence=SEEK_SET, start=1073741826, len=510}) = 0
+fcntl(3, F_SETLK, {type=F_UNLCK, whence=SEEK_SET, start=1073741824, len=1}) = 0
+access("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db-journal", F_OK) = -1 ENOENT (No such file or directory)
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+lseek(3, 24, SEEK_SET)                  = 24
+read(3, "\0\0\5\246\0\0\0\241\0\0\0v\0\0\0\2", 16) = 16
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+access("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db-wal", F_OK) = -1 ENOENT (No such file or directory)
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+fcntl(3, F_SETLK, {type=F_UNLCK, whence=SEEK_SET, start=0, len=0}) = 0
+fcntl(3, F_SETLK, {type=F_RDLCK, whence=SEEK_SET, start=1073741824, len=1}) = 0
+fcntl(3, F_SETLK, {type=F_RDLCK, whence=SEEK_SET, start=1073741826, len=510}) = 0
+fcntl(3, F_SETLK, {type=F_UNLCK, whence=SEEK_SET, start=1073741824, len=1}) = 0
+access("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db-journal", F_OK) = -1 ENOENT (No such file or directory)
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+lseek(3, 24, SEEK_SET)                  = 24
+read(3, "\0\0\5\246\0\0\0\241\0\0\0v\0\0\0\2", 16) = 16
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+access("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db-wal", F_OK) = -1 ENOENT (No such file or directory)
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+fcntl(3, F_SETLK, {type=F_UNLCK, whence=SEEK_SET, start=0, len=0}) = 0
+fcntl(3, F_SETLK, {type=F_RDLCK, whence=SEEK_SET, start=1073741824, len=1}) = 0
+fcntl(3, F_SETLK, {type=F_RDLCK, whence=SEEK_SET, start=1073741826, len=510}) = 0
+fcntl(3, F_SETLK, {type=F_UNLCK, whence=SEEK_SET, start=1073741824, len=1}) = 0
+access("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db-journal", F_OK) = -1 ENOENT (No such file or directory)
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+lseek(3, 24, SEEK_SET)                  = 24
+read(3, "\0\0\5\246\0\0\0\241\0\0\0v\0\0\0\2", 16) = 16
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+access("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db-wal", F_OK) = -1 ENOENT (No such file or directory)
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+fcntl(3, F_SETLK, {type=F_UNLCK, whence=SEEK_SET, start=0, len=0}) = 0
+fcntl(3, F_SETLK, {type=F_RDLCK, whence=SEEK_SET, start=1073741824, len=1}) = 0
+fcntl(3, F_SETLK, {type=F_RDLCK, whence=SEEK_SET, start=1073741826, len=510}) = 0
+fcntl(3, F_SETLK, {type=F_UNLCK, whence=SEEK_SET, start=1073741824, len=1}) = 0
+access("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db-journal", F_OK) = -1 ENOENT (No such file or directory)
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+lseek(3, 24, SEEK_SET)                  = 24
+read(3, "\0\0\5\246\0\0\0\241\0\0\0v\0\0\0\2", 16) = 16
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+access("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db-wal", F_OK) = -1 ENOENT (No such file or directory)
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+fcntl(3, F_SETLK, {type=F_UNLCK, whence=SEEK_SET, start=0, len=0}) = 0
+lstat("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/doc/aprx-manual.pdf", {st_mode=S_IFREG|0664, st_size=438348, ...}) = 0
+lstat("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/doc/aprx-manual.pdf", {st_mode=S_IFREG|0664, st_size=438348, ...}) = 0
+lstat("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/doc/aprx-manual.pdf", {st_mode=S_IFREG|0664, st_size=438348, ...}) = 0
+fcntl(3, F_SETLK, {type=F_RDLCK, whence=SEEK_SET, start=1073741824, len=1}) = 0
+fcntl(3, F_SETLK, {type=F_RDLCK, whence=SEEK_SET, start=1073741826, len=510}) = 0
+fcntl(3, F_SETLK, {type=F_UNLCK, whence=SEEK_SET, start=1073741824, len=1}) = 0
+access("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db-journal", F_OK) = -1 ENOENT (No such file or directory)
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+lseek(3, 24, SEEK_SET)                  = 24
+read(3, "\0\0\5\246\0\0\0\241\0\0\0v\0\0\0\2", 16) = 16
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+access("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db-wal", F_OK) = -1 ENOENT (No such file or directory)
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+fcntl(3, F_SETLK, {type=F_WRLCK, whence=SEEK_SET, start=1073741825, len=1}) = 0
+stat("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db", {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+stat("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db", {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+open("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db-journal", O_RDWR|O_CREAT|O_CLOEXEC, 0644) = 6
+fstat(6, {st_mode=S_IFREG|0644, st_size=0, ...}) = 0
+geteuid()                               = 530
+fstat(6, {st_mode=S_IFREG|0644, st_size=0, ...}) = 0
+lseek(6, 0, SEEK_SET)                   = 0
+write(6, "\331\325\5\371 \241c\327\377\377\377\377\314\357S\363\0\0\0\241\0\0\2\0\0\0\4\0\0\0\0\0"..., 512) = 512
+lseek(6, 512, SEEK_SET)                 = 512
+write(6, "\0\0\0\241", 4)               = 4
+lseek(6, 516, SEEK_SET)                 = 516
+write(6, "\r\0\0\0\4\0t\0\3\35\2\231\0t\1\214\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 1024) = 1024
+lseek(6, 1540, SEEK_SET)                = 1540
+write(6, "\314\357T\316", 4)            = 4
+fcntl(3, F_SETLK, {type=F_WRLCK, whence=SEEK_SET, start=1073741824, len=1}) = 0
+fcntl(3, F_SETLK, {type=F_WRLCK, whence=SEEK_SET, start=1073741826, len=510}) = 0
+lseek(6, 1544, SEEK_SET)                = 1544
+write(6, "\0\0\0\1", 4)                 = 4
+lseek(6, 1548, SEEK_SET)                = 1548
+write(6, "SQLite format 3\0\4\0\1\1\0@  \0\0\5\246\0\0\0\241"..., 1024) = 1024
+lseek(6, 2572, SEEK_SET)                = 2572
+write(6, "\314\357S\363", 4)            = 4
+lseek(3, 0, SEEK_SET)                   = 0
+write(3, "SQLite format 3\0\4\0\1\1\0@  \0\0\5\247\0\0\0\241"..., 1024) = 1024
+lseek(3, 163840, SEEK_SET)              = 163840
+write(3, "\r\0\0\0\4\0i\0\3\35\2\231\1\201\0i\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 1024) = 1024
+close(6)                                = 0
+unlink("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db-journal") = 0
+fcntl(3, F_SETLK, {type=F_RDLCK, whence=SEEK_SET, start=1073741826, len=510}) = 0
+fcntl(3, F_SETLK, {type=F_UNLCK, whence=SEEK_SET, start=1073741824, len=2}) = 0
+fcntl(3, F_SETLK, {type=F_UNLCK, whence=SEEK_SET, start=0, len=0}) = 0
+fcntl(3, F_SETLK, {type=F_RDLCK, whence=SEEK_SET, start=1073741824, len=1}) = 0
+fcntl(3, F_SETLK, {type=F_RDLCK, whence=SEEK_SET, start=1073741826, len=510}) = 0
+fcntl(3, F_SETLK, {type=F_UNLCK, whence=SEEK_SET, start=1073741824, len=1}) = 0
+access("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db-journal", F_OK) = -1 ENOENT (No such file or directory)
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+lseek(3, 24, SEEK_SET)                  = 24
+read(3, "\0\0\5\247\0\0\0\241\0\0\0v\0\0\0\2", 16) = 16
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+access("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db-wal", F_OK) = -1 ENOENT (No such file or directory)
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+fcntl(3, F_SETLK, {type=F_WRLCK, whence=SEEK_SET, start=1073741825, len=1}) = 0
+stat("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db", {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+stat("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db", {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+open("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db-journal", O_RDWR|O_CREAT|O_CLOEXEC, 0644) = 6
+fstat(6, {st_mode=S_IFREG|0644, st_size=0, ...}) = 0
+geteuid()                               = 530
+fstat(6, {st_mode=S_IFREG|0644, st_size=0, ...}) = 0
+lseek(6, 0, SEEK_SET)                   = 0
+write(6, "\331\325\5\371 \241c\327\377\377\377\377\345u\251\254\0\0\0\241\0\0\2\0\0\0\4\0\0\0\0\0"..., 512) = 512
+lseek(6, 512, SEEK_SET)                 = 512
+write(6, "\0\0\0\25", 4)                = 4
+lseek(6, 516, SEEK_SET)                 = 516
+write(6, "\r\3\331\0\1\3\262\0\3\262\3\262\2\230\2\230\2\230\2\230\2\230\2\230\2\230\1\232\1\232\1\232"..., 1024) = 1024
+lseek(6, 1540, SEEK_SET)                = 1540
+write(6, "\345u\251\256", 4)            = 4
+fcntl(3, F_SETLK, {type=F_WRLCK, whence=SEEK_SET, start=1073741824, len=1}) = 0
+fcntl(3, F_SETLK, {type=F_WRLCK, whence=SEEK_SET, start=1073741826, len=510}) = 0
+lseek(6, 1544, SEEK_SET)                = 1544
+write(6, "\0\0\0\1", 4)                 = 4
+lseek(6, 1548, SEEK_SET)                = 1548
+write(6, "SQLite format 3\0\4\0\1\1\0@  \0\0\5\247\0\0\0\241"..., 1024) = 1024
+lseek(6, 2572, SEEK_SET)                = 2572
+write(6, "\345u\251\254", 4)            = 4
+lseek(3, 0, SEEK_SET)                   = 0
+write(3, "SQLite format 3\0\4\0\1\1\0@  \0\0\5\250\0\0\0\241"..., 1024) = 1024
+lseek(3, 20480, SEEK_SET)               = 20480
+write(3, "\r\0\0\0\0\4\0\0\3\262\3\262\2\230\2\230\2\230\2\230\2\230\2\230\2\230\1\232\1\232\1\232"..., 1024) = 1024
+close(6)                                = 0
+unlink("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db-journal") = 0
+fcntl(3, F_SETLK, {type=F_RDLCK, whence=SEEK_SET, start=1073741826, len=510}) = 0
+fcntl(3, F_SETLK, {type=F_UNLCK, whence=SEEK_SET, start=1073741824, len=2}) = 0
+fcntl(3, F_SETLK, {type=F_UNLCK, whence=SEEK_SET, start=0, len=0}) = 0
+lstat("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
+select(0, NULL, NULL, NULL, {0, 1000})  = 0 (Timeout)
+fcntl(3, F_SETLK, {type=F_RDLCK, whence=SEEK_SET, start=1073741824, len=1}) = 0
+fcntl(3, F_SETLK, {type=F_RDLCK, whence=SEEK_SET, start=1073741826, len=510}) = 0
+fcntl(3, F_SETLK, {type=F_UNLCK, whence=SEEK_SET, start=1073741824, len=1}) = 0
+access("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db-journal", F_OK) = -1 ENOENT (No such file or directory)
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+lseek(3, 24, SEEK_SET)                  = 24
+read(3, "\0\0\5\250\0\0\0\241\0\0\0v\0\0\0\2", 16) = 16
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+access("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db-wal", F_OK) = -1 ENOENT (No such file or directory)
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+fcntl(3, F_SETLK, {type=F_UNLCK, whence=SEEK_SET, start=0, len=0}) = 0
+fcntl(3, F_SETLK, {type=F_RDLCK, whence=SEEK_SET, start=1073741824, len=1}) = 0
+fcntl(3, F_SETLK, {type=F_RDLCK, whence=SEEK_SET, start=1073741826, len=510}) = 0
+fcntl(3, F_SETLK, {type=F_UNLCK, whence=SEEK_SET, start=1073741824, len=1}) = 0
+access("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db-journal", F_OK) = -1 ENOENT (No such file or directory)
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+lseek(3, 24, SEEK_SET)                  = 24
+read(3, "\0\0\5\250\0\0\0\241\0\0\0v\0\0\0\2", 16) = 16
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+access("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db-wal", F_OK) = -1 ENOENT (No such file or directory)
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+fcntl(3, F_SETLK, {type=F_WRLCK, whence=SEEK_SET, start=1073741825, len=1}) = 0
+stat("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db", {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+stat("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db", {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+open("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db-journal", O_RDWR|O_CREAT|O_CLOEXEC, 0644) = 6
+fstat(6, {st_mode=S_IFREG|0644, st_size=0, ...}) = 0
+geteuid()                               = 530
+fstat(6, {st_mode=S_IFREG|0644, st_size=0, ...}) = 0
+lseek(6, 0, SEEK_SET)                   = 0
+write(6, "\331\325\5\371 \241c\327\377\377\377\377m)H%\0\0\0\241\0\0\2\0\0\0\4\0\0\0\0\0"..., 512) = 512
+lseek(6, 512, SEEK_SET)                 = 512
+write(6, "\0\0\0\27", 4)                = 4
+lseek(6, 516, SEEK_SET)                 = 516
+write(6, "\n\0\0\0\1\3\373\0\3\373\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 1024) = 1024
+lseek(6, 1540, SEEK_SET)                = 1540
+write(6, "m)H%", 4)                     = 4
+lseek(6, 1544, SEEK_SET)                = 1544
+write(6, "\0\0\0\26", 4)                = 4
+lseek(6, 1548, SEEK_SET)                = 1548
+write(6, "\r\0\0\0\1\3\371\0\3\371\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 1024) = 1024
+lseek(6, 2572, SEEK_SET)                = 2572
+write(6, "m)H%", 4)                     = 4
+fcntl(3, F_SETLK, {type=F_WRLCK, whence=SEEK_SET, start=1073741824, len=1}) = 0
+fcntl(3, F_SETLK, {type=F_WRLCK, whence=SEEK_SET, start=1073741826, len=510}) = 0
+lseek(6, 2576, SEEK_SET)                = 2576
+write(6, "\0\0\0\1", 4)                 = 4
+lseek(6, 2580, SEEK_SET)                = 2580
+write(6, "SQLite format 3\0\4\0\1\1\0@  \0\0\5\250\0\0\0\241"..., 1024) = 1024
+lseek(6, 3604, SEEK_SET)                = 3604
+write(6, "m)H%", 4)                     = 4
+lseek(3, 0, SEEK_SET)                   = 0
+write(3, "SQLite format 3\0\4\0\1\1\0@  \0\0\5\251\0\0\0\241"..., 1024) = 1024
+lseek(3, 21504, SEEK_SET)               = 21504
+write(3, "\r\0\0\0\0\4\0\0\3\371\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 1024) = 1024
+lseek(3, 22528, SEEK_SET)               = 22528
+write(3, "\n\0\0\0\0\4\0\0\3\373\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 1024) = 1024
+close(6)                                = 0
+unlink("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db-journal") = 0
+fcntl(3, F_SETLK, {type=F_RDLCK, whence=SEEK_SET, start=1073741826, len=510}) = 0
+fcntl(3, F_SETLK, {type=F_UNLCK, whence=SEEK_SET, start=1073741824, len=2}) = 0
+fcntl(3, F_SETLK, {type=F_UNLCK, whence=SEEK_SET, start=0, len=0}) = 0
+close(5)                                = 0
+close(-1)                               = -1 EBADF (Bad file descriptor)
+close(4)                                = 0
+fstat(3, {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+stat("/net/fileserver.methics.fi/mnt/mirror/common/scratch/mea/ham/aprx/aprx-trunk/.svn/wc.db", {st_mode=S_IFREG|0644, st_size=164864, ...}) = 0
+close(3)                                = 0
+munmap(0x7fb0c4174000, 212992)          = 0
+munmap(0x7fb0c41d2000, 139264)          = 0
+munmap(0x7fb0c4152000, 139264)          = 0
+exit_group(0)                           = ?
++++ exited with 0 +++
diff --git a/ttyreader.c b/ttyreader.c
new file mode 100644
index 0000000..888a5d9
--- /dev/null
+++ b/ttyreader.c
@@ -0,0 +1,1080 @@
+/* **************************************************************** *
+ *                                                                  *
+ *  APRX -- 2nd generation receive-only APRS-i-gate with            *
+ *          minimal requirement of esoteric facilities or           *
+ *          libraries of any kind beyond UNIX system libc.          *
+ *                                                                  *
+ * (c) Matti Aarnio - OH2MQK,  2007-2014                            *
+ *                                                                  *
+ * **************************************************************** */
+
+#define _SVID_SOURCE 1
+
+#include "aprx.h"
+#include <sys/socket.h>
+#include <netdb.h>
+#include <netinet/in.h>
+
+
+/* The ttyreader does read TTY ports into a big buffer, and then from there
+   to packet frames depending on what is attached...  */
+
+
+static struct serialport **ttys;
+static int ttycount;		/* How many are defined ? */
+
+#define TTY_OPEN_RETRY_DELAY_SECS 30
+
+static int poll_millis;         /* milliseconds (0 = none.)             */
+static struct timeval poll_millis_tv;
+
+
+void hexdumpfp(FILE *fp, const uint8_t *buf, const int len, int axaddr)
+{
+	int i, j;
+	for (i = 0, j=1; i < len; ++i,++j) {
+	  int c = buf[i] & 0xFF;
+	  fprintf(fp, "%02x", c);
+	  if (j < 8)
+	    fputc(' ',fp);
+	  else {
+	    fputc('|',fp);
+	    j = 0;
+	  }
+	}
+	fprintf(fp, " = ");
+	for (i = 0, j = 1; i < len; ++i,++j) {
+	  int c = buf[i] & 0xFF;
+          /*
+	  if ((c & 0x81) == 0x80 && (i < 8)) {
+	    // Auto-trigger AX.25 address plaintext converting
+	    axaddr = 1;
+	  }
+          */
+	  if (axaddr && ((c & 0x01) == 1) && i > 3) {
+	    // Definitely not AX.25 address anymore..
+	    axaddr = 0;
+	  }
+	  if (axaddr) {
+	    // Shifted AX.25 address byte?
+	    c >>= 1;
+	  }
+	  if (c < 0x20 || c > 0x7E)
+	    c = '.';
+	  fputc(c, fp);
+	  if (j >= 8) {
+	    fputc('|',fp);
+	    j = 0;
+	  }
+	}
+}
+
+
+/*
+ *  ttyreader_getc()  -- pick one char ( >= 0 ) out of input buffer, or -1 if out of buffer
+ */
+int ttyreader_getc(struct serialport *S)
+{
+	if (S->rdcursor >= S->rdlen) {	/* Out of data ? */
+		if (S->rdcursor)
+			S->rdcursor = S->rdlen = 0;
+		/* printf("-\n"); */
+		return -1;
+	}
+
+	/* printf(" %02X", 0xFF & S->rdbuf[S->rdcursor++]); */
+
+	return (0xFF & S->rdbuf[S->rdcursor++]);
+}
+
+
+
+/*
+ *  ttyreader_pulltnc2()  --  process a line of text by calling
+ *				TNC2 UI Monitor analyzer
+ */
+
+static int ttyreader_pulltnc2(struct serialport *S)
+{
+	const uint8_t *p;
+	int addrlen = 0;
+	p = memchr(S->rdline, ':', S->rdlinelen);
+	if (p != NULL)
+	  addrlen = (int)(p - S->rdline);
+
+	erlang_add(S->ttycallsign[0], ERLANG_RX, S->rdlinelen, 1);	/* Account one packet */
+
+	/* Send the frame to internal AX.25 network */
+	/* netax25_sendax25_tnc2(S->rdline, S->rdlinelen); */
+
+#ifndef DISABLE_IGATE
+	/* S->rdline[] has text line without line ending CR/LF chars   */
+	igate_to_aprsis(S->ttycallsign[0], 0, (char *) (S->rdline), addrlen, S->rdlinelen, 0, 1);
+#endif
+
+	return 0;
+}
+
+#if 0
+/*
+ * ttyreader_pullaea()  --  process a line of text by calling
+ * 			    AEA MONITOR 1 analyzer
+ */
+
+static int ttyreader_pullaea(struct serialport *S)
+{
+	int i;
+
+	if (S->rdline[S->rdlinelen - 1] == ':') {
+		/* Could this be the AX25 header ? */
+		char *s = strchr(S->rdline, '>');
+		if (s) {
+			/* Ah yes, it well could be.. */
+			strcpy(S->rdline2, S->rdline);
+			return;
+		}
+	}
+
+	/* FIXME: re-arrange the  S->rdline2  contained AX25 address tokens 
+	   and flags..
+
+	   perl code:
+	   @addrs = split('>', $rdline2);
+	   $out = shift @addrs; # pop first token in sequence
+	   $out .= '>';
+	   $out .= pop @addrs;  # pop last token in sequence
+	   foreach $a (@addrs) { # rest of the tokens in sequence, if any
+	   $out .= ',' . $a;
+	   }
+	   # now $out has address data in TNC2 sequence.
+	 */
+
+	/* printf("%s%s\n", S->rdline2, S->rdline); fflush(stdout); */
+
+	return 0;
+}
+#endif
+
+
+/*
+ *  ttyreader_pulltext()  -- process a line of text from the serial port..
+ */
+
+static int ttyreader_pulltext(struct serialport *S)
+{
+	int c;
+	const time_t rdtime = S->rdline_time;
+        // "rdtime > now" case ("now" going backwards) is always overwritten below
+
+	if (timecmp(rdtime+2, tick.tv_sec) < 0) {
+		// A timeout has happen? Either data is added constantly, or
+		// nothing was received from TEXT datastream for couple seconds!
+		S->rdlinelen = 0;
+		// S->kissstate = KISSSTATE_SYNCHUNT;
+	}
+	S->rdline_time = tick.tv_sec;
+
+	for (;;) {
+
+		c = ttyreader_getc(S);
+		if (c < 0)
+			return c;	/* Out of input.. */
+
+		/* S->kissstate != 0: read data into S->rdline,
+		   == 0: discard data until CR|LF.
+		   Zero-size read line is discarded as well
+		   (only CR|LF on input frame)  */
+
+		if (S->kissstate == KISSSTATE_SYNCHUNT) {
+			/* Looking for CR or LF.. */
+			if (c == '\n' || c == '\r')
+				S->kissstate = KISSSTATE_COLLECTING;
+
+			S->rdlinelen = 0;
+			continue;
+		}
+
+		/* Now: (S->kissstate != KISSSTATE_SYNCHUNT)  */
+
+		if (c == '\n' || c == '\r') {
+			/* End of line seen! */
+			if (S->rdlinelen > 0) {
+
+				/* Non-zero-size string, put terminating 0 byte on it. */
+				S->rdline[S->rdlinelen] = 0;
+
+				/* .. and process it depending ..  */
+
+				if (S->linetype == LINETYPE_TNC2) {
+					ttyreader_pulltnc2(S);
+#if 0
+				} else {	/* .. it is LINETYPE_AEA ? */
+					ttyreader_pullaea(S);
+#endif
+				}
+			}
+			S->rdlinelen = 0;
+			continue;
+		}
+
+		/* Now place the char in the linebuffer, if there is space.. */
+		if (S->rdlinelen >= (sizeof(S->rdline) - 3)) {	/* Too long !  Way too long ! */
+			S->kissstate = KISSSTATE_SYNCHUNT;	/* Sigh.. discard it. */
+			S->rdlinelen = 0;
+			continue;
+		}
+
+		/* Put it on line store: */
+		S->rdline[S->rdlinelen++] = c;
+
+	}			/* .. input loop */
+
+	return 0;		/* not reached */
+}
+
+
+
+/*
+ *  ttyreader_linewrite()  -- write out buffered data
+ */
+void ttyreader_linewrite(struct serialport *S)
+{
+	int i, len;
+
+	if ((S->wrlen == 0) || (S->wrlen > 0 && S->wrcursor >= S->wrlen)) {
+		S->wrlen = S->wrcursor = 0;	/* already all written */
+		return;
+	}
+
+	/* Now there is some data in between wrcursor and wrlen */
+
+	len = S->wrlen - S->wrcursor;
+	if (len > 0)
+	  i = write(S->fd, S->wrbuf + S->wrcursor, len);
+	else
+	  i = 0;
+	if (i > 0) {		/* wrote something */
+		S->wrcursor += i;
+		len = S->wrlen - S->wrcursor;
+		if (len == 0) {
+			S->wrcursor = S->wrlen = 0;	/* wrote all ! */
+		} else {
+			/* compact the buffer a bit */
+			memcpy(S->wrbuf, S->wrbuf + S->wrcursor, len);
+			S->wrcursor = 0;
+			S->wrlen = len;
+		}
+	}
+}
+
+
+/*
+ *  ttyreader_lineread()  --  read what there is into our buffer,
+ *			      and process the buffer..
+ */
+
+static void ttyreader_lineread(struct serialport *S)
+{
+	int i;
+
+	int rdspace = sizeof(S->rdbuf) - S->rdlen;
+
+	if (S->rdcursor > 0) {
+		/* Read-out cursor is not at block beginning,
+		   is there unread data too ?  */
+		if (S->rdlen > S->rdcursor) {
+			/* Uh..  lets move buffer down a bit,
+			   to make room for more to the end.. */
+			memcpy(S->rdbuf, S->rdbuf + S->rdcursor,
+			       S->rdlen - S->rdcursor);
+			S->rdlen = S->rdlen - S->rdcursor;
+		} else
+			S->rdlen = 0;	/* all processed, mark its size zero */
+		/* Cursor to zero, rdspace recalculated */
+		S->rdcursor = 0;
+
+		/* recalculate */
+		rdspace = sizeof(S->rdbuf) - S->rdlen;
+	}
+
+	if (rdspace > 0) {	/* We have room to read into.. */
+		i = read(S->fd, S->rdbuf + S->rdlen, rdspace);
+		if (i == 0) {	/* EOF ?  USB unplugged ? */
+			close(S->fd);
+			S->fd = -1;
+                        tv_timeradd_seconds(&S->wait_until, &tick, TTY_OPEN_RETRY_DELAY_SECS);
+                        aprxlog("TTY %s EOF - CLOSED, WAITING %d SECS\n", S->ttyname, TTY_OPEN_RETRY_DELAY_SECS);
+			return;
+		}
+		if (i < 0)	/* EAGAIN or whatever.. */
+			return;
+
+		/* Some data has been accumulated ! */
+		if (debug > 2) {
+		  printf("%ld\tTTY %s: read() frame: ", tick.tv_sec, S->ttyname);
+		  hexdumpfp(stdout, S->rdbuf+S->rdlen, i, 1);
+		  printf("\n");
+		}
+                
+		S->rdlen += i;
+		S->last_read_something = tick.tv_sec;
+	}
+
+	/* Done reading, maybe.  Now processing.
+	   The pullXX does read up all input, and does
+	   however many frames there are in, and pauses
+	   when there is no enough input data for a full
+	   frame/line/whatever.
+	 */
+
+	if (S->linetype == LINETYPE_KISS ||
+	    S->linetype == LINETYPE_KISSFLEXNET ||
+	    S->linetype == LINETYPE_KISSBPQCRC ||
+	    S->linetype == LINETYPE_KISSSMACK) {
+
+		kiss_pullkiss(S);
+
+
+#ifndef DISABLE_IGATE
+	} else if (S->linetype == LINETYPE_DPRSGW) {
+
+		dprsgw_pulldprs(S);
+
+#endif
+	} else if (S->linetype == LINETYPE_TNC2
+#if 0
+		   || S->linetype == LINETYPE_AEA
+#endif
+		   ) {
+
+		ttyreader_pulltext(S);
+
+	} else {
+		close(S->fd);	/* Urgh ?? Bad linetype value ?? */
+		S->fd = -1;
+                tv_timeradd_seconds(&S->wait_until, &tick, TTY_OPEN_RETRY_DELAY_SECS);
+                aprxlog("TTY %s Unsupported linetype - CLOSED, WAITING %d SECS\n", S->ttyname, TTY_OPEN_RETRY_DELAY_SECS);
+	}
+
+	/* Consumed something, and our read cursor is not in the beginning ? */
+	if (S->rdcursor > 0 && S->rdcursor < S->rdlen) {
+		/* Compact the input buffer! */
+		memcpy(S->rdbuf, S->rdbuf + S->rdcursor,
+		       S->rdlen - S->rdcursor);
+	}
+	S->rdlen -= S->rdcursor;
+	S->rdcursor = 0;
+}
+
+
+/*
+ * ttyreader_linesetup()  --  open and configure the serial port
+ */
+
+static void ttyreader_linesetup(struct serialport *S)
+{
+	int i;
+
+	S->wait_until.tv_sec = 0;	// Zero it just to be safe
+	S->wait_until.tv_usec = 0;	// Zero it just to be safe
+
+	S->wrlen = S->wrcursor = 0;	// init them at first
+
+        // If NOT tcp! type socket, it is presumably openable with
+        // open(2) instead of something else, like socket(2)...
+	if (memcmp(S->ttyname, "tcp!", 4) != 0) {
+		int e;
+        	// Open the serial port as RW, non-blocking, no-control-tty
+		S->fd = open(S->ttyname, O_RDWR | O_NOCTTY | O_NONBLOCK, 0);
+                e = errno;
+
+		if (debug) {
+                	printf("%ld\tTTY %s OPEN - fd=%d - ",
+                               tick.tv_sec, S->ttyname, S->fd);
+                        if (S->fd < 0) {
+                          printf("errno=%d (%s) - ", e, strerror(e));
+                        }
+                }
+		if (S->fd < 0) {	/* Urgh.. an error.. */
+			tv_timeradd_seconds(&S->wait_until, &tick, TTY_OPEN_RETRY_DELAY_SECS);
+			if (debug)
+				printf("FAILED, WAITING %d SECS\n",
+				       TTY_OPEN_RETRY_DELAY_SECS);
+                        aprxlog("TTY %s failed to open; errno=%d (%s)",
+                                S->ttyname, e, strerror(e));
+			return;
+		}
+		if (debug)
+			printf("OK\n");
+
+                aprxlog("TTY %s Opened.\n", S->ttyname);
+
+
+		/* Set attributes */
+		aprx_cfmakeraw(&S->tio, 1); /* hw-flow on */
+		i = tcsetattr(S->fd, TCSAFLUSH, &S->tio);
+
+		if (i < 0) {
+			if (debug)
+			  printf("%ld\tERROR: TCSETATTR failed; errno=%d\n",
+				 tick.tv_sec, errno);
+			close(S->fd);
+			S->fd = -1;
+			tv_timeradd_seconds(&S->wait_until, &tick, TTY_OPEN_RETRY_DELAY_SECS);
+                        aprxlog("TTY %s tcsetattr() failed. CLOSING TTY.\n", S->ttyname);
+			return;
+		}
+		// FIXME: ??  Set baud-rates ?
+		//   Used system (Linux) has them in   'struct termios'  so they
+		//   are now set, but other systems may have different ways..
+
+		// Flush buffers once again.
+		i = tcflush(S->fd, TCIOFLUSH);
+
+		for (i = 0; i < 16; ++i) {
+		  if (S->initstring[i] != NULL) {
+		    memcpy(S->wrbuf + S->wrlen, S->initstring[i], S->initlen[i]);
+		    S->wrlen += S->initlen[i];
+		  }
+		}
+
+		/* Flush it out..  and if not successfull,
+		   poll(2) will take care of it soon enough.. */
+		ttyreader_linewrite(S);
+
+	} else {		/* socket connection to remote TTY.. */
+		/*   "tcp!hostname-or-ip!port!opt-parameters" */
+		char *par = strdup(S->ttyname);
+		char *host = NULL, *port = NULL, *opts = NULL;
+		struct addrinfo req, *ai;
+		int i;
+
+		if (debug)
+			printf("socket connect() preparing: %s\n", par);
+
+                while (1) {
+			host = strchr(par, '!');
+			if (host)
+				++host;
+			else
+				break;	/* Found no '!' ! */
+			port = strchr(host, '!');
+			if (port)
+				*port++ = 0;
+			else
+				break;	/* Found no '!' ! */
+			opts = strchr(port, '!');
+			if (opts)
+				*opts++ = 0;
+			break;
+		}
+
+		if (!port) {
+			/* Still error condition.. no port data */
+		}
+
+		memset(&req, 0, sizeof(req));
+		req.ai_socktype = SOCK_STREAM;
+		req.ai_protocol = IPPROTO_TCP;
+		req.ai_flags = 0;
+#if 1
+		req.ai_family = AF_UNSPEC;	/* IPv4 and IPv6 are both OK */
+#else
+		req.ai_family = AF_INET;	/* IPv4 only */
+#endif
+		ai = NULL;
+
+		i = getaddrinfo(host, port, &req, &ai);
+
+		if (ai) {
+			S->fd = socket(ai->ai_family, SOCK_STREAM, 0);
+			if (S->fd >= 0) {
+
+				fd_nonblockingmode(S->fd);
+
+				i = connect(S->fd, ai->ai_addr,
+					    ai->ai_addrlen);
+				if ((i != 0) && (errno != EINPROGRESS)) {
+					/* non-blocking connect() yields EINPROGRESS,
+					   anything else and we fail entirely...      */
+					if (debug)
+						printf("ttyreader socket connect call failed: %d : %s\n", errno, strerror(errno));
+					close(S->fd);
+					S->fd = -1;
+                                        aprxlog("TTY %s Socket open failed.\n", S->ttyname);
+				}
+			}
+
+			freeaddrinfo(ai);
+                }
+		free(par);
+	}
+
+	S->last_read_something = tick.tv_sec;	/* mark the timeout for future.. */
+
+	S->rdlen = S->rdcursor = S->rdlinelen = 0;
+	S->kissstate = KISSSTATE_SYNCHUNT;
+
+	memset( S->smack_probe, 0, sizeof(S->smack_probe) );
+	S->smack_subids = 0;
+}
+
+/*
+ *  ttyreader_init()
+ */
+
+void ttyreader_init(void)
+{
+	/* nothing.. */
+}
+
+
+
+/*
+ *  ttyreader_prepoll()  --  prepare system for next round of polling
+ */
+
+int ttyreader_prepoll(struct aprxpolls *app)
+{
+	int idx = 0;		/* returns number of *fds filled.. */
+	int i;
+	struct serialport *S;
+	struct pollfd *pfd;
+
+        if (poll_millis_tv.tv_sec == 0) {
+        	poll_millis_tv = tick;
+        }
+
+        // if (debug) printf("ttyreader_prepoll() %d\n", poll_millis);
+	for (i = 0; i < ttycount; ++i) {
+		S = ttys[i];
+		if (!S->ttyname)
+			continue;	/* No name, no look... */
+
+
+#if 0 // occasional debug mode without real hardware at hand
+                if (poll_millis > 0) {
+                  int deltams = tv_timerdelta_millis(&tick, &poll_millis_tv);
+                  struct timeval tv;
+                  if (debug) printf("%d.%06d .. defining %d ms KISS POLL\n", tick.tv_sec, tick.tv_usec, poll_millis);
+                }
+#endif
+
+		if (S->fd < 0) {
+                	if (time_reset && (S->wait_until.tv_sec != 0)) {
+                        	// System time jumped, reset it to NOW.
+                        	S->wait_until = tick;
+                        }
+
+			/* Not an open TTY, but perhaps waiting ? */
+			if ((S->wait_until.tv_sec != 0) && tv_timercmp( &S->wait_until, &tick) > 0) {
+				/* .. waiting for future! */
+                        	if (tv_timercmp( &app->next_timeout, &S->wait_until ) > 0) {
+                                	app->next_timeout = S->wait_until;
+                                }
+				/* .. but only until our timeout,
+				   if it is sooner than global one. */
+				continue;	/* Waiting on this one.. */
+			}
+
+			/* Waiting or not, FD is not open, and deadline is past.
+			   Lets try to open! */
+
+			ttyreader_linesetup(S);
+
+		}
+		/* .. No open FD */
+		/* Still no open FD ? */
+		if (S->fd < 0)
+			continue;
+
+		// FD is open, check read/idle timeout ...
+                if (time_reset) {
+                  // System time has jumped, Reset the read time to NOW.
+                  S->last_read_something = tick.tv_sec;
+                }
+
+		// FD is open, check read/idle timeout ...
+		if ((S->read_timeout > 0) &&
+		    timecmp(tick.tv_sec, (S->last_read_something + S->read_timeout)) > 0) {
+			if (debug)
+			  printf("%ld\tRead timeout on %s; %d seconds w/o input. fd=%d\n",
+				 tick.tv_sec, S->ttyname, S->read_timeout, S->fd);
+			close(S->fd);	/* Close and mark for re-open */
+			S->fd = -1;
+                        tv_timeradd_seconds( &S->wait_until, &tick, TTY_OPEN_RETRY_DELAY_SECS);
+                        aprxlog("TTY %s read timeout. Closing TTY for later re-open.\n", S->ttyname);
+			continue;
+		}
+
+
+                if (poll_millis > 0) {
+                        int margin  = poll_millis*2;
+                        // Limit large delta time to within 0..2*poll_millis.
+			int deltams = tv_timerdelta_millis(&tick, &poll_millis_tv);
+                        if (deltams > margin)  deltams = poll_millis;
+                        if (deltams < -margin) deltams = poll_millis;
+                        tv_timeradd_millis(&poll_millis_tv, &tick, deltams);
+
+                        if (debug) printf("%ld.%06d .. defining %d ms KISS POLL\n", (long)tick.tv_sec, (int)tick.tv_usec, poll_millis);
+                }
+
+		/* FD is open, lets mark it for poll read.. */
+		pfd = aprxpolls_new(app);
+		pfd->fd = S->fd;
+		pfd->events = POLLIN | POLLPRI;
+		pfd->revents = 0;
+		if (S->wrlen > 0 && S->wrlen > S->wrcursor)
+			pfd->events |= POLLOUT;
+
+		++idx;
+	}
+	return idx;
+}
+
+
+/*
+ *  ttyreader_postpoll()  -- Done polling, what happened ?
+ */
+
+int ttyreader_postpoll(struct aprxpolls *app)
+{
+	int idx, i;
+
+	struct serialport *S;
+	struct pollfd *P;
+
+        // if (debug) printf("ttyreader_postpoll()\n");
+
+	for (idx = 0, P = app->polls; idx < app->pollcount; ++idx, ++P) {
+
+        	// Are we operating in active KISS polling mode?
+        	if (poll_millis > 0) {
+			for (i = 0; i < ttycount; ++i) {
+                               	S = ttys[i];
+
+#if 0  // occasional debug mode without real hardware at hand
+                                if (tv_timercmp(&poll_millis_tv, &tick) <= 0) {
+	                                // Poll interval gone, time for next active POLL request!
+                                        kiss_poll(S);
+                                        tv_timeradd_millis(&poll_millis_tv, &poll_millis_tv, poll_millis);
+                                }
+#endif
+
+                                if (S->fd != P->fd)
+                                	continue;	/* Not this one ? */
+                                if (S->fd < 0)
+                                	continue;	/* Not this one ? */
+
+                                if (!(S->linetype == LINETYPE_KISS ||
+                                      S->linetype == LINETYPE_KISSFLEXNET ||
+                                      S->linetype == LINETYPE_KISSBPQCRC ||
+                                      S->linetype == LINETYPE_KISSSMACK)) {
+                                        // Not a KISS line..
+                                        continue;
+                                }
+                                if (tv_timercmp(&poll_millis_tv, &tick) <= 0) {
+	                                // Poll interval gone, time for next active POLL request!
+                                        kiss_poll(S);
+                                        tv_timeradd_millis(&poll_millis_tv, &poll_millis_tv, poll_millis);
+                                }
+                        }
+                }
+
+		for (i = 0; i < ttycount; ++i) {
+			S = ttys[i];
+			if (S->fd != P->fd)
+				continue;	/* Not this one ? */
+			/* It is this one! */
+
+			if (P->revents & POLLOUT)
+				ttyreader_linewrite(S);
+
+                        if (P->revents & (POLLIN | POLLPRI | POLLERR | POLLHUP))
+                		ttyreader_lineread(S);
+		}
+	}
+
+	return 0;
+}
+
+/*
+ * Make a pre-existing termios structure into "raw" mode: character-at-a-time
+ * mode with no characters interpreted, 8-bit data path.
+ */
+void
+aprx_cfmakeraw(t, f)
+	struct termios *t;
+{
+
+	t->c_iflag &= ~(IMAXBEL|IXOFF|INPCK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON|IGNPAR);
+	t->c_iflag |= IGNBRK;
+
+	t->c_oflag &= ~OPOST;
+	if (f) {
+	  t->c_oflag |= CRTSCTS;
+	} else {
+	  t->c_oflag &= ~CRTSCTS;
+	}
+
+	t->c_lflag &= ~(ECHO|ECHOE|ECHOK|ECHONL|ICANON|ISIG|IEXTEN|NOFLSH|TOSTOP|PENDIN);
+	t->c_cflag &= ~(CSIZE|PARENB);
+	t->c_cflag |= CS8|CREAD;
+	t->c_cc[VMIN] = 80;
+	t->c_cc[VTIME] = 3;
+}
+
+struct serialport *ttyreader_new(void)
+{
+	struct serialport *tty = calloc(1, sizeof(*tty));
+	int baud = B1200;
+
+	tty->fd = -1;
+        tv_timeradd_seconds( &tty->wait_until, &tick, -1); /* begin opening immediately */
+	tty->last_read_something = tick.tv_sec;	/* well, not really.. */
+	tty->linetype  = LINETYPE_KISS;	/* default */
+	tty->kissstate = KISSSTATE_SYNCHUNT;
+        tty->read_timeout = 3600;  /* Default port read timeout is 60 minutes. */
+
+	tty->ttyname = NULL;
+
+
+	/* setup termios parameters for this line.. */
+	aprx_cfmakeraw(&tty->tio, 0);
+	tty->tio.c_cc[VMIN] = 80;	/* pick at least one char .. */
+	tty->tio.c_cc[VTIME] = 3;	/* 0.3 seconds timeout - 36 chars @ 1200 baud */
+	tty->tio.c_cflag |= (CREAD | CLOCAL);
+
+	cfsetispeed(&tty->tio, baud);
+	cfsetospeed(&tty->tio, baud);
+
+	return tty;
+}
+
+/*
+ * Parse tty related parameters, return 0 for OK, 1 for error
+ */
+int ttyreader_parse_nullparams(struct configfile *cf, struct serialport *tty, char *str)
+{
+	char *param1 = 0;
+        int has_fault = 0;
+
+	/* FIXME: analyze correct serial port data and parity format settings,
+	   now hardwired to 8-n-1 -- does not work without for KISS anyway.. */
+	
+	config_STRLOWER(str);	/* until end of line */
+
+	/* Optional parameters */
+	while (*str != 0) {
+		param1 = str;
+		str = config_SKIPTEXT(str, NULL);
+		str = config_SKIPSPACE(str);
+
+		if (debug)
+		  printf(" .. param='%s'",param1);
+
+
+		/* Note:  param1  is now lower-case string */
+
+                if (strcmp(param1, "pollmillis") == 0) {
+			param1 = str;
+			str = config_SKIPTEXT(str, NULL);
+			str = config_SKIPSPACE(str);
+			tty->poll_millis = atol(param1); // milliseconds
+                        if (poll_millis == 0)
+                          poll_millis = tty->poll_millis;
+                        if (tty->poll_millis < poll_millis)
+                          poll_millis = tty->poll_millis;
+                        if (poll_millis < 1 || poll_millis > 10000) {
+                          has_fault = 1;
+                          printf("%s:%d POLLMILLIS value not in sanity range of 1 to 10 000: '%s'", cf->name, cf->linenum, param1);
+                        } else {
+                          if (debug)
+                            printf(" .. pollmillis %d  -- polling interval\n", tty->poll_millis);
+                        }
+
+		} else {
+		  printf("%s:%d ERROR: Unknown sub-keyword on a serial/tcp device configuration: '%s'\n",
+			 cf->name, cf->linenum, param1);
+                  has_fault = 1;
+		}
+	}
+	if (debug) printf("\n");
+	return has_fault;
+}
+
+/*
+ * Parse tty related parameters, return 0 for OK, 1 for error
+ */
+int ttyreader_parse_ttyparams(struct configfile *cf, struct serialport *tty, char *str)
+{
+	int i;
+	speed_t baud;
+	int tncid   = 0;
+	char *param1 = 0;
+        int has_fault = 0;
+
+	/* FIXME: analyze correct serial port data and parity format settings,
+	   now hardwired to 8-n-1 -- does not work without for KISS anyway.. */
+	
+	config_STRLOWER(str);	/* until end of line */
+
+	/* Optional parameters */
+	while (*str != 0) {
+		param1 = str;
+		str = config_SKIPTEXT(str, NULL);
+		str = config_SKIPSPACE(str);
+
+		if (debug)
+		  printf(" .. param='%s'",param1);
+
+		/* See if it is baud-rate ? */
+		i = atol(param1);	/* serial port speed - baud rate */
+		baud = B1200;
+		switch (i) {
+		case 1200:
+			baud = B1200;
+			break;
+#ifdef B1800
+		case 1800:
+			baud = B1800;
+			break;
+#endif
+		case 2400:
+			baud = B2400;
+			break;
+		case 4800:
+			baud = B4800;
+			break;
+		case 9600:
+			baud = B9600;
+			break;
+#ifdef B19200
+		case 19200:
+			baud = B19200;
+			break;
+#endif
+#ifdef B38400
+		case 38400:
+			baud = B38400;
+			break;
+#endif
+#ifdef B57600
+		case 57600:
+			baud = B57600;
+			break;
+#endif
+#ifdef B115200
+		case 115200:
+			baud = B115200;
+			break;
+#endif
+#ifdef B230400
+		case B230400:
+			baud = B230400;
+			break;
+#endif
+#ifdef B460800
+		case 460800:
+			baud = B460800;
+			break;
+#endif
+#ifdef B500000
+		case 500000:
+			baud = B500000;
+			break;
+#endif
+#ifdef B576000
+		case 576000:
+			baud = B576000;
+			break;
+#endif
+		default:
+			i = -1;
+			break;
+		}
+		if (baud != B1200) {
+			cfsetispeed(&tty->tio, baud);
+			cfsetospeed(&tty->tio, baud);
+		}
+
+		/* Note:  param1  is now lower-case string */
+
+		if (i > 0) {
+			;
+		} else if (strcmp(param1, "8n1") == 0) {
+			/* default behaviour, ignore */
+		} else if (strcmp(param1, "kiss") == 0) {
+			tty->linetype = LINETYPE_KISS;	/* plain basic KISS */
+
+		} else if (strcmp(param1, "xorsum") == 0) {
+			tty->linetype = LINETYPE_KISSBPQCRC;	/* KISS with BPQ "CRC" */
+		} else if (strcmp(param1, "xkiss") == 0) {
+			tty->linetype = LINETYPE_KISSBPQCRC;	/* KISS with BPQ "CRC" */
+		} else if (strcmp(param1, "bpqcrc") == 0) {
+			tty->linetype = LINETYPE_KISSBPQCRC;	/* KISS with BPQ "CRC" */
+
+		} else if (strcmp(param1, "flexnet") == 0) {
+			tty->linetype = LINETYPE_KISSFLEXNET;	/* KISS with FLEXNET's CRC16 */
+		} else if (strcmp(param1, "smack") == 0) {
+			tty->linetype = LINETYPE_KISSSMACK;	/* KISS with SMACK / CRC16 */
+		} else if (strcmp(param1, "crc16") == 0) {
+			tty->linetype = LINETYPE_KISSSMACK;	/* KISS with SMACK / CRC16 */
+
+		} else if (strcmp(param1, "poll") == 0) {
+			/* FIXME: Some systems want polling... */
+
+		} else if (strcmp(param1, "callsign") == 0 ||
+			   strcmp(param1, "alias") == 0) {
+			param1 = str;
+			str = config_SKIPTEXT(str, NULL);
+			str = config_SKIPSPACE(str);
+			config_STRUPPER(param1);
+			tty->ttycallsign[tncid] = strdup(param1);
+
+#ifdef PF_AX25	/* PF_AX25 exists -- highly likely a Linux system ! */
+			tty->netax25[tncid] = netax25_open(param1);
+#endif
+
+			/* Use side-effect: this defines the tty into
+			   erlang accounting */
+
+			erlang_set(param1, /* Heuristic constant for max channel capa.. */ (int) ((1200.0 * 60) / 8.2));
+
+		} else if (strcmp(param1, "timeout") == 0) {
+			param1 = str;
+			str = config_SKIPTEXT(str, NULL);
+			str = config_SKIPSPACE(str);
+			tty->read_timeout = atol(param1);
+
+		} else if (strcmp(param1, "tncid") == 0) {
+			param1 = str;
+			str = config_SKIPTEXT(str, NULL);
+			str = config_SKIPSPACE(str);
+			tncid = atoi(param1);
+			if (tncid < 0 || tncid > 15) {
+				tncid = 0;
+                                printf("%s:%d TNCID value not in sanity range of 0 to 15: '%s'", cf->name, cf->linenum, param1);
+                                has_fault = 1;
+                        }
+
+		} else if (strcmp(param1, "pollmillis") == 0) {
+			param1 = str;
+			str = config_SKIPTEXT(str, NULL);
+			str = config_SKIPSPACE(str);
+			tty->poll_millis = atol(param1); // milliseconds
+                        if (poll_millis == 0)
+                          poll_millis = tty->poll_millis;
+                        if (tty->poll_millis < poll_millis)
+                          poll_millis = tty->poll_millis;
+                        if (poll_millis < 1 || poll_millis > 10000) {
+                          has_fault = 1;
+                          printf("%s:%d POLLMILLIS value not in sanity range of 1 to 10 000: '%s'", cf->name, cf->linenum, param1);
+                        } else {
+                          if (debug)
+                            printf(" .. pollmillis %d  -- polling interval\n", tty->poll_millis);
+                        }
+
+#ifndef DISABLE_IGATE
+		} else if (strcmp(param1, "tnc2") == 0) {
+			tty->linetype = LINETYPE_TNC2;	/* TNC2 monitor */
+
+		} else if (strcmp(param1, "dprs") == 0) {
+			tty->linetype = LINETYPE_DPRSGW;
+#endif
+
+		} else if (strcmp(param1, "initstring") == 0) {
+			int parlen;
+			param1 = str;
+			str = config_SKIPTEXT(str, &parlen);
+			str = config_SKIPSPACE(str);
+			tty->initlen[tncid]    = parlen;
+			tty->initstring[tncid] = malloc(parlen);
+			memcpy(tty->initstring[tncid], param1, parlen);
+
+			if (debug)
+			  printf("initstring len=%d\n",parlen);
+		} else {
+		  printf("%s:%d ERROR: Unknown sub-keyword on a serial/tcp device configuration: '%s'\n",
+			 cf->name, cf->linenum, param1);
+                  has_fault = 1;
+		}
+	}
+	if (debug) printf("\n");
+	return has_fault;
+}
+
+
+void ttyreader_register(struct serialport *tty)
+{
+	/* Grow the array as is needed.. - this is array of pointers,
+	   not array of blocks so that memory allocation does not
+	   grow into way too big chunks. */
+	ttys = realloc(ttys, sizeof(void *) * (ttycount + 1));
+	ttys[ttycount++] = tty;
+}
+
+const char *ttyreader_serialcfg(struct configfile *cf, char *param1, char *str)
+{				/* serialport /dev/ttyUSB123   19200  8n1   {KISS|TNC2|AEA|..}  */
+	struct serialport *tty;
+
+	/*
+	   radio serial /dev/ttyUSB123  [19200 [8n1]]  KISS
+	   radio tcp 12.34.56.78 4001 KISS
+
+	 */
+
+	if (*param1 == 0)
+		return "Bad mode keyword";
+	if (*str == 0)
+		return "Bad tty-name/param";
+
+	tty = ttyreader_new();
+	ttyreader_register(tty);
+
+	if (strcmp(param1, "serial") == 0) {
+		/* New style! */
+		free((char *) (tty->ttyname));
+
+		param1 = str;
+		str = config_SKIPTEXT(str, NULL);
+		str = config_SKIPSPACE(str);
+
+		tty->ttyname = strdup(param1);
+
+		if (debug)
+			printf(".. new style serial:  '%s' '%s'..\n",
+			       tty->ttyname, str);
+
+	} else if (strcmp(param1, "tcp") == 0) {
+		/* New style! */
+		int len;
+		char *host, *port;
+
+		free((char *) (tty->ttyname));
+
+		host = str;
+		str = config_SKIPTEXT(str, NULL);
+		str = config_SKIPSPACE(str);
+
+		port = str;
+		str = config_SKIPTEXT(str, NULL);
+		str = config_SKIPSPACE(str);
+
+		if (debug)
+			printf(".. new style tcp!:  '%s' '%s' '%s'..\n",
+			       host, port, str);
+
+		len = strlen(host) + strlen(port) + 8;
+
+		tty->ttyname = malloc(len);
+		sprintf((char *) (tty->ttyname), "tcp!%s!%s!", host, port);
+
+	}
+
+	if (ttyreader_parse_ttyparams( cf, tty, str))
+	  return "Bad ttyparameters";
+
+	return NULL; // All OK
+}
+
diff --git a/valgrind.c b/valgrind.c
new file mode 100644
index 0000000..e23506f
--- /dev/null
+++ b/valgrind.c
@@ -0,0 +1,101 @@
+/* **************************************************************** *
+ *                                                                  *
+ *  APRX -- 2nd generation receive-only APRS-i-gate with            *
+ *          minimal requirement of esoteric facilities or           *
+ *          libraries of any kind beyond UNIX system libc.          *
+ *                                                                  *
+ * (c) Matti Aarnio - OH2MQK,  2007-2014                            *
+ *                                                                  *
+ * **************************************************************** */
+
+#ifdef _FOR_VALGRIND_
+#include "aprx.h"
+
+/*
+ * High-efficiency algorithms used by libc cause terrible complaints
+ * from valgrind..
+ *
+ * These naive single char at the time things don't go reading into
+ * uninitialized areas..
+ *
+ */
+
+int memcmp(const void *p1, const void *p2, size_t n) {
+  const char *s1 = p1;
+  const char *s2 = p2;
+  for( ; n > 0 && *s1 == *s2 ; ++s1, ++s2, --n ) ;
+  if (n == 0) return 0;
+  return (*s1 - *s2);
+}
+void *memcpy(void *dest, const void *src, size_t n) {
+  char *p = dest;
+  const char *s = src;
+  for ( ; n > 0; --n ) {
+    *p++ = *s++;
+  }
+  return dest;
+}
+size_t strlen(const char *p) {
+  size_t i;
+  for ( i = 0; *p != 0; ++p, ++i ) ;
+  return i;
+}
+char *strdup(const char *s) {
+  int len = strlen(s)+1;
+  char *p = malloc(len);
+  memcpy(p, s, len);
+  return p;
+}
+int strcmp(const char *s1, const char *s2) {
+  for( ; *s1 && *s2 && *s1 == *s2 ; ++s1, ++s2 ) ;
+  if (*s1 == 0 && *s2 == 0) return 0;
+  if (*s1 == 0) return -1;
+  if (*s2 == 0) return  1;
+  return (*s1 - *s2);
+}
+int strncmp(const char *s1, const char *s2, size_t n) {
+  for( ; n > 0 && *s1 && *s2 && *s1 == *s2 ; ++s1, ++s2, --n ) ;
+  if (n == 0) return 0;
+  if (*s1 == 0) return -1;
+  if (*s2 == 0) return  1;
+  return (*s1 - *s2);
+}
+char   *strcpy(char *dest, const char *src) {
+  char *p = dest;
+  while (*src != 0) {
+    *p++ = *src++;
+  }
+  return dest;
+}
+char   *strncpy(char *dest, const char *src, size_t n) {
+  char *p = dest;
+  for (;*src != 0 && n > 0; --n) {
+    *p++ = *src++;
+  }
+  return dest;
+}
+void   *memchr(const void *s, int c, size_t n) {
+  const unsigned char *p = s;
+  c &= 0xFF;
+  for (p = s; n > 0; --n, ++p) {
+    if (*p == c) return (void*)p;
+  }
+  return NULL;
+}
+void   *memrchr(const void *s, int c, size_t n) {
+  const unsigned char *p = s;
+  c &= 0xFF;
+  for (p = s+n; n > 0; --n, --p) {
+    if (*p == c) return (void*)p;
+  }
+  return NULL;
+}
+char  *strchr(const char *s, int c) {
+  c &= 0xFF;
+  for (; *s != 0; ++s) {
+    if (((*s) & 0xFF) == c) return (char*)s;
+  }
+  return NULL;
+}
+
+#endif

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-hamradio/aprx.git



More information about the pkg-hamradio-commits mailing list