[hamradio-commits] [uronode] 01/03: Imported Upstream version 2.3.1

Dave Hibberd hibby-guest at moszumanska.debian.org
Thu Sep 3 19:47:32 UTC 2015


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

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

commit 4013fe89dba7bcbd25ffded96d12bba6c9c78476
Author: Dave Hibberd <d at vehibberd.com>
Date:   Thu Sep 3 20:01:45 2015 +0100

    Imported Upstream version 2.3.1
---
 BBS.txt                |    6 +
 CHANGES.1              |  929 +++++++++++++++++++++++++++++++++++++++
 CHANGES.2              |  637 +++++++++++++++++++++++++++
 COLORS                 |   25 ++
 COPYING                |  339 +++++++++++++++
 FAQ                    |   35 ++
 INSTALL                |   79 ++++
 Makefile.in            |  100 +++++
 Makefile.include.in    |   13 +
 README                 |   95 ++++
 URONode.his            |   49 +++
 axcalluser.c           |   77 ++++
 axcalluser.h           |   16 +
 axdigi.c               |  255 +++++++++++
 cmdparse.c             |  300 +++++++++++++
 command.c              | 1058 ++++++++++++++++++++++++++++++++++++++++++++
 config.c               |  485 +++++++++++++++++++++
 config.h.in            |   36 ++
 configure              |  303 +++++++++++++
 etc/axdigi.conf        |   20 +
 etc/flexd.conf         |   14 +
 etc/gateways           |    0
 etc/help/bye.hlp       |    6 +
 etc/help/color.hlp     |   18 +
 etc/help/connect.hlp   |   25 ++
 etc/help/desti.hlp     |   14 +
 etc/help/escape.hlp    |   16 +
 etc/help/finger.hlp    |   13 +
 etc/help/help.hlp      |   10 +
 etc/help/host.hlp      |   11 +
 etc/help/info.hlp      |    8 +
 etc/help/links.hlp     |   16 +
 etc/help/mail.hlp      |   12 +
 etc/help/message.hlp   |   14 +
 etc/help/mheard.hlp    |    8 +
 etc/help/msg.hlp       |   15 +
 etc/help/netstat.hlp   |    7 +
 etc/help/nodes.hlp     |   15 +
 etc/help/ping.hlp      |   15 +
 etc/help/ports.hlp     |   12 +
 etc/help/quit.hlp      |    6 +
 etc/help/rose.hlp      |    2 +
 etc/help/routes.hlp    |   16 +
 etc/help/sessions.hlp  |   10 +
 etc/help/status.hlp    |   14 +
 etc/help/telnet.hlp    |   26 ++
 etc/help/users.hlp     |    8 +
 etc/help/version.hlp   |    6 +
 etc/help/who.hlp       |    8 +
 etc/help/zconnect.hlp  |   23 +
 etc/help/ztelnet.hlp   |   25 ++
 etc/lastlog            |    0
 etc/loggedin           |    0
 etc/uronode.conf       |   89 ++++
 etc/uronode.info       |    3 +
 etc/uronode.motd       |    4 +
 etc/uronode.perms      |   26 ++
 etc/uronode.routes     |   21 +
 etc/uronode.users      |    6 +
 extcmd.c               |  203 +++++++++
 flexd.c                |  431 ++++++++++++++++++
 gateway.c              | 1131 ++++++++++++++++++++++++++++++++++++++++++++++++
 ipc.c                  |  193 +++++++++
 man/axdigi.8.gz        |  Bin 0 -> 1006 bytes
 man/flexd.conf.5.gz    |  Bin 0 -> 988 bytes
 man/nodeusers.1.gz     |  Bin 0 -> 596 bytes
 man/uronode.8.gz       |  Bin 0 -> 3287 bytes
 man/uronode.conf.5.gz  |  Bin 0 -> 3333 bytes
 man/uronode.perms.5.gz |  Bin 0 -> 1267 bytes
 mheard.c               |  151 +++++++
 node.c                 |  419 ++++++++++++++++++
 node.h                 |  172 ++++++++
 nodeusers.c            |   82 ++++
 procinfo.c             |  358 +++++++++++++++
 procinfo.h             |   99 +++++
 router.c               |  261 +++++++++++
 sysinfo.c              |  243 +++++++++++
 sysinfo.h              |   26 ++
 system.c               |  632 +++++++++++++++++++++++++++
 user.c                 |  289 +++++++++++++
 util.c                 |  115 +++++
 81 files changed, 10204 insertions(+)

diff --git a/BBS.txt b/BBS.txt
new file mode 100644
index 0000000..22e94cf
--- /dev/null
+++ b/BBS.txt
@@ -0,0 +1,6 @@
+Note in regards to PBBS forwarding:
+If you do compressed forwarding with other PBBS systems, insure you flag
+your connection so that you do NOT have ANSI turned on for that interface
+AND that you disable the escape character. See: man uronode.perms
+for the proper flags. This insures that compression will stay enabled
+and that a compressed ctrl+t is not sent via compressed ascii codes.
diff --git a/CHANGES.1 b/CHANGES.1
new file mode 100644
index 0000000..aa59b32
--- /dev/null
+++ b/CHANGES.1
@@ -0,0 +1,929 @@
+URONode bug fix and change notes:
+
+30/4/1998 v0.3a:
+Users with no permissions on AX25, NETROM, ROSE, TELNET outgoing connections,
+can use alias commands that connect a remote node by AX25, NETROM, ROSE and
+TELNET outgoing connections.
+
+30/4/1998 v0.3b:
+"!" command crashed on systems with no swap: CORRECTED!
+Reconnected on Telnet sended two prompt-line: CORRECTED!
+
+ 8/1/2000 v0.4-pre1:
+Now compile and run under kernel 2.2.x, glibc6 and new ax25 and ax25io libs! 
+Added Gateway special tranfer mode.
+
+18/2/2000 v0.4-pre2:
+"Ports" command crashed on systems without listening sockets: CORRECTED!
+Bad Pre-compiler directive order for systems without ROSE support: CORRECTED!
+Now AWZNode have a better I/O flushing.
+Other little code bugs resolved.
+
+*Rewrites by Brian N1URO
+**Note: this is being done on a debian linux server running kernel 2.4.20.
+  your milage may vary depending on the flavor of linux you're using. It
+  may be possible that with the exception of screen pushes, the AWZNode
+  could infact be working 100% fine, this I don't know.
+
+5/4/2003 v0.5.2:
+Renamed the project to AWZ-URONode.
+Stripped out the recursing prompt to the end users. 
+Redesigned the output of the node to be similar to that of TheNet X1J type
+nodes.
+Added NodeId variable header of several command output lines, this is
+totally configurable in /etc/ax25/node.conf under the "NodeId" option. I
+suggest in keeping with the design of TheNet X1J to use a format similar
+to: UROHUB:N1URO-2} (that's my personal preference hi!)
+In flexd.c (line 310), changed i++ from (2) to (16) to ignore additional ctext.
+If by chance you only get one packet burst worth of ctext or login.fpr 
+information, you may reduce (16) below to 8, or if yo uget 3 packets worth 
+of information you may go higher. In my case, I receive two packets of connect
+texts from my FlexNet gateway node so I use 16 for myself. You will have to 
+experiment with this. You have been notified. Failure to adjust the parsing
+code properly -will- result in any connect text strings as being falsely
+parsed as bogus flexnet destinations and will maintain a sloppy list.
+
+5/4/2003 v0.5.3:
+With the amount of rewrites, I decided to rename the node to URONode.
+Did more cosmetic cleanups and changed the node to look more like TheNet
+type node. This also included some code cleanup and rewrites of some
+minor routines.
+Readded a node prompt as an option, however unlike the previous way
+the prompt was programmed, if there was no prompt defined, a generic
+AWZNode -> prompt displayed. If in /etc/ax25/node.conf the prompt
+was left blank (aka: "") then a null line feed occurred. Now in
+regards to the prompt, if no Prompt is defined in /etc/ax25/node.conf
+a flexnet type prompt "=>" will display, or if you set the prompt in
+/etc/ax25/node.conf to Prompt "", then the prompt will be defeated
+and no additional lines of text (null or not) will be displayed.
+*I found it VERY frustrating that when a sysop or a user with 
+shell permissions accessed the shell, upon return, there was
+no notification that you were back into the node! Added a routine
+that welcomed the user back to the node upon shell logout.
+Repeated the above for the PMS gateway. I guess AWZ hardcoded in
+a prompt for such notifications so I assume I am the one who
+broke this hi!
+
+6/4/2003 v0.5.4
+Cleaned out some coded carriage returns which to me only adds junk to the
+code (unless the intent was for this to ensure a local echo wasn't working
+or something of that nature... ) at any rate, commented it out for now.
+Tightned some more of the displays which also cleans up some code as well.
+By now you may be wondering the madness behind my logic:
+As I stated when I first started this project, my goal was to use the
+existing AWZNode code and make it behave (oh austin powers behave!) as
+much like a TheNet X1J node as I could, with enhancing upon the existing
+tcp/ip and flexnet features this node has. Of course, code cleanup is part
+of the process. One thing I noticed on both AWZ and Tomi's node programs
+were the added strings both push such as the "Trying" messages when a
+user requests a connect to another node, etc. Personally, and especially
+on busy 1k2 baud links, i find it a bit irritating (as I'm sure end users
+do also) that additional lag due to a null line-feed or the node telling 
+me what I asked it to is in process. In essance, this *should* make the
+node appear to connect faster for the end user... I hope *grin*
+Cleaned up the Sessions display... the net/rom sessions screen had an 
+allocation for Rtt when it's not in use. This also caused the Sendq
+colum to appear grunged/misplaced. 
+There's still some line-feeds here n there I'm cleaning as I go to which
+the subversion will increase hi!
+
+6/4/2003 v0.5.5
+Changed mailbox.c and system.c from looking at the users's environment
+mail variable to point to /usr/bin/mail and /var/spool/mail/ respectively.
+I noticed (on debian anyway) that the hardcoded paths failed mail to no
+end. Doing more work on mail as I go along. Note: this only affects internet
+based email! A seperate PBBS such as F6FBB is recommended for AX.25 mail.
+Changed MSession command back to Sessions. I have no idea why this was done.
+Deleted the Send command. It refuses to send no matter what I do anyway, so
+to me it's useless. Also changed ! (STats) to STats to match Tomi's node.
+Personally, I found this confusing between the two nodes. Added a Quit 
+hardcoded command to match both TheNet X1J and FlexNet style nodes.
+Tweeked the way the Stats displayed. Memory shows not just 'memory' but
+the definitions between swap and physical ram are displayed. Also AX.25
+daemon socket stats are also a bit more defined.
+Mail checking sometimes worked, other times didn't. Fixed the mailpoll
+routines so that polling would keep displaying to the user that he/she
+has new mail. This may irritate the user, but considering it's your
+hard disk space that's storing their internet email, for them to be
+on the node and simply choose *not* to read and/or delete mail from
+your resources is just as rude to you (my train of thought anyway).
+**NOTE: I can't stress enough on how dangerous (in regards to spam)
+the mail feature can be! I **highly** suggest that you *only* give
+access to those you know are hams! Needless to say, I would *not*
+turn access for this feature on for global access!!! Not only would
+you upset many people who are against receiving junk emails, but you
+could risk losing any and all internet connectivity from your ISP as
+some are *very* picky about spam mail that's relayed! Working for ISPs
+in the past, I can verify this :-)
+
+8/4/2003 v0.5.6
+Still cleaning up some displays...this will be a task as I go along.
+One thing I'm not positive about is whether or not on multiple port
+usage how some diplays will read since I only have a single ax0 port
+I'm using.
+Fixed some routines in the do_finger command and added user usage
+messages. In some cases, routines were forced so that if certain
+strings (even null) weren't set after the finger command, it 
+was programmed to force the user to finger the localhost whether
+or not that was their intentions. Personally, I found it better
+to push a usage message of one line to the user than to go ahead
+and process an errant finger request to the localhost. I did
+force finger to require an @ within the command... since you're
+fingering something"@"somewhere. This is displayed in the usage
+message to the end user whether or not the input string after
+the command is null.
+Mail checking still seems buggy, and the bug seems somehow (so far)
+to be linked with the mailbox.c routines. This is also where the
+do_sendmessage command is. Fixed some routines in the send command
+where if the To: or Subject fields comtained an UPPERCASE 
+character, it could cause the node to segfault out and leave
+the ipcs open. This is bad! More on this in the Known Bugs section.
+
+10/4/2003 v0.5.7
+Whew! After much hassle...FIXED the former (and I mean former hi!)
+SEnd command. While I was at it I also renamed it from Send to
+MEssage. I thought Mail and MEssage were similar in function so
+I decided to keep them together on the prompt as well.
+
+11/4/2003 v0.5.8
+Found a bug in the MEssage command *sigh* more on this below.
+Moved the location of the help files from /usr/lib/ax25/node/help/
+to /var/ax25/node/help/ so that all created node files are together.
+Changed/fixed some of the help files to reflect changed commands, etc.
+Cleaned up more diplay text. (since I'm more a code hacker than a true
+coder, this is what I do best hi!.. but I learn as I go.)
+Edited the man pages and changed them from a text to a compressed format.
+Changed the configure script to grab the server's hostname. If your
+server's hostname is already an *.ampr.org host, then you should be
+fine with everything. If your server's hostname is a commercial domain
+based name, then you will have to edit config.h and insert the proper
+your.ampr.org hostname inside, or if you wish replied mail to be auto
+redirected to a NOS based node, enter in your NOS' ampr.org hostname.
+Added a warning message in the ./configure script to alert the sysop
+to check their config.h file for proper paths, etc. I was going to force
+a load of vi, but now-a-day most people don't use vi from my discussions
+but another editor such as ae, joe, pico, etc. Since the sysop will be
+editing their config files anyway, I feel the sysop can take a minute to
+verify paths and variables. Please pay close attention to any and all
+comments within this file!
+Added Makefile.in which is a 'generic' Makefile. Makefile is now created
+when you run the configure script. Also added some other environment 
+grabber functions to the configure script which adds to the proper files
+that requires them for you.
+Added removal of Makefile in the command 'make distclean'.
+Removed local echo of "To:" field when using the MEssage command. That was
+for debugging purposes anyway.
+
+12/4/2003 v0.5.9
+Fixed the bug that drove me nuts with the mail command. Now the mail
+command will reject/refuse a parameter. One more down off of the
+hitlist of bugs :-) It was suggested by N1UAN to make a configure
+script toggle for the MEssage command too. I may do that in the future.
+Fixed a bug in the POrts output. Since I only have one port, this was
+hard for me to test. N1UAN has multiple ports and using his node I was
+able to see and fix this bug before it made it to the buglist.
+
+12/4/2003 v0.5.10
+Woops, fixed a bug in the Info command where there wasn't a line
+feed after the compile date. Reported by N1UAN. I also found a bug
+in the display of: Node Call|Alias where lines were grunging. I
+*think* I fixed this. Unfortunately this is the result of me only
+having one port to work with hi! I happened to find this myself
+using the copy N1UAN is running. Hopefully I fixed this bug.
+More of a maintenance release than anything else. Fixed a few tweeks
+here and there, nothing worthwhile to mention. The key thing in this 
+version was to make it more customizable for the hard-set commands.
+This was suggested by N1UAN to which I kind of agree. It is possible that
+one could have a linux box on an amateur radio packet network but not wish
+to have it connected to the ampr.org or any other TCP/IP network. Coding in
+these commands would then become a bit of a tease to the end user who may
+wish to use URONode as a 'NOS' substitute for outbound telnet links, etc.
+Now hardcoded commands will be toggled on/off depending on how you answer
+the configure script. Answering NO to ALL questions will enable ONLY the
+following hardcoded commands:
+?, Bye, Escape, Help, Info, Quit, Status.
+Answering YES to AX.25 enables:
+Connect, Desti, Ports, Links, SEssions, Users.
+Answering YES to Email enables:
+MEssage.
+Answering NO to FlexNet:
+Disables the Desti command and will NOT compile or install the flexd
+daemon...however if you have a destinations file that is valid that
+will allow users to connect to digipeated paths without having to 
+manually type a 'via' statement in.
+Answering YES to FlexNet enables:
+Desti. 
+Answering YES to MHEARD enables:
+MHeard.
+Answering YES to NETROM enables:
+Nodes, Routes.
+Answering YES to ROSE enables:
+Rose based protocol strings within ax.25
+Answering YES to TCP/IP enables:
+Finger, HOst, Ping, Telnet
+Answering YES to TALK enables:
+TAlk.
+I may move the users to the default hardcoded commands..but for now my 
+thinking at 5:00am on a saturday morning is, if you're not going to run
+ax.25, then you probably aren't as concerned who's in the node :-) Also
+the use of the linux netstat command will show you who's on. The commands
+I'm considering moving to the default are the ax.25 related commands...
+since after all, if you're on RF, you'll -need- ax.25 right?
+The Mail and SYsop commands are flagged on|off by the node.user file.
+
+14/4/2003 v.0.5.11
+Another change to the configure script. This time it checks your local
+hostname and requests that you verify it. If you see it's correct, 
+just hit enter. If not, change it. Now... and this is tricky...
+*if* you do NOT wish to have users RECEIVE mail on the node but have another
+smtp based server such as a NOS node in which you wish your users to receive
+smtp mail, then what I suggest you do is set hostname to the hostname of
+THAT server. What this will do is send mail from the user with a 'return'
+path of your NOS server. For example;
+On my system I have an MFNOS node which users may send and receive SMTP
+based mail. It has a hostname of "n1uro.ampr.org". While users may have
+permission to SEND mail from URONode "dx.n1uro.ampr.org", I wish them to
+only receive their mail at n1uro.ampr.org, so in this case I would tell
+the configure script my hostname is: n1uro.ampr.org. It's sort of a way
+you can allow mail with some sort of anti-third-party protection. Its not
+perfect, but it helps. The configure script *will* prompt you for this
+whether or not you enable the Email feature.
+I added two neat commands. One is the new Version command. This is set
+as part of the default hardcoded commands. All it does is shows the
+version information of the node. This same data is also shown in the
+Users command to keep the node in line with the display parameters of
+TheNet/X1J style nodes (as I like). The other is what I call a Whowas
+command. I got the idea from being on IRC, and borrowed code from    
+PE1RJA's node. With the W command, this will show you when a callsign 
+was last on the node, and how that user connected... ie: which port,    
+ip address, etc. If the user connected multiple times within the scope  
+of the log rotation then a columnized listing of that user's information
+will be displayed. My happy news is that the SSID stripper from the
+user's connection in sending email is fixed. One bug down!
+
+15/4/2003 v0.5-R1
+WooHOO! MHeard table read/write of digipeated MHeard routing is FIXED!
+What I had to do was get argv to parse up to two digipeaters and then
+print to the device each in reverse order. Now since my RF digipeater
+gateway is a direct flexnet neighbor on axip, this was all I had to
+test with, your milage may vary. If the digipeated path is not yet in
+the mheard table, then it will fail. Another bug off of the list!
+*whew* I knew I was close <G>. Also found some more screen writes
+to tighten up. As far as I know, I'm going to (for now) close this
+chapter of my life's efforts and make a release. I"m happy with how
+URONode is performing and my alpha tester N1UAN appears to be just
+as pleased :) 
+Found a bug in the output of the Who command when *
+was entered. While this didn't seem to affect me on a debian system,
+it did seem to act funky on a SuSe system. Flexd needs NOT be edited
+now. Cleaned up some time variables in the MHeard routine and added
+a column for the port heard, and the frame (pid) type. Since the
+users can now see the pid types, they'll have a hint as to how their
+connect request will be handled.
+Found two bugs in the finger routine, both which appear to be in ALL
+flavors of "*node". The first one I fixed, and that was quite simple.
+When fingering information, the [address] or [hostname] was omitted.
+I don't know if this was intentional, but I fixed it anyway to match
+that of standard 'finger' displays. The second appears to be that
+on a long RF hop, or a socket that's become broke due to routing
+being cut, etc... there's *no* escape. For now, I've omitted the
+Escape: CTRL-* display in all routines. It will still work for
+telnet, netrom, and other types of connects. Since the Escape
+command is a seperate command at the moment, I think it's fine
+for users to check|set their Escape sequence. Hopefully I'll be
+able to figure out a routine to escape from a 'stuck finger' :-)
+Also tweeked the output of the HOst command.
+*Welp, further research shows that there is no "escape" in the
+native linux finger command... as there is none with the ftp command.
+Needless to say, the better 'fix' was to simply disable all 'trying' state
+messages. Personally I find them to be excess traffic that's not needed as
+either the node will tell you that it's connected or it will tell you that
+it failed. I know flexnet will tell you that it's trying a link setup and
+xnet will take that a step further and show you which port the link is being
+setup on. I may add the set escape sequence in the login screen as default
+prior to users attempting connections so that it'll be easier on them to
+know that there is a way to break a connect if needed.
+
+16/4/2003 v0.5-R2
+Ok, well I did decide to add the CTRL-* message as part of the
+initial user login screen. Also made some minor tweeks to the
+telnet login where now it shows more of a 'linux' style login.
+Did some more screens cleanups and stripped out a lot of the debugs
+I had commented out of the code. Ok..enough for now...I'm considering
+this version 'done' unless bugs are reported. :)
+
+22/08/2003 - Bug/security report
+Morgan sm6tky publically posed a security report with some PoC listed but 
+not all. While I was able to duplicate what he did submit for PoC, I 
+wasn't able to find others. I'm very greatful to Morgan for bringing such 
+information to my attention, I'm surprised that his first step was to post 
+it in a public email list and list that I didn't reply when I wasn't even 
+given the chance to... however with that being said, I still took his 
+notations to heart and put the project a bit on the back-burner until I 
+had time to do the fixes. I also offered Morgan a chance to submit code 
+fixes to which he failed to do such. I don't claim to be a coder but just 
+a hobbiest in regards to C and always welcome patches as I have with htppu 
+with patches submitted by Thomas dl9sau who's also released his own flavor 
+entitled SAUPP. Version 0.6.x will be in process as I have the time to do 
+such.
+
+v0.6.0 - never happened. Just made the directory structure and took an 
+initial peek at Morgan's reports.
+
+12/7/2005 v0.6.1
+Security issues fixed/removed. Rather than fix the talk command I decided 
+to just eliminate it in favor of an external conversd command. I figure 
+there's plenty of channels and lord knows there's actually more convers
+servers now than users to use them... why not just use that?
+
+Another security issue was mail. Instead of having mail routines built 
+into the node itself, I figure a node sysop can grab my updated axmail
+node plugin and use that. I've done some basic security tests and it 
+seems to be a better way to go.
+
+12/7/2005 v0.6.2
+Just a beta version, never released while working on more security 
+fixes... I think I'm getting close now! 
+
+Changed some code in the do_help routine in command.c where Morgan 
+reported the possibility of a buffer overflow. 
+
+Changed some code in the syslog routine in util.c hopefully fixing the 
+formatstring vulnerability in that routine.
+
+Changed some code in gateway.c in hopes of fixing the reported buffer 
+overflow.
+
+Found what I thought to be an open hole in ipc.c, should be fixed and
+with any luck the ipcs build-up issues will vanish with it. Only time
+and your debug reports will tell.
+
+Fixed a bug in Makefile where the man pages weren't installed due to the 
+fact I gzipped them and didn't change this in Makefile.
+
+Changed the ftp url path, listed below.
+
+v0.6.3 - some cosmetic tweeks I can't recall what they were.
+
+04/07/2006 v0.6.4
+
+Found a bug where if a user's permissions were flagged for "no escape"
+such as a xNOS, F6FBB BBS, etc, that the node tried to display an Esc-?
+as part of the prompt/screens. Removed the Esc-? from displaying. That
+simply annoyed me and I'm surprised it wasn't reported... after all if
+there's no escape why show "?" as one since "?" can be used as an escape
+character with CTRL.
+
+Added an Email flag in node.conf. Simply add: 
+Email  <your at node.ampr.org>
+on a blank line within node.conf for it to get pulled into the node. If you
+don't "(null)" will display. It won't prevent the node from functioning but
+will show users how lazy you are hi! This allows a sysop to deny all users
+connection access _unless_ they have a password, while at the same time
+allowing the node sysop a means of displaying a point of contact so that
+users wishing to use their node and it requires a password can send a
+communication to gain access. I strongly suggest for any account that has
+sysop privs on the node that you force a password on _all_ connects and
+that you only grant access via internet/amprnet to those who request a
+password for security reasons if anything at all. Because I feel this is
+security related, I'm making this a release.
+
+Fixed a bug in the install routine for the man pages. The default 
+install for man pages was /usr/man, now it's /usr/share/man. I also
+updated the manpage for node.conf.5 and re-gzipped it.
+
+24/10/2006 v0.6.5
+After a nudge from Stefano in Italy, I reintroduced a method in which one
+user on the node can send a brief "msg" to another. The command once was
+"talk" and still is on node (or if you prefer linuxnode that Tomi has
+set the standard for!). For the sender, they get a full status report
+as to what happened to their "msg" once the "enter" key is hit. For
+the receiver, if they're truely idle on the node, the message will pop up
+on them and the prompt will not return until they acknowledge receipt
+of the msg by hitting the "enter" key. Also note that a system bell
+will return on both sides, or just the sender's side *if* the msg
+wasn't delivered. Since this acts sort of similar to today's Instant
+Messaging world... I figure "what the hay they play noises too". I still
+stand on the theory that if one wishes to engage in keyboard chat, they
+should make direct TNC<>TNC connects or use convers but Stefano
+made me rethink this and I can see how it could be used for one user
+to "ping" another user with a msg saying "hey meet me on conv channel
+32767 and see if we can wake the sleeping sysops!" :-) Originally this
+was part of Morgan's security report filed back in 2003 (what? me
+procrastinate? LOL) so with convers so easily available to URONode as
+a plugin I felt it just as simple and quicker a fix just to remove
+"talk". I renamed the command to "msg" since you're really just sending
+a message and not really "talking" to the remote end.
+
+Fixed the help files a bit to move talk.hlp to msg.hlp, and edited the
+content of such to fit the re-introduced command.
+
+26/10/2006 v1.0.0
+First off, many thanks to Stefano and Alessio for their interest and
+contributions to URONode. They've inspired me to help improve this
+spinoff of AWZNode (which is a spinoff of FlexNode which is a
+spinoff of node which is a spinoff of.... :-} ) Stefano asked me a while
+back about putting in compression for Telnet and Connect commands. 
+Considering so many have broadband now on their wired links, I somewhat felt
+this to be unnecessary, and here in the U.S. ax25 based transmissions are
+supposed to be in plain text... so between those two major reasons I had
+thought it best to just eliminate this feature a while back... not to 
+mention security issues with zlib that were going on. Since those have
+been cleared and in respect to the motivation Stefano and Alessio have
+given me with their interest in this project I thought it only nice that
+I try and fullfill their desires as best as I can. Recieving compressed
+requests into URONode was always there but not an outgoing client... so
+I spent a few moments and coded one back into the front end. Needless
+to say, ZTelnet and ZConnect (as with node) are in URONode now as
+client gateway commands. 
+You need to set up another inetd/xinetd instance on an unused port
+that calls "node -c" to enable receiving compressed connections via
+telnet. Make a new alias/ssid for ax25/netrom if you wish to support 
+ZConnect client requests. Failure to do such will result in the remote
+end getting an error message.
+
+27/12/2007 v1.0.1
+After a heated discussion with w0rli (as if that has never happened
+on packet before, and him accusing me of knowing nothing about packet
+or it's protocols) I decided to keep him happy while working on a system
+that's linked to one of his. Hank feels that by having a login screen this
+makes a node an application. While I can understand how he determines this
+in his one-sided point of view, I still disagree with it but can appreciate
+his concerns. Apparently he has never logged into a backbone router at an
+ISP and seen a cisco MOTD file... or is a backbone core or border router
+not a node on a network? :) In any event, I decided that I'd make the whole
+login sequence of displaying the node version and /etc/ax25/node.motd file
+an option to the node sysop upon running the ./configure script. Along
+with not displaying a MOTD file, the default FlexNet style prompt of
+"=>" will also not display. This will make URONode act more like
+Hank's snos and like TheNet X1J-4 (with the "welcome" message flagged
+off upon connect). Thanks are given to w0rli for this idea.
+
+I also added a flag for the "NODE} Goodbye." string so that if you
+do not have a MOTD displayed, it will also halt the display of the
+node front-end saying bye to the user. 
+
+01/01/2008 v1.0.1a
+I decided that I'd go through the code and search for more cases that
+if MOTD is *not* defined, to ignore any and all reconnect flags, whether or not
+they're defined for external plugins (ie: axMail) or alias commands in the
+/etc/ax25/node.conf file. If during configure you decided to add MOTD during
+the option questions, then the node will infact act more like a user 
+application including allowing reconnects etc.
+
+I had thought I fixed the man pages install, appearantly I never saved it.
+This should now be fixed. My apologies.
+
+* Author's Note: If you're linking the node to systems such as SNOS, or
+you're on a very busy network, or if you forward with other BBS systems
+who for whatever reason feel the need to connect to your node first
+before connecting to the BBS (which I feel is unneccessary but happens), I
+strongly suggest that you do NOT enable the MOTD which is the default option
+now in the configure script. 
+
+*** Important: I just don't have the time to clean up all the gcc-3.x
+compiler warnings however URONode compiles just fine under gcc-2.95
+so I made a decision to force gcc-2.95 for compiling URONode under.
+Configure was rewritten to check for this, and if it doesn't it will
+instruct you on where you can get a copy. This will not interfere with
+your installed copy of gcc-3.x if you so have it. I have verified that
+URONode compiles quite cleanly under gcc-2.95 and I do have both
+versions on my box:
+root at schlitz:/usr/bin# ls -al gcc
+lrwxrwxrwx  1 root root 7 Jun 25 00:00 gcc -> gcc-3.3
+root at schlitz:/usr/bin# ls -al gcc-*
+-rwxr-x---  1 root root 69960 Mar 10  2004 gcc-2.95
+-rwxr-x---  1 root root 85196 May 24  2005 gcc-3.3
+As you see above, gcc by itself is just a symlink to the latest 
+version of gcc-*. Ensure that gcc-2.95 is in your executable
+path.
+
+23-24/01/2008 v1.0.2
+Huge news! I finally got off my duff and cleaned up compile warnings.
+URONode will now compile fine on gcc-4.1 and under! This was just something
+that was under my craw for a very long time, but not that critical enough
+so you can really ignore the above notes in regards to GCC.
+
+I ended up also making some modifications to the configure script, Makefile
+and config.h. Part of cleaning up some of the compile errors was a dupe
+conflict between library "log" routines and the internal node "log" routine.
+URONode now has it's own node_log() routine as to keep it seperate from
+library log routines. There's no change in it writing to syslog for you,
+just the function was renamed to avoid compiler warnings. Many files were
+updated due to this.
+
+**Man file for uronode is now called "uronode", not "node". The binary made now
+is also "uronode".** This is *very* important because when you run 
+"make install" or "make installbin", your inetd.conf/xinetd files will need
+to be changed to spawn the new binary, and your config within 
+/etc/ax25/ax25d.conf will also need to be changed from calling "node" to
+call "uronode" now!! If you do NOT do this, you will be stuck running either
+an older compile or it won't launch at all. Please see the examples in the
+INSTALL file for help on how to configure this properly. In the future
+I may change the config files from node.* to uronode.* too. The advantage
+of doing this would be tri fold:
+1) it'd allow sysops to compare and test URONode side by side with another
+   package such as Tomi's LinuxNode
+2) sysops could offer both flavors of a "node" to users if they so desired
+   to do such.
+3) a sysop might prefer to have 2 compiles of URONode... one with full
+   MOTD compiled in, one without.
+Those who know me, know I believe in allowing a sysop to have the freedom
+to pick and choose just how they run their nodes... and this just adds
+to their options. I do however discourage doing this unless it's for
+testing reasons but c'est la vie. 
+
+**** Actually, I figured why wait to change files around, so I changed
+all the config files from "node.*" to "uronode.*". Now if you're doing
+an UPGRADE, you'll need to rename your config files in /etc/ax25/node.*
+to /etc/ax25/uronode.* or else you'll have issues with some routines.
+I also deleted the *.ex files and changed installconf so that the proper
+files get copied into /etc/ax25 for new installs. I also changed all the
+man page files that were node.* to uronode.*
+
+As much as it sorta kinda but not really pained me to do this, I decided
+that it may be cool to have *something* to let the user know that their
+outbound ax25-type connect is via flexnet, so I added a routine in
+gateway.c which checks the connect type and if the request is via FlexNet,
+the user will see the standard "link setup..." message like they would on
+a flexnet node, followed by "*** connected to <desti>". This MAY have an
+adverse affect on FBB forwarding since FBB looks for "Connected..." instead
+of "*** connected...", but there's ways around that in your FBB forward
+file.
+
+25/01/2008 v1.0.3
+
+*Big News*
+For Debian and (K)ubuntu users, I've decided to make a release of
+uronode as a .deb package. This is my first time doing this and I'm really
+not that comfortable with rolling it out officially since it's my first 
+pre-packaged binary so here's what I suggest you do if you decide to use it:
+cd /etc and tar cvf ax25/* ax25files.tar
+dpkg -i /path/to/uronode*.deb
+tar xvf ax25files.tar
+For now this will preserve your current config as the .deb package *will*
+overwrite your current files in full including configs!
+YOU HAVE BEEN WARNED!
+
+Found a bug in the WHO command when MOTD was disabled. Currently if you
+don't define that, then the WHO command is deactivated and not compiled
+in. MH works fine and should be enough to be used to track recent connects
+to your node.
+
+Discovered a bug in the newly introduced FlexNet style cosmetics where
+after "link setup..." if the connect request times out, error isn't printed
+on a new line. I wrote a new string to push to the user so that if their
+request does time out, it matches that of FlexNet's timeout string while
+leaving vanilla ax25 and netrom timeout errors the same. Again, these
+strings will inform end users the type of outgoing request was made
+whether it was FlexNet or vanilla ax25.
+
+While I was add it, I decided it would be helpful to end users who are
+making FlexNet links to show which ax25 interface is being used for
+connects similar to that of how Xnet shows connect requests. The interface
+will be displayed in parentheses () such as: Link setup (ax0)...
+so if the link fails, the user can see which interface to try a direct ax25
+connect request out from.
+
+I think I fixed a slight bug in flexd.c where if the LO.FPR and C.FPR 
+weren't formatted just right, it'd exit prematurely and issue a false
+error. Apparantly the buffer was set a bit too high and captured too much
+to parse, so I lowered "buffer" from 1024 to 512 and it now appears to be
+fine.
+
+A "bug" was reported about the config of the backend of URONode when infact
+the bug was with ax25d.conf and nrports. Remember, when you configure your
+node, ALL your SSIDs for ax25, netrom ports, and axports *MUST BE UNIQUE* if
+you have RF links to native netrom nodes. Failure to do such will result in
+some flooding issues because if an ssid in axports, ax25d.conf and nrports
+is shared, an X1J node connecting into URONode will result in the ax25 link
+layer being seen as a user and not a network socket. You'll ping-pong
+the node with X1J in almost an endless loop. *You have been warned!*
+
+22/02/2008 v1.0.4
+
+I decided to make the node text more "technically correct" in it's display
+of things... mainly in regards to "ports". We don't have "ports" per say
+but we do have "interfaces". Needless to say, any reference to "port(s)"
+has been changed to "interface(s)" including the former Ports command. This
+has been replaced with the new INTerfaces command.
+
+Users now will show the "interface" a user may be coming in on if it's ax25
+or if inbound from FlexNet.
+
+The PIng command has been shortened to Ping now with the refactor of the
+"Ports" command. Ping now only requires "P" to ping another node.
+
+*Note: this will be the last release for a while as I'm moving and won't
+have a server or test bed to test with.
+
+10/05/2008 v1.0.5r1
+
+The move has completed and of course in my own sick and twisted mind, I have
+decided to do a release that I call version 1.0.5 release candidate 1. This
+is a minor release but it's something I despirately wanted to do for a while
+and was just sitting like an itch under my skin to do, and sometimes you have
+to just take a break from it <all> to clear the noggin and get the code the
+way you want it. What was bothering me was the fact that not one flavor of
+a linux-node complies with that of the Software 2000, inc specifications of
+Net/Rom... and I desired to be the first to do such... yay me? 
+
+In any event I went through the code and made changes to the following files: 
+command.c, config.c, extcmd.c, gateway.c, node.c, node.h, and system.c. 
+What this does for you is makes your URONode behave more to the specifications 
+of Net/Rom regardless of how you define the MOTD flag. If you define the MOTD 
+flag, the node will continue to behave as it has <all> along, however it forces
+it in "off" mode when the incoming connection is Net/Rom based. This is
+extremely useful if a robot script (such as FBB forwarding) is used to
+go through your node.
+
+The decision of making this a release candidate was because I'm sure I may 
+have missed testing some of it's behavior and will have to do some cosmetic
+and/or bug fixes.. so if you find any, please report them to me and I'll do
+what I can to fix it.
+
+Source, .deb, and .rpm packages are available at the typical location of
+ftp://ftp.uroweb.net/pub/ax25/ ...enjoy for now!
+
+12/05/2008 v1.0.5r2
+
+I had this really irritating bug that appearantly I just never noticed 
+all this time when HAVEMOTD was undefined. Thanks to some assistance from
+K2MF, I was able to identify and fix this bug. Inside the main loop statement
+for the node, when a user disconnected, it was adding an extra frame to
+the stream that contained only a line feed. Looking back at this, I did this
+due to the fact that X1J handles it's output to the terminal differently than
+does any other node that I'm aware of.
+
+In any event, taking out this line feed somewhat caused other outputs of
+text to lack a line feed when it needed it... so this meant changes in
+command.c, extcmd.c, gateway.c, ipc.c, node.c, system.c, user.c and maybe
+more that I can't quite recall as of this writing.
+
+The good news is that I did fix 2 minor bugs that were under my skin!
+One minor bug was that when a nodes or destis list ended with a row of
+4, an extra line-feed was displayed. While this bug still exists under
+certain conditions, it's no longer present during netrom connects.
+
+Also during a netrom disconnect, an extra line-feed no longer sends to
+the remote node thus making it more Software 2000, inc. compliant. I'll fix
+the previous mentioned bug for release 1.0.6 sometime.
+
+21/05/08 v1.0.5r3
+
+Fixed some screen cosmetics that I introduced while making the node more 
+Software2000 compliant... I'm sure I missed a few more.
+
+***Big News***
+I've finally tracked down and fixed the remote escape bug (I think)!
+What I saw was happening was that the SIGPIPE handler wasn't being
+executed properly and it appeared to be waiting for more data which
+it never received. I added a quit_handler routine in the main loop
+which now will execute a node_logout(), flush out the IPCs,
+log the event to syslog, and close out the application properly.
+Due to this bug lingering in all flavors of *node for linux, and not
+having the resources to fully stress-test this, I'm going to leave this
+as release candidate 3 for now until (hopefully not!) someone reports
+that this routine is causing ill-behavior.
+
+26/05/08 v1.0.5r4
+
+There was a LOT of cosmetic changes in this one which caused me to add
+a LOT of conditional calls into the code, many of which I'm unsure whether
+or not it'll fly properly under every condition so your milage will definately
+vary depending on your specific setup! Since URONode has become very popular
+within the EastNet packet system I decided to make the node appear for both
+the ax25/FlexNet side or its NetRom side, dependant on how the user logs into
+the node. Because of the massive changes in structures, rather than listing
+them <all>, the above description should do. 
+**Note: you MUST add a new line in uronode.conf that defines
+FlexId		XX#XX-##
+Either take yourcall-ssid from ax25d.conf OR if you're linked to a
+node that does flexnet, use yourcall-ssid as it is on the remote flexnet
+system. If you don't, and a user connects in via telnet or ax25/flex you'll
+display (null) to them. Also: if you added a } after your NodeId 
+callsign-ssid, remove it. It's been hardcoded into URONode now.
+
+I decided to mute the banner section of the login sequence however 
+it will still display your MOTD if it's defined during ./configure.
+If there's a demand for it, I may add it as a configurable option.
+
+Even though I put r4 out for download, I did find a couple minor bugs
+which have since been fixed.
+
+29/05/08 v1.0.5r5
+
+In a nutshell, if the user connects to your URONode via NetRom, then
+they will get standard NetRom prompts with "ALIAS:CALL-#} " as a result
+header to all of your commands with the exception of FlexNet gateway
+connects.
+
+Now in uronode.conf, a *new* line _must_ be added for FlexId. The parameter
+is:
+FlexId	<call-flexssid>
+An example since my URONode is on FlexNet as ssid 3:
+FlexId	N1URO-3
+
+Also note that the need to have a closed bracket "}" after your NodeId
+now is not required and should be deleted. I finally got off my butt and
+hard-coded it into the software.
+
+The Version routine was also changed depending on how the user is connected
+in. If the incoming connect is made using NetRom, then the standard prompt
+is displayed. If the incoming connect is via any other type of link, then
+a columnized display is made showing Software version, NodeId, and FlexId
+in hopes of eliminating confusion to the end user.
+
+While in the midst of all the above, I did find some cosmetics to fix.
+
+Before I make this release candidate an official, I'm curious as to 
+whether or not anyone would object to me eliminating some of the
+standards of the login banner of the node (non-NetRom displayed).
+Please let me know and I'll make the necessary changes if need be.
+-- actually I already decided to do this.
+
+I added a new routine in util.c which now will give the end user
+the type of prompt based upon the type of connection. The default
+for ax25/FlexNet is: "=> " (note the space after > unlike Flex)
+for NetRom is: "ALIAS:CALL-ID} "
+for tcp/ip is: "usercall at hostname:/uronode$ "
+
+With the new routine, I changed the main loop in node.c from defaulting to
+Prompt simply to using node_prompt().
+
+01/06/08 v 1.0.5
+URONode version 1.0.5 is now considered to be "final". With the new month
+is a new final release, and in this release it has more face-lifts than
+Joan Rivers hihi!
+
+I added a new routine in the configure script which will prompt you for
+telnet colored routines... yes we have ANSI! Now, a couple things about
+pushing ANSI code:
+1 - consider network bandwidth if you have IP users via RF
+2 - many windows apps such as WinPack do NOT support ansi. This is NOT
+    a fault of URONode, but that of the Windows application. If you
+    find you have trouble decoding ansi, try PuTTY or use HyperTerminal
+    in telnet mode. Ansi is hard disabled for ax25/Flex and NetRom connects.
+I also added ansi codes for "Nodes" and for "Desti" lists commands if the
+inbound connect is made via IP.
+
+Added an "EXit" command for users in IP mode since you now feel like you're
+in a bash shell... just a 'force of habit' thing. Bye still works.
+
+Fixed a bug introduced with the new node_prompt changes to node.c. If
+the user was required to enter a password outside of being on the localhost
+or amprnet, the prompt displayed twice... this is now fixed. I also found
+and fixed soem more cosmetics that I considered to be wrong. This bug was
+driving me insane as to why it was doing this, but I finally tracked it
+down.
+
+Found and fixed another bug where if the user's permissions were set
+to a perm "escape off", prompts didn't properly function.
+
+Made a change to nodeusers where now if no one is on the node, it'll
+say such instead of simply being blank.
+
+A note about ansi:
+linux shells will decode ansi pretty good as will old DOS based terminal
+programs such as Qmodem, Telix, etc. If you use a raw terminal such as
+xNOS, you'll need to insure you load ANSI.SYS in your C:\CONFIG.SYS file
+and reboot so the terminal will decode ansi.
+Windows telnet *will* decode ansi as well however since XP, local echoing
+by default is set to OFF. You can CTRL-] and type: set localecho, then hit
+enter twice and you can get echoing back on.
+If you use something such as WinPack which doesn't decode ANSI, please do
+NOT contact me! Contact the authors of WinPack and report the lack of
+ansi as a bug.
+
+I also am including a copy of axdigi from the original FlexNode package.
+This is compiled as a static binary and a copy of axdigi.conf IS
+also included in the source package, but I won't package it with the .deb
+or .rpm packages... however I do reserve the right to change my mind :)
+
+Static binary packages are compiled with the following options OFF:
+Rose support
+All other options are compiled in.
+
+04/07/2008 v1.0.6
+Found and fixed a bug in the Who routine where a netrom prompt was merging
+with the last entry of a list even if the connect was not netrom. This change 
+was made in system.c.
+
+Added some more ansi routines if #defined COLOR. Here's the schema:
+Connects display in green as in "gateway go"
+Reconnects display in red as in "gateway stop"
+Commands display in bright white
+Netrom Nodes (full list) in bold cyan
+FlexNet destis (full list) in yellow
+Current users in magenta
+Aborts and timeouts blink bright red
+Logouts in low cyan
+I'm making the color schema a bit more consistant through out the application.
+While doing such, I'm cleaning things up so that just the headers are in
+color, not the actual results so that if one is NOT decoding in ansi (and
+again if not that's a fault of the client NOT of the node) the node won't 
+appear as offensive. 
+
+Found a bug in the auto router where it wasn't parsing the digi path
+from the mheard table, HUGE credit goes to Barry K2MF (of MFNOS fame) for 
+supplying the code that properly handles this. Fixed.
+
+Did a lot of clean-up for how the node/shell responds dependant on how the
+user connects in. Many changes done in gateway.c, extcmd.c and node.c.
+
+Now made ANSI a flag in uronode.perm... I may change this later however
+because of such, it forced me to have to make a new nuser_list routine
+in command.c as well as move node_prompt from util.c elsewhere so 
+command.c seemed like the best choice. Setting the user bit +512 will
+now grant them telnet ANSI color. Not giving them this will turn
+it off. I'd like to make it an end-user toggle so that depending on
+which client the user is coming in with they can choose online to get
+color or not. The user perm flag replaces defining Color during the
+configure script.
+
+Defining MOTD now serves multiple functions:
+1) Display of the MOTD screen/file
+2) Display of prompts for all interfaces
+3) Reconnect back to the node upon a gateway link out
+I suggest compiling with MOTD on, which configured by default in the 
+.deb and .rpm packages.
+
+Changed some of the technical correctness of the node in regards to IP
+functions. Ping now returns ICMP Echo request/reply messages and IP based
+connects out now show the service/port that the connection request is being 
+opened to.
+
+Added color schemas to the NetRom and ax25/Flex interfaces if the user 
+requests it to be on. The same color schema is used on all 3 interfaces.
+
+Fixed a very irritating bug that some folks have reported on which
+when do_ports() was called, and the axport description was over 42 
+characters in length, do_ports() was *not* properly truncating the
+additional characters, and making things looks a bit sloppy. A similar
+bug exists in LinuxNode =< 0.3.2. Note: In your axports file, you *MUST*
+have a tab after the window digit before writing your interface 
+description or else the parser will consider the spaces as just that...
+empty spaces! You have been WARNED!
+
+Updated uronode.conf and uronode.perms files to show examples of recently
+added features.
+
+Long overdue: Updated the MAN pages!! I'm so sorry for letting these slide!
+It really is hard enough trying to keep track of things in this file, never
+mind actually documenting it in a manual page or two hihi!
+
+Found and fixed a bug in the logout routine where a false error was being
+reported that the shared memory segment (IPC) couldn't close. Somehow this
+was introduced by me duping the lines in the routines so that it was actually
+trying to close the shared memory segment twice! I guess in reality, the
+log error was indeed correct since there was no second segment to close hi!
+
+Added a "make update" option to the Makefile. This option *must* be used
+in version release sequential order or else it may fail!
+
+Fixed a cosmetic bug in the way NetRom nodes introduced by me when I created
+multiple interfaces. The word "NetRom" appeared twice in the header when
+a user would request a Nodes list.
+
+15/11/2008 v1.0.7
+
+Made some cosmetic changes to text and ansi color displays, still a few
+more to do but not critical so it gives me an excuse to do a maintenance
+release one of these days hihi!
+
+With the assistance of the great and mighty <all>, the <all> of c coding
+knowledge, I was able to incorporate a loop detection system when making
+FlexNet or ax25 connects... now if there's a loop in the outbound connect
+request, the user will be informed of such which includes a system bell
+(beep). I thought about adding a loop connect block such as with FlexNet
+however in the case of axip/axudp links many links may share the same
+interface which really would be unfair to the user trying to gateway out
+that's also coming in from the same axip interface.
+
+Now for the big news of this release: By request of Bob Anderson K2BJG,
+I wrote a kluge for flexd.c which now requires 2 additional fields in
+/etc/ax25/flexd.conf - MyGate and MyRange. Inside flexd.conf, MyGate
+is your neighbor FlexNet gateway without ssid, and MyRange would be
+the full ssid range of the FlexNet gateway you poll. This will add your
+FlexNet gateway into your local desti table complete with SSID range and
+give it a ttl of 0 since there's no true ttl polling going on... but there
+is a catch to this: you MUST add each ssid of the remote FlexNet system
+into uronode.routes as a direct link or else connect requests will fail
+because the connect will try to digi off of the remote FlexNet system
+to itself. I don't know if I agree with this yet or not as a local
+FlexNet system never shows itself in it's desti table, and that's what
+K2BJG has asked me to do with URONode. As I said, for now this is all
+a kluge but it does appear to work if instructions are followed
+verbatim.
+
+Examples:
+MyGate N1URO
+MyRange 1-11
+
+Made a change in the Makefile so that the axdigi module does NOT copy over
+by default. Now you MUST do this manually and add it to your scripts. Not
+everyone would wish to use this so why force more junk in a directory? :)
+
+--------------------------------------------------------------------------
+
+See CHANGES.2 for more notes in regards to changes.
diff --git a/CHANGES.2 b/CHANGES.2
new file mode 100644
index 0000000..1e742f3
--- /dev/null
+++ b/CHANGES.2
@@ -0,0 +1,637 @@
+
+28/11/2008 v1.0.8
+*notes lost, sorry.
+
+27/05/2009 v1.0.9
+**production copy stolen. See LICENSE for who did this and my response.
+
+11/05/2013 v2.0
+Clean up of some code... I had a copy of 1.0.8 from 2008 I recovered. I 
+did
+have a version 1.0.9 in production but can't seem to locate it for some
+reason so starting from memory using 1.0.8. Thanks to Brett WA7V for
+supplying me with some teaser code :-)
+
+Updated version! We're on 2.0... finally! (yea, big news right? Maybe
+not!)
+
+Moved the "Who" commmand to the list of basic internal node commands.
+I can't recall why on earth I had it defined with MOTD. Perhaps it may
+come to me later but for now I can't recall. I may have to move it
+somewhere else, but I believe it has to do something with logging
+features or something along those lines. For now, you need to define
+MOTD as a compile selective to have the <Who (call)> defined.
+
+Fixed the sysop shell warning, this needed to be a tad more specific
+in my point of view... then again who am I? Also cleaned up the return
+prompt as it could be confusing if the incoming connection was done via
+NetRom. I removed the default FlexNet Identifier out. Now it just says:
+"Welcome back.".
+
+In regards to the "Who" command; I see what was going on here and where
+I left off with it! Logging and the "Who" command pretty much go hand in
+hand - so they're combined. The initial design of FlexNode was to have a
+MOTD based off of the logging of when the user last was on, otherwise if
+they did not exist, push the "new user" screen to them. The down and
+dirty quick fix is to simply remove it from netrom connections into the
+system! Who cares if you get a MOTD on a flex/ax25 or a telnet connect
+into the system!
+
+With the above said, I changed the sequence of "configure" to ask if the
+sysop/admin wishes to log user connects into the system. In the future I
+will either move this to be included with protocols or I may simply hard
+code it in as a defaulted option, and move the "Who" command as being
+defined into TCP/IP functions. For now, it's hard coded in as a selected
+option but will NOT display for NetRom connects.
+
+While I was at it, I changed some of the routines in the configure script.
+Nothing major but did improve upon a few things. While doing this, and
+running "make upgrade" I noticed that flexd.conf was being overwritten!
+OUCH! I'm surprised this went on for as long as it did. I *think* I did
+this to force people to add the new lines in flexd.conf that K2BJG/SK had
+asked me to do.
+
+Created a man page for flexd.conf(5)! I'm surprised no one asked me why this
+was missing! It explains further how to create the file. Keep in mind, this
+also works on Xnet as well as Flexnet. If this doesn't help you figure out
+how to create this file or edit the sample one... I don't honestly know what
+to tell you. In doing such, it also forced me to change the generated
+Makefile so that "install upgrade" and "install man" installs it.
+
+Changed the licensing! This is (I'll admit) very personal and _must_
+remain as is! I could fill a TB hard disk with reasons and debates
+as to why it's no longer GPL code. Please insure you are in an area
+where you can use this code. Thank you.
+
+Fixed an ANSI bug I had in the "Users" command which was driving me nuts!
+On NetRom, it would change the prompt to magenta which it shouldn't. What
+I did as a fix was to force a removal of ANSI on the prompt for NetRom
+based connects... simple enough. There may be other ANSIs for me to fix
+and I'll cross those bridges when I get to them. Found another in gateway.c
+and fixed the netrom ANSI to properly reflect that once a connection was
+made, it was "systems GO" (green) without changing the Node's ID string.
+
+Created a COLORS file which somewhat explains the hows/whys of not only
+how I came up with a schema, but when it should and should NOT be used. 
+It may also be used as a quick reference guide for the local sysop. It's 
+a nice little cheat sheet one may print and keep near their keyboard if 
+they want.
+
+Added text to both the colors.hlp and help.hlp file for a users better
+understanding of the color schema and how to gain colors to their terminal
+if they so choose to have it. See my wishlist below for more information on
+where I wish to go with this.
+
+Added an item to the Wish List located further below in this file. With so
+many spend-thrifty hams, do I really need to go through the code and match
+it with the most up-to-date version(s) of GCC for compiling? I originally
+developed the code using GCC version 2.95, now I'm compiling it on version
+4.2.4 and it's not showing any errors during compile. If you have a specific
+version of GCC you're using, please submit that and proper hardware for me
+to run it on and I'll be more than happy to march forward :-)
+
+Changed the inactivity timeout message so that it does NOT show
+the FlexNet node call and gives a more specific message as to why the user
+was disconnected. This was a call I originally edited and have now cleaned
+up in node.c. There may be more of such messages. I can only test so much
+and for so long :)
+
+Made some more ANSI cleanups - in regards to Status and Users commands. I
+had them as magenta and they should only be bright white as they don't
+fit into any real category except for local system informations. For these
+I had to make routine changes as well as ANSI changes in user.c and in
+command.c. Also fixed the ANSI for version in NetRom. It currently had none.
+This was done in command.c. Also cleaned up Links and Routes ANSI in command.c
+and other places where needed. Originally I had the Routes as yellow which
+even though it points the ax25-interface that NetRom is encapsulated under,
+it's really more for NetRom "route"-ing... so changed it to cyan to keep with
+the schema.
+
+Found a disaster in ANSI routines for the Links command and the variant
+switches along with it! The ANSI ran to the table which I did not want
+to have happen and I believe I was very diligent in cleaning this up
+in ver 1.0.8 or 1.0.9. In any event, I recall doing this and now I have
+repeated my work... thus taken time away from more important tasks 
+*sigh*.
+
+These were worked in router.c. I also cleaned up other places where ANSI
+ran over other strings that it shouldn't, and where it may have engaged
+prior to where it should. Such instances are when it would highlight over
+the Node-ID string (ex: MYNODE:mycall-5}). This really made my skin crawl
+and I *know* I fixed this before... who knows perhaps I made a cleaner
+routine than I had.
+
+I recall doing a LOT of code clean-up, and it appears I need to revisit this
+again. When I'm done, hopefully I can get rid of a few hundred lines of code
+that's simply commented out for testing purposes only. The sizes of your
+binaries should not be affected by this and I believe I've been diligent
+to clean up the configure script to somewhat automate this process for you.
+This task will be excessively time consuming! If anything it'd be an excuse
+for a maintenance release!
+
+Fixed a minor routine in ipc.c in regards to the Msg command. I deliberately
+did NOT add ANSI to this because in a way the Msg command I feel is a tad
+intrusive such as with an instant message, however I did clean up how an
+incoming message was handled to the recipient. It now (in my opinion)
+shows a cleaner screen.
+
+I found Craig Small's old axdigi code and made an elf compile. In layman's
+terms, it's a static binary and should run as-is for you. This binary
+claims to be fully automagic in regards to crossport digipeating unless you
+make changes to your interfaces in which you should restart it. This binary
+also should NOT require /etc/ax25/axdigi.conf anymore. I have the other
+binary so if you think you need it, let me know.
+
+Added an install for axdigi in Makefile.in under "install bin".  Previously
+this file was not included, now it is. I may write a shell script to launch
+the daemons for you... keep an eye on this file for further info!
+
+26/05/2013 v2.1
+
+Fixed a bug in gateway.c where the finger "stop" ansi was white instead
+of red (for stop). This was one I missed not having proper routing yet
+to fully test. Thanks Brett WA7V for the link!!
+
+Made another change in gateway.c in regards to the handling of the
+flexnet destinations listing when using Flex/AX25 ONLY. There is a
+reason for this (believe it or not) and that's in the shell and netrom
+interfaces they both begin the destinations list with the string
+"Flexnet Destinations:". This may cause neighbor URONode/AWZNode/etc
+systems using flexd to improperly parse flexnet destinations from each
+other. At the moment, I don't have the facilities to properly test this
+but am hoping to work something out.
+
+Thanks to Bob K2JJT, I added an include for socket.h in ipc.c. While I
+never saw any errors here, I don't believe I've ever tested or compiled
+on a Slackware system... Bob uses Slack. K2JJT reported adding this to
+ipc.c helped him fix issues with his compile as it was griping about
+AF_NETROM. Adding it here made no difference so since it helps Slackware
+I'm all for being multi-distro compatable as much as humanly possible.
+
+In reviewing 2.0 changes, it had me look more into the shell function
+for sysops. I made a change that more defines which shell you may be
+in when you do a 'w' or a 'who' in a linux shell via the node. This
+was changed in system.c
+
+Made a patch to node.c where if called from a shell, it would coredump.
+Now, if it's called from a shell it simply exits back to the shell
+prompt. I believe the same is in other "node" variants to which
+the documentation directs the local sysop not to call the node from
+a prompt, however KI6ZHD felt this was an issue. Being harmless in
+nature to the function of my design I felt it wasn't harmful to add
+it in. This patch was provided by David Ranch KI6ZHD. Thanks to him
+for providing this, and eliminating any accidental core files on your
+hard drives, and to Steven, K6SPI for coding the patch.
+
+Thanks to David KI6ZHD for motivating me to do something I wanted to do
+but put it way on the back burner, and to Barry K2MF for his elite C
+skills. MHeard now will only print up to the 20 most recent heards. With
+the initial routine, it would just dump either the global list heard
+or if the user selected a specific interface the entire list for that
+interface. At first, it worked fine for telnet and/or ax25/flex
+connections but in NetRom it was double spacing. This was fixed by me. I
+chose 20 to leave room for system headers and prompt returns. In a
+standard 80x25 terminal screen, with a full listing, this should fill
+the entire screen without a need for the end user to scroll up and
+should help keep some traffic down on a busy network.
+
+Made a change in gateway.c to eliminate the "trying state" message only
+in NetRom when trying to connect to a remote NetRom node. This should
+keep the node more in compliance with Software2000 specifications.
+
+There was chatter within the BPQ32 user group on Yahoo that URONode was
+not releasing any keep-alive timers. Please, this is NOT the duty of
+a node Front End to control what the native protocol stack is designed
+to do. This is totally sysop configurable. To flag this I strongly
+suggest the following be added to your scripts:
+echo "600000" > /proc/sys/net/ax25/ax0/idle_timeout
+echo "600000" > /proc/sys/net/ax25/ax1/idle_timeout
+echo "600000" > /proc/sys/net/ax25/ax2/idle_timeout
+and so on... one line for each ax25 interface. This will break the
+keep-alive virtual circuit Netrom AND IP will use for transport, and
+thus break your IP as well. If you're running IP through an ax25
+interface I suggest you leave this defaulted to 0 (disabled).
+
+Rewrote the auto-find routine in gateway.c in do_connect so that first
+order of preference for connects searches the destis table from flexd
+BEFORE checking the netrom nodes and mheard tables, THEN it will search
+for the destination in the netrom nodes if not found in the destis
+table and prior to searching the mheard list. If you don't use flexnet,
+then this shouldn't be an issue for you. As of this time, I'm unsure
+if this would create any bugs if you don't define FlexNet during
+the configure procedure. If it does, please file a report on the
+online forum at https://www.n1uro.net/forum for me!
+
+Made some changes in util.c and gateway.c in regards to duplicate ax25
+route connection attempts. If you attempt to connect twice through the
+same path, same call, etc, to clarify the error handling. This was
+something I worked with K2MF on in regards to MFNOS. This does not mean
+you can't make a connect on the same interface you came in on, you will
+get a loop warning but the connect will attempt. If you connect from
+the node, and try to connect to <callsign>, loop back into the node,
+and try to connect to the same <callsign> again, you will NOT be allowed
+to connect. URONode will tell you that a duplicate connection is not
+allowed.
+
+Cleaned up the do_routes routine in command.c. Shortened "Quality" to
+"Qual" and renamed "Destinations" to "Nodes". After all, netrom doesn't
+really use "Destinations", that's more a flexnet thing. Still more
+cleanup to do in there *sigh*.
+
+While I was at the do_routes, I noticed missing ansi in do_routes and
+do_nodes. This has been fixed (and was previously in 1.0.10). I also
+cleaned up the ansi routine in do_destinations in router.c to match
+that of the netrom counterpart routines in command.c. Again, this was
+done in 1.0.10 *double sigh*.
+
+Rather than include an i686 elf of Craig Small's axdigi cross-port
+digipeater which probably would NOT work on a Raspberry PI, I added
+it into the Makefile by default. I also added an additional routine
+in the configure script to check to insure that this file is made.
+
+I also had to update axdigi.c so that it wouldn't error on the newer
+(as if I run newer ha!) gcc. This was done for strcpy so that it
+wouldn't produce errors as it does. I suspect in the "OLD" days of
+linux/gcc it may have been OK as I consider Craig to be one of the
+"village elders" of the packet system on linux.
+
+Added a man page for axdigi. READ THIS VERY CAREFULLY!! To digi through
+linux you *must* know some specific information and you might have to
+educate your users on how exactly to cross-port digi through you if
+they intend to do such. It's not something normally visible to them!
+I may add a node-help file on digi...but for now please study the man
+page on how. It works and works very slick as I've been testing it for
+a couple of months. Mheard also will learn digi paths and use them to
+connect to digipeated nodes if need be.
+
+Cleaned up do_nodes in command.c. Shortened Quality to Qual, and the
+equivilant of Obs. This will use less chars per line when doing a
+node <node> or node * . I've been wanting to do this but saved
+it for one of those rainy day things. Guess today was that rainy day?
+
+Cleaned up more code and hope to have it finished before 2.1's final
+release. So far I'm doing flexd.c at this point. FYI; code cleanup will
+be a 2-fold process. First; I'll be formatting each file so it's at a
+level of consistency. Second, things I have commented out for testing
+that aren't needed may be permanently removed. I may leave a few things
+in in case someone desires to say add a 'Welcome." message to netrom
+(which is NOT Software2000 compliant!).
+
+Speaking of which, I see I introduced a bug when ANSI is defined for
+a specific user which violates Software2000 specs. I believe I did this
+as a fail-safe in the prompt routine however now I see it's not needed
+with all the other ANSI cleanups I've done. This change (deletion)
+was done in node.c where I forced a shutoff of ANSI upon NetRom connects
+only, as NetRom does not display the MOTD.
+
+I rewrote a bit of the reconnect string. The "reconnect" in uronode.conf
+should be set to OFF. All connections with the exception of NetRom WILL
+reconnect. NetRom defaults to off, however with the {S|D} flags you may
+manually request you stay connected. Eventually I will remove this flag
+in the file so it will become moot. Please change it now to OFF! This
+was done in gateway.c. Previously, these flags were moot in NetRom
+connects. With the default to OFF, this keeps the NetRom in URONode
+Software2000 compliant. A NetRom disconnect should *never* send any
+text back whether it's a user or robot/script. Now a user can request
+staying connected to URONode from a incoming NetRom connection. For
+clarity sake, this only affects the user IF they connect INTO URONode
+via NetRom. The "S" flag works for ax25/Flex/NetRom outbound connects.
+A user connecting INTO URONode via ax25/Flex/IP will still automatically
+be reconnected after an outbound connect.
+
+N1UAN reports make install fails to install the config files. He's
+correct. Changed Makefile.in so that "make install" also includes
+make installconf which run by itself will install just the config
+files for /etc/ax25.
+
+I'm also working on changing the configure script to have some
+"eye candy". This will be a continuing work in progress. You'll see it
+as it comes. You will need the package "whiptail" in order to see this
+new configuration routine. I don't know if this is standard amongst
+ALL distributions, however I do know it comes default in debian and
+debian based systems. If this *is* too much of an issue, I'll revert
+back to the old method.
+
+Almost forgot about an ANSI bug in extcmd.c where if you created an
+external command in the node and the user was in via NetRom, when the
+node issued "Welcome back." the ansi did NOT clear the color. I found
+this in ver 2.0 and thought I fixed it, apparently not (age catching
+up to me?) In any event, this is now fixed and working properly again.
+Since most people don't use the +512 Color flags I'm sure it was missed.
+
+Found a non-critical bug in cmdparse.s in regards to running external
+commands - where it would automatically input a line feed before it
+executed the command. This was the only routine which did this. A
+routine like this really got under my skin and I was determined to find
+and fix this finally... this was a routine I never changed, and that
+was halted today (28 July 2013). Instead of totally removing this line
+of code, I changed it to now display "Executing command... " and where
+ANSI is defined, it is, naturally, green.
+
+Found a non-critical bug in the Info command where it would show as
+the first string to the user: "Help command for help" then it would push
+the uronode.info file. This is very wrong. While the Info command does
+use the routine of do_help in command.c, Info is an independent internal
+command and this should not have occurred. This is now fixed with ANSI
+if permissions display ANSI.
+
+Updated the outdated INSTALL text document. It had some now misleading
+pieces of information in it as some paths and make options have been
+changed. Since no one has said anything to this, I'll assume no one
+RTFM? (not surprised! email me and say in the subject line: surprise!
+if you do!)
+
+Went through the example config files and heavily commented them so for
+new installs, it explains each line more specifically in hopes less
+misconfigured systems will be created. I also found some typos as to
+man page references - fixed. Also updated some of the help files in
+regards to the new changes in relation to the "stay" sub command when
+connecting out from URONode.
+
+Note: in node.c I modified the pre-provided segfault patch to now
+push text to the local console instructing the local sysop or user
+what/how to properly execute the node. This will (I hope) force
+some RTFM to occur. Syslog logging was also added in the event this
+occurs. Actually, after thinking about this, I figured I'd dummy it up
+a bit and have it launch a login anyway. This depends that the local
+administrator/sysop -properly configures their box- and does the
+following:
+1 - add a line in /etc/services to point tcp/3694 to uronode
+2 - add uronode as a service in inetd or xinetd
+3 - insure you have a local telnet client on the box
+4 - enjoy!
+You will be reminded about this during the login, and syslog will
+reflect a local console login as well.I strongly urge you not to open
+2 shells and tail your syslog in one while you try to run URONode from
+the console. Wink
+
+Cleaned up a minor routine in do_nodes which lays in command.c where
+under an incoming NetRom connect, a user who did "Nodes" received
+an extra line feed if the columns were all equal at 4 per row. This
+was a bit under my skin... fixed/changed. While I was at it, I changed
+the output string when doing "Nodes *" from 'Nodes:' to "Detailed
+nodes listing:' which actually makes more sense since it is a detailed
+list.
+
+Fixed a minor bug in the way the prompts were handled under certain
+telnet clients. This was reported also by Marius Petrescu yo2loj. Under
+telnet, I added a carriage return (/r) along with the line feed (/n).
+Thank you Marius for the report.
+
+Slightly rewrote the way meminfo() was being handled. While I may have
+created a bug in 2.4 and lower kernels, this now should work in 2.6 and
+higher kernels. I guess the phrase "if it's not broke don't fix it"
+doesn't apply anymore?
+
+FINALLY - split the CHANGES file into a new page!! This makes it easier
+for me to input the change notes instead of having to scroll down for 30
+seconds Smile Call me lazy but don't call me late for supper! <G>
+
+04/09/2013 v2.2
+
+Made multiple .c file edits to reflect the new libax25-devel .h files.
+Currently these were pointing to the older kernel_*.h files and on newer
+linux systems was preventing compile. Now URONode should work fine.
+
+Added Marius Petrescu to the URONode team! With his c version of ripv2d, 
+Marius will (and already has) make a huge impact on the future of 
+URONode! Welcome Marius to the team! Made a reflection of this in the
+configure script.
+
+Marius brought to my attention the issue in the log timer routine where 
+it was forcing 32-bit. He supplied code to fix this in both system.c and
+flexd.c.
+
+While in discussions, Marius brought it to my attention that Ubuntu (and
+this includes Mint and any other Ubuntu backed distributions) where they
+run as he calls it a "fortified libc6" which segfaults on every (what it
+thinks is suspicious) buffer accesseD to prevent overflows however this
+libc6 itself causes buffer overflowing. Why on earth did the Ubuntu team
+ever do this?? Anyway, we're investigating how we're going to handle 
+this issue. I personally have verified URONode to compile and work on 
+the new kernel 3.x series on Debian and Fedora.
+
+In "fixing" the prompt bug earlier reported by Marius, I made an error in 
+the non-ANSI telnet prompt where the (/r) was also chopping off the first 
+letter of a callsign! OOPS! This was reported by Ted K1YON. Fixed.
+
+** Key news of this release: ROSE is a LOT more user friendly, AND it also
+has the ability to display color screens to the end user. This now means
+that URONode is an 8-prompt system! 4 main prompts, and 4 color prompts.
+The prompt system is designed to show the end user what protocol/method
+they used to connect into URONode with. Also proper SSIDs are displayed
+to match that of how the end user connected. I did this because seeing
+other nodes, they don't and when (as a user) connect into, for example,
+a NetRom node who's ssid is -12 and the node displays something 
+-=totally=- different, I often wonder if I connected to the proper node.
+
+The new prompt schema is:
+telnet   :	user@<sysop>.ampr.org:/uronode$
+netrom   :	<none> - this keeps in spec with Software2000
+flex/ax25:	=> 
+rose     :	-=> 
+
+Each matches with its own colors as well if you run the ansi flag. The
+goodbye message for rose is also different than it is for flex/ax25 and
+telnet links. The new RoseID flag is used as a personalized message to
+the remote user to say a nice goodbye, and to remind them of your Rose
+information. The (V)ersion command also has a rose column added to show
+the remote user your rose information. An example of this is included
+in the uronode.conf.5 man page.
+
+With such, a new uronode.conf file string called RoseID has been created.
+Details are in the file. You must keep the single quotes ' ' around the
+string for it to display properly. You have been warned. Also, I've added
+a default ExtCmd called ROSe so those who connect remotely can get rose
+addresses for now. I'm sure I'll be changing this in the future.
+
+Also, I decided to eliminate the permissions flag for use of hidden interfaces.
+Reason being is if a sysop flags an interface to be hidden, they did so for a
+specific reason. With that, I moved the ANSI flag from 512 in it's place to
+64. This was also changed in the man page uronode.perms.5.
+
+In regards to PBBS forwarding, I -=URGE=- you to read BBS.txt. Since
+there's no need for me to rewrite it, please heed my warning here. This
+is not something critical, just informational to help you improve your
+link with URONode systems.
+
+Fixed a cosmetic bug in regards to windows->linux emulation where when
+logging in, sentences were not getting properly wrapped. This was done
+in node.c. Other emulations such as PuTTY do not give you in windows
+full linux-type emulation. Higher profile programs such as SecureCRT
+will. For a free/shareware program I suggest MobiXterm. This also
+gives you a raw Xserver emulated screen. Of course, there are no issues
+if you use a standard linux console.
+
+Added a .pid file to flexd, code supplied by Jaroslav, OK2JRQ and other
+patches such as installer edits, etc. The only patches he supplied that I
+have yet to add is the install location patch, and one he feels is good
+for non-interactive. Source installs need to be interactive, if not you
+would not be compliling - just my honest opinion. I can see in the case
+of a possible distro package this may not be desired. The distros for now
+can hash that out on their own. 
+
+Many more cosmetic bugs fixed/changed. Moreso in ROSE but I did find a
+few others in there which needed my attention. I have noticed windows terminal
+based programs such as PuTTY have an issue determining \n based line feeds
+vs \r carriage returns in C code. This mainly seems to affect the various
+8 prompts. It seems if I put both in the code, Windows is happy but *nx
+may issue an added line-feed. I had thought I cleaned these all up but
+I introduced a couple old ones and some new ones with the ROSE work.
+
+01/10/2014 -2.2 released!
+
+02/10/2014 - 2.2.1
+
+Improperly packaged an old flexd.c! This one should compile. This is NOT
+the one I want, I've been fighting with flexd for a while now.
+
+uronode.conf may not update. If it does, you will need to redo yours from
+scratch. Look at the one in the etc/ directory in the source and add the
+line for RoseId. This is required. Thanks for the above reports from
+VE1JOT and SP2LOB.
+
+Removed the need to have quotes around the RoseId string in URONode.conf. I 
+found it unneccessary to have to do this. Keep the string togther ex: 
+callsign-ssid at 1000,200000 now is fine. I also find this cleaner.
+
+12/10/2014 - v5.1
+URONode release ver 51 is out!.. um.. I mean its main developer *sigh*
+
+21/12/2014 - v2.3
+
+Added Bob Tenty ve3tok to the development team and created a subversion
+server. Please welcome Bob to the team!
+
+Bob Tenty ve3tok reports when NOT using the official ax25 packages and
+on Ubuntu, the node when compiled natively may buffer overflow. He made
+changes to buffers in gateway.c, router.c, and flexd.c which prevent this.
+I have incorporated these changes and there's no ill effect on non Ubuntu
+distros.
+
+Fixed a bug I introduced into the ROSE ansi prompt where it wasn't
+executing a proper \n because I inadvertantly removed it. Restored.
+
+Fixed a warning in the axdigi code. Now that I'm on a more modern system
+I can fix these things as now I can see them better. This was also brought
+to my attention by Tomasz SP2L... thanks Tomasz!
+
+Figured out a way to compile and have it NOT segfault under Ubuntu. While
+I'll admit for the time being it's somewhat of a hack, but it *does* work
+for Ubuntu. There are warnings on Ubuntu compiles that don't exist on other
+platforms - interesting to say the least - but I think I see a relation
+between the warnings and the pervious Makefile. The prior statement is being
+left in as a comment deliberately as I hope to try and revert back to
+the previous method.
+
+**IMPORTANT: Per distro downstreams, I've been asked to change the paths
+of the URONode installs. Now your uronode and binaries will be placed in
+/usr/local/sbin instead of /usr/sbin. Config files will be in 
+/usr/local/etc/ax25 instead of /usr/ax25/. Node files will now be in
+/usr/local/var/ax25/node or flexd instead of /var/ax25/node or flexd.
+If you're a thrifty ham such as myself, you'll already have symlinks created
+for easier management, so that /etc/ax25 is symlinked into /usr/local/etc/ax25
+and so forth. Local files I can think of that would need editing if you use
+my standard config:
+/usr/local/bin/ax25
+/etc/xinetd.d/uronode
+/etc/xinetd.d/telnet (?)
+/etc/ax25/ax25d.conf
+
+Added a compile flag to keep Ubuntu happy. This and other routines were at the
+suggestions of YO2LOJ and VE3TOK.
+
+SYSop command does NOT spawn a shell anymore. This is due to the changes
+with the UNIX98 file system. I'm debating on whether or not I wish to 
+continue to keep this or possibly eliminate this (for possible security
+reasons). I see both PROs and CONs with it. Note: this ONLY affects those
+systems which force the use of /dev/ptmx in which one needs to use SOCAT
+to create static /dev/tty*# and /dev/pty*# pipes. This only affects the
+Kernel 3-series in which the older /dev/pty# system is no longer used and
+a master ptyx is used.
+
+I did notice UBUNTU made changes to their libraries last year (2013) in
+which URONode compiled but failed to execute any direct disk read/write
+routines. In any event, they fixed this bug late fall 2014 (at least in
+12.0.4LTS). One of the nice things about Ubuntu doing this is that you 
+can add a line in your grub configuration to have the kernel create a
+number of satic pseudo terminals upon boot. Debian, however, breaks this
+ruleset. I contacted my downstream and he hasn't responded. This would
+help a sysop gain a shell... however also creates a possible backdoor.
+
+Edited gateway.c so that the callsign-ssid is force altered on outbound
+ax25 connect requests regardless of how the inbound connect was initiated.
+VE1JOT reports that when a user telnets in, and gateway ax25 connects out,
+the callsign-0 is kept. This should be altered to a -15. This was always 
+true when inbound connects were ax25 and also outbound connects the same.
+VE1JOT reports this is troublesome, and in some cases causing DM frames
+to occur. While I tested this and found this not to be true on my own
+system, I did make a code adjustment to handle this.
+
+Fixed a bug in config.h which may cause flexd not to find the proper
+config lines. When I changed file paths I missed a couple. Now the system as 
+a whole should be consistant in regards to config files.
+
+Removed the need for MyGate and MyRange in flexd.conf! This was added by
+the request of K2BJG/SK so that the flexgate itself would be listed. Actually
+it is in the LINKS file. Unfortunately when trying to connect to a listed
+flexgate, it would try to digi via itself! Not good. While I was at it, I
+also increased the buffer from 512 to 1024. This may help with those gates
+that insist on making L A R G E MOTDs.
+
+
+14/02/2015 - v2.3.1
+Happy Valentine's day to the one we all love: Our Compilers!
+This is a critical security patch! I URGE you *all* to recompile.
+If anything, hopefully you've all patched your systems against GHOST.
+For those who wish to test their system I have a tool on my ftp site
+which can do this for you.
+
+Through Paul G4APL, Andy G0HXT reported a condition on Ubuntu-based 
+systems in which a user may enter a malformed NetRom connect string
+into URONode and the node will buffer overflow. I fixed this in
+gateway.c limiting the string for searching connects on the first parameter.
+Also changed the error output to the user so that they may know the error
+may be their own.
+
+Made edits to all the man pages and the INSTALL file as suggested by Tomasz
+SP2L. I also grepped for certain strings in other files and made a change
+to the README file as well.
+
+Changed the version in node.h to reflect this security patch.
+
+
+
+Known NON-Critical Bugs:
+Status memory/swap reporting fix
+
+Wish-list:
+Who file sorter
+pactor - requested by sv1uy
+-----------
+
+Original Development Information (aka Disclaimer):
+URONode was developed on an IBM eSeries 330 eServer with dual 1.2GHz CPUs
+The OS is Debian Linux 4 using kernel 2.4.27, libax25 v0.0.11,
+ax25-tools v0.0.8 and ax25-apps v0.0.6. This software comes with
+absolutely NO guarantees so crash n burn at your own risk. We all may
+be surprised and find out that it actually DOES something useful!
+URONode may not run 100% depending on environmental conditions specific
+to your system.
+
+URONode is GLPv2 code, and tested by it's main author on the following
+platforms: Raspberry Pi ver. B, Debian 7.7 on a Core-i3, Ubuntu 12.0.4LTS
+on a Core-i3, Fedora ver. 19
+
+------------
+
+Comments/suggestions? email: n1uro at n1uro.ampr.org
+Gripes??? cat gripes > /dev/null Smile just kidding!
+
+This version will get you going for now. I'll post any changes to:
+ftp://ftp.n1uro.net/packet
+
+Join our support mail list graciously donated by TAPR!
+http://www.tapr.org/mailman/listinfo/uronode
+
+73 de Brian N1URO
diff --git a/COLORS b/COLORS
new file mode 100644
index 0000000..ba14b9b
--- /dev/null
+++ b/COLORS
@@ -0,0 +1,25 @@
+Incase you're wondering about the method behind the madness in my color
+schema it's very simple. Picture yourself with 3 vehicles to drive on
+different roads with; a scooter, a compact car, and an SUV. Each vehicle
+(or protocol) has it's own color. Each vehicle follows the same rules
+of the road (green for go, red for stop, blinking red for alarms). When
+you command URONode to go somewhere, you get green. When you return and
+the process has completed it's red. Ax25/Flex is Yellow, NetRom is Cyan,
+and IP/System messages are Magenta.
+
+It's VERY IMPORTANT that you program any automated scripts that connect
+to URONode that they do NOT use colors! Simply remove 512 from their
+permissions. If you do NOT do this, the robot script may attempt to 
+decipher ANSI code and it may cause it to hang. YOU HAVE BEEN WARNED!
+
+
+Here's the schema:
+Connects display in green as in "gateway go"
+Reconnects display in red as in "gateway stop"
+IP based information is in magenta
+Netrom Nodes (full list) in bold cyan
+FlexNet destis (full list) in yellow
+System info in bright white
+Aborts and timeouts blink bright red
+Logouts in low cyan
+
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..a43ea21
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,339 @@
+		    GNU GENERAL PUBLIC LICENSE
+		       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+                          675 Mass Ave, Cambridge, MA 02139, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+

+		    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+

+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+

+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+

+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+			    NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+

+	Appendix: How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) 19yy  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) 19yy name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/FAQ b/FAQ
new file mode 100644
index 0000000..3376db7
--- /dev/null
+++ b/FAQ
@@ -0,0 +1,35 @@
+Welcome to the official FAQ file for URONode.
+
+The purpose of this file is to help explain better about URONode and what
+the various features were designed for. Since this file will be maintained
+via URONode Sysop reports, I'll consider this file a constant 'work in
+progress' type file.
+
+When using URONode or really any other linux node flavor, keep in mind
+that the actual node program itself is only a front-end for the users
+to do various functions your linux server may have to provide. Node really
+doesn't do any sort of control features whatsoever, it merely acts as a
+sort of proxy to your linux daemons. Those features are toggled on/off at
+compile time by the operator of the node. I've taken time to rework the
+configure script to give the node ops more flexibility in what they wish
+to service their end users with. Nothing about URONode was ever designed
+as a 'replacement' for any existing services such as email and convers.
+I'm not even going to suggest one chooses to run URONode as a replacement
+for LinuxNode by Tomi, AWZNode, or even FlexNode. The goals I set when
+starting this project were moreso to custom fit my unique setup and its
+something I can share with the amateur community at the same time.
+
+URONode is NOT:
+A replacement for *NOS
+A replacement for Email
+A replacement for PBBS
+A replacement for convers
+A FlexNet router
+
+URONode IS:
+A user front-end with some additional features to help compliment those 
+existing features an end user may need but for whatever reason doesn't
+have access to at the moment, while allowing links to various entities
+such as AX.25 links, Net/Rom routing, FlexNet destinations, general and
+amprnet TCP/IP services.
+
diff --git a/INSTALL b/INSTALL
new file mode 100644
index 0000000..3bf51a6
--- /dev/null
+++ b/INSTALL
@@ -0,0 +1,79 @@
+1. COMPILING and INSTALLING
+
+To compile and run URONode you will need to have libax25-0.0.4 or newer
+installed on your system. It should work on any platform where libax25 can
+be compiled and installed. 
+Note however that it will NOT work with 2.0.x kernels.
+
+To install you should first run:
+
+  ./configure
+
+and answer to the questions it makes. 
+
+** IF ** this is an ** UPGRADE **:
+and if you said no to configure running a "make", just type:
+make; make upgrade
+This will *not* overwrite your config files, and will freshen up
+your binaries only. If you told the configure script to make, then
+all you need to type to upgrade is: make upgrade.
+
+** IF ** this is a new install:
+
+If all files needed are present everything should work. Next:
+
+  make (if you said "no" to the configure script launching it for you)
+  make install
+  make installhelp
+
+Optionally you may want to run also:
+
+  make installconf
+
+to install the default configuration files. 
+Note however this copy example files in /usr/local/etc/ax25 but with ".ex". 
+You should rename it by removing ".ex" at the end of filenames.
+
+After that you need to edit the configuration files to suit your system. 
+The manual pages for uronode.conf(5) and uronode.perms(5) should give
+an idea of what to put into these files. The AX25-HOWTO is a must read also.
+
+2. RUNNING
+
+URONode is intended to be called from ax25d or inetd. It doesn't need
+any command line arguments. See the uronode(8) manual page.
+
+To run URONode from ax25d, /usr/local/etc/ax25/ax25d.conf should have something
+like this in it:
+
+  # AX25 Port ax0
+  # Belows SSID can not be the same as your netrom node SSID!
+  [N1URO-2 VIA ax0]
+  default  * * * * * *  -    root  /usr/local/sbin/uronode  uronode
+
+  # NETROM Port
+  <nr0>
+  default  * * * * * *  -    root  /usr/local/sbin/uronode  uronode
+
+add uronode as a service in /etc/services:
+uronode         3694/tcp                        # Node/URONode packet
+
+if you use inetd -
+/etc/inetd.conf could have something like this in it:
+
+# Listen at telnet port -> URONode
+uronode  stream  tcp     nowait  nobody    /usr/local/sbin/uronode  uronode
+
+if you use xinetd -
+/etc/xinetd.d/uronode should look like this:
+
+service uronode
+{
+        disable         = no
+        socket_type     = stream
+        protocol        = tcp
+        user            = nobody
+        server          = /usr/local/sbin/uronode
+        wait            = no
+        instances       = 20
+}
diff --git a/Makefile.in b/Makefile.in
new file mode 100644
index 0000000..750e546
--- /dev/null
+++ b/Makefile.in
@@ -0,0 +1,100 @@
+all: nodeusers uronode axdigi @FLEXNET@
+
+CC = gcc
+LD = gcc
+# CFLAGS = -O2 -g -s -Wstrict-prototypes
+CFLAGS = -O2 -g -Wno-unused-result -Wstrict-prototypes
+LDFLAGS =
+LIBS = -lax25 -lax25io
+
+include Makefile.include
+
+COMMON_SRC =		user.c util.c
+NODE_SRC =		node.c cmdparse.c config.c command.c mheard.c axcalluser.c \
+			gateway.c extcmd.c procinfo.c router.c system.c sysinfo.c ipc.c
+NODEUSERS_SRC =		nodeusers.c
+FLEXD_SRC = 		flexd.c procinfo.c
+DIGI_SRC =		axdigi.c
+
+COMMON_OBJS =		$(COMMON_SRC:.c=.o)
+NODE_OBJS =		$(NODE_SRC:.c=.o)
+NODEUSERS_OBJS =	$(NODEUSERS_SRC:.c=.o)
+FLEXD_OBJS =		$(FLEXD_SRC:.c=.o)
+DIGI_OBJS =		$(DIGI_SRC:.c=.o)
+.c.o:
+	$(CC) $(CFLAGS) -c $<
+
+install: installbin installman installhelp installconf
+	install -m 755    -D -d	$(VAR_DIR)
+	install -m 755    -D -d	$(VAR_DIR)/node
+	install -m 644    -p etc/loggedin	$(VAR_DIR)/node
+	install -m 644    -p etc/lastlog	$(VAR_DIR)/node
+	install -m 755    -D -d	$(VAR_DIR)/flex
+	install -m 644    -p etc/gateways	 $(VAR_DIR)/flex
+	
+installbin: all
+	install -m 755 	-s -p	uronode		$(SBIN_DIR)
+	install -m 755  -s -p	nodeusers	$(SBIN_DIR)
+	install -m 755  -s -p	axdigi		$(SBIN_DIR)
+ at IN@	install -m 755  -s -p	flexd		$(SBIN_DIR)
+
+installhelp:
+	install -m 755    -D -d		 $(VAR_DIR)
+	install -m 755    -D -d		 $(VAR_DIR)/node/help
+	install -m 644    -p etc/help/*.hlp $(VAR_DIR)/node/help
+
+installconf: installhelp
+	install -m 755    -D -d		 $(ETC_DIR)
+	install -m 600    -p etc/uronode.conf  $(ETC_DIR)
+	install -m 600    -p etc/uronode.perms $(ETC_DIR)
+	install -m 600    -p etc/uronode.info  $(ETC_DIR)
+	install -m 600    -p etc/uronode.motd  $(ETC_DIR)
+	install -m 600    -p etc/uronode.users $(ETC_DIR)
+	install -m 600    -p etc/uronode.routes   $(ETC_DIR)
+	install -m 600    -p etc/flexd.conf  $(ETC_DIR)
+
+installman:
+	install -m 755	  -D -d $(MAN_DIR)/man1 $(MAN_DIR)/man5 $(MAN_DIR)/man8
+	install -m 644    -p man/nodeusers.1.gz  $(MAN_DIR)/man1
+	install -m 644    -p man/uronode.conf.5.gz  $(MAN_DIR)/man5
+	install -m 644    -p man/uronode.perms.5.gz $(MAN_DIR)/man5
+	install -m 644    -p man/flexd.conf.5.gz $(MAN_DIR)/man5
+	install -m 644    -p man/uronode.8.gz       $(MAN_DIR)/man8
+	install -m 644	  -p man/axdigi.8.gz	 $(MAN_DIR)/man8
+
+upgrade: installman
+	install -m 755 -p uronode       $(SBIN_DIR)
+	install -m 755 -p nodeusers     $(SBIN_DIR)
+	install -m 755 -p flexd		$(SBIN_DIR)
+	install -m 755 -p axdigi	$(SBIN_DIR)
+	install -m 644 -p uronode.conf	$(ETC_DIR)
+	install -m 644 -p uronode.perms $(ETC_DIR)
+ 
+clean:
+	rm -f *.o *~ *.bak *.orig make.debug nodeusers uronode flexd axdigi
+	rm -f etc/*~ etc/*.bak etc/*.orig
+	rm -f etc/help/*~ etc/help/*.bak etc/help/*.orig
+
+distclean: clean
+	rm -f .depend Makefile.include config.h
+	rm -f uronode nodeusers axdigi @FLEXNET@
+	rm -f Makefile make.debug
+
+depend:
+	$(CC) $(CFLAGS) -M $(COMMON_SRC) $(NODE_SRC) $(NODEUSERS_SRC) $(FLEXD_SRC) > .depend
+
+uronode: $(COMMON_OBJS) $(NODE_OBJS)
+	$(LD) $(LDFLAGS) -o uronode $(COMMON_OBJS) $(NODE_OBJS) $(LIBS) $(ZLIB)
+
+nodeusers: $(COMMON_OBJS) $(NODEUSERS_OBJS)
+	$(LD) $(LDFLAGS) -o nodeusers $(COMMON_OBJS) $(NODEUSERS_OBJS) $(LIBS) $(ZLIB)
+
+flexd: $(FLEXD_OBJS)
+	$(LD) $(LDFLAGS) -o flexd $(FLEXD_OBJS) $(LIBS) $(ZLIB)
+
+axdigi: $(DIGI_OBJS)
+	$(LD) $(LDFLAGS) -o axdigi $(DIGI_OBJS) 
+
+ifeq (.depend,$(wildcard .depend))
+include .depend
+endif
diff --git a/Makefile.include.in b/Makefile.include.in
new file mode 100644
index 0000000..aca87b5
--- /dev/null
+++ b/Makefile.include.in
@@ -0,0 +1,13 @@
+# Processor architecture
+ARCH		= @ARCH@
+
+# Paths
+ETC_DIR		= @ETC_DIR@
+SBIN_DIR	= @SBIN_DIR@
+BIN_DIR		= @BIN_DIR@
+LIB_DIR		= @LIB_DIR@
+MAN_DIR		= @MAN_DIR@
+VAR_DIR		= @VAR_DIR@
+
+# Is Zlib available?
+ZLIB		= @ZLIB@
\ No newline at end of file
diff --git a/README b/README
new file mode 100644
index 0000000..974b485
--- /dev/null
+++ b/README
@@ -0,0 +1,95 @@
+Please check out the file INSTALL to compile and install URONode.
+Also please read the CHANGES.* file for all version history changes.URONode README file	September 09, 2013
+
+Note: Please read the CHANGES file for detailed information
+about the changes from AWZNode to URONode and what I've
+done with it... along with current version info! - Brian N1URO
+
+Hi linuxers!
+
+First all, I thanks PE1RJA and OH2BNS for their very great job!
+
+*****************************************************************************
+The v0.5.x release is a temporary version of URONode running and compiling
+under linux 2.4.x, with glibc 6 and new ax25 and ax25io libraries. v0.0.11
+*****************************************************************************
+
+UROnode is based on AWZ|LinuxNode by Tomi Manninen OH2BNS and FlexNode 
+by Roy PE1RJA. It was born initially for the aripisa.ampr.org system 
+by Stefano Noferi IZ5AWZ of ARI Ham Radio Association of Pisa (ITALY).
+Users in URONode can connect all ham packet world: all AX25, NETROM, ROSE, 
+FLEXNET, ITANET, TCP/IP nodes in the world are now near.
+
+Comment from Stefano:
+I have a "packet" dream: all the packet networks can interchange connections.
+My version of node software for Linux is an attempt to realize this idea
+and I hope it can help the ham radio digital world to come back one. ;)
+
+I thanks ARI association of Pisa and Alex Del Chicca IK5PWJ,
+for their trust and supports.
+
+This README file, the documentation etc. are very incomplete! 
+Sorry, but my free time is very very very... very little.. :)
+
+If you decide to use URONode, send me a mail.
+     
+Routing features include: (in order preferance)
+- netrom routing
+- fixed routes
+	Create and/or modify /usr/local/etc/ax25/uronode.routes, the format of 
+	this file is in the example file uronode.route.ex.
+	Now fixed link nodes in this file have an alias and 3 connection 
+	modes, can be queried using the Links command and can be 
+	connected directly using: Connect <call>|<alias> (ie. without 
+	specifying the downlink port)
+- flexnet destination lists
+	A separate daemon (flexd) queries a neighbouring flexnet node for its
+        reachable destinations, these destinations are stored on the local
+        disk and can be queried using the Dest command and can be connected
+        directly using: Connect <destination>
+	Config file: flexd.conf:
+	MyCall <call>            # the callsign used during the connection
+	PollInterval <interval>  # how often the destinations are downloaded
+	FlexGate <call>          # the neighbouring flexnet node
+	The pollinterval is specified in seconds and the callsign after
+        flexgate must be defined in uronode.routes !!
+- mheard based routing
+        When users are using your node the mheard tables are filled with
+        callsigns, callsigns heard on ports can be connected directly with
+        the Connect <call> command, without specifying the downlink port.
+
+Other features:
+- local users of the linux machine can be granted access to the mailreader
+  and optionally to the shell. Config file: /etc/ax25/node.users
+  <call>:<password>:<username>:[mail][,shell]
+  call : the callsign of the user that is allowed to access special features
+  password : a string pasword
+  username : the (real)-username on the linux side
+  options : mail  - the user has permission to access his or her mailbox
+            shell - the user has permission to access the shell
+  Users with the mail option enabled will receive messages like "New mail
+  has arrived", mostly when the stated condition is met ;-)
+- all users can send messages to a callsign associated in the kernel table
+  with a linux username ("send" command).
+- now the sysop can modified the node prompt and password prompt 
+- "!" command show system statistics
+- old "SEssions" command is now "MSessions"
+- now "MHeard" command can be used without port specification
+- changed the output of several query programs (like ports/routes etc.) also
+  included more netrom specific output in these commands
+- included a lastlog, which shows the time, date and port of your previous
+  session, if this is your first connect, you are requested to read the
+  info text
+
+The official FTP Site of URONode is:
+https://sourceforge.net/projects/uronode/?source=directory
+ftp://ftp.n1uro.net/packet/
+
+The official Forums site is:
+http://www.tapr.org/mailman/listinfo/uronode
+
+URONode is also a part of Fedora 20 and higher. 
+"yum install uronode" to install the .rpm package.
+
+Please check out the file INSTALL to compile and install URONode.
+Also please read the CHANGES.* file for all version history changes.
diff --git a/URONode.his b/URONode.his
new file mode 100644
index 0000000..48ca670
--- /dev/null
+++ b/URONode.his
@@ -0,0 +1,49 @@
+** Note: this file is depreciated, refer to CHANGES.*
+
+URONode was spawned off of the original linuxnode by Tomi Manninen OH2BNS
+Before URONode was FlexNode by Roy PE1RJA, and then by Stefano Noferi IZ5AWZ
+who called it AWZNode. I took over the code willingly and on my own mainly
+as a project I could do under C program coding in April 2003 after it 
+appeared that AWZNode was no longer being developed. 
+
+My first goal was to make it appear and act more like TheNet X1J and spent
+most of my time configuring the node to behave as such which I felt I did
+quite successfully. While doing that I thought I'd try to add in email
+features by using the old PMS system written by Alan Cox, who has a lot
+of code in the main linux kernel for it's IP stack (most of which is taken
+directly out of KA9Q nos). While I was successful in doing that, Morgan
+SM6TKY reported that the code was old and exploitable... unfortunately I had
+a period where I couldn't devote the time into getting it repaired quickly 
+and URONode sat and suffered with a note explaining that certain features
+should not be used or enabled. As a quick fix, I simply commented out the
+found exploits and did some more cosmetics to the code and released a patch.
+
+Still with users wanting EMAIL as a feature to the software, this inspired me
+to pick up with the dropped axMail code and bring that more up to date. axMail
+was originally started by Heikki Hannikainen, and then mailbox routines were
+added by Marius Petrescu, however system configs were lacking. I took the 
+code and added in the routines which are in there now so that new users
+are properly created within the basic linux filesystem schema, and passwords
+can be created (optional) so that a web front-end such as NeoMail can be
+used in conjunction with axMail giving users the choice of the web or RF
+packet to do their SMTP based EMAIL with. It was and always will be an optional
+add-on module for URONode, and other flavors of *node for linux.
+
+These two packages together, along with F6FBB make for one heck of a feature
+packed system a sysop can piece together on one server. Because of such, 
+URONode has become very popular in the NorthEast USA and in Central East
+Florida within the EastNet FlexNet network and with the Florida MARS 
+networks. With this, I've taken the look and feel of URONode to try and
+match that of a FlexNet interface.
+
+The latest version of URONode under-went many face lifts! The node not only
+auto-senses the incoming connection but delivers an interface which clones
+that of the type of system they're connecting in from. A user connecting
+in via IP will actually get a prompt that looks and acts similar to a
+Unix bash prompt with custom aliased commands!.. and to top that all off
+I've added an ansi schema to the IP interface!!
+
+URONode is used world-wide in Europe, Africa, Asia, and in North America.
+A web bbs is available at https://www.n1uro.net/forum where release notes
+for URONode are posted. If the functionality of URONode isn't enough to
+get interest in packet growing, the stability of URONode should!
diff --git a/axcalluser.c b/axcalluser.c
new file mode 100644
index 0000000..107a285
--- /dev/null
+++ b/axcalluser.c
@@ -0,0 +1,77 @@
+/* axcalluser.c - determine username corresponding to callsign */
+#include <stdio.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <errno.h>
+#include "config.h"
+#include "axcalluser.h"
+
+int axcalluserid(char *call)
+{
+  char callsign[10];
+  char username[80];
+  int id;
+  int userid = -1;
+  FILE *f = fopen(PROC_AX25_CALLS_FILE,"r");
+  if (f) {                                     /* VE3TOK, 18Nov2014, return value usage */
+    if (fgets(username,79,f) == NULL) {
+       syslog(LOG_DEBUG, "Can't get username: %s", strerror(errno));
+       return 1;
+    }
+    while (fscanf(f," %d %9s",&id,callsign) != EOF) {
+      char *a,*b;
+      for (a=call,b=callsign;
+	   *a && *b && toupper(*a)==toupper(*b) && *b!='-';
+	   a++,b++) ;
+      if (!isalnum(*a) && !isalnum(*b)) {
+	userid = id;
+      }
+    }
+
+  }
+  fclose(f);
+  return userid;
+}
+char *getusername(int userid)
+{
+  int colons;
+  int c,i;
+  char token[80];
+  static char name[80];
+  char *retval = NULL;
+  FILE *f;
+  f = fopen("/etc/passwd","r");
+  if (f) {
+    i = 0;
+    colons = 0;
+    while ((c = getc(f)) != EOF) {
+      switch (c) {
+      case ':':
+	token[i] = '\0';
+	colons++;
+	if (colons == 3) {
+	  if (userid == atoi(token)) {
+	    retval = name;
+	    goto endloop;
+	  }
+	} else if (colons == 1) {
+	  strcpy(name,token);
+	}
+	i = 0;
+	break;
+      case '\n':
+	colons = 0;
+	i = 0;
+	break;
+      default:
+	token[i++] = c;
+	break;
+      }
+    }
+  endloop:
+    fclose(f);
+  }
+  return retval;
+}
diff --git a/axcalluser.h b/axcalluser.h
new file mode 100644
index 0000000..f802c30
--- /dev/null
+++ b/axcalluser.h
@@ -0,0 +1,16 @@
+#ifndef AXCALLUSER_H
+#define AXCALLUSER_H
+
+/* Simple functions to return userid of a callsign, and */
+/* username of a userid, by reading appropriate files.  */
+/* Surely there's a better way to do 'getusername', but */
+/* this works.                                          */
+/* Dave Brown N2RJT 5/5/96                              */
+
+/* return userid of given callsign, or -1 if not found */
+int axcalluserid(char *callsign);
+
+/* return username of given userid, or NULL if not found */
+char *getusername(int userid);
+
+#endif
diff --git a/axdigi.c b/axdigi.c
new file mode 100644
index 0000000..252d7e5
--- /dev/null
+++ b/axdigi.c
@@ -0,0 +1,255 @@
+/* 
+ * axdigi: Cross and straight port digipeater program
+ * Copyright (C) 1995 Craig Small VK2XLZ
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *  JSN - Small tweaks to ensure compilation and execution under Linux 2.1.x.
+ *        12th June 1997.
+ */
+
+#include </usr/include/net/if.h>
+#include <linux/if_ether.h>
+#include <netinet/in.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+/* below added by N1URO */
+#include <string.h>
+#include <unistd.h>
+#include <linux/ax25.h>
+
+int recv_packet(unsigned char *buf, int size, unsigned char *port);
+void print_call(unsigned char *buf);
+unsigned char *find_call(char *port);
+void add_port(char *call, char *port);
+void get_interfaces(int skt);
+
+/*
+ * The defines we use
+ */
+#define AXALEN 7
+#define E_BIT 0x01	/* Address extension bit */
+#define REPEATED 0x80	/* Has-been-repeated bit */
+#define MAX_PORTS 16
+#define VERSION "0.2"
+
+int port_count = 0;
+unsigned char portname[MAX_PORTS][20];
+unsigned char portcall[MAX_PORTS][8];
+
+
+
+int main(int argc, char *argv[])
+{
+  int skt;
+  int size, rt;
+  unsigned char buf[4096];
+  struct sockaddr sa;
+  int asize;
+	
+  /* Check our huge range of flags */
+  if (argc > 1)
+    {
+      if (strcmp(argv[1], "-v") == 0 || strcmp(argv[1], "-h") ==0)
+	{
+	  printf("axdigi version %s. Copyright (C) 1995 Craig Small VK2XLZ\n\n", VERSION);
+	  printf("axdigi comes with ABSOLUTELY NO WARRANTY.\n");
+	  printf("This is free software, and you are welcome to redistribute it\n");
+	  printf("under the terms of GNU General Public Licence as published\n");
+	  printf("by Free Software Foundation; either version 2 of the License, or\n");
+	  printf("(at your option) any later version.\n");
+	  return 0;
+	}
+    }		
+/* Change to keep code more modern - N1URO */
+  if ((skt = socket(PF_PACKET, SOCK_PACKET, htons(ETH_P_AX25))) == -1)
+    {
+      perror("socket");
+      return(1);
+    }
+  get_interfaces(skt);
+	
+  while(1)
+    {
+      asize = sizeof(sa);
+
+      if ((size = recvfrom(skt, buf, sizeof(buf), 0, &sa, &asize)) == -1)
+	{
+	  perror("recv");
+	  exit(1);
+	}
+      if ((rt = recv_packet(buf, size, sa.sa_data)) >= 0)
+	{
+	  if (rt < port_count)
+	    {
+	      asize = sizeof(sa);
+	      strcpy(sa.sa_data, portname[rt]);
+	      if (sendto(skt, buf, size, 0, &sa, asize) == -1)
+		perror("sendto");
+	      continue;
+	    }
+	  /*			printf("Unknown port %s\n", sa.sa_data);*/
+	} /* recv_packet true */
+    } /* while(1) */
+  close(skt);
+}
+
+int recv_packet(unsigned char *buf, int size, unsigned char *port)
+{
+  unsigned char *bptr;
+  int count, i;
+  unsigned char *call;
+	
+  /*	printf("Got packet size %d\n", size);*/
+	
+  /*
+   * Decode the AX.25 Packet 
+   */
+  /* Find packet, skip over flag */
+  bptr = buf+1;
+  /* Now at destination address */
+  /*	print_call(bptr);
+	printf("<-");*/
+  bptr += AXALEN;
+	
+  /* Now at source address */
+  /*	print_call(bptr);*/
+  if (bptr[6] & E_BIT)
+    {
+      /*		printf("\n");*/
+      return -1;	/* No digis, we're not interested */
+    }
+  /*	printf(" ");*/
+  bptr += AXALEN;
+  /* Now at digipeaters */
+	
+  count = 0;
+  while( count < AX25_MAX_DIGIS && ( (bptr - buf) < size))
+    {
+      /*		print_call(bptr);
+			printf(", ");*/
+      if (bptr[6] & REPEATED)
+	{
+	  /* This one has been repeated, move to next one */
+	  bptr += AXALEN;
+	  count++;
+	  continue;
+	}
+      /* Check to see if callsign is one of ours */
+      for (i = 0; i < port_count; i++)
+	{
+	  /*			printf("compare ");
+				print_call(bptr);
+				printf(" ");
+				print_call(portcall[i]);
+				printf("\n");*/
+	  if ( (bcmp(bptr, portcall[i], AXALEN-1) == 0) && ((bptr[6] & 0x1e) == portcall[i][6]))
+	    {
+	      /* Copy new address over and turn on repeated bit*/
+	      call = find_call(port);
+	      if (call == NULL)
+		return -1;
+	      bcopy(call, bptr, AXALEN-1);
+	      bptr[6] = (bptr[6] & ~0x1e) | call[6];
+	      bptr[6] |= REPEATED;
+	      return i;
+	    }
+	} /* for */
+      return -1;
+    }
+  return -1;
+}	
+	
+void print_call(unsigned char *bptr)
+{
+  printf("%c%c%c%c%c%c-%d", bptr[0] >> 1, bptr[1] >> 1,
+	 bptr[2] >> 1, bptr[3] >> 1, bptr[4] >> 1, bptr[5] >> 1,
+	 (bptr[6] >> 1) & 0xf);
+}	
+
+void add_port(char *call, char *port)
+{
+  unsigned char *s;
+  int n;
+	
+  if (port_count == MAX_PORTS)
+    return;
+	
+  s = portcall[port_count];
+	
+  while( (*call != '-') && ( (int)(s - portcall[port_count])< 6))
+    *s++ = (*call++) << 1;
+  call++; /* skip over dash */
+  n = atoi(call);
+  *s = n << 1;	
+
+  strcpy(portname[port_count], port);
+  port_count++;
+}	
+	
+	
+unsigned char *find_call(char *port)
+{
+  static unsigned char callsign[8];
+  int i;
+	
+  for(i = 0; i < port_count; i++)
+    {
+      if (strcmp(port, portname[i]) == 0)
+	{
+	  bcopy(portcall[i], callsign, 7);
+	  return callsign;
+	}
+    }
+  return (char*)NULL;
+}
+
+void get_interfaces(int skt)
+{
+  char buf[1024];
+  struct ifconf ifc;
+  struct ifreq *ifr;
+  int i;
+	
+  ifc.ifc_len = sizeof(buf);
+  ifc.ifc_buf = buf;
+  if (ioctl(skt, SIOCGIFCONF, &ifc) < 0)
+    {
+      perror("ioctl");
+      exit(1);
+    }
+	
+  ifr = ifc.ifc_req;
+  for (i = ifc.ifc_len / sizeof(struct ifreq); --i >= 0; ifr++)
+    {
+      if (ioctl(skt, SIOCGIFHWADDR, ifr) < 0)
+	continue;
+      if (ifr->ifr_hwaddr.sa_family == AF_AX25)
+	{
+	  /* AX25 port, add to list */
+	  if (port_count < MAX_PORTS)
+	    {
+	      bcopy(ifr->ifr_hwaddr.sa_data, portcall[port_count], 7);
+	      strcpy(portname[port_count], ifr->ifr_name);
+	      port_count++;
+	    }	
+	}
+    } /* for */
+}	
+		
diff --git a/cmdparse.c b/cmdparse.c
new file mode 100644
index 0000000..298b1cf
--- /dev/null
+++ b/cmdparse.c
@@ -0,0 +1,300 @@
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+
+
+#include <sys/socket.h>
+#include <netax25/ax25.h>
+#include <netrose/rose.h>
+#include <netax25/axlib.h>
+
+#include "node.h"
+
+static void expand_string(char *dest, char *src, int argc, char **argv)
+{
+  char tmpbuf[64], def[64];
+  char *p1, *p2, *cp;
+  int n, skip, nocopy;
+
+  if (strchr(src, '%') == NULL) {
+    strcpy(dest, src);
+    return;
+  }
+  p1 = src;
+  p2 = dest;
+  while (*p1) {
+    if (*p1 == '%') {
+      nocopy=1;
+      p1++;
+      skip = 1;
+      def[0] = 0;
+      if (*p1 == '{') {
+	p1++;
+	if ((cp = strchr(p1, '}')) != NULL) {
+	  skip = cp - p1 + 1;
+	  cp = p1;
+	  if (*++cp == ':') {
+	    cp++;
+	    n = min(skip - 3, 63);
+	    strncpy(def, cp, n);
+	    def[n] = 0;
+	  }
+	}
+      }
+      switch (*p1) {
+      case 'u':
+      case 'U':
+	strcpy(tmpbuf, User.call);
+	if ((cp = strrchr(tmpbuf, '-'))) *cp = 0;
+	break;
+      case 's':
+      case 'S':
+	strcpy(tmpbuf, User.call);
+	break;
+      case 'p':
+      case 'P':
+	strcpy(tmpbuf, User.ul_name);
+	if ((cp = strrchr(tmpbuf, '-'))) *cp = 0;
+	break;
+      case 'r':
+      case 'R':
+	strcpy(tmpbuf, User.ul_name);
+	break;
+      case 't':
+      case 'T':
+	switch (User.ul_type) {
+	case AF_FLEXNET:
+	  strcpy(tmpbuf, "flexnet");
+	  break;
+	case AF_AX25:
+	  strcpy(tmpbuf, "ax25");
+	  break;
+	case AF_NETROM:
+	  strcpy(tmpbuf, "netrom");
+	  break;
+#ifdef HAVE_ROSE	  
+	case AF_ROSE:
+	  strcpy(tmpbuf, "rose");
+	  break;
+#endif	  
+	case AF_INET:
+	  strcpy(tmpbuf, "inet");
+	  break;
+	case AF_UNSPEC:
+	  strcpy(tmpbuf, "host");
+	  break;
+	}
+	break;
+      case '0':
+      case '1':
+      case '2':
+      case '3':
+      case '4':
+      case '5':
+      case '6':
+      case '7':
+      case '8':
+      case '9':
+	n = *p1 - '0';
+	if (n < argc) strcpy(tmpbuf, argv[n]);
+	else          strcpy(tmpbuf, def);
+	break;
+      case '*':
+	nocopy=0;
+	for(n=2;n<argc;n++) {
+	  if (argv[n]==NULL) break;
+	  strcpy(tmpbuf, argv[n]);
+	  if (isalpha(*p1)) {
+	    if (isupper(*p1)) strupr(tmpbuf);
+	    else              strlwr(tmpbuf);
+	  }
+	  strcpy(p2, tmpbuf);
+	  p2 += strlen(tmpbuf);
+	}
+	break;
+      default:
+	strcpy(tmpbuf, "%");
+	break;
+      }
+      if (nocopy==1) {
+	if (isalpha(*p1)) {
+	  if (isupper(*p1)) strupr(tmpbuf);
+	  else              strlwr(tmpbuf);
+	}
+	strcpy(p2, tmpbuf);
+	p2 += strlen(tmpbuf);
+      }
+      p1 += skip;
+    } else
+      *p2++ = *p1++;
+  }
+  *p2 = 0;
+  return;
+}
+
+/* This function is straight from *NOS */
+
+static char *parse_string(char *str)
+{
+  char *cp = str;
+  unsigned long num;
+
+  while (*str != '\0' && *str != '\"') {
+    if (*str == '\\') {
+      str++;
+      switch (*str++) {
+      case 'n':  *cp++ = '\n';   break;
+      case 't':  *cp++ = '\t';   break;
+      case 'v':  *cp++ = '\v';   break;
+      case 'b':  *cp++ = '\b';   break;
+      case 'r':  *cp++ = '\r';   break;
+      case 'f':  *cp++ = '\f';   break;
+      case 'a':  *cp++ = '\007'; break;
+      case '\\': *cp++ = '\\';   break;
+      case '\"': *cp++ = '\"';   break;
+      case 'x':
+	num = strtoul(--str, &str, 16);
+	*cp++ = (char) num;
+	break;
+      case '0':
+      case '1':
+      case '2':
+      case '3':
+      case '4':
+      case '5':
+      case '6':
+      case '7':
+	num = strtoul(--str, &str, 8);
+	*cp++ = (char) num;
+	break;
+      case '\0':
+	return NULL;
+      default:
+	*cp++ = *(str - 1);
+	break;
+      };
+    } else {
+      *cp++ = *str++;
+    }
+  }
+  if (*str == '\"') str++; /* skip final quote */
+  *cp = '\0';	        /* terminate string */
+  return str;
+}
+
+int parse_args(char **argv, char *cmd)
+{
+  int ct = 0;
+  int quoted;
+
+  while (ct < 31) {
+    quoted = 0;
+    while (*cmd && isspace(*cmd)) cmd++;
+    if (*cmd == 0) break;
+    if (*cmd == '"') {
+      quoted++;
+      cmd++;
+    }
+    argv[ct++] = cmd;
+    if (quoted) {
+      if ((cmd = parse_string(cmd)) == NULL)
+	return 0;
+    } else {
+      while (*cmd && !isspace(*cmd)) cmd++;
+    }
+    if (*cmd) *cmd++ = 0;
+  }
+  argv[ct] = NULL;
+  return ct;
+}
+
+int cmdparse(struct cmd *list, char *cmdline)
+{
+  struct cmd *cmdp;
+  int argc;
+  char *argv[32];
+  static char cmdbuf[1024];
+
+  /* convert cmdline to argc,argv[]  if '#' or empty: return */
+  if ((argc = parse_args(argv, cmdline)) == 0 || *argv[0] == '#') return 2;
+  /* check if the command in argv[0] is in the list */
+  for (cmdp = list; cmdp != NULL; cmdp = cmdp->next) {
+    if (strlen(argv[0]) < cmdp->len || strlen(argv[0]) > strlen(cmdp->name)) continue;
+    if (strncasecmp(cmdp->name, argv[0], strlen(argv[0])) == 0) break;
+  }
+  if (cmdp == NULL) return -1;
+  strlwr(argv[0]);
+  switch (cmdp->type) {
+  case CMD_INTERNAL: /* execute internal command */
+    return (*cmdp->function)(argc, argv);
+  case CMD_ALIAS:
+    /* evaluate arguments */
+    expand_string(cmdbuf, cmdp->command, argc, argv);
+    aliascmd=1;
+    /* re-execute the command */
+    return cmdparse(list, cmdbuf);
+  case CMD_EXTERNAL:
+    /* evaluate arguments */
+    expand_string(cmdbuf, cmdp->command, argc, argv);
+    /* convert the cmdline to argc,argv[] */
+    argc = parse_args(argv, cmdbuf);
+    /* execute an external command */
+    if (User.ul_type == AF_NETROM) {
+      axio_printf(NodeIo, "%s} ", NodeId);
+    }
+    if (check_perms(PERM_ANSI, 0L) != -1) {
+      axio_printf(NodeIo,"\e[01;32mExecuting command...\e[0m\n");
+    } else {
+      axio_puts("Executing command... \n", NodeIo);
+    }
+    return extcmd(cmdp, argv);
+  }
+  return -1;
+}
+
+void insert_cmd(struct cmd **list, struct cmd *new)
+{
+  struct cmd *tmp, *p;
+
+  if (*list == NULL || strcasecmp(new->name, (*list)->name) < 0) {
+    tmp = *list;
+    *list = new;
+    new->next = tmp;
+  } else {
+    for (p = *list; p->next != NULL; p = p->next)
+      if (strcasecmp(new->name, p->next->name) < 0) break;
+    tmp = p->next;
+    p->next = new;
+    new->next = tmp;
+  }
+}
+
+int add_internal_cmd(struct cmd **list, char *name, int len, int (*function) (int argc, char **argv))
+{
+  struct cmd *new;
+
+  if ((new = calloc(1, sizeof(struct cmd))) == NULL) {
+    node_perror("add_internal_cmd: calloc", errno);
+    return -1;
+  }
+  new->name = strdup(name);
+  new->len = len;
+  new->type = CMD_INTERNAL;
+  new->function = function;
+  insert_cmd(list, new);
+  return 0;
+}
+
+void free_cmdlist(struct cmd *list)
+{
+  struct cmd *tmp;
+
+  while (list != NULL) {
+    free(list->name);
+    free(list->command);
+    free(list->path);
+    tmp = list;
+    list = list->next;
+    free(tmp);
+  }
+}
diff --git a/command.c b/command.c
new file mode 100644
index 0000000..53fbcbb
--- /dev/null
+++ b/command.c
@@ -0,0 +1,1058 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <time.h>
+#include <fcntl.h>
+#include <sys/utsname.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <netax25/ax25.h>
+#include <netrose/rose.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <arpa/inet.h>
+#include <netax25/axlib.h>
+#include <netax25/axconfig.h>
+#include <netax25/nrconfig.h>
+#include <netax25/rsconfig.h>
+#include <netax25/procutils.h>
+#include <netax25/mheard.h>
+
+#include "node.h"
+#include "procinfo.h"
+#include "sysinfo.h"
+
+struct cmd *Nodecmds = NULL;
+
+void init_nodecmds(void)
+{
+  add_internal_cmd(&Nodecmds, "?",        1, do_help);
+  add_internal_cmd(&Nodecmds, "Bye",      1, do_bye);
+  add_internal_cmd(&Nodecmds, "Escape",   1, do_escape);
+  if (User.ul_type == AF_INET) {
+    add_internal_cmd(&Nodecmds, "EXit",	  1, do_bye);
+  }
+  add_internal_cmd(&Nodecmds, "Help",     1, do_help);
+  add_internal_cmd(&Nodecmds, "Info",     1, do_help);
+  add_internal_cmd(&Nodecmds, "Quit",     1, do_bye);
+  add_internal_cmd(&Nodecmds, "Status",   1, do_status);
+  add_internal_cmd(&Nodecmds, "Version",  1, do_version);
+#ifdef HAVEMOTD
+  add_internal_cmd(&Nodecmds, "Who",      1, do_last);
+#endif
+  add_internal_cmd(&Nodecmds, "MSg",	  2, do_msg);
+#ifdef HAVE_AX25
+  add_internal_cmd(&Nodecmds, "Connect",  1, do_connect);
+  add_internal_cmd(&Nodecmds, "Links",    1, do_links);
+  add_internal_cmd(&Nodecmds, "INTerfaces",    3, do_ports);
+  add_internal_cmd(&Nodecmds, "SEssions", 2, do_sessions);
+  add_internal_cmd(&Nodecmds, "Users",    1, nuser_list);
+#ifdef HAVE_FLEX
+  add_internal_cmd(&Nodecmds, "Desti",    1, do_dest);
+#endif
+#ifdef HAVE_MHEARD
+  add_internal_cmd(&Nodecmds, "MHeard",   2, do_mheard);
+#endif
+#ifdef HAVE_NETROM
+  add_internal_cmd(&Nodecmds, "Nodes",    1, do_nodes);
+  add_internal_cmd(&Nodecmds, "Routes",   1, do_routes);
+#endif
+#endif
+#ifdef HAVE_TCPIP
+  add_internal_cmd(&Nodecmds, "Finger",   1, do_finger); 
+  add_internal_cmd(&Nodecmds, "HOst",     2, do_host);
+  add_internal_cmd(&Nodecmds, "Ping",     1, do_ping);
+  add_internal_cmd(&Nodecmds, "Telnet",   1, do_connect);
+#endif
+#ifdef HAVE_ZLIB_H
+  add_internal_cmd(&Nodecmds, "ZConnect", 1, do_connect);
+  add_internal_cmd(&Nodecmds, "ZTelnet",  1, do_connect);
+#endif
+};
+
+void node_prompt(const char *fmt, ...)
+{
+  if (User.ul_type == AF_NETROM) {
+    axio_printf(NodeIo,"%s} ", NodeId);
+  }
+  if ((User.ul_type == AF_INET) && (check_perms(PERM_ANSI, 0L) != -1)) {
+    axio_printf(NodeIo,"\r\n\e[01;31m%s\e[0m@\e[01;34m%s\e[0m:/uronode$ ",User.call, HostName);
+  }
+  if ((User.ul_type == AF_INET) && (check_perms(PERM_ANSI, 0L) == -1)) {
+    axio_printf(NodeIo,"\r\n%s@%s:/uronode$ ", User.call, HostName);
+  }
+  if ((User.ul_type == AF_AX25) && (check_perms(PERM_ANSI, 0L) != -1)) {
+    axio_printf(NodeIo,"\b\e[01;33m");
+  }
+  if (User.ul_type == AF_AX25) {
+    axio_printf(NodeIo,"%s",Prompt);
+  }
+  if ((User.ul_type == AF_ROSE) && (check_perms(PERM_ANSI, 0L) == -1))  {
+    axio_printf(NodeIo,"\r-=> ");
+  }
+  if ((User.ul_type == AF_ROSE) && (check_perms(PERM_ANSI, 0L) != -1)) {
+   axio_printf(NodeIo,"\r\e[01;35m-=>\e[0m  \b");
+  }
+  axio_flush(NodeIo);
+}
+
+void node_logout(char *reason)
+{
+#ifdef HAVEMOTD
+  if (User.ul_type == AF_INET) {
+    if (check_perms(PERM_ANSI, 0L) != -1) {
+      axio_printf(NodeIo, "\e[03;36m");
+    }
+    axio_printf(NodeIo, "Thank you %s, for connecting to the \n%s URONode packet shell.\n", User.call, HostName);
+    if (check_perms(PERM_ANSI, 0L) != -1) {
+      axio_printf(NodeIo, "\e[0;m");
+    }
+  } 
+  if (User.ul_type == AF_NETROM) {
+    axio_printf(NodeIo,"");
+  } 
+  if (User.ul_type == AF_ROSE) {
+      if (check_perms(PERM_ANSI, 0L) != -1) {
+      axio_printf(NodeIo, "\e[03;36m");
+    }   
+    axio_printf(NodeIo, "%s, thank you for connecting to the %s\nURONode ROSE network node. Come back again soon, 73!\r ", User.call, RoseId);
+    if (check_perms(PERM_ANSI, 0L) != -1) {
+      axio_printf(NodeIo, "\e[0;m\b");
+    }
+  } else 
+  if ((User.ul_type == AF_FLEXNET) || (User.ul_type == AF_AX25)) {
+    if (check_perms(PERM_ANSI, 0L) != -1) {
+      axio_printf(NodeIo, "\e[03;36m");
+    } 
+    axio_printf(NodeIo, "%s de %s\n73! ", User.call, FlexId);
+    if (check_perms(PERM_ANSI, 0L) != -1) {
+      axio_printf(NodeIo, "\e[0;m\b");
+    }
+  }
+#endif
+  axio_flush(NodeIo);
+  axio_end_all();
+  logout_user();
+  ipc_close();
+  node_log(LOGLVL_LOGIN, "%s @ %s logged out", User.call, User.ul_name);
+  node_log(LOGLVL_LOGIN, "%s %s", NodeId, reason);
+  free_cmdlist(Nodecmds);
+  Nodecmds = NULL;
+  exit(0);
+}
+
+int do_bye(int argc, char **argv)
+{
+  node_logout("User hit bye or quit");
+  return 0;	/* Keep gcc happy */
+}
+
+int do_escape(int argc, char **argv)
+{
+  int now = 0;
+
+  if (argc > 1) {
+    EscChar = get_escape(argv[1]);
+    now = 1;
+  }
+  if (EscChar < -1 || EscChar > 255) {
+    if (User.ul_type == AF_NETROM) {
+      node_msg("%s} ", NodeId);
+    }
+    node_msg("Invalid escape character: %s", argv[1]);
+    return 0;
+  }
+  
+  if (EscChar == -1) {
+    if (User.ul_type == AF_NETROM) {
+      axio_printf(NodeIo, "%s} ", NodeId);
+    }
+    axio_printf(NodeIo,"The escape mechanism is %sdisabled", now ? "now " : "");
+    if (User.ul_type == AF_NETROM) {
+      node_msg("");
+    }
+    return 0;
+  }
+  if (User.ul_type == AF_NETROM) {
+    axio_printf(NodeIo, "%s} ", NodeId);
+  }
+  axio_printf(NodeIo,"The escape character is %s%s%c", 
+	      now ? "now " : "",
+	      EscChar < 32 ? "CTRL-" : "",
+	      EscChar < 32 ? (EscChar + 'A' - 1) : EscChar);
+  if (User.ul_type == AF_NETROM) {
+    node_msg("");
+  }
+  return 0;
+}
+
+int do_help(int argc, char **argv)
+{
+  FILE *fp;
+  char fname[256], line[256];
+  struct cmd *cmdp;
+  int i = 0;
+
+  if (*argv[0] == '?') {                          /* "?"          */
+    if (User.ul_type == AF_NETROM) {
+      axio_printf(NodeIo, "%s} ", NodeId);
+    }
+    if (User.ul_type == AF_INET)  {
+      if (check_perms(PERM_ANSI, 0L) != -1) {
+	axio_printf(NodeIo, "\e[01;37m");
+      }
+      axio_printf(NodeIo, "Shell ");
+    }
+    if (check_perms(PERM_ANSI, 0L) != -1) {
+      axio_printf(NodeIo, "\e[01;37m");
+    }
+    axio_printf(NodeIo,"Commands:");
+    if (check_perms(PERM_ANSI, 0L) != -1) {
+      axio_printf(NodeIo, "\e[0;m");
+    }
+    for (cmdp = Nodecmds; cmdp != NULL; cmdp = cmdp->next) {
+      axio_printf(NodeIo,"%s%s", i ? ", " : "\n", cmdp->name);
+      if (++i == 10) {
+	axio_printf(NodeIo,"");
+	i = 0;
+      }
+    }
+    if (i) axio_printf(NodeIo,"");
+    if (User.ul_type == AF_NETROM) {
+      node_msg("");
+    }
+    return 0;
+  }
+  if (argv[1] && strchr(argv[1], '/')) {
+    if (User.ul_type == AF_NETROM) {
+      axio_printf(NodeIo,"%s} ", NodeId);
+    }
+    node_msg("Invalid command %s", argv[1]);
+    return 0;
+  }
+  if (*argv[0] == 'i') {                          /* "info"       */
+    strcpy(fname, CONF_NODE_INFO_FILE);
+    if (User.ul_type == AF_NETROM) {
+
+      axio_printf(NodeIo,"%s} ", NodeId);
+    }
+    if (check_perms(PERM_ANSI, 0L) != -1) {
+      axio_printf(NodeIo, "\e[01;37m");
+    }
+    axio_printf(NodeIo,"System Information:\n");
+    if (check_perms(PERM_ANSI, 0L) != -1) {
+      axio_printf(NodeIo, "\e[0;m");
+    }
+    axio_printf(NodeIo,"%s - %s \n", VERSION, COMPILING);
+  } else if (!argv[1]) {                 /* "help"       */
+    strcpy(fname, DATA_NODE_HELP_DIR "help.hlp");
+  } else {                               /* "help <cmd>" */
+    strlwr(argv[1]);
+    snprintf(fname, sizeof(fname), DATA_NODE_HELP_DIR "%s.hlp", argv[1]);
+    fname[sizeof(fname) - 1] = 0;
+  }
+  if ((fp = fopen(fname, "r")) == NULL) {
+    if (*argv[0] != 'i')
+      if (User.ul_type == AF_NETROM) {
+	axio_printf(NodeIo,"%s} ", NodeId);
+      }
+    axio_printf(NodeIo,"No help for command %s", argv[1] ? argv[1] : "help");
+    if (User.ul_type == AF_NETROM) {
+      node_msg("");
+    }
+    return 0;
+  }
+  if (User.ul_type == AF_NETROM) {
+    axio_printf(NodeIo,"%s} ", NodeId);
+  }
+  if (*argv[0] != 'i')
+    node_msg("Help for command %s", argv[1] ? argv[1] : "help"); 
+  while (fgets(line, 256, fp) != NULL)
+    axio_puts(line,NodeIo);
+  fclose(fp);
+  if (User.ul_type == AF_NETROM) {
+    node_msg("");
+  }
+  return 0;
+}
+
+int do_host(int argc, char **argv)
+{
+  struct hostent *h;
+  struct in_addr addr;
+  char **p, *cp;
+  
+  if (argc < 2) {
+    if (User.ul_type == AF_NETROM) {
+      axio_printf(NodeIo,"%s} ", NodeId);
+    }
+    node_msg("Usage: host <hostname>|<ip address>");
+    return 0;
+  }
+  if (inet_aton(argv[1], &addr) != 0)
+    h = gethostbyaddr((char *)&addr, sizeof(addr), AF_INET);
+  else
+    h = gethostbyname(argv[1]);
+  if (h == NULL) {
+    switch (h_errno) {
+    case HOST_NOT_FOUND:
+      cp = "Unknown host";
+      break;
+    case TRY_AGAIN:
+      cp = "Temporary name server error";
+      break;
+    case NO_RECOVERY:
+      cp = "Non-recoverable name server error";
+      break;
+    case NO_ADDRESS:
+      cp = "No address";
+      break;
+    default:
+      cp = "Unknown error";
+      break;
+    }
+    node_msg("%s", cp);
+    return 0;
+  }
+  if (User.ul_type == AF_NETROM) {
+    axio_printf(NodeIo,"%s} ", NodeId);
+  }
+  node_msg("Host name information for %s:", argv[1]);
+  axio_printf(NodeIo,"Hostname:    %s", h->h_name); 
+  axio_puts("\nAliases:    ",NodeIo);
+  p = h->h_aliases;
+  while (*p != NULL) {
+    axio_printf(NodeIo," %s", *p);
+    p++;
+  }
+  axio_puts("\nAddress(es):",NodeIo);
+  p = h->h_addr_list;
+  while (*p != NULL) {
+    addr.s_addr = ((struct in_addr *)(*p))->s_addr;
+    axio_printf(NodeIo," %s", inet_ntoa(addr));
+    p++;
+  }
+  if (User.ul_type == AF_NETROM) {
+    node_msg("");
+  }
+  return 0;
+}
+
+int do_ports(int argc, char **argv)
+{
+  struct proc_ax25 *ax, *ax_list;
+  struct proc_dev *dev, *dev_list;
+  char *cp = NULL;
+  int n, tx, rx;
+  
+  ax_list=read_proc_ax25();
+  dev_list=read_proc_dev();
+  if (User.ul_type == AF_NETROM) {
+    axio_printf(NodeIo,"%s} ", NodeId);
+  }
+  if (check_perms(PERM_ANSI, 0L) != -1) {
+    axio_printf(NodeIo, "\e[01;35m");
+  }
+  node_msg("Interfaces:");
+  if (check_perms(PERM_ANSI, 0L) != -1) {
+    axio_printf(NodeIo, "\e[0;m");
+  }
+  axio_printf(NodeIo,"Name    Description                                 QSO  RX packets  TX packets\n");
+  axio_printf(NodeIo,"------- ------------------------------------------ ---- ----------- -----------");
+  while ((cp = ax25_config_get_next(cp)) != NULL) {
+    n=0;
+    if (ax_list) for (ax=ax_list;ax!=NULL;ax=ax->next) {
+	//      		if (strcmp(ax25_config_get_name(ax->dev), cp)==0 && strcmp(ax->dest_addr, "*")!=0) n++;
+	if (strcmp(ax->dest_addr, "*")!=0 && strcmp(ax25_config_get_name(ax->dev), cp)==0) n++;
+      }
+    tx=0; rx=0;
+    if (dev_list) for (dev=dev_list;dev!=NULL;dev=dev->next) {
+	if (strcmp(dev->interface, ax25_config_get_dev(cp))==0) {
+	  tx=dev->tx_packets;
+	  rx=dev->rx_packets;
+	}
+      }
+    if (is_hidden(cp) && check_perms(PERM_HIDDEN, 0L) == -1)
+      continue;
+    axio_printf(NodeIo,"\n%-7.7s %-42.42s %4d %11d %11d", cp, ax25_config_get_desc(cp), n, rx, tx);
+  }
+
+  free_proc_ax25(ax_list);
+  free_proc_dev(dev_list);
+  if (User.ul_type == AF_NETROM) {
+    node_msg("");
+  }
+  return 0;
+}
+
+int do_sessions(int argc, char **argv)
+{
+  struct proc_ax25 *ax_p, *ax_list;
+#ifdef HAVE_NETROM
+  struct proc_nr *nr_p, *nr_list;
+#endif
+  char *cp;
+
+  if (User.ul_type == AF_NETROM) {
+    axio_printf(NodeIo,"%s} %s\n", NodeId, VERSION);
+  }
+  if ((ax_list = read_proc_ax25()) == NULL) {
+    if (errno) node_perror("sessions: read_proc_ax25:", errno);
+    else axio_printf (NodeIo,"No such AX25 sessions actives.");
+    
+  } else {
+    if (check_perms(PERM_ANSI, 0L) != -1) {
+      axio_printf(NodeIo, "\e[01;33m");
+    }
+    node_msg("AX.25 Sessions:");
+    if (check_perms(PERM_ANSI, 0L) != -1) {
+      axio_printf(NodeIo,"\e[0;m");
+    }
+    axio_printf(NodeIo,"Int.    Dest addr Src addr  State        Unack T1      Retr   Rtt Snd-Q Rcv-Q\n");
+    axio_printf(NodeIo,"------- --------- --------- ------------ ----- ------- ------ --- ----- -----\n");
+    for (ax_p = ax_list; ax_p != NULL; ax_p = ax_p->next) {
+      if (argc > 1 && strcasecmp(argv[1], "*") && strcasecmp(ax_p->dest_addr, argv[1]) && 
+	  strcasecmp(ax_p->src_addr, argv[1])) continue;
+      if ((argc < 2) && !strcmp(ax_p->dest_addr, "*"))
+	continue;
+      cp = ax25_config_get_name(ax_p->dev);
+      axio_printf(NodeIo,"%-7s %-9s %-9s ", cp, ax_p->dest_addr, ax_p->src_addr);
+      if (!strcmp(ax_p->dest_addr, "*")) {
+	axio_printf(NodeIo,"Listening\n");
+	continue;
+      }
+      switch (ax_p->st) {
+      case 0:
+	cp = "Disconnected";
+	break;
+      case 1:
+	cp = "Conn pending";
+	break;
+      case 2:
+	cp = "Disc pending";
+	break;
+      case 3:
+	cp = "Connected   ";
+	break;
+      case 4:
+	cp = "Recovery    ";
+	break;
+      default:
+	cp = "Unknown     ";
+	break;
+      }
+      axio_printf(NodeIo,"%s %02d/%02d %03d/%03d %02d/%03d %3d %5ld %5ld\n",
+		  cp,
+		  ax_p->vs < ax_p->va ? ax_p->vs - ax_p->va + 8 : ax_p->vs - ax_p->va,
+		  ax_p->window,
+		  ax_p->t1timer, ax_p->t1,
+		  ax_p->n2count, ax_p->n2,
+		  ax_p->rtt,
+		  ax_p->sndq, ax_p->rcvq);
+    }
+    free_proc_ax25(ax_list);
+    axio_puts("",NodeIo);
+  }
+
+#ifdef HAVE_NETROM
+  if ((nr_list = read_proc_nr()) == NULL) {
+    if (errno) node_perror("sessions: read_proc_nr", errno);
+    else axio_printf (NodeIo,"No such NET/ROM sessions actives.\n");
+  } else {
+    if (check_perms(PERM_ANSI, 0L) != -1) {
+      axio_printf(NodeIo, "\e[01;36m");
+    }
+    node_msg("\nNET/ROM Sessions:");
+    if (check_perms(PERM_ANSI, 0L) != -1) {
+      axio_printf(NodeIo, "\e[0;m");
+    }
+    axio_printf(NodeIo,"User addr Dest node Src node  State        Unack T1      Retr   Snd-Q Rcv-Q\n");
+    axio_printf(NodeIo,"--------- --------- --------- ------------ ----- ------- ------ ----- -----");
+    for (nr_p = nr_list; nr_p != NULL; nr_p = nr_p->next) {
+      if (argc > 1 && strcasecmp(argv[1], "*") && strcasecmp(nr_p->user_addr, argv[1]) && 
+	  strcasecmp(nr_p->dest_node, argv[1]) && strcasecmp(nr_p->src_node, argv[1])) continue;
+      if ((argc < 2) && !strcmp(nr_p->user_addr, "*")) continue;
+      cp = nr_config_get_name(nr_p->dev);
+      axio_printf(NodeIo,"\n%-9s %-9s %-9s ", nr_p->user_addr, nr_p->dest_node, nr_p->src_node);
+      if (!strcmp(nr_p->user_addr, "*")) {
+	axio_printf(NodeIo,"Listening\n");
+	continue;
+      }
+      switch (nr_p->st) {
+      case 0:
+	cp = "Disconnected";
+	break;
+      case 1:
+	cp = "Conn pending";
+	break;
+      case 2:
+	cp = "Disc pending";
+	break;
+      case 3:
+	cp = "Connected   ";
+	break;
+      case 4:
+	cp = "Recovery    ";
+	break;
+      default:
+	cp = "Unknown     ";
+	break;
+      }
+      axio_printf(NodeIo,"%s %02d/%02d %03d/%03d %02d/%03d %5ld %5ld",
+		  cp,
+		  nr_p->vs < nr_p->va ? nr_p->vs - nr_p->va + 8 : nr_p->vs - nr_p->va,
+		  nr_p->window,
+		  nr_p->t1timer, nr_p->t1,
+		  nr_p->n2count, nr_p->n2,
+		  nr_p->sndq, nr_p->rcvq);
+    }
+    free_proc_nr(nr_list);
+  }
+
+#endif
+  if (User.ul_type == AF_NETROM) {
+    node_msg("");
+  }
+  return 0;
+}
+
+int do_routes(int argc, char **argv)
+{
+  struct proc_nr *nr, *nr_list;
+  struct proc_nr_neigh *nrh, *nrh_list;
+  struct proc_nr_nodes *nrn, *nrn_list;
+  struct proc_ax25 *ap;
+  char *cp, portcall[10];
+  int link, n;
+
+  nr_list=read_proc_nr();
+  nrn_list=read_proc_nr_nodes();
+  if ((nrh_list = read_proc_nr_neigh()) == NULL) {
+    if (errno) node_perror("do_routes: read_proc_nr_neigh", errno);
+    else 
+      if (User.ul_type == AF_NETROM) {
+	axio_printf(NodeIo,"%s} ", NodeId);
+      }
+    axio_printf (NodeIo,"No such routes");
+    if (User.ul_type == AF_NETROM) {
+      node_msg("");
+    }
+    free_proc_nr_neigh(nrh_list);
+    free_proc_nr_nodes(nrn_list);
+    free_proc_nr(nr_list);
+
+    return 0;
+  }
+  /*	if (check_perms(PERM_ANSI, 0L) != -1) {
+	axio_printf(NodeIo, "\e[01;33m");
+	} */
+  if (User.ul_type == AF_NETROM) {
+    axio_printf(NodeIo,"%s} ", NodeId);
+  }
+  if (check_perms(PERM_ANSI, 0L) != -1) {
+    axio_printf(NodeIo, "\e[01;36m");
+  }
+  node_msg("Routes:");
+  if (check_perms(PERM_ANSI, 0L) != -1) {
+    axio_printf(NodeIo, "\e[0;m");
+  }
+  axio_printf(NodeIo,"Link Intface Callsign  Qual Nodes Lock  QSO\n");
+  axio_printf(NodeIo,"---- ------- --------- ---- ----- ----  ---");
+  strcpy(portcall,nr_config_get_addr(nr_config_get_next(NULL)));
+  if (strchr(portcall, '-')==NULL) strcat(portcall, "-0");  
+  for (nrh = nrh_list; nrh != NULL; nrh = nrh->next) {
+    link=0; n=0;
+    if ((ap = find_link(portcall, nrh->call, nrh->dev)) != NULL && ap->st >= 3) link = 1;
+    if ((ap = find_link(nrh->call, portcall, nrh->dev)) != NULL && ap->st >= 3) link = 2;
+    cp = ax25_config_get_name(nrh->dev);
+
+    if (nr_list) for (nr=nr_list;nr!=NULL;nr=nr->next) {
+	if (strcmp(nr->dest_node, nrh->call)==0) {
+	  n++;
+	} else {
+	  if (nrn_list) for(nrn=nrn_list;nrn!=NULL;nrn=nrn->next) {
+	      if (strcmp(nrn->call, nr->dest_node)==0) {
+		switch(nrn->w) {
+		case 1: if (nrn->addr1==nrh->addr) n++; break;
+		case 2: if (nrn->addr2==nrh->addr) n++; break;
+		case 3: if (nrn->addr3==nrh->addr) n++; break;
+		}
+	      }
+	    }
+	}
+      }
+    
+    axio_printf(NodeIo,"\n%c    %-7s %-9s %4d %5d    %c %4d",
+		link == 0 ? ' ' : '>',
+		cp,
+		nrh->call,
+		nrh->qual,
+		nrh->cnt,
+		nrh->lock == 1 ? '!' : ' ',
+		n);
+  }
+
+  free_proc_nr_neigh(nrh_list);
+  free_proc_nr_nodes(nrn_list);
+  free_proc_nr(nr_list);
+  free_proc_ax25(ap);
+  if (User.ul_type == AF_NETROM) {
+    node_msg("");
+  }
+  return 0;
+}
+
+int do_nodes(int argc, char **argv)
+{
+  struct proc_nr_nodes *p, *list;
+  struct proc_nr_neigh *np, *nlist;
+  int i = 0;
+  if (User.ul_type == AF_NETROM) {
+    axio_printf(NodeIo,"%s} ", NodeId);
+  }
+  if ((list = read_proc_nr_nodes()) == NULL) {
+    if (errno)
+      node_perror("do_nodes: read_proc_nr_nodes", errno);
+    else 
+      axio_printf(NodeIo,"No known nodes");
+    if (User.ul_type == AF_NETROM) {
+      node_msg("");
+    }
+    return 0;
+  }
+  /* "nodes" */
+  if (argc == 1) {
+    if (check_perms(PERM_ANSI, 0L) != -1) {
+      axio_printf(NodeIo, "\e[01;36m");
+    } else if (check_perms(PERM_ANSI, 0L) == -1) {
+      axio_printf(NodeIo, "");
+    }
+    if (check_perms(PERM_ANSI, 0L) != -1) {
+      axio_printf(NodeIo, "\e[01;36m");
+    }
+    node_msg("Nodes:");
+    if (check_perms(PERM_ANSI, 0L) != -1) {
+      axio_printf(NodeIo, "\e[0;m");
+    }
+    for (p = list; p != NULL; p = p->next) {
+      axio_printf(NodeIo,"%-16.16s %c",print_node(p->alias, p->call),(++i % 4) ? ' ' : '\n');
+    }
+    if ((User.ul_type == AF_NETROM) && (i % 4) != 0) {
+	node_msg("");
+    }
+    free_proc_nr_nodes(list);
+    return 0;
+  }
+  if ((nlist = read_proc_nr_neigh()) == NULL) {
+    node_perror("do_nodes: read_proc_nr_neigh", errno);
+    if (User.ul_type == AF_NETROM) {
+      node_msg("");
+    } 
+    return 0; 
+  }
+  /* "nodes *" */
+  if (*argv[1] == '*') {
+    if (check_perms(PERM_ANSI, 0L) != -1) {
+      axio_printf(NodeIo, "\e[01;36m");
+    }
+
+    node_msg("Detailed nodes listing:");
+    if (check_perms(PERM_ANSI, 0L) != -1) {
+      axio_printf(NodeIo, "\e[0;m");
+    }
+    axio_printf(NodeIo,"Node              Qual Obs Intface Neighbour\n");
+    axio_printf(NodeIo,"----------------- ---- --- ------- ---------");
+    for (p = list; p != NULL; p = p->next) {
+      axio_printf(NodeIo,"\n%-16.16s  ", print_node(p->alias, p->call));
+      if ((np = find_neigh(p->addr1, nlist)) != NULL) {
+	axio_printf(NodeIo,"%4d %3d %-7s %s",p->qual1,p->obs1,ax25_config_get_name(np->dev),np->call);
+      }
+      else if (p->n > 1 && (np = find_neigh(p->addr2, nlist)) != NULL) {
+	axio_printf(NodeIo,"                  ");
+	axio_printf(NodeIo,"%7d %12d %-7s %s",p->qual2, p->obs2,ax25_config_get_name(np->dev),np->call);
+      }
+      else if (p->n > 2 && (np = find_neigh(p->addr3, nlist)) != NULL) {
+	axio_printf(NodeIo,"                  ");
+	axio_printf(NodeIo,"%7d %12d %-7s %s",p->qual3, p->obs3,ax25_config_get_name(np->dev),np->call);
+      }
+      else if (p->n == 0) axio_puts("",NodeIo); 
+    }
+    free_proc_nr_nodes(list);
+    free_proc_nr_neigh(nlist);
+    if (User.ul_type == AF_NETROM) {
+      node_msg("");
+    }
+    return 0;
+  }
+  /* "nodes <node>" */
+  p = find_node(argv[1], list);
+  if (p != NULL) {
+    if (p->n == 0)  axio_printf(NodeIo,"Local node without routes: %s", print_node(p->alias, p->call));
+    else {
+      if (check_perms(PERM_ANSI, 0L) != -1) {
+	axio_printf(NodeIo, "\e[01;36m");
+      }
+      node_msg("Routes to: %s", print_node(p->alias, p->call));
+      if (check_perms(PERM_ANSI, 0L) != -1) {
+	axio_printf(NodeIo, "\e[0;m");
+      }
+      axio_printf(NodeIo,"Which Qual Obs Intface Neighbour\n");
+      axio_printf(NodeIo,"----- ---- --- ------- ---------");
+
+      if ((np = find_neigh(p->addr1, nlist)) != NULL) {
+	axio_printf(NodeIo,"\n%c     %4d %3d %-7s %s",p->w == 1 ? '>' : ' ',p->qual1,p->obs1,
+		    ax25_config_get_name(np->dev),np->call);
+      }
+      if (p->n > 1 && (np = find_neigh(p->addr2, nlist)) != NULL) {
+	axio_printf(NodeIo,"\n%c     %4d %3d %-7s %s",p->w == 2 ? '>' : ' ',p->qual2, p->obs2,
+		    ax25_config_get_name(np->dev),np->call);
+      }
+      if (p->n > 1 && (np = find_neigh(p->addr3, nlist)) != NULL) {
+	axio_printf(NodeIo,"\n%c     %4d %3d %-7s %s",p->w == 3 ? '>' : ' ',p->qual3, p->obs3,
+		    ax25_config_get_name(np->dev),np->call);
+      }
+    }
+  } else {
+    axio_printf(NodeIo,"No such node");
+  }
+  free_proc_nr_nodes(list);
+  free_proc_nr_neigh(nlist);
+  if (User.ul_type == AF_NETROM) {
+    node_msg("");
+  }
+  return 0;
+}
+
+/*
+ * by Heikki Hannikainen <hessu at pspt.fi> 
+ * The following was mostly learnt from the procps package and the
+ * gnu sh-utils (mainly uname).
+ */
+int do_status(int argc, char **argv)
+{
+  int upminutes, uphours, updays;
+  double uptime_secs, idle_secs;
+  double av[3];
+  unsigned **mem;
+  struct utsname name;
+  time_t t;
+#ifdef HAVE_AX25
+  struct flex_dst *fd, *fd_list;
+  struct ax_routes *ar, *ar_list;
+  struct proc_ax25 *ax, *ax_list;
+#ifdef HAVE_NETROM
+  struct proc_nr *nr, *nr_list;
+  struct proc_nr_nodes *nop, *nolist;
+  struct proc_nr_neigh *nep, *nelist;
+  int n, r, nn;
+#endif
+  int na, nl, nd;
+#endif
+  int ma, mu, mf, sa, su, sf;
+  if (User.ul_type == AF_NETROM) {
+    axio_printf(NodeIo,"%s} ", NodeId);
+  }
+  if (check_perms(PERM_ANSI, 0L) != -1) {
+    axio_printf(NodeIo, "\e[01;37m");
+  }
+  node_msg("Status:");
+  if (check_perms(PERM_ANSI, 0L) != -1) {
+    axio_printf(NodeIo, "\e[0;m");
+  }
+  time(&t);
+  axio_printf(NodeIo,"System time:       %s", ctime(&t));
+  if (uname(&name) == -1) axio_printf(NodeIo,"Cannot get system name\n");
+  else {
+    axio_printf(NodeIo,"Hostname:          %s\n", HostName);  
+    axio_printf(NodeIo,"Operating system:  %s %s (%s)\n", name.sysname, name.release, name.machine);
+  }
+  /* read and calculate the amount of uptime and format it nicely */
+  uptime(&uptime_secs, &idle_secs);
+  updays = (int) uptime_secs / (60*60*24);
+  upminutes = (int) uptime_secs / 60;
+  uphours = upminutes / 60;
+  uphours = uphours % 24;
+  upminutes = upminutes % 60;
+  axio_printf(NodeIo,"Uptime:            ");
+  if (updays) axio_printf(NodeIo,"%d day%s, ", updays, (updays != 1) ? "s" : "");
+  if(uphours) axio_printf(NodeIo,"%d hour%s ", uphours, (uphours != 1) ? "s" : "");
+  axio_printf(NodeIo,"%d minute%s\n", upminutes, (upminutes != 1) ? "s" : "");
+  loadavg(&av[0], &av[1], &av[2]);
+  axio_printf(NodeIo,"Load average:      %.2f, %.2f, %.2f\n", av[0], av[1], av[2]);
+  axio_printf(NodeIo,"Users:             %d node, %d system\n", user_count(), system_user_count());
+
+  if (!(mem = meminfo()) || mem[meminfo_main][meminfo_total] == 0) {
+    /* cannot normalize mem usage */
+    axio_printf(NodeIo,"Cannot get memory information!\n"); 
+  } else  {
+    ma = mem[meminfo_main][meminfo_total];
+    mu = (mem[meminfo_main][meminfo_total] - mem[meminfo_free][meminfo_total]);
+    mf = mem[meminfo_free][meminfo_total];
+    axio_printf(NodeIo,"Memory:            Available  Used       Free       perc. Used\n");
+    axio_printf(NodeIo,"------------------ ---------- ---------- ---------- ----------\n");
+    axio_printf(NodeIo,"Physical:          %-7d kB %-7d kB %-7d kB %3d %%\n", ma, mu, mf, (mu*100)/ma);
+    
+    if  (!(mem = meminfo()) || mem[meminfo_stotal][meminfo_total] != 0) 
+{ 
+    sa = mem[meminfo_stotal][meminfo_total]; 
+    su = (mem[meminfo_stotal][meminfo_total] - mem[meminfo_sfree][meminfo_total]);
+    sf = mem[meminfo_sfree][meminfo_total];
+    axio_printf(NodeIo,"Swap:              %-7d kB %-7d kB %-7d kB %3d %%\n",sa,su,sf,(su*100)/sa);   
+    } 
+    else 
+/*    axio_printf(NodeIo,"Cannot get swap information!\n"); */
+      axio_printf(NodeIo," ");
+    
+  }
+
+#ifdef HAVE_AX25
+#ifdef HAVE_NETROM
+  if ((nolist = read_proc_nr_nodes()) == NULL && errno != 0)
+    node_perror("sessions: read_proc_nr_nodes", errno);
+  n = 0;
+  for (nop = nolist; nop != NULL; nop = nop->next)
+    n++;
+  free_proc_nr_nodes(nolist);
+  if ((nelist = read_proc_nr_neigh()) == NULL && errno != 0)
+    node_perror("sessions: read_proc_nr_neigh", errno);
+  r = 0;
+  for (nep = nelist; nep != NULL; nep = nep->next)
+    r++;
+  free_proc_nr_neigh(nelist);
+#endif
+  na=0;
+  ax_list=read_proc_ax25();
+  if (ax_list) for (ax=ax_list;ax!=NULL;ax=ax->next) {
+      if (strcmp(ax->dest_addr, "*")==0) continue;
+      na++;
+    }
+  free_proc_ax25(ax_list);
+#ifdef HAVE_NETROM
+  nn=0;
+  nr_list=read_proc_nr();
+  if (nr_list) for (nr=nr_list;nr!=NULL;nr=nr->next) {
+      if (strcmp(nr->dest_node, "*")==0) continue;
+      nn++;
+    }
+  free_proc_nr(nr_list);
+#endif
+  nl=0;
+  ar_list=read_ax_routes();
+  if (ar_list) for (ar=ar_list;ar!=NULL;ar=ar->next) {
+      nl++;
+    }
+  free_ax_routes(ar_list);
+  nd=0;
+  fd_list=read_flex_dst();
+  if (fd_list) for (fd=fd_list;fd!=NULL;fd=fd->next) {
+      nd++;
+    }
+  free_flex_dst(fd_list);
+
+  axio_printf(NodeIo,"Sockets:           Sessions   Dest/Nodes Links/Routes\n");
+  axio_printf(NodeIo,"------------------ ---------- ---------- ------------\n");
+  axio_printf(NodeIo,"AX25:              %-10d %-10d %-10d\n",na,nd,nl);
+#ifdef HAVE_NETROM
+  axio_printf(NodeIo,"NET/ROM:           %-10d %-10d %-10d",nn,n,r);
+#endif
+#endif
+  if (User.ul_type == AF_NETROM) {
+    node_msg("");
+  }
+  return 0;
+}
+
+int do_version(int argc, char **argv)
+{
+  if (User.ul_type != AF_NETROM) {
+    if (check_perms(PERM_ANSI, 0L) != -1) {
+      axio_printf(NodeIo,"\e[01;37mShell    : %s\n\e[01;35mHostname : %s\n\e[01;33max25/Flex: %s\n\e[01;36mNetRom   : %s\n\e[01;35mRose     : %s \e[0;m", VERSION, HostName, FlexId, NodeId, RoseId); 
+      return 0;
+    }
+    if (check_perms(PERM_ANSI, 0L) == -1) {
+      axio_printf(NodeIo,"Shell    : %s\nHostname : %s\nax25/Flex: %s\nNetRom   : %s\nRose     : %s", VERSION, HostName, FlexId, NodeId, RoseId);
+      return 0;
+    }
+    /*
+      if (User.ul_type != AF_NETROM) {
+      axio_printf(NodeIo, "Version  : %s\nax25/Flex: %s\nNetRom   : %s", VERSION, FlexId, NodeId);
+      return 0;
+      }
+    */
+  } else
+    axio_printf(NodeIo,"%s} ", NodeId);
+  if (check_perms(PERM_ANSI ,0L) != -1) {
+    axio_printf(NodeIo,"\e[01;37m");
+  }
+  axio_printf(NodeIo,"%s", VERSION);
+  node_msg("");
+  if (check_perms(PERM_ANSI ,0L) != -1) {
+    axio_printf(NodeIo,"\e[0;m");
+  }
+  return 0;
+}
+int nuser_list(int argc, char **argv)
+{
+  FILE *f;
+  struct user u;
+  struct tm *tp;
+  struct proc_nr_nodes *np;
+  char buf[80];
+  long l;
+  axio_puts("",NodeIo);
+  if ((f = fopen(DATA_NODE_LOGIN_FILE, "r")) == NULL) {
+    node_perror(DATA_NODE_LOGIN_FILE, errno);
+    return 0;
+  }
+  if (User.ul_type == AF_NETROM) {
+    axio_printf(NodeIo, "%s} ", NodeId);
+  }
+  if (check_perms(PERM_ANSI, 0L) != -1) {
+    axio_printf(NodeIo, "\e[01;37m");
+  } 
+  if (User.ul_type == AF_NETROM) {
+    /*	   axio_printf(NodeIo, "\e[0;m%s} %s", NodeId, VERSION); */
+    axio_printf(NodeIo, "%s", VERSION);
+  } else {
+    axio_printf(NodeIo, "Current users:");
+  }
+  if (user_count() == 0) {
+    axio_printf(NodeIo, " No users online.\n");
+  }
+  if (check_perms(PERM_ANSI, 0L) != -1) {
+    axio_printf(NodeIo,"\e[0;m");
+  }
+  if (user_count() != 0) /* axio_printf(NodeIo,"") */ ;
+  while (fread(&u, sizeof(u), 1, f) == 1) {
+    if (u.pid == -1 || (kill(u.pid, 0) == -1 && errno == ESRCH))
+      continue;
+    switch (u.ul_type) {
+    case AF_FLEXNET:
+      sprintf(buf, "\nFlexNet (%.9s)",
+	      u.call);
+      break;
+    case AF_AX25:
+      sprintf(buf, "\nUplink (%.9s on interface %.10s)",
+	      u.call, u.ul_name);
+      break;
+    case AF_NETROM:
+      if ((np = find_node(u.ul_name, NULL)) != NULL) {
+	sprintf(buf, "\nCircuit (%.9s %.18s)",
+		u.call,
+		print_node(np->alias, np->call));
+      } else {
+	sprintf(buf, "\nCircuit (%.9s %.18s)",
+		u.call, u.ul_name);
+      }
+      break;
+#ifdef HAVE_ROSE
+    case AF_ROSE:
+      sprintf(buf, "\nROSE (%.9s %.18s)",
+	      u.call, u.ul_name);
+      break;
+#endif
+    case AF_INET:
+      sprintf(buf, "\nTelnet (%.9s @ %.16s)",
+	      u.call, u.ul_name);
+      break;
+    case AF_UNSPEC:
+      sprintf(buf, "\nHost (%.9s on local)",
+	      u.call);
+      break;
+    default:
+      sprintf(buf, "\n?????? (%.9s %.18s)",
+	      u.call, u.ul_name);
+      break;
+    }
+    axio_printf(NodeIo,"%-37.37s ", buf);
+    switch (u.state) {
+    case STATE_QUIT:
+      logout_user();
+      break;
+    case STATE_LOGIN:
+      axio_puts("  -> Logging in",NodeIo);
+      break;
+    case STATE_IDLE:
+      time(&l);
+      l -= u.cmdtime;
+      tp = gmtime(&l);
+      axio_printf(NodeIo,"  -> Idle (%d:%02d:%02d:%02d)",
+		  tp->tm_yday, tp->tm_hour,
+		  tp->tm_min, tp->tm_sec);
+      break;
+    case STATE_TRYING:
+      switch (u.dl_type) {
+      case AF_FLEXNET:
+	axio_printf(NodeIo,"  -> Trying (%s)",
+		    u.dl_name);
+	break;
+      case AF_AX25:
+	axio_printf(NodeIo,"  -> Trying (%s on interface %s)",
+		    u.dl_name, u.dl_port);
+	break;
+      case AF_NETROM:
+	axio_printf(NodeIo,"  -> Trying (%s)",
+		    u.dl_name);
+	break;
+#ifdef HAVE_ROSE
+      case AF_ROSE:
+	axio_printf(NodeIo,"  -> Trying (%s)",
+		    u.dl_name);
+	break;
+#endif
+      case AF_INET:
+	axio_printf(NodeIo,"  -> Trying (%s:%s)",
+		    u.dl_name, u.dl_port);
+	break;
+      default:
+	axio_puts("  -> ???",NodeIo);
+	break;
+      }
+      break;
+    case STATE_CONNECTED:
+      switch (u.dl_type) {
+      case AF_FLEXNET:
+	axio_printf(NodeIo,"<--> FlexNet (%s)",
+		    u.dl_name);
+	break;
+      case AF_AX25:
+	axio_printf(NodeIo,"<--> Downlink (%s on interface %s)",
+		    u.dl_name, u.dl_port);
+	break;
+      case AF_NETROM:
+	axio_printf(NodeIo,"<--> Circuit (%s)",
+		    u.dl_name);
+	break;
+#ifdef HAVE_ROSE
+      case AF_ROSE:
+	axio_printf(NodeIo,"<--> ROSE (%s)",
+		    u.dl_name);
+	break;
+#endif
+      case AF_INET:
+	axio_printf(NodeIo,"<--> Telnet (%s:%s)",
+		    u.dl_name, u.dl_port);
+	break;
+      default:
+	axio_printf(NodeIo,"<--> ???");
+	break;
+      }
+      break;
+    case STATE_PINGING:
+      axio_printf(NodeIo,"<--> Pinging (%s)", u.dl_name);
+      break;
+    case STATE_EXTCMD:
+      axio_printf(NodeIo,"<--> Extcmd  (%s)", u.dl_name);
+      break;
+    }
+    axio_puts("",NodeIo);
+  }
+  if (User.ul_type == AF_NETROM) {
+    node_msg("");
+  }
+  fclose(f);
+  return 0;
+}
diff --git a/config.c b/config.c
new file mode 100644
index 0000000..f222db6
--- /dev/null
+++ b/config.c
@@ -0,0 +1,485 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <pwd.h>
+#include <netax25/ax25.h>			/* axutils.h needs this...	*/
+#include <netrose/rose.h>
+#include <netax25/axlib.h>
+#include <netax25/axconfig.h>
+
+#include "node.h"
+
+long IdleTimeout	= 360L;		/* default to 6 mins */
+long ConnTimeout	= 300L;		/* default to 5 mins */
+int ReConnectTo		= 0;
+int LogLevel		= LOGLVL_ERROR;
+int EscChar		= 20;		/* CTRL-T */
+
+char *Email		= NULL;
+char *HostName		= NULL;
+char *NodeId		= NULL;
+char *NrPort		= NULL;		/* first netrom port */
+char *FlexId		= NULL;
+char *RoseId		= NULL;
+
+#ifdef HAVEMOTD
+char *Prompt		= "\n=> ";        /* Prompt by IZ5AWZ */
+#else
+char *Prompt		= "\n";
+#endif
+char *PassPrompt	= "\nPassword >";      /* Prompt Password by IZ5AWZ */
+
+static unsigned long Permissions	= 0L;
+static unsigned long LocalNet		= 0L;
+static unsigned long LocalMask		= ~0L;
+static char *HiddenPorts[32]		= {0};
+
+/*
+ * Return non-zero if `port' is a hidden port.
+ */
+int is_hidden(const char *port)
+{
+  int i;
+
+  for (i = 0; HiddenPorts[i] != NULL && i < 31; i++)
+    if (!strcmp(port, HiddenPorts[i]))
+      return 1;
+  return 0;
+}
+
+/*
+ * Return non-zero if peer is on "local" or loopback network.
+ */
+static int is_local(unsigned long peer)
+{
+  return ((peer & LocalMask) == LocalNet) || ((peer & 0xff) == 127);
+}
+
+/*
+ * Return non-zero if peer is on amprnet.
+ */
+static int is_ampr(unsigned long peer)
+{
+  return ((peer & 0xff) == 44);
+}
+
+/*
+ * Convert NOS style width to a netmask in network byte order.
+ */
+static unsigned long bits_to_mask(int bits)
+{
+  return htonl(~0L << (32 - bits));
+}
+
+int check_perms(int what, unsigned long peer)
+{
+  if (what == PERM_TELNET) {
+    if (is_local(peer)) {
+      if (Permissions & PERM_TELNET_LOCAL)
+	return 0;
+    } else if (is_ampr(peer)) {
+      if (Permissions & PERM_TELNET_AMPR)
+	return 0;
+    } else {
+      if (Permissions & PERM_TELNET_INET)
+	return 0;
+    }
+    return -1;
+  }
+  if ((Permissions & what) == 0) {
+    return -1;
+  }
+  return 0;
+}
+
+/*
+ * Read permissions file and return a password if needed or "*" if not.
+ * If user access is denied return NULL.
+ */
+char *read_perms(struct user *up, unsigned long peer)
+{
+  FILE *fp;
+  char line[256], *argv[32], *cp;
+  int argc, n = 0;
+
+  if ((fp = fopen(CONF_NODE_PERMS_FILE, "r")) == NULL) {
+    node_perror(CONF_NODE_PERMS_FILE, errno);
+    return NULL;
+  }
+  if ((cp = strchr(up->call, '-')) != NULL)
+    *cp = 0;
+  while (fgets(line, 256, fp) != NULL) {
+    n++;
+    argc = parse_args(argv, line);
+    if (argc == 0 || *argv[0] == '#')
+      continue;
+    if (argc != 5) {
+      node_msg("Configuration error");
+      node_log(LOGLVL_ERROR, "Syntax error in permission file at line %d", n);
+      break;
+    }
+    if (strcmp(argv[0], "*") && strcasecmp(argv[0], up->call))
+      continue;
+    switch (up->ul_type) {
+    case AF_FLEXNET:
+      if (!strcmp(argv[1], "*"))
+	break;
+      if (!strcasecmp(argv[1], "flexnet"))
+	break;
+      continue;
+    case AF_AX25:
+      if (!strcmp(argv[1], "*"))
+	break;
+      if (!strcasecmp(argv[1], "ax25"))
+	break;
+      continue;
+    case AF_NETROM:
+      if (!strcmp(argv[1], "*"))
+	break;
+      if (!strcasecmp(argv[1], "netrom"))
+	break;
+      continue;
+#ifdef HAVE_ROSE			
+    case AF_ROSE:
+      if (!strcmp(argv[1], "*"))
+	break;
+      if (!strcasecmp(argv[1], "rose"))
+	break;
+      continue;
+#endif			
+    case AF_INET:
+      if (!strcmp(argv[1], "*"))
+	break;
+      if (!strcasecmp(argv[1], "local") && is_local(peer))
+	break;
+      if (!strcasecmp(argv[1], "ampr") && is_ampr(peer))
+	break;
+      if (!strcasecmp(argv[1], "inet") && !is_local(peer) && !is_ampr(peer))
+	break;
+      continue;
+    case AF_UNSPEC:
+      if (!strcmp(argv[1], "*"))
+	break;
+      if (!strcasecmp(argv[1], "host"))
+	break;
+      continue;
+    }
+    if (up->ul_type == AF_AX25) {
+      if (strcmp(argv[2], "*") && strcmp(argv[2], up->ul_name))
+	continue;
+    }
+    if (cp != NULL)
+      *cp = '-';
+    if ((Permissions = strtoul(argv[4], NULL, 10)) == 0)
+      return NULL;
+    else
+      return strdup(argv[3]);
+  }
+  return NULL;
+}
+
+static int do_alias(int argc, char **argv)
+{
+  struct cmd *new;
+  int len = 0;
+
+  if (argc < 3)
+    return -1;
+  if ((new = calloc(1, sizeof(struct cmd))) == NULL) {
+    node_perror("do_alias: malloc", errno);
+    return -2;
+  }
+  new->name = strdup(argv[1]);
+  while (isupper(new->name[len]))
+    len++;
+  /* Ok. So they can't read... */
+  if (len == 0) {
+    strupr(new->name);
+    len = strlen(new->name);
+  }
+  new->len = len;
+  new->command = strdup(argv[2]);
+  new->type = CMD_ALIAS;
+  insert_cmd(&Nodecmds, new);
+  return 0;
+}
+
+static int do_loglevel(int argc, char **argv)
+{
+  if (argc < 2)
+    return -1;
+  LogLevel = atoi(argv[1]);
+  return 0;
+}
+
+int get_escape(char *s)
+{
+  int escape;
+  char *endptr[1];
+
+  if (isdigit(*s)) {
+    escape = strtol(s, endptr, 0);
+    if (**endptr)
+      return -2;
+    else
+      return escape;
+  }
+
+  if (strlen(s) == 1)
+    return *s;
+
+  if (strlen(s) == 2 && *s == '^')
+    return (toupper(*++s) - 'A' + 1);
+
+  if (strcasecmp(s, "off") == 0 || strcmp(s, "-1") == 0)
+    return -1;
+
+  return -2;
+}
+
+
+static int do_escapechar(int argc, char **argv)
+{
+  if (argc < 2)
+    return -1;
+
+  EscChar = get_escape(argv[1]);
+
+  if (EscChar < -1 || EscChar > 255) {
+    node_msg("Configuration error");
+    node_log(LOGLVL_ERROR, "do_escapechar: Invalid escape character %s",
+	     argv[1]);
+    return -2;
+  }
+
+  return 0;
+}
+
+static int do_idletimeout(int argc, char **argv)
+{
+  if (argc < 2)
+    return -1;
+  IdleTimeout = atol(argv[1]);
+  return 0;
+}
+
+static int do_conntimeout(int argc, char **argv)
+{
+  if (argc < 2)
+    return -1;
+  ConnTimeout = atol(argv[1]);
+  return 0;
+}
+
+static int do_hostname(int argc, char **argv)
+{
+  if (argc < 2)
+    return -1;
+  HostName = strdup(argv[1]);
+  return 0;
+}
+
+static int do_localnet(int argc, char **argv)
+{
+  char *cp;
+
+  if (argc < 2)
+    return -1;
+  if ((cp = strchr(argv[1], '/')) != NULL) {
+    *cp = 0;
+    LocalMask = bits_to_mask(atoi(++cp));
+  }
+  LocalNet = inet_addr(argv[1]);
+  LocalNet &= LocalMask;
+  return 0;
+}
+
+static int do_reconnect(int argc, char **argv)
+{
+#ifdef HAVEMOTD
+  if (argc < 2)
+    return -1;
+  if (!strcasecmp(argv[1], "on"))
+    ReConnectTo = 1;
+  else
+#endif
+    ReConnectTo = 0;
+  return 0;
+}
+
+static int do_hiddenports(int argc, char **argv)
+{
+  int i;
+
+  if (argc < 2)
+    return -1;
+  for (i = 1; i < argc && i < 31; i++) {
+    if (ax25_config_get_dev(argv[i]) == NULL) {
+      node_msg("Configuration error");
+      node_log(LOGLVL_ERROR, "do_hiddenports: invalid port %s", argv[i]);
+      return -2;
+    }
+    HiddenPorts[i - 1] = strdup(argv[i]);
+  }
+  HiddenPorts[i - 1] = NULL;
+  return 0;
+}
+
+static int do_extcmd(int argc, char **argv)
+{
+  struct cmd *new;
+  struct passwd *pw;
+  char buf[1024];
+  int i, len;
+
+  if (argc < 6)
+    return -1;
+  if ((new = calloc(1, sizeof(struct cmd))) == NULL) {
+    node_perror("do_extcmd: malloc", errno);
+    return -2;
+  }
+  new->name = strdup(argv[1]);
+  len = 0;
+  while (isupper(new->name[len]))
+    len++;
+  /* Ok. So they can't read... */
+  if (len == 0) {
+    strupr(new->name);
+    len = strlen(new->name);
+  }
+  new->len = len;
+  new->flags = atoi(argv[2]);
+  if ((pw = getpwnam(argv[3])) == NULL) {
+    node_msg("Configuration error");
+    node_log(LOGLVL_ERROR, "do_extcmd: Unknown user %s", argv[3]);
+    return -2;
+  }
+  new->uid = pw->pw_uid;
+  new->gid = pw->pw_gid;
+  new->path = strdup(argv[4]);
+  len = 0;
+  for (i = 0; argv[i + 5] != NULL; i++) {
+    sprintf(&buf[len], "\"%s\" ", argv[i + 5]);
+    len = strlen(buf);
+  }
+  new->command = strdup(buf);
+  new->type = CMD_EXTERNAL;
+  insert_cmd(&Nodecmds, new);
+  return 0;
+}
+
+static int do_nodeid(int argc, char **argv)
+{
+  if (User.ul_type == AF_NETROM) {
+    if (argc < 2) 
+      return -1;
+    NodeId = strdup(argv[1]);
+  }  else  if (User.ul_type != AF_NETROM) {
+    NodeId = strdup(argv[1]);
+  } 
+  return 0;
+}
+
+static int do_flexid(int argc, char **argv)
+{
+  if (argc < 2 )
+    return -1;
+  FlexId = ("%s ;" , strdup(argv[1]));
+  return 0;
+}
+
+static int do_roseid(int argc, char **argv)
+{
+  if (argc < 2 )
+    return -1;
+  RoseId = ("%s ;" , strdup(argv[1]));
+  return 0;
+}
+
+static int do_prompt(int argc, char **argv)
+{
+  if ((User.ul_type != AF_NETROM) || (User.ul_type != AF_INET)) {
+    if (argc < 2) {
+      return -1;
+      Prompt = strdup(argv[1]);
+      return 0;
+    }
+  }
+} 
+
+static int do_passprompt(int argc, char **argv)
+{
+  if (User.ul_type != AF_NETROM) {
+    if (argc < 2)
+      return -1;
+    PassPrompt = strdup(argv[1]);
+    return 0;
+  }
+}
+
+static int do_nrport(int argc, char **argv)
+{
+  if (argc < 2)
+    return -1;
+  NrPort = strdup(argv[1]);
+  return 0;
+}
+
+static int do_email(int argc, char **argv)
+{
+  if (argc < 2)
+    return -1;
+  Email = strdup(argv[1]);
+  return 0;
+}
+
+int read_config(void)
+{
+  struct cmd *cfg_cmds = NULL;
+  FILE *fp;
+  char line[256];
+  int ret, n = 0;
+
+  add_internal_cmd(&cfg_cmds, "alias",       5,  do_alias);
+  add_internal_cmd(&cfg_cmds, "conntimeout", 11, do_conntimeout);
+  add_internal_cmd(&cfg_cmds, "email",	   5,  do_email);
+  add_internal_cmd(&cfg_cmds, "escapechar",  10, do_escapechar);
+  add_internal_cmd(&cfg_cmds, "extcmd",      6,  do_extcmd);
+  add_internal_cmd(&cfg_cmds, "hiddenports", 11, do_hiddenports);
+  add_internal_cmd(&cfg_cmds, "hostname",    8,  do_hostname);
+  add_internal_cmd(&cfg_cmds, "idletimeout", 11, do_idletimeout);
+  add_internal_cmd(&cfg_cmds, "localnet",    8,  do_localnet);
+  add_internal_cmd(&cfg_cmds, "loglevel",    8,  do_loglevel);
+  add_internal_cmd(&cfg_cmds, "nodeid",      6,  do_nodeid);
+  add_internal_cmd(&cfg_cmds, "flexid",      6,  do_flexid); 
+  add_internal_cmd(&cfg_cmds, "roseid",	     6,	 do_roseid);
+  add_internal_cmd(&cfg_cmds, "prompt",      6,  do_prompt);
+  add_internal_cmd(&cfg_cmds, "nrport",      6,  do_nrport);
+  add_internal_cmd(&cfg_cmds, "reconnect",   8,  do_reconnect);
+  add_internal_cmd(&cfg_cmds, "passprompt",  6,  do_passprompt);
+
+  if ((fp = fopen(CONF_NODE_FILE, "r")) == NULL) {
+    node_perror(CONF_NODE_FILE, errno);
+    return -1;
+  }
+  while (fgets(line, 256, fp) != NULL) {
+    n++;
+    ret = cmdparse(cfg_cmds, line);
+    if (ret == -1) {
+      node_msg("Configuration error");
+      node_log(LOGLVL_ERROR, "Syntax error in config file at line %d: %s", n, line);
+    }
+    if (ret < 0) {
+      fclose(fp);
+      return -1;
+    }
+  }
+  fclose(fp);
+  free_cmdlist(cfg_cmds);
+  cfg_cmds = NULL;
+  return 0;
+}
diff --git a/config.h.in b/config.h.in
new file mode 100644
index 0000000..76a7e9e
--- /dev/null
+++ b/config.h.in
@@ -0,0 +1,36 @@
+#ifndef	CONFIG_H
+#define	CONFIG_H
+
+/*
+ * Some global #defines for programmers to use for conditional compilation
+ */
+ at HAVEAX25@
+ at HAVEFLEX@
+ at HAVEROSE@
+ at HAVENETROM@
+ at HAVEZLIB@
+ at HAVEMHEARD@
+ at HAVETCPIP@
+#define	PROC_AX25_CALLS_FILE	"/proc/net/ax25_calls"
+
+/*
+ * node specific
+ */
+#define	CONF_NODE_FILE		"@ETC_DIR@/uronode.conf"
+#define	CONF_NODE_PERMS_FILE	"@ETC_DIR@/uronode.perms"
+ at HAVEMOTD@		@MOTDPATH@
+#define	CONF_NODE_INFO_FILE	"@ETC_DIR@/uronode.info"
+#define AX_ROUTES_FILE          "@ETC_DIR@/uronode.routes"
+#define CONF_USERS_FILE         "@ETC_DIR@/uronode.users"
+#define FLEXD_CONF_FILE         "@ETC_DIR@/flexd.conf"
+#define FLEXD_TEMP_PATH         "@VAR_DIR@/flex/"
+#define FLEXD_PID_FILE		"/var/run/flexd.pid"
+#define FLEX_GT_FILE            "@VAR_DIR@/flex/gateways"
+#define FLEX_DST_FILE           "@VAR_DIR@/flex/destinations"
+#define DATA_MHEARD_FILE        "@VAR_DIR@/mheard/mheard.dat"
+#define	DATA_NODE_LOGIN_FILE	"@VAR_DIR@/node/loggedin"
+#define	DATA_NODE_HELP_DIR	"@VAR_DIR@/node/help/"
+#define DATA_NODE_LAST_FILE     "@VAR_DIR@/node/lastlog"
+#define DATA_NODE_IP_FILE       "@VAR_DIR@/node/iplog"
+
+#endif
diff --git a/configure b/configure
new file mode 100755
index 0000000..68fde56
--- /dev/null
+++ b/configure
@@ -0,0 +1,303 @@
+#!/bin/sh
+
+_sleep()
+{
+  [ "$NON_INTERACTIVE" = 1 ] || sleep "$@"
+}
+
+_whiptail()
+{
+  [ "$NON_INTERACTIVE" = 1 ] || whiptail "$@"
+}
+
+echo "Cleaning the directory for a fresh configuration..."
+_sleep 2
+make distclean > make.debug
+
+ETC_DIR=/usr/local/etc/ax25
+SBIN_DIR=/usr/local/sbin
+BIN_DIR=/usr/local/bin
+LIB_DIR=/usr/local/lib
+MAN_DIR=/usr/local/share/man
+VAR_DIR=/usr/local/var/ax25
+
+echo "Welcome to the configuration utility for URONode. This configure script"
+echo "will very simply and easily guide you into installling URONode with as"
+echo "very little trouble as possible. All you need to really do is simply"
+echo "answer the following questions below properly. If you make a mistake"
+echo "just break out of it (ctrl+c) and rerun ./configure. Let's get started!"
+_sleep 1
+echo " "
+_sleep 1
+echo -n "you need gcc to build URONode: "
+GCC=`which gcc`
+_sleep 2
+if [ -e "$GCC" ]
+   then
+   echo -n "saw $GCC... "
+   _sleep 1
+   echo "GCC found! Congratulations!!"
+else
+   echo "gcc not found!"
+   echo " "
+   echo "You need this compiler to build URONode."
+   echo "Please install gcc, and rerun this ./configure script."
+   echo "If you have a copy of gcc installed, please insure you have a"
+   echo "symlink by typing as root: ln -s /usr/bin/gcc-#.## /usr/bin/gcc"
+   echo "and rerun ./configure to continue."
+   exit 1
+fi
+echo -n "Your machine architecture is: "
+_sleep 1
+ARCH=`uname -m`
+echo $ARCH
+_sleep 1
+echo -n "Checking for the existence of the Zlib headers... "
+ZLIB=""
+HAVEZLIB="#undef HAVE_ZLIB"
+for zlibdir in /usr/include /usr/local/include
+do
+	if [ -f $zlibdir/zlib.h ]
+	then
+		echo $zlibdir/zlib.h
+		ZLIB="-lz"
+		HAVEZLIB="#define HAVE_ZLIB	1"
+	fi
+done
+if [ -z "$ZLIB" ]
+then
+	echo "not found."
+	echo "            Without Zlib Node will lack compression support"
+	echo "            See INSTALL for more information."
+	echo
+fi
+
+# Global protocol definition symbols for programmers that want to conditionally
+# compile
+	HAVEAX25="#undef HAVE_AX25"
+	HAVEFLEX="#undef HAVE_FLEX"
+	FLEXNET=" "
+	IN="#"
+	HAVENETROM="#undef HAVE_NETROM"
+	HAVEROSE="#undef HAVE_ROSE"
+	HAVEMHEARD="#undef HAVE_MHEARD"
+	HAVETCPIP="#undef HAVE_TCPIP"
+	HAVEMOTD="#undef HAVE_MOTD"
+	MOTDPATH=
+#	echo -n "Include support for the AX.25 protocol ? [Y/n]: "; read answer
+#	if [ "$answer" = "Y" -o "$answer" = "y" -o "$answer" = "" ]
+	if [ "$NON_INTERACTIVE" = 1 ]
+	then
+		echo "$@" | grep -vqe "--without-ax25"
+	else
+		whiptail --title "URONode Options:" --yesno "Support AX25?" 7 22
+	fi
+	if [ $? -ne 1 ]
+	then
+		HAVEAX25="#define HAVE_AX25	1"
+	fi
+	#
+#        echo -n "Include support for the FlexNet protocol ? [Y/n]: "; read answer
+#        if [ "$answer" = "Y" -o "$answer" = "y" -o "$answer" = "" ]
+
+	if [ "$NON_INTERACTIVE" = 1 ]
+	then
+		echo "$@" | grep -vqe "--without-flexnet"
+	else
+		whiptail --title "URONode Options:" --yesno "Support FlexNet?" 7 22
+	fi
+	if [ $? -ne 1 ]
+        then
+                HAVEAX25="#define HAVE_AX25	1"
+		HAVEFLEX="#define HAVE_FLEX	1"
+		FLEXNET="flexd"
+		IN=""
+        fi
+        # 
+#	echo -n "Include support for the NetRom protocol ? [Y/n]: "; read answer
+#	if [ "$answer" = "Y" -o "$answer" = "y" -o "$answer" = "" ]
+	if [ "$NON_INTERACTIVE" = 1 ]
+	then
+		echo "$@" | grep -vqe "--without-netrom"
+	else
+		whiptail --title "URONode Options:" --yesno "Support NetRom?" 7 22
+	fi
+	if [ $? -ne 1 ]
+	then
+		HAVEAX25="#define HAVE_AX25	1"
+		HAVENETROM="#define HAVE_NETROM	1"
+	fi
+	#
+#	echo -n "Include support for the Rose protocol ? [Y/n]: "; read answer
+#	if [ "$answer" = "Y" -o "$answer" = "y" -o "$answer" = "" ]
+	if [ "$NON_INTERACTIVE" = 1 ]
+	then
+		echo "$@" | grep -vqe "--without-rose"
+	else
+		whiptail --title "URONode Options:" --yesno "Support ROSE?" 7 22
+	fi
+	if [ $? -ne 1 ]
+	then
+		HAVEAX25="#define HAVE_AX25	1"
+		HAVEROSE="#define HAVE_ROSE               1"
+	fi
+	#
+#	echo -n "Include support for MHeard ports listen ? [Y/n]: "; read answer
+#	if [ "$answer" = "Y" -o "$answer" = "y" -o "$answer" = "" ]
+	if [ "$NON_INTERACTIVE" = 1 ]
+	then
+		echo "$@" | grep -vqe "--without-mheard"
+	else
+		whiptail --title "URONode Options:" --yesno "Support MHeard?" 7 22
+	fi
+	if [ $? -ne 1 ]
+	then
+		HAVEAX25="#define HAVE_AX25	1"
+		HAVEMHEARD="#define HAVE_MHEARD	1"
+	fi
+	#
+#	echo -n "Include support for TCP/IP functions ? [Y/n]: "; read answer
+#	if [ "$answer" = "Y" -o "$answer" = "y" -o "$answer" = "" ]
+	if [ "$NON_INTERACTIVE" = 1 ]
+	then
+		echo "$@" | grep -vqe "--without-tcpip"
+	else
+		whiptail --title "URONode Options:" --yesno "Support TCP/IP?" 7 22
+	fi
+	if [ $? -ne 1 ]
+	then
+		HAVETCPIP="#define HAVE_TCPIP	1"
+		HAVEMOTD="#define HAVEMOTD"
+		MOTDPATH='"/etc/ax25/uronode.motd"'
+	fi
+
+echo "Creating Makefile"
+
+sed -e  "s~@FLEXNET@~$FLEXNET~g; \
+	 s~@IN@~$IN~g" <Makefile.in > Makefile
+
+echo "Creating Makefile.include"
+
+sed -e "s~@ARCH@~$ARCH~g; \
+	s~@ETC_DIR@~$ETC_DIR~g; \
+	s~@LIB_DIR@~$LIB_DIR~g; \
+	s~@SBIN_DIR@~$SBIN_DIR~g; \
+	s~@BIN_DIR@~$BIN_DIR~g; \
+	s~@VAR_DIR@~$VAR_DIR~g; \
+	s~@MAN_DIR@~$MAN_DIR~g; \
+	s~@ZLIB@~$ZLIB~g" <Makefile.include.in >Makefile.include
+
+echo "Creating config.h"
+
+sed -e "s~@ETC_DIR@~$ETC_DIR~g; \
+	s~@LIB_DIR@~$LIB_DIR~g; \
+	s~@SBIN_DIR@~$SBIN_DIR~g; \
+	s~@BIN_DIR@~$BIN_DIR~g; \
+	s~@VAR_DIR@~$VAR_DIR~g; \
+	s~@MAN_DIR@~$MAN_DIR~g; \
+	s~@HAVEAX25@~$HAVEAX25~g; \
+	s~@HAVEFLEX@~$HAVEFLEX~g; \
+	s~@HAVENETROM@~$HAVENETROM~g; \
+	s~@HAVEROSE@~$HAVEROSE~g; \
+	s~@HAVEMHEARD@~$HAVEMHEARD~g; \
+	s~@HAVETCPIP@~$HAVETCPIP~g; \
+	s~@HAVEMOTD@~$HAVEMOTD~g; \
+	s~@MOTDPATH@~$MOTDPATH~g; \
+	s~@HAVEZLIB@~$HAVEZLIB~g" <config.h.in >config.h
+
+echo "Creating dependancy files..."
+make depend > /dev/null 2>&1
+echo "Configuration successful!!"
+_sleep 1
+echo "about the authors..."
+_sleep 3
+echo "URONode is a combined effort of years worth of work. Those who's code"
+echo "is included in this flavor of a linux based node are:"
+_sleep 1
+echo "Brian Rogers N1URO (current maintainer), "
+_sleep 1
+echo "Marius Petrescu YO2LOJ (current team member),"
+_sleep 1
+echo "Bob Tenty VE3TOK (current team member),"
+_sleep 1
+echo "Stefano Noferi IZ5AWZ (AWZNode)"
+_sleep 1
+echo -n "Tomi Manninen OH2BNS, "
+_sleep 1
+echo -n "Alan Cox GW4PTS, "
+_sleep 1
+echo "and Roy Van Zundert PE1RJA"
+echo ""
+_sleep 1
+echo "Special thanks to: Morgan, sm6tky for his security report"
+echo "and Barry K2MF for his input on some of my routines and supplying"
+echo "some source code."
+_sleep 1
+echo ""
+#echo -n "Shall I run the make command for you ? [Y/n]: "
+	_whiptail --title "Shall I make URONode?" --yesno "Yes to make or No to exit" 7 30 
+#	if [ "$answer" = "Y" -o "$answer" = "y" -o "$answer" = "" ]
+	if [ "$NON_INTERACTIVE" != 1 -a $? -ne 1 ]
+        then
+#		echo "Making URONode! Please be patient."
+#		_sleep 1
+#		echo "compile errors will be in make.debug."
+#		echo ""
+#		_sleep 1
+#		echo "You may not see anything until the process is complete..."
+		_whiptail --title "Making URONODE..." --msgbox "Making. Check make.debug for errors. Hit OK to continue. You may not see anything for a minute..." 10 45
+		make >> make.debug
+		echo "let's check for binary errors..."
+		_sleep 1
+		echo -n "nodeusers: "
+		_sleep 1
+		if [ -x ./nodeusers ]; then
+			echo "SUCCESS!"
+		else
+			echo "FAILED!"
+		fi
+		_sleep 1
+		echo -n "uronode:   "
+		_sleep 1
+		if [ -x ./uronode ]; then
+			echo "SUCCESS!"
+		else
+			echo "FAILED!"
+		fi
+		_sleep 1
+		echo -n "axdigi:    "
+		_sleep 1
+		if [ -x ./axdigi ]; then
+			echo "SUCCESS!"
+		fi
+		_sleep 1
+		echo -n "flexd:     "
+		_sleep 1
+		if [ -x ./flexd ]; then
+			echo "SUCCESS!"
+		_sleep 1
+		else
+			echo "FAILED! - perhaps you didn't want flexnet?"
+			echo "This is not an error if you chose NO to flexnet."
+			echo "This only means the flexnet daemon binary was not found."
+			echo ""
+			echo "Process complete!"
+			echo ""
+		fi
+		_sleep 1
+		_whiptail --title "URONode" --msgbox "Check the file make.debug if you had errors. If no errors, type: make install (new install) or make upgrade (existing install) and edit your files in /usr/local/etc/ax25/\n\n**WARNING: if you haven't already, add the following to your startup scripts:\n/usr/local/sbin/axdigi & \nto insure cross-port digipeating.\n\nFor help and release news join the forum at\nhttps://www.n1uro.net/forum\n\nEnjoy URONode - 73 de Brian N1URO" 20 50
+
+#		echo "Check the file make.debug if you had errors."
+#		echo "If no errors, type: make install or make upgrade" 
+#		echo "and edit your files in /etc/ax25/"
+#		echo "**WARNING: if you haven't already, add the following to your"
+#		echo "startup scripts:"
+#		echo "/usr/sbin/axdigi &"
+#		echo "to insure cross-port digipeating."
+#		echo ""
+#		echo "For support and release news join the forum"
+#		echo "at https://www.n1uro.net/forum"
+#		echo ""
+#		echo "Enjoy URONode! 73 de N1URO."
+        fi
+exit 0
diff --git a/etc/axdigi.conf b/etc/axdigi.conf
new file mode 100644
index 0000000..55c809d
--- /dev/null
+++ b/etc/axdigi.conf
@@ -0,0 +1,20 @@
+# URONode axdigi module
+# load using /usr/sbin/axdigi &
+#
+#print debuginfo on/off
+Debug off
+#
+#The digi call
+MyCall	xx0xx
+#
+# on use ssid 0-15 for digicall ,off use only ssid of mycall
+IgnoreSSID on
+#
+#number of entrys for autorouting
+lookupsize	100
+#
+#timeout auto routing data in sec.
+TIMEOUT	3600
+#
+DefaultPort ln.tue
+#
diff --git a/etc/flexd.conf b/etc/flexd.conf
new file mode 100644
index 0000000..b9e9190
--- /dev/null
+++ b/etc/flexd.conf
@@ -0,0 +1,14 @@
+# /etc/ax25/flexd.conf 		URONode example configuration file
+# see man flexd.conf
+
+# The callsign-ssid you wish to poll your flex neighbor with:
+
+MyCall		xx0xx
+
+# How often do we poll our flex neighbor (in seconds):
+
+PollInterval	300
+
+# The FlexNet node we're to poll:
+
+FlexGate	xx0xx-#
diff --git a/etc/gateways b/etc/gateways
new file mode 100644
index 0000000..e69de29
diff --git a/etc/help/bye.hlp b/etc/help/bye.hlp
new file mode 100644
index 0000000..9359a79
--- /dev/null
+++ b/etc/help/bye.hlp
@@ -0,0 +1,6 @@
+
+USAGE
+        Bye
+
+DESCRIPTION
+        Disconnects you from this node.
\ No newline at end of file
diff --git a/etc/help/color.hlp b/etc/help/color.hlp
new file mode 100644
index 0000000..443c251
--- /dev/null
+++ b/etc/help/color.hlp
@@ -0,0 +1,18 @@
+
+USAGE
+        <none>
+
+DESCRIPTION
+        Adds ANSI color to the system for you. Send a message to
+	the sysop and request that they add 512 to your permissions
+	flag for the interface(s) you connect in from to get the
+	color schema. You *must* use an ANSI compliant terminal such
+	as Qmodem, Telix, telnet, etc.
+	Interfaces available:	Schema:
+	ax25			ax25	- yellow
+	netrom			netrom	- cyan
+	internet		internet- magenta
+	amprnet			system 	- white
+	localhost		starts	- green
+				stops	- red
+				alarms	- flashing red
diff --git a/etc/help/connect.hlp b/etc/help/connect.hlp
new file mode 100644
index 0000000..1fad0aa
--- /dev/null
+++ b/etc/help/connect.hlp
@@ -0,0 +1,25 @@
+
+USAGE
+        Connect <call | alias> [s|d]                   For NET/ROM or Links
+        Connect <intf> <call> [via <digi1> ...] [s|d]  For AX25
+	Connect <call> <address> [<digi>] [d|s]        For ROSE
+	Connect <destination> [s|d]                    For FlexNet
+
+DESCRIPTION
+        Initiates an AX25, NET/ROM, ROSE or Flexnet connection to a
+	remote host. If more than two parameters are entered and the
+        second parameter is ten charachers in length then it is
+        interpreted as a ROSE connection, otherwise the first
+        parameter is interpreted as a port name and AX25 is used
+        to make the connection via that port. If only one parameter
+        is given the connection is made searching for the callsign
+	in NET/ROM nodes, in AX25 Fixed links, in FlexNet destinations
+	and last in Mheard database in this order.	
+
+        If a single `s' is entered as the last parameter, then when
+        the remote host disconnects you will be returned to this node.
+        If a single `d' is entered as the last parameter, you will
+        be disconnected from this node too. Default behaviour depends
+	on how the user connects in:
+	NetRom - defaults to disconnect
+	all others - defaults to reconnect
diff --git a/etc/help/desti.hlp b/etc/help/desti.hlp
new file mode 100644
index 0000000..5a92410
--- /dev/null
+++ b/etc/help/desti.hlp
@@ -0,0 +1,14 @@
+
+USAGE
+        Dest [*|<nodecall>]
+
+DESCRIPTION
+        Shows the FlexNet destination table of the local node. The
+        destinations on this list can be reached using the Connect
+        command without knowing the actual network path used 
+        (assuming the network is OK).
+
+        The optional parameter * toggles verbose mode, showing the
+        ssid mask, the round-trip-time and the path used to reach each
+        node. You can also specify a node callsign to get the verbose
+        information for a single node.
\ No newline at end of file
diff --git a/etc/help/escape.hlp b/etc/help/escape.hlp
new file mode 100644
index 0000000..24f9bb4
--- /dev/null
+++ b/etc/help/escape.hlp
@@ -0,0 +1,16 @@
+
+USAGE
+        Escape <escape char>
+
+DESCRIPTION
+        Sets the character will be treated as the signal to close down any
+        open connection made from the node.
+
+	You can specify the escape character in a number of ways. They are:
+
+           <char> the actual binary character
+           ^T     to set it to Control-T (or any other control character)
+           0xNN   to set it to hexadecimal value NN
+           0NNN   to set it to Octal value NNN
+           NNN    to set it to decimal value NNN (no leading zero!)
+           -1     to disable this feature
\ No newline at end of file
diff --git a/etc/help/finger.hlp b/etc/help/finger.hlp
new file mode 100644
index 0000000..a5ac691
--- /dev/null
+++ b/etc/help/finger.hlp
@@ -0,0 +1,13 @@
+
+USAGE
+        Finger [<username>][@<hostname>]
+
+DESCRIPTION
+        Retrieves information about users of a system. If the user
+        name is omitted, shows the users currently logged on the 
+        host. If the hostname is omitted, defaults to the local host.
+
+EXAMPLES
+        finger @aripisa.ampr.org
+        finger iz5awz at aripisa.ampr.org
+        finger iz5awz
\ No newline at end of file
diff --git a/etc/help/help.hlp b/etc/help/help.hlp
new file mode 100644
index 0000000..25afe58
--- /dev/null
+++ b/etc/help/help.hlp
@@ -0,0 +1,10 @@
+
+USAGE
+        Help [<command>]
+
+DESCRIPTION
+        Gives help for the specified command or this text if no
+        command is specified. Commands can not be abbreviated.
+        Use the "?" command to retrieve a list of available commands,
+	except for the COLOR command which you need to contact your
+	sysop to add. "Help color" to see about the color schema.
diff --git a/etc/help/host.hlp b/etc/help/host.hlp
new file mode 100644
index 0000000..cbf64fe
--- /dev/null
+++ b/etc/help/host.hlp
@@ -0,0 +1,11 @@
+
+USAGE
+        Host <hostname>|<ip address>
+
+DESCRIPTION
+        Tells information about an Internet host. The host can be identified
+        using a host name (for example, aripisa.ampr.org) or an IP 
+        address (for example, 44.134.208.29).
+
+        Returns the host name, IP addresses and known aliases for the host.
+        The information is gathered from the DNS (domain name service).
\ No newline at end of file
diff --git a/etc/help/info.hlp b/etc/help/info.hlp
new file mode 100644
index 0000000..4ee8cb9
--- /dev/null
+++ b/etc/help/info.hlp
@@ -0,0 +1,8 @@
+
+USAGE
+        Info
+
+DESCRIPTION
+       Displays the version information and the contents of the
+       /etc/ax25/uronode.info file, which describes those aspects of
+       the system that the sysop likes to brag about.
diff --git a/etc/help/links.hlp b/etc/help/links.hlp
new file mode 100644
index 0000000..66480d3
--- /dev/null
+++ b/etc/help/links.hlp
@@ -0,0 +1,16 @@
+
+USAGE
+        Links [ d | n | v | <call>]
+
+DESCRIPTION
+        Shows the AX25 link table of the local node. The destinations 
+        on this list can be reached using the Connect command without 
+	knowing the actual network path used (assuming the network is OK).
+
+        The optional parameter d show the AX25 nodes directly linked.
+	The optional parameter n show the AX25 nodes linked connecting 
+	another node and passing a string type "C XX0XX".
+	The optional parameter v show the AX25 links via digipeaters.
+
+	You can also specify a destination callsign to get the verbose 
+	information for a single destination.
\ No newline at end of file
diff --git a/etc/help/mail.hlp b/etc/help/mail.hlp
new file mode 100644
index 0000000..003272c
--- /dev/null
+++ b/etc/help/mail.hlp
@@ -0,0 +1,12 @@
+
+USAGE
+        Mail
+
+DESCRIPTION
+        Access your mailbox and send mail to other users
+	if you have mail waiting.
+	(only available for sysops and some users).
+
+        Note: this feature is initially disabled, contact the sysop
+        if you like to have it enabled.
+
diff --git a/etc/help/message.hlp b/etc/help/message.hlp
new file mode 100644
index 0000000..44fe46d
--- /dev/null
+++ b/etc/help/message.hlp
@@ -0,0 +1,14 @@
+
+USAGE 
+	MEssage <callsign or user at domain>
+
+DESCRIPTION
+
+        Send email to users (now only available for messages to sysop).
+	Note: sysop has to enable your mail flag for you to be able to
+	receive mail, otherwise you may only send from here.
+
+	*Sysop Note: use your adduser or userconf program and create
+	the users account as well as adding the mail flag to the
+	configuration file. Select: /bin/false for a shell.
+
diff --git a/etc/help/mheard.hlp b/etc/help/mheard.hlp
new file mode 100644
index 0000000..4a08386
--- /dev/null
+++ b/etc/help/mheard.hlp
@@ -0,0 +1,8 @@
+
+USAGE
+        Mheard [<port>]
+
+DESCRIPTION
+        Gives a list of heard AX25 stations on all ports and, if 
+	specified, on the specified port.
+        Use the "Ports" command to get a list of available ports.
\ No newline at end of file
diff --git a/etc/help/msg.hlp b/etc/help/msg.hlp
new file mode 100644
index 0000000..1700183
--- /dev/null
+++ b/etc/help/msg.hlp
@@ -0,0 +1,15 @@
+
+USAGE
+        MSg <call> <message>
+
+DESCRIPTION
+        Sends a one-line message to another user of the node. The user
+        in question must be in idle state (ie. not connected/connecting
+        anywhere or running a program).
+
+        If the user has an SSID other than zero, the SSID must be
+        specified. If multiple users are logged in with the same
+        callsign/SSID pair, those who are in idle state, get the message.
+
+EXAMPLES
+        msg k2mf Hello, Bawee!
diff --git a/etc/help/netstat.hlp b/etc/help/netstat.hlp
new file mode 100644
index 0000000..54f598a
--- /dev/null
+++ b/etc/help/netstat.hlp
@@ -0,0 +1,7 @@
+
+USAGE
+        NEtstat
+
+DESCRIPTION
+        Gives a list of active TCP/IP connections to and from the local
+        host.
\ No newline at end of file
diff --git a/etc/help/nodes.hlp b/etc/help/nodes.hlp
new file mode 100644
index 0000000..93005de
--- /dev/null
+++ b/etc/help/nodes.hlp
@@ -0,0 +1,15 @@
+
+USAGE
+        Nodes [*|<nodecall>]
+
+DESCRIPTION
+        Shows the NET/ROM node table of the local host. The nodes on this
+        list can be reached using the Connect command without knowing the
+        actual network path used (assuming the network is OK).
+
+        The optional parameter * toggles verbose mode, showing the
+        Obsolescence counter, relative path quality and the port and
+        neighbour node used to reach each node. You can also specify
+        a node callsign to get the verbose information for a single node.
+        In that case a "which" field that tells what route the kernel
+        will use to reach the node is shown.
diff --git a/etc/help/ping.hlp b/etc/help/ping.hlp
new file mode 100644
index 0000000..30eb4ac
--- /dev/null
+++ b/etc/help/ping.hlp
@@ -0,0 +1,15 @@
+
+USAGE
+        PIng <hostname> [<length>]
+
+DESCRIPTION
+        Checks if a host can be reached trough the network by sending
+        an ICMP Echo Request packet to the host and waiting for it to
+        reply. If a reply is received the round-trip-time (RTT)
+        between the local and remote hosts is shown.
+
+        If an optional length is specified the data portion of the
+        packet is filled with length number of bytes.
+
+EXAMPLE
+        ping aripisa.ampr.org
diff --git a/etc/help/ports.hlp b/etc/help/ports.hlp
new file mode 100644
index 0000000..959db42
--- /dev/null
+++ b/etc/help/ports.hlp
@@ -0,0 +1,12 @@
+
+USAGE
+        Ports
+
+DESCRIPTION
+        Shows the available AX25 ports. Shown are the port name, a short 
+        description for the port, the number of sessions via the port (qso)
+        and the number received and transmitted packets via the port.
+        The port name is used when using the Connect command to connect
+        to an user or service not running NET/ROM or FlexNet (eg. not visible
+        in the Nodes and Destinations lists). The port name is also visible
+        in the Route, MHeard and MSession lists.
\ No newline at end of file
diff --git a/etc/help/quit.hlp b/etc/help/quit.hlp
new file mode 100644
index 0000000..58cd7bc
--- /dev/null
+++ b/etc/help/quit.hlp
@@ -0,0 +1,6 @@
+
+USAGE
+        Quit
+
+DESCRIPTION
+        Disconnects you from this node.
diff --git a/etc/help/rose.hlp b/etc/help/rose.hlp
new file mode 100644
index 0000000..69c1f6e
--- /dev/null
+++ b/etc/help/rose.hlp
@@ -0,0 +1,2 @@
+<enter your rose routes here. Ex:>
+c n1uro-8 3100860906
diff --git a/etc/help/routes.hlp b/etc/help/routes.hlp
new file mode 100644
index 0000000..e1bf3ff
--- /dev/null
+++ b/etc/help/routes.hlp
@@ -0,0 +1,16 @@
+
+USAGE
+        Routes
+
+DESCRIPTION
+        Shows the NET/ROM route table of the local host (eg. the nodes
+        which the local node directly talks with). These nodes are used
+        to reach the other nodes on the node table. Fields shown are:
+
+         Link           - Is there an AX25 connection active to this node
+         Port           - Which port is this route on
+         Callsign       - The callsign of the neighbour node
+         Quality        - A relative quality for the path (0-255)
+         Destinations   - Number of other nodes reached via this route
+         Lock           - Is the quality of this route locked by the operator
+         QSO            - Number of NET/ROM session enties
\ No newline at end of file
diff --git a/etc/help/sessions.hlp b/etc/help/sessions.hlp
new file mode 100644
index 0000000..ecd55ce
--- /dev/null
+++ b/etc/help/sessions.hlp
@@ -0,0 +1,10 @@
+
+USAGE
+        SEssions [* | <call>]
+
+DESCRIPTION
+        Gives a list of active AX25 and NET/ROM connections to and 
+        from the local host. With an asterisk (*) as an argument 
+        shows also AX25 and NET/ROM sockets in listening state. With
+        a callsign as an argument gives a list of all connections with
+        either source or destination callsign <call>.
diff --git a/etc/help/status.hlp b/etc/help/status.hlp
new file mode 100644
index 0000000..44c18c7
--- /dev/null
+++ b/etc/help/status.hlp
@@ -0,0 +1,14 @@
+
+USAGE
+        STatus
+
+DESCRIPTION
+        Returns information about the status of the Linux system which this 
+        URONode runs on. All information is taken directly from the 
+        operating system.
+
+        The "load average" values indicate the average amount of processes
+        waiting for processor time during the last 1, 5 and 15 minutes.
+        Load average of 1.0 would mean that the all of the processor time is
+        used by the processes, and all processes still get all of the time
+        they can use.
diff --git a/etc/help/telnet.hlp b/etc/help/telnet.hlp
new file mode 100644
index 0000000..26f474f
--- /dev/null
+++ b/etc/help/telnet.hlp
@@ -0,0 +1,26 @@
+
+USAGE
+        Telnet <host> [<port>] [s|d]
+
+DESCRIPTION
+        Initiates a telnet session to a remote host using TCP/IP.
+        You might not be able to connect to a given host due to the
+        local operator's policy of using this node, or simply because
+        the host is unreachable due to a network failure. You can use
+        the ping command to check if a host is reachable.
+
+        By default, the telnet command connects to the TCP port 23
+        (allocated for telnet). You can specify another TCP port or
+        a TCP port name.
+
+        If a single `s' is entered as the last parameter, then when
+        the remote host disconnects you will be returned to this node.
+	This is only valid if the user connects into your node via
+	NetRom, otherwise the user is automatically reconnected to
+	the node.
+
+EXAMPLES
+        telnet aripisa.ampr.org
+        telnet aripisa.ampr.org 1024
+        telnet 44.134.208.29 s
+	telnet 44.88.0.9 23 s
diff --git a/etc/help/users.hlp b/etc/help/users.hlp
new file mode 100644
index 0000000..8ac0cb1
--- /dev/null
+++ b/etc/help/users.hlp
@@ -0,0 +1,8 @@
+
+USAGE
+        Users
+
+DESCRIPTION
+        Shows a list of users currently connected to the local node,
+        where the users are coming from, and what are they doing at the
+        moment.
diff --git a/etc/help/version.hlp b/etc/help/version.hlp
new file mode 100644
index 0000000..a17ce1a
--- /dev/null
+++ b/etc/help/version.hlp
@@ -0,0 +1,6 @@
+
+USAGE
+        Version
+
+DESCRIPTION
+       Displays the software version information, 
diff --git a/etc/help/who.hlp b/etc/help/who.hlp
new file mode 100644
index 0000000..8e8eef9
--- /dev/null
+++ b/etc/help/who.hlp
@@ -0,0 +1,8 @@
+
+USAGE
+        Who (<call> | *)
+
+DESCRIPTION
+        Shows a list when the user with the callsign <call> last
+        connected to this node. Use the asterisk to print out
+        the entire log table.
diff --git a/etc/help/zconnect.hlp b/etc/help/zconnect.hlp
new file mode 100644
index 0000000..c58fff0
--- /dev/null
+++ b/etc/help/zconnect.hlp
@@ -0,0 +1,23 @@
+
+USAGE
+        ZConnect <call | alias> [s|d]                   For NET/ROM or Links
+        ZConnect <port> <call> [via <digi1> ...] [s|d]  For AX25
+	ZConnect <call> <address> [<digi>] [d|s]        For ROSE
+	ZConnect <destination> [s|d]                    For FlexNet
+
+DESCRIPTION
+        Compresses an AX25, NET/ROM, ROSE or Flexnet connection to a
+	remote host. If more than two parameters are entered and the
+        second parameter is ten charachers in length then it is
+        interpreted as a ROSE connection, otherwise the first
+        parameter is interpreted as a port name and AX25 is used
+        to make the connection via that port. If only one parameter
+        is given the connection is made searching for the callsign
+	in NET/ROM nodes, in AX25 Fixed links, in FlexNet destinations
+	and last in Mheard database in this order.	
+
+        If a single `s' is entered as the last parameter, then when
+        the remote host disconnects you will be returned to this node.
+        If a single `d' is entered as the last parameter, you will
+        be disconnected from this node too. Default behaviour (neither
+        `s' nor `d' entered) depends on sysop configuration.
diff --git a/etc/help/ztelnet.hlp b/etc/help/ztelnet.hlp
new file mode 100644
index 0000000..e4b36ee
--- /dev/null
+++ b/etc/help/ztelnet.hlp
@@ -0,0 +1,25 @@
+
+USAGE
+        ZTelnet <host> [<port>] [s|d]
+
+DESCRIPTION
+        Compresses a telnet session to a remote host using TCP/IP.
+        You might not be able to connect to a given host due to the
+        local operator's policy of using this node, or simply because
+        the host is unreachable due to a network failure. You can use
+        the ping command to check if a host is reachable.
+
+        By default, the telnet command connects to the TCP port 23
+        (allocated for telnet). You can specify another TCP port or
+        a TCP port name.
+
+        If a single `s' is entered as the last parameter, then when
+        the remote host disconnects you will be returned to this node.
+        If a single `d' is entered as the last parameter, you will
+        be disconnected from this node too. Default behaviour (neither
+        `s' nor `d' entered) depends on sysop configuration.
+
+EXAMPLES
+        ztelnet aripisa.ampr.org
+        ztelnet aripisa.ampr.org 1024
+        ztelnet 44.134.208.29
diff --git a/etc/lastlog b/etc/lastlog
new file mode 100644
index 0000000..e69de29
diff --git a/etc/loggedin b/etc/loggedin
new file mode 100644
index 0000000..e69de29
diff --git a/etc/uronode.conf b/etc/uronode.conf
new file mode 100644
index 0000000..e2af7f6
--- /dev/null
+++ b/etc/uronode.conf
@@ -0,0 +1,89 @@
+# /etc/ax25/uronode.conf - URONode example configuration file
+#
+# see uronode.conf(5)
+
+# Idle timeout (seconds).
+# This is how long we hold onto a dead link. 0 disables (this is NOT
+# recommended! Time is in seconds.
+
+IdleTimeout	900
+
+# Timeout when gatewaying (seconds).
+# This (in seconds) is a keep-alive for dead connects out of the node.
+
+ConnTimeout	600
+
+# Visible hostname. Will be shown at telnet login.
+# set this to your ampr.org hostname.
+
+HostName	xx#xx.ampr.org
+
+# SysOp email address
+# Set this to your email address - preferred to use an ampr.org email.
+
+Email <your at email.ampr.org>
+
+# "Local" network.
+# This is your local amprnet subnet in full. Do NOT use 44.0.0.0/8!
+
+LocalNet	44.0.0.0/32
+
+# Command aliases. See uronode.conf(5) for the meaning of the uppercase
+# letters in the name of the alias. Examples below:
+
+Alias		CAllbook "telnet %{3:144.167.99.66} 2000 %1 s"
+Alias		CONVers  "telnet %{2:44.88.0.9} 3600 \"/n %u %{1:1}\""
+Alias		DXCluster "connect dxnet"
+Alias		Quit	"bye"
+Alias		WX	"telnet %{3:38.102.137.140} %1 s"
+
+# Hidden ports.
+# List interfaces you wish not to display. Not suggested.
+
+#HiddenPorts	inet
+
+# External commands. See uronode.conf(5) for the meaning of the uppercase
+# letters in the name of the extcmd.
+#
+# Flags:	1	Run command through pipe
+#		2	Reconnected flag
+#		3	Run through pipe and reconnect
+#
+ExtCmd		NEstat	1	nobody	/bin/netstat netstat --inet
+#ExtCmd		PMS	1	root	/usr/sbin/pms pms -u %U -o XX0XX
+
+# Node ID.
+# This displays before all output texts when the user connects into 
+# your node via NetRom. Set to "" to leave blank.
+# Note: This -must- be defined or will display as "(null)". A space
+# is hardcoded in. Example: UROHUB:N1URO-2 do NOT add the bracket
+# afterwards "}" this is predefined in URONode.
+#
+NodeId		XXXXXX:XX#XX-#
+
+# Ax25/Flex ID.
+# This displays before some strings and at logout to the end user when
+# they connect in via ax25 as defined in your ax25d.conf file. If
+# you don't define this "(null)" will be presented to the end user. Its
+# suggested you take this from your ax25d config which either faces a
+# flexnet system OR your 2-meter user interface. Note: do NOT make this
+# ssid the same as your NetRom SSID here or in ax25d.conf.
+
+FlexId		XX#XX-#
+
+# ROSE ssid at network - if none, enter in: none. 
+
+RoseId		XX#XX-#@####,######
+
+# Netrom port name. This port is used for outgoing netrom connects.
+
+NrPort		nr0
+
+# Syslog Logging level - suggest leaving this at 3 for debugging. 0
+# halts logging.
+
+LogLevel	3
+
+# The default escape character (CTRL-T)
+#
+EscapeChar      ^T
diff --git a/etc/uronode.info b/etc/uronode.info
new file mode 100644
index 0000000..f41b887
--- /dev/null
+++ b/etc/uronode.info
@@ -0,0 +1,3 @@
+This is a new system running URONode.
+*** please edit /etc/ax25/uronode.info to change this text to display
+    information about your system.
diff --git a/etc/uronode.motd b/etc/uronode.motd
new file mode 100644
index 0000000..048cf8a
--- /dev/null
+++ b/etc/uronode.motd
@@ -0,0 +1,4 @@
+This is copy of URONode is located in <town>, 
+<county>, <state/province> [XX##xx] (grid)
+Type "?" for commands or H <command> for more detailed help on a command.
+*** please edit /etc/ax25/uronode.motd to change this text
diff --git a/etc/uronode.perms b/etc/uronode.perms
new file mode 100644
index 0000000..fcbe6e8
--- /dev/null
+++ b/etc/uronode.perms
@@ -0,0 +1,26 @@
+# /etc/ax25/uronode.perms - URONode example permissions file
+#
+# see uronode.perms(5)
+#
+# Note: The flags have been changed as of 2014/08/23
+#
+# user	type	port	passwd	perms
+
+# User oh2bns can login without password from anywhere else but 'inet'.
+#
+#xx0xx	inet	*	qwerty	95
+#xx0xx	*	*	*	95
+n1uro	*	*	*	255
+
+# OH2RBI is a bbs so it needs escape disabled.
+#
+#xx0xx	*	*	*	287
+
+# Default permissions per connection type.
+#
+*	ax25	*	*	31
+*	netrom	*	*	31
+*	local	*	*	31
+*	ampr	*	*	31
+*	inet	*	*	0
+*	host	*	*	31
diff --git a/etc/uronode.routes b/etc/uronode.routes
new file mode 100644
index 0000000..9b94f1e
--- /dev/null
+++ b/etc/uronode.routes
@@ -0,0 +1,21 @@
+# /etc/ax25/uronode.routes     URONode example configuration file
+# This is used for quick ax25 connects so users need not add an interface
+# when making a connect. You also need a statement in here for flexd to
+# poll your flexnet neighbor.
+
+# URONode shows links with this order. Examples below:
+
+# Direct Routing 
+# route <call> <alias> <port> d 'description'
+#
+#route 	n1uro-1	fxuro	ax0 	d 	'N1URO FlexNet Hub'
+
+# Routing across another node with sending a string "C <call>"
+# route <call> 		<alias> 	<port> n 	'description' 	<node>
+#
+#route 	n1uro-14 	WMASS		ax0 	n 	'N1URO-NOS' 	n1uro-1 
+
+# Routing via digipeaters
+# route <call> 		<alias>		<port> 	v 	'description' 	<digipeaters>
+#
+#route 	n1uro-9 	MACTFX		ax0 	v 	'N1URO Xnet' 	n1uro-1
diff --git a/etc/uronode.users b/etc/uronode.users
new file mode 100644
index 0000000..59d7dd0
--- /dev/null
+++ b/etc/uronode.users
@@ -0,0 +1,6 @@
+# /etc/ax25/uronode.users	URONode example configuration file
+# Shell access for Sysop users
+
+# callsign:password:local linux username:shell
+# xx#xx:password:xx#xx:shell
+# yy#yy:password:thomas:shell
diff --git a/extcmd.c b/extcmd.c
new file mode 100644
index 0000000..e108cac
--- /dev/null
+++ b/extcmd.c
@@ -0,0 +1,203 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <ctype.h>
+#include <signal.h>
+#include <fcntl.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netax25/ax25.h>
+#include <netrose/rose.h>
+#include <grp.h>
+#include <sys/wait.h>
+#include <netax25/axlib.h>
+#include <netax25/axconfig.h>
+
+#include "node.h"
+
+#define ECMD_PIPE	1		/* Run through pipe 		*/
+
+#ifdef HAVEMOTD
+#define ECMD_RECONN	2		/* */
+#endif
+
+static int norm_extcmd(struct cmd *cmdp, char **argv)
+{
+  int pid;
+
+  alarm(0L);
+  pid = fork();
+  if (pid == -1) {
+    /* fork error */
+    node_perror("norm_extcmd: fork", errno);
+    return 0;
+  }
+  if (pid == 0) {
+    /* child */
+    setgroups(0, NULL);
+    setgid(cmdp->gid);
+    setuid(cmdp->uid);
+    execve(cmdp->path, argv, NULL);
+    node_perror("norm_extcmd: execve", errno);
+    exit(1);
+  }
+  /* parent */
+  waitpid(pid, NULL, 0);
+  return 0;
+}
+
+static int pipe_extcmd(struct cmd *cmdp, char **argv)
+{
+  ax25io *iop;
+  int pipe_in[2], pipe_out[2];
+  int pid, c;
+  fd_set fdset;
+
+  if (pipe(pipe_in) == -1) {
+    node_perror("pipe_extcmd: pipe_in", errno);
+    return 0;
+  }
+  if (pipe(pipe_out) == -1) {
+    node_perror("pipe_extcmd: pipe_out", errno);
+    return 0;
+  }
+  signal(SIGCHLD, SIG_IGN);
+  pid = fork();
+  if (pid == -1) {
+    /* fork error */
+    node_perror("pipe_extcmd: fork", errno);
+    signal(SIGCHLD, SIG_DFL);
+    return 0;
+  }
+  if (pid == 0) {
+    /* child */
+    /*
+     * Redirect childs output to the pipes closing
+     * stdin/out/err as we go.
+     */
+    dup2(pipe_in[0], STDIN_FILENO);
+    dup2(pipe_out[1], STDOUT_FILENO);
+    dup2(pipe_out[1], STDERR_FILENO);
+    /* Close the other ends */
+    close(pipe_in[1]);
+    close(pipe_out[0]);
+    setgroups(0, NULL);
+    setgid(cmdp->gid);
+    setuid(cmdp->uid);
+    execve(cmdp->path, argv, NULL);
+    perror("pipe_extcmd: execve");
+    exit(1);
+  }
+  /* parent */
+  close(pipe_in[0]);
+  close(pipe_out[1]);
+  if (fcntl(STDIN_FILENO, F_SETFL, O_NONBLOCK) == -1 ||
+      fcntl(pipe_out[0], F_SETFL, O_NONBLOCK) == -1) {
+    node_perror("pipe_extcmd: fcntl - pipe_out", errno);
+    goto end;
+  }
+  iop = axio_init(pipe_out[0], pipe_in[1], 1024, UNSPEC_EOL);
+  if (iop == NULL) {
+    node_perror("pipe_extcmd: Error initializing I/O", -1);
+    goto end;
+  }
+  while (1) {
+    FD_ZERO(&fdset);
+    FD_SET(STDIN_FILENO, &fdset);
+    FD_SET(pipe_out[0], &fdset);
+    if (select(32, &fdset, 0, 0, 0) == -1) {
+      node_perror("pipe_extcmd: select", errno);
+      break;
+    }
+    if (FD_ISSET(STDIN_FILENO, &fdset)) {
+      alarm(ConnTimeout);
+      while((c = axio_getc(NodeIo)) != -1)
+	axio_putc(c, iop);
+      if (errno != EAGAIN)
+	break;
+    }
+    if (FD_ISSET(pipe_out[0], &fdset)) {
+      alarm(ConnTimeout);
+      while((c = axio_getc(iop)) != -1)
+	axio_putc(c, NodeIo);
+      if (errno != EAGAIN) {
+	if (errno)
+	  node_msg("%s", strerror(errno));
+	break;
+      }
+    }
+    axio_flush(NodeIo);
+    axio_flush(iop);
+  }
+#ifdef HAVEMOTD
+  if (User.ul_type == AF_NETROM) {
+    axio_printf(NodeIo, "%s} ", NodeId);
+    if (check_perms(PERM_ANSI, 0L) != -1) {
+      axio_printf(NodeIo,"\e[01;31mWelcome back.\e[0m");
+    } else {
+      axio_printf(NodeIo, "Welcome back.");
+    }
+
+  } else if (User.ul_type == AF_INET) {
+    if (check_perms(PERM_ANSI, 0L) != -1) {
+      axio_printf(NodeIo, "\e[01;31m");
+    }  
+    axio_printf(NodeIo, "Returning you to the shell... ");
+  } else if (User.ul_type == AF_AX25) {
+    if (check_perms(PERM_ANSI, 0L) != -1) {
+      axio_printf(NodeIo,"\e[01;31m");
+    } 
+    axio_printf(NodeIo,"Welcome back to %s.", FlexId);
+  } else if (User.ul_type == AF_ROSE) {
+    if (check_perms(PERM_ANSI, 0L) != -1) {
+      axio_printf(NodeIo,"\e[01;31m");
+    }
+    axio_printf(NodeIo,"Back to %s", RoseId);
+  }
+
+#endif
+  axio_end(iop);
+ end:
+  signal(SIGCHLD, SIG_DFL);
+  kill(pid, SIGKILL);
+  close(pipe_in[1]);
+  close(pipe_out[0]);
+  if (fcntl(STDIN_FILENO, F_SETFL, 0) == -1)
+    node_perror("pipe_extcmd: fcntl - stdin", errno);
+  return 0;
+}
+
+int extcmd(struct cmd *cmdp, char **argv)
+{
+  int ret;
+
+  User.state = STATE_EXTCMD;
+  User.dl_type = AF_UNSPEC;
+  strcpy(User.dl_name, cmdp->name);
+  strupr(User.dl_name);
+  update_user();
+  if (cmdp->flags & ECMD_PIPE)
+    ret = pipe_extcmd(cmdp, argv);
+  else
+    ret = norm_extcmd(cmdp, argv);
+
+#ifdef HAVEMOTD
+  if (cmdp->flags & ECMD_RECONN) {
+    if (User.ul_type == AF_NETROM) {
+      axio_printf(NodeIo, "%s} Welcome back.", NodeId);
+    }
+  }
+  else if (User.ul_type == AF_AX25) { 
+    /*		axio_printf(NodeIo, "Welcome back to %s.", FlexId); */
+  }
+  if (User.ul_type == AF_NETROM) {
+    node_msg("");
+  }
+#else
+  if (cmdp->flags)
+    node_logout("");
+#endif
+  return ret;
+}
diff --git a/flexd.c b/flexd.c
new file mode 100644
index 0000000..b82e5bd
--- /dev/null
+++ b/flexd.c
@@ -0,0 +1,431 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <signal.h>
+
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <netax25/ax25.h>
+#include <netrose/rose.h>
+#include <netinet/ip_icmp.h>
+#include <netinet/ip.h>
+
+#include <netax25/axlib.h>
+#include <netax25/axconfig.h>
+#include <netax25/nrconfig.h>
+#include <netax25/rsconfig.h>
+#include <netax25/procutils.h>
+#include <netax25/daemon.h>
+
+#include "config.h"
+#include "procinfo.h"
+
+#define DEFAULT_POLL_TIME 600
+#define MINIMUM_POLL_TIME 300
+
+int poll_time=DEFAULT_POLL_TIME;
+char flexgate[10]="\0";
+char mycall[10]="\0";
+struct ax_routes *gw;
+int s;
+void (*sigterm_defhnd)(int);
+
+void read_conf(void)
+{
+  FILE *fp, *fgt;
+  char buf[1024], line[1024], *cp;
+  int i=0,k;
+  char digipath[AX25_MAX_DIGIS*10];
+
+  if ((fp=fopen(FLEXD_CONF_FILE, "r")) == NULL) {
+    fprintf(stderr, "flexd config: Cannot open config file: %s\n", FLEXD_CONF_FILE);
+    exit(1);
+  }  
+  if ((fgt=fopen(FLEX_GT_FILE, "w")) == NULL) {
+    fprintf(stderr, "flexd config: Cannot open flexnet gateways file: %s\n", FLEX_GT_FILE);
+    fclose(fp);
+    exit(1);
+  }
+
+  fputs("addr  callsign  dev  digipeaters\n", fgt);
+  
+  while(fgets(buf, sizeof(buf), fp)) {
+    if(*buf=='#' || *buf==' ') continue; /* comment line/empty line */
+    cp=strchr(buf, '#');
+    if (cp) *cp='\0';
+    cp=strtok(buf, " \t\n\r");
+    if(cp==NULL) continue; /* empty line */
+
+    if(strcasecmp(cp,"pollinterval")==0) { /* set poll interval */
+      cp=strtok(NULL, " \t\n\r");
+      if(cp==NULL) {
+	fprintf(stderr, "flexd config: PollInterval needs an argument\n");
+	fclose(fp);
+	fclose(fgt);
+	exit(1);        
+      }
+      poll_time=safe_atoi(cp);
+      if (poll_time<MINIMUM_POLL_TIME) poll_time=MINIMUM_POLL_TIME;
+    }
+    if(strcasecmp(cp,"mycall")==0) { /* set connect call for download */
+      cp=strtok(NULL, " \t\n\r");
+      if(cp==NULL) {
+	fprintf(stderr, "flexd config: MyCall needs an argument\n");
+	fclose(fp);
+	fclose(fgt);
+	exit(1);        
+      }
+      safe_strncpy(mycall, cp, 9);
+    }
+    if(strcasecmp(cp,"flexgate")==0) { /* set flexnet gateway */
+      cp=strtok(NULL, " \t\n\r");
+      if(cp==NULL) {
+	fprintf(stderr, "flexd config: FlexGate needs an argument\n");
+	fclose(fp);
+	fclose(fgt);
+	exit(1);        
+      }      
+      safe_strncpy(flexgate, cp, 9);
+      gw=find_route(flexgate, NULL);
+      if (gw==NULL) {
+	fprintf(stderr, "flexd config: FlexGate %s not found in route file: %s\n", flexgate, AX_ROUTES_FILE);
+	fclose(fp);
+	fclose(fgt);
+	exit(1);
+      } else {
+	*digipath='\0';
+	for(k=0;k<AX25_MAX_DIGIS;k++) {
+	  if (gw->digis[k]==NULL) break;
+	  strcat(digipath," ");
+	  strcat(digipath, gw->digis[k]);
+	}
+	sprintf(line, "%05d %-8s %4s %s\n", i++, gw->dest_call, ax25_config_get_dev(gw->dev), digipath);
+	fputs(line, fgt);
+      }
+    }
+  }	 
+
+  fclose(fgt);
+  fclose(fp);
+}
+
+int download_dest(char *gateway, char *fname)
+{
+  FILE *tmp;
+  char buffer[1024], port[14], path[AX25_MAX_DIGIS*10];
+  char *addr, *commands[10], *dlist[9]; /* Destination + 8 digipeaters */
+  fd_set read_fd;
+  int n, addrlen, cmd_send=0, cmd_ack=0, c, k;
+  struct full_sockaddr_ax25 axbind, axconnect;
+  struct timeval tv;
+
+  gw=find_route(gateway, NULL);
+  if (gw==NULL) {
+    fprintf(stderr, "flexd connect: FlexGate %s not found in route file: %s\n", gateway, AX_ROUTES_FILE);
+    return 1;
+  } else {
+    *path='\0';
+    for(k=0;k<AX25_MAX_DIGIS;k++) {
+      if (gw->digis[k][0]=='\0') dlist[k+1]=NULL;
+      else dlist[k+1]=gw->digis[k];
+    }
+    dlist[0]=gw->dest_call;
+    strcpy(port,gw->dev);
+  }
+
+  if ((addr = ax25_config_get_addr(port)) == NULL) {
+    sprintf(buffer, "flexd connect: invalid AX.25 port name - %s\r\n", port);
+    write(STDOUT_FILENO, buffer, strlen(buffer));
+    return 1;
+  }
+  
+  /*
+   * Open the socket into the kernel.
+   */
+  if ((s = socket(AF_AX25, SOCK_SEQPACKET, 0)) < 0) {
+    sprintf(buffer, "flexd connect: cannot open AX.25 socket, %s\r\n", strerror(errno));
+    write(STDOUT_FILENO, buffer, strlen(buffer));
+    return 1;
+  }
+  
+  /*
+   * Set our AX.25 callsign and AX.25 port callsign accordingly.
+   */
+  if (*mycall=='\0') sprintf(buffer, "%s %s", addr, addr);
+  else sprintf(buffer, "%s %s", mycall, addr);
+  ax25_aton(buffer, &axbind);
+  axbind.fsa_ax25.sax25_family = AF_AX25;
+  addrlen=sizeof(struct full_sockaddr_ax25);
+  
+  if (bind(s, (struct sockaddr *)&axbind, addrlen) != 0) {
+    sprintf(buffer, "flexd connect: cannot bind AX.25 socket, %s\r\n", strerror(errno));
+    write(STDOUT_FILENO, buffer, strlen(buffer));
+    close(s);
+    return 1;
+  }
+  
+  /*
+   * Lets try and connect to the far end.
+   */
+  addrlen=sizeof(struct full_sockaddr_ax25);
+  axconnect.fsa_ax25.sax25_family = AF_AX25;
+  
+  if (fcntl(s, F_SETFL, O_NONBLOCK) == -1) {
+    sprintf(buffer, "flexd connect: fcntl on socket: %s\r\n", strerror(errno));
+    write(STDOUT_FILENO, buffer, strlen(buffer));
+    close(s);
+    return 1;
+  }
+
+  if (ax25_aton_arglist((const char **)dlist, &axconnect) == -1) {
+    sprintf(buffer, "flexd connect: invalid destination callsign or digipeater\r\n");
+    write(STDOUT_FILENO, buffer, strlen(buffer));
+    close(s);
+    return 1;
+  }
+  
+  if (connect(s, (struct sockaddr *)&axconnect, addrlen) == -1 && errno != EINPROGRESS) {
+    switch (errno) {
+    case ECONNREFUSED:
+      strcpy(buffer, "*** Connection refused - aborting\r\n");
+      break;
+    case ENETUNREACH:
+      strcpy(buffer, "*** No known route - aborting\r\n");
+      break;
+    case EINTR:
+      strcpy(buffer, "*** Connection timed out - aborting\r\n");
+      break;
+    default:
+      sprintf(buffer, "*** Cannot connect, %s\r\n", strerror(errno));
+      break;
+    }
+    
+    write(STDOUT_FILENO, buffer, strlen(buffer));
+    close(s);
+    return 1;
+  }
+  
+  while (1) {
+    FD_ZERO(&read_fd);
+    FD_SET(s, &read_fd);
+
+    tv.tv_sec=180;
+    tv.tv_usec=0;
+    
+    k=select(s + 3, &read_fd, NULL, 0, &tv);
+    
+    if (k<1) { /* error or timeout */
+      break;
+    }
+    if (FD_ISSET(s, &read_fd)) {
+      int ret, retlen;
+      char *cp;
+      
+      /* See if we got connected or if this was an error */
+      getsockopt(s, SOL_SOCKET, SO_ERROR, &ret, &retlen);
+      if (ret != 0) {
+	cp = strdup(strerror(ret));
+	strlwr(cp);
+	sprintf(buffer, "flexd connect: Failure with %s: %sr\r\n", gateway, cp);
+	write(STDOUT_FILENO, buffer, strlen(buffer));
+	free(cp);
+	close(s);
+	return 1;
+      }
+     break;
+    }
+  }
+  
+  commands[0]="d\r\n";
+  commands[1]="q\r\n";
+  commands[2]=NULL;
+  
+  /*
+   * Loop until one end of the connection goes away.
+   */
+
+  if ((tmp=fopen(fname, "w")) == NULL) {
+    fprintf(stderr, "flexd connect: Cannot open temporary file: %s\n", fname);
+    close(s);
+    return 1;
+  }
+  
+  for (;;) {
+    FD_ZERO(&read_fd);
+    FD_SET(s, &read_fd);
+    
+    tv.tv_sec=180;
+    tv.tv_usec=0;
+    
+    k=select(s + 1, &read_fd, NULL, NULL, &tv);
+    
+    if (k<1) { /* error or timeout */
+      break;
+    }
+    
+    if (FD_ISSET(s, &read_fd)) {
+      if ((n = read(s, buffer, 512)) == -1) break;
+      for(c=0;c<n;c++) { 
+	if (buffer[c]=='\r') buffer[c]='\n';
+	if (buffer[c]=='=' && c<n-1 && buffer[c+1]=='>') {
+	  /* fprintf(stderr, "flex interact: ack[%d]\n", cmd_ack); */
+	  cmd_ack++;
+	}
+      }
+      fwrite(buffer, sizeof(char), n, tmp);
+    }
+ 
+    if (cmd_ack!=0) {
+      if (commands[cmd_send]!=NULL) {
+	write(s, commands[cmd_send], 2);
+	/* fprintf(stderr, "flexd interact: send[%d]: %s\n", cmd_send, commands[cmd_send]); */
+	cmd_send++;
+      }
+      cmd_ack=0;
+    }
+  }
+  
+  close(s);
+
+  fputs("\n",tmp);
+
+  fclose(tmp);
+  return 0;
+}
+
+int parse_dest(char *gateway, char *fname)
+{
+  FILE *fdst, *tmp;
+  char *call, *ssid, *rtt, *cp, buf[1024], line[1024], ax[10];
+  int i=0;
+
+  if ((tmp=fopen(fname, "r")) == NULL) {
+    fprintf(stderr, "flexd update: Cannot open temporary file: %s\n", fname);
+    return 1;
+  }
+  
+  if ((fdst=fopen(FLEX_DST_FILE, "w")) == NULL) {
+    fprintf(stderr, "flexd update: Cannot open flexnet destinations file: %s\n", FLEX_DST_FILE);
+    fclose(tmp);
+    return 1;
+  }
+  
+  fputs("callsign  ssid     rtt  gateway\n", fdst);
+/*   fprintf(fdst, "%s	  %s	     0	  00000\n", mygate, myrange); */
+  while(fgets(buf, sizeof(buf), tmp)) {
+    cp=strtok(buf, " \t\n\r");
+    if(cp==NULL) continue; /* empty line */
+    if(strstr(cp,"=>")) i++; /* system prompt */
+    if(i==0) continue; /* skip connect text */
+    if(*cp=='#' || *cp=='=' || *cp==' ' || *cp=='*' || *cp=='-' || *cp==':') continue; /* comment line/system prompt */
+    if(strncmp(cp,"73!",3)==0) continue; /* End greeting */
+
+    /* CALL SSID-ESID RTT */
+    do {
+      call=cp;
+      if (call==NULL) break;
+      if (strlen(call)>6) break;
+      if (strchr(call,'-')) break;
+      if (ax25_aton_entry(call,ax)!=0) break;
+      if (!ax25_validate(ax)) break;
+      ssid=strtok(NULL, " \t\n\r");
+      if (ssid==NULL) break;
+      if (!strchr(ssid,'-')) break;
+      rtt=strtok(NULL, " \t\n\r");
+      if (rtt==NULL) break;
+      if (atoi(rtt)==0) break;
+      sprintf(line, "%-8s  %-5s %6d    %05d\n", call, ssid, safe_atoi(rtt), 0);
+      fputs(line, fdst);
+      cp=strtok(NULL, " \t\n\r");
+    } while(cp!=NULL);
+  }	 
+
+  fclose(fdst);
+  fclose(tmp);
+
+  return 0;
+}
+
+int update_flex(void)
+{
+  char fname[80];
+
+  sprintf(fname, "%s/.session.%s", FLEXD_TEMP_PATH, flexgate);
+
+  if (download_dest(flexgate, fname)==0) parse_dest(flexgate, fname);
+  remove(fname);
+
+  return 0;
+}
+
+void hup_handler(int sig)
+{
+  signal(SIGHUP, SIG_IGN);
+  
+  read_conf();
+  
+  signal(SIGHUP, hup_handler); /* Restore hangup handler */
+}
+
+void alarm_handler(int sig)
+{
+  signal(SIGALRM, SIG_IGN);
+
+  update_flex();
+
+  signal(SIGALRM, alarm_handler); /* Restore alarm handler */
+  alarm(poll_time); 
+}
+
+void quit_handler(int sig) 
+{
+  signal(SIGTERM, SIG_IGN);
+
+  unlink(FLEXD_PID_FILE);
+  
+  signal(SIGTERM, sigterm_defhnd);
+  raise(SIGTERM);
+}
+
+int main(int argc, char *argv[])
+{       
+  FILE *pidfile; 
+
+ signal(SIGPIPE, SIG_IGN);
+
+  if (ax25_config_load_ports() == 0) {
+    fprintf(stderr, "flexd error: No AX25 port data configured\n");
+    return 1;
+  }
+
+  read_conf();
+
+  if (!daemon_start(TRUE)) {
+    fprintf(stderr, "flexd: cannot become a daemon\n");
+    return 1;
+  }
+
+  signal(SIGTERM, quit_handler);
+  pidfile = fopen(FLEXD_PID_FILE, "w");
+  fprintf(pidfile, "%d\n", (int)getpid());
+  fclose(pidfile);
+
+  update_flex();
+  
+  signal(SIGHUP, hup_handler);
+  signal(SIGALRM, alarm_handler);
+  sigterm_defhnd = signal(SIGTERM, quit_handler);
+  if (sigterm_defhnd == SIG_ERR)
+    sigterm_defhnd = SIG_DFL;
+  alarm(poll_time); 
+  
+  for(;;) pause();
+
+  return 0;
+}
+
diff --git a/gateway.c b/gateway.c
new file mode 100644
index 0000000..603201d
--- /dev/null
+++ b/gateway.c
@@ -0,0 +1,1131 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <time.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/file.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netax25/ax25.h>
+#include <netrose/rose.h>
+#include <netinet/ip_icmp.h>
+#include <netinet/ip.h>
+
+#include <netax25/axlib.h>
+#include <netax25/axconfig.h>
+#include <netax25/nrconfig.h>
+#include <netax25/rsconfig.h>
+#include <netax25/procutils.h>
+
+#include "procinfo.h"
+#include "node.h"
+
+static void invert_ssid(char *out, char *in)
+{
+  char *cp;
+
+  if ((cp = strchr(in, '-')) != NULL) {
+    *cp = 0;
+    sprintf(out, "%s-%d", in, 15 - atoi(cp + 1));
+    *cp = '-';
+  } else {
+    sprintf(out, "%s-15", in);
+  }
+}
+
+/*
+ * Initiate a AX.25, NET/ROM, ROSE or TCP connection to the host
+ * specified by `address'.
+ */
+static ax25io *connect_to(char **addr, int family, int escape, int compr)
+{
+  int fd;
+  ax25io *riop;
+  fd_set read_fdset;
+  fd_set write_fdset;
+  int salen;
+  union {
+    struct full_sockaddr_ax25 ax;
+#ifdef HAVE_ROSE
+    struct sockaddr_rose      rs;
+#endif		
+    struct sockaddr_in        in;
+  } sa;
+  char call[10], path[20], *cp, *eol;
+  int ret, retlen = sizeof(int);
+  int paclen;
+  struct hostent *hp;
+  struct servent *sp;
+  struct user u;
+#ifdef HAVE_NETROM
+  struct proc_nr_nodes *np;
+#endif
+
+  strcpy(call, User.call);
+  /*
+   * Fill in protocol spesific stuff.
+   */
+  switch (family) {
+#ifdef HAVE_ROSE	
+  case AF_ROSE:
+    if (aliascmd==0) {
+      if (check_perms(PERM_ROSE, 0L) == -1) {
+	axio_printf(NodeIo,"Permission denied");
+	if (User.ul_type == AF_NETROM) {
+	  node_msg("");
+	}
+	node_log(LOGLVL_GW, "Permission denied: rose");
+	return NULL;
+      }
+    }
+    if ((fd = socket(AF_ROSE, SOCK_SEQPACKET, 0)) < 0) {
+      node_perror("connect_to: socket", errno);
+      return NULL;
+    }
+    sa.rs.srose_family = AF_ROSE;
+    sa.rs.srose_ndigis = 0;
+    ax25_aton_entry(call, sa.rs.srose_call.ax25_call);
+    rose_aton(rs_config_get_addr(NULL), sa.rs.srose_addr.rose_addr);
+    salen = sizeof(struct sockaddr_rose);
+    if (bind(fd, (struct sockaddr *)&sa, salen) == -1) {
+      node_perror("connect_to: bind", errno);
+      close(fd);
+      return NULL;
+    }
+    memset(path, 0, 11);
+    memcpy(path, rs_config_get_addr(NULL), 4);
+    salen = strlen(addr[1]);
+    if ((salen != 6) && (salen != 10))
+      {
+	axio_printf(NodeIo,"Invalid ROSE address");
+	if (User.ul_type == AF_NETROM) {
+	  node_msg("");
+	}
+	return(NULL);
+      }
+    memcpy(path + (10-salen), addr[1], salen);
+    sprintf(User.dl_name, "%s @ %s", addr[0], path);
+    sa.rs.srose_family = AF_ROSE;
+    sa.rs.srose_ndigis = 0;
+    if (ax25_aton_entry(addr[0], sa.rs.srose_call.ax25_call) < 0) {
+      close(fd);
+      return NULL;
+    }
+    if (rose_aton(path, sa.rs.srose_addr.rose_addr) < 0) {
+      close(fd);
+      return NULL;
+    }
+    if (addr[2] != NULL) {
+      if (ax25_aton_entry(addr[2], sa.rs.srose_digi.ax25_call) < 0) {
+	close(fd);
+	return NULL;
+      }
+      sa.rs.srose_ndigis = 1;
+    }
+    salen = sizeof(struct sockaddr_rose);
+    paclen = rs_config_get_paclen(NULL);
+    eol = ROSE_EOL;
+    /* Uncomment the below if you wish to have the node show a 'Trying' state */
+	if (check_perms(PERM_ANSI, 0L) != -1) {
+          axio_printf(NodeIo, "\e[01;35m");
+	}
+        axio_printf(NodeIo,"Trying %s... press <Enter> to abort", User.dl_name); 
+	
+    break;
+#endif		
+#ifdef HAVE_NETROM
+  case AF_NETROM:
+    if (aliascmd==0) {
+      if (check_perms(PERM_NETROM, 0L) == -1) {
+	axio_printf(NodeIo,"Permission denied");
+	if (User.ul_type == AF_NETROM) {
+	  node_msg("");
+	}
+	node_log(LOGLVL_GW, "Permission denied: netrom");
+	return NULL;
+      }
+    }
+    if ((fd = socket(AF_NETROM, SOCK_SEQPACKET, 0)) < 0) {
+      node_perror("connect_to: socket", errno);
+      return NULL;
+    }
+    /* Why on earth is this different from ax.25 ????? */
+    sprintf(path, "%s %s", nr_config_get_addr(NrPort), call); 
+    ax25_aton(path, &sa.ax);
+    sa.ax.fsa_ax25.sax25_family = AF_NETROM;
+    salen = sizeof(struct full_sockaddr_ax25);
+    if (bind(fd, (struct sockaddr *)&sa, salen) == -1) {
+      node_perror("connect_to: bind", errno);
+      close(fd);
+      return NULL;
+    }
+    if ((np = find_node(addr[0], NULL)) == NULL) {
+      axio_printf(NodeIo,"No such node");
+      if (User.ul_type == AF_NETROM) {
+	node_msg("");
+      }
+      return NULL;
+    }
+    strcpy(User.dl_name, print_node(np->alias, np->call));
+    if (ax25_aton(np->call, &sa.ax) == -1) {
+      close(fd);
+      return NULL;
+    }
+    sa.ax.fsa_ax25.sax25_family = AF_NETROM;
+    salen = sizeof(struct sockaddr_ax25);
+    paclen = nr_config_get_paclen(NrPort); 
+    eol = NETROM_EOL;
+    /* Uncomment the below if you wish the node to show a 'Trying' state */
+    if (check_perms(PERM_ANSI, 0L) != -1) {
+      if (User.ul_type == AF_NETROM) {
+	break;
+      }
+      node_msg("\e[01;36mTrying %s... hit <Enter> to abort", User.dl_name);
+    }
+    break;
+#endif
+#ifdef HAVE_AX25
+  case AF_FLEXNET:
+  case AF_AX25:
+    if (aliascmd==0) {    
+      if (check_perms(PERM_AX25, 0L) == -1 || (is_hidden(addr[0]) && check_perms(PERM_HIDDEN, 0L) == -1)) {
+	axio_printf(NodeIo,"Permission denied");
+	if (User.ul_type == AF_NETROM) {
+	  node_msg("");
+	}
+	node_log(LOGLVL_GW, "Permission denied: ax.25 port %s", addr[0]);
+	return NULL;
+      }
+    }
+    if (ax25_config_get_addr(addr[0]) == NULL) {
+      if (User.ul_type == AF_NETROM) {
+	axio_printf(NodeIo,"%s} ", NodeId);
+      }
+      axio_printf(NodeIo,"Invalid port");
+      if (User.ul_type == AF_NETROM) {
+      	node_msg("");
+      }
+      return NULL;
+    }
+    if ((fd = socket(AF_AX25, SOCK_SEQPACKET, 0)) < 0) {
+      node_perror("connect_to: socket", errno);
+      return NULL;
+    }
+    /*
+     * Invert the SSID only if user is coming in with AX.25
+     * and going out on the same port he is coming in via.
+     */
+/*    if (User.ul_type == AF_AX25 && !strcasecmp(addr[0], User.ul_name)) */
+      invert_ssid(call, User.call);
+    sprintf(path, "%s %s", call, ax25_config_get_addr(addr[0]));
+    ax25_aton(path, &sa.ax);
+    sa.ax.fsa_ax25.sax25_family = AF_AX25;
+    salen = sizeof(struct full_sockaddr_ax25);
+    if (bind(fd, (struct sockaddr *)&sa, salen) < 0) {
+      node_perror("connect_to: bind", errno);
+      close(fd);
+      return NULL;
+    }
+    if (ax25_aton_arglist((const char **)addr+1, &sa.ax) < 0) {
+      close(fd);
+      return NULL;
+    }
+    strcpy(User.dl_name, strupr(addr[1]));
+    strcpy(User.dl_port, strlwr(addr[0]));
+    sa.ax.fsa_ax25.sax25_family = AF_AX25;
+    salen = sizeof(struct full_sockaddr_ax25);
+    paclen = ax25_config_get_paclen(addr[0]);
+    eol = AX25_EOL;
+    /* Uncomment the below if you wish the node to show a 'Trying' state */
+    /*    if (family==AF_FLEXNET) node_msg("Trying %s via FlexNet... Type <RETURN> to abort", User.dl_name); */
+    if ((family==AF_FLEXNET) || (family == AF_AX25)) { 
+      if (!strcmp(User.dl_port,User.ul_name)) {
+        if (check_perms(PERM_ANSI, 0L) != -1) {
+	  axio_printf(NodeIo, "\e[05;31m");
+	}
+        axio_printf(NodeIo,"\aLoop detected on ");
+      }
+      if (check_perms(PERM_ANSI, 0L) != -1) {
+	axio_printf(NodeIo, "\e[0;m");
+      }
+      if (User.ul_type == AF_NETROM) {
+	axio_printf(NodeIo, "%s} ", NodeId);
+      }
+      if (check_perms(PERM_ANSI, 0L) != -1) {
+	axio_printf(NodeIo, "\e[01;33m");
+      }
+      axio_printf(NodeIo,"link setup (%s)...", User.dl_port);
+    }
+    /*    else node_msg("Trying %s on %s... Type <RETURN> to abort", User.dl_name, User.dl_port); */
+    break;
+#endif
+  case AF_INET:
+    if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+      node_perror("connect_to: socket", errno);
+      return NULL;
+    }
+    if ((hp = gethostbyname(addr[0])) == NULL) {
+      if (User.ul_type == AF_NETROM) {
+      	axio_printf(NodeIo, "%s} ", NodeId);
+      }
+      axio_printf(NodeIo,"Unknown host %s", addr[0]);
+      if (User.ul_type == AF_NETROM) {
+	node_msg("");
+      }
+      close(fd);
+      return NULL;
+    }
+    sa.in.sin_family = AF_INET;
+    sa.in.sin_addr.s_addr = ((struct in_addr *)(hp->h_addr))->s_addr;
+    sp = NULL;
+    if (addr[1] == NULL)
+      sp = getservbyname("telnet", "tcp");
+    if (sp == NULL)
+      sp = getservbyname(addr[1], "tcp");
+    if (sp == NULL)
+      sp = getservbyport(htons(atoi(addr[1])), "tcp");
+    if (sp != NULL) {
+      sa.in.sin_port = sp->s_port;
+    } else if (atoi(addr[1]) != 0) {
+      sa.in.sin_port = htons(atoi(addr[1]));
+    } else {
+      axio_printf(NodeIo,"%s Unknown service %s", NodeId, addr[1]);
+      if (User.ul_type == AF_NETROM) {
+	node_msg("");
+      }
+      close(fd);
+      return NULL;
+    }
+    strcpy(User.dl_name, inet_ntoa(sa.in.sin_addr));
+    if (sp != NULL)
+      strcpy(User.dl_port, sp->s_name);
+    else
+      sprintf(User.dl_port, "%d", ntohs(sa.in.sin_port));
+    salen = sizeof(struct sockaddr_in);
+    paclen = 1024;
+    eol = INET_EOL;
+    if (aliascmd==0) {
+      if (check_perms(PERM_TELNET, sa.in.sin_addr.s_addr) == -1) {
+	if (User.ul_type == AF_NETROM) {
+	  axio_printf(NodeIo,"%s} ", NodeId);
+	}	 
+	axio_printf(NodeIo,"Permission denied");
+	if (User.ul_type == AF_NETROM) {
+	  node_msg("");
+	}
+	node_log(LOGLVL_GW, "Permission denied: telnet %s", User.dl_name);
+	close(fd);
+	return NULL;
+      }
+    }
+    /*    if ((check_perms(PERM_ANSI, 0L) != -1) && (family == AF_NETROM)) {
+	  axio_printf(NodeIo,"\e[01;36m%s Trying %s... Type <RETURN> to abort. (Escape: %s%c) \n",NodeId,
+	  User.dl_name,
+	  escape < 32 ? "CTRL-" : "",
+	  escape < 32 ? (escape + 'A' - 1) : escape);
+	  axio_flush(NodeIo);
+	  } */
+    break;
+  default:
+    axio_printf(NodeIo,"%s Unsupported address family", NodeId);
+    if (User.ul_type == AF_NETROM) {
+      node_msg("");
+    }
+    return NULL;
+  }
+  axio_flush(NodeIo);
+  /*
+   * Ok. Now set up a non-blocking connect...
+   */
+  if (fcntl(fd, F_SETFL, O_NONBLOCK) == -1) {
+    node_perror("connect_to: fcntl - fd", errno);
+    close(fd);
+    return NULL;
+  }
+  if (fcntl(STDIN_FILENO, F_SETFL, O_NONBLOCK) == -1) {
+    node_perror("connect_to: fcntl - stdin", errno);
+    close(fd);
+    return NULL;
+  }
+  if (connect(fd, (struct sockaddr *)&sa, salen) == -1 && errno != EINPROGRESS) {
+    node_perror("Duplicate connection not allowed", errno);
+    close(fd);
+    return NULL;
+  }
+  User.dl_type = family;
+  User.state = STATE_TRYING;
+  update_user();
+  /*
+   * ... and wait for it to finish (or user to abort).
+   */
+  while (1) {
+    FD_ZERO(&read_fdset);
+    FD_ZERO(&write_fdset);
+    FD_SET(fd, &write_fdset);
+    FD_SET(STDIN_FILENO, &read_fdset);
+    if (select(fd + 1, &read_fdset, &write_fdset, 0, 0) == -1) {
+      node_perror("connect_to: select", errno);
+      break;
+    }
+    if (FD_ISSET(fd, &write_fdset)) {
+      /* See if we got connected or if this was an error */
+      getsockopt(fd, SOL_SOCKET, SO_ERROR, &ret, &retlen);
+      if (ret != 0) {
+	/*
+	 * This is STUPID !!!!
+	 * FBB interprets "Connection refused" as
+	 * success because it contains the string
+	 * "Connect"...
+	 * But I'm NOT going to toss away valuable
+	 * information (the strerror() info).
+	 * Fortunately (???) FBB is case sensitive
+	 * when examining the return string so
+	 * simply converting the strerror() message
+	 * to lower case fixes the problem. Ugly
+	 * but it _should_ work.
+	 */
+	cp = strdup(strerror(ret));
+	strlwr(cp);
+	if (family==AF_FLEXNET) {
+	  axio_printf(NodeIo,"\n*** failure with %s", User.dl_name); 
+	  if (User.ul_type == AF_NETROM) {
+	    node_msg("");
+	  }
+	} 
+	else  
+	  if (User.ul_type == AF_NETROM) {
+	    axio_printf(NodeIo, "\n%s} Failure with %s: %s\n", NodeId, User.dl_name, cp);
+	  } else {
+	    axio_printf(NodeIo,"\nFailure with %s: %s", User.dl_name, cp);
+	  }
+	node_log(LOGLVL_GW, "Failure with %s: %s", User.dl_name, cp);
+	free(cp);
+	close(fd);
+	return NULL;
+      }
+      break;
+    }
+    if (FD_ISSET(STDIN_FILENO, &read_fdset)) {
+      errno = 0;
+      if (axio_getline(NodeIo) != NULL) {
+        if (User.ul_type == AF_NETROM) {
+	  axio_printf(NodeIo,"%s} ", NodeId);
+	}
+	if (check_perms(PERM_ANSI, 0L) != -1) {
+	  axio_printf(NodeIo, "\e[05;31m");
+	}
+	axio_printf(NodeIo,"Aborted");
+	if (check_perms(PERM_ANSI, 0L) != -1) {
+	  axio_printf(NodeIo, "\e[0;m");
+	}
+	if (User.ul_type == AF_NETROM) {
+	  node_msg("");
+	}
+	close(fd);
+	return NULL;
+      } else if (errno != EAGAIN) {
+	close(fd);
+	return NULL;
+      }
+    }
+  }
+  if (User.dl_type == AF_INET) {
+    if ((User.ul_type == AF_NETROM) || (User.ul_type == AF_ROSE)) {
+      axio_printf(NodeIo,"%s} ", NodeId);
+    }
+    if (check_perms(PERM_ANSI, 0L) != -1) {
+      axio_printf(NodeIo,"\e[01;32m");
+    }
+    node_msg("Socket established to %s:%s", User.dl_name, User.dl_port);
+    if (check_perms(PERM_ANSI, 0L) != -1) {
+      axio_printf(NodeIo,"\e[0;m");
+    }
+  }
+    else
+/*    if (family==AF_FLEXNET) {
+      if (check_perms(PERM_ANSI, 0L) != -1) {
+	axio_printf(NodeIo,"\e[01;32m");
+      }
+      node_msg("\n*** connected to %s", User.dl_name);
+      if (check_perms(PERM_ANSI, 0L) != -1) {
+	axio_printf(NodeIo,"\e[0;m");
+      } 
+    }  
+    else */
+      if ((family==AF_AX25) || (family==AF_FLEXNET) || (family==AF_ROSE)) {
+        if (check_perms(PERM_ANSI, 0L) != -1) {
+	  axio_printf(NodeIo,"\e[01;32m");
+	}
+	if ((family==AF_AX25) || (family==AF_FLEXNET)) {
+/*	  node_msg("\n"); */
+	  } 
+	node_msg("\n*** connected to %s", User.dl_name);
+	if (check_perms(PERM_ANSI, 0L) != -1) {
+	  axio_printf(NodeIo,"\e[0;m");
+	}
+      }
+      else 
+	if (family == AF_NETROM) {
+	  if (check_perms(PERM_ANSI, 0L) != -1) {
+	    axio_printf(NodeIo,"\e[01;32m");
+	  }
+	  if (User.ul_type == AF_INET) {
+	    axio_printf(NodeIo,"Virtual circuit established to %s\n", User.dl_name);
+	  }
+	  if (User.ul_type == AF_NETROM) {
+	    if (check_perms(PERM_ANSI, 0L) != -1) {
+	      axio_printf(NodeIo,"\e[0;m");
+            }
+	    axio_printf(NodeIo,"%s} ", NodeId);
+	    if (check_perms(PERM_ANSI, 0L) != -1) {
+	      axio_printf(NodeIo,"\e[01;32m");
+	    }
+	    axio_printf(NodeIo, "Connected to %s\n", User.dl_name);
+	  } 
+	  if ((User.ul_type == AF_AX25) || (User.ul_type == AF_ROSE)) {
+	    axio_printf(NodeIo,"*** connected to %s\n", User.dl_name); 
+	  } 
+	  if (check_perms(PERM_ANSI, 0L) != -1) {
+	    axio_printf(NodeIo,"\e[0;m");
+	  }
+	}
+  /*
+    else
+    if (family == AF_NETROM) {
+    node_msg("%s} Connected to %s\n", NodeId, User.dl_name);
+    } else {
+    if (check_perms(PERM_ANSI, 0L) != -1) {
+    axio_printf(NodeIo,"\e[01;32m");
+    }
+    node_msg("*** connected to %s\n",
+    User.dl_name,
+    escape < 32 ? "CTRL-" : "",
+    escape < 32 ? (escape + 'A' - 1) : escape);
+    }
+    if (check_perms(PERM_ANSI, 0L) != -1) {
+    axio_printf(NodeIo, "\e[0;m");
+    }
+  */
+  axio_flush(NodeIo);
+  node_log(LOGLVL_GW, "%s Connected to %s", NodeId, User.dl_name);
+  errno = 0;
+  if ((riop = axio_init(fd, fd, paclen, eol)) == NULL) {
+    node_perror("connect_to: Initializing I/O failed", errno);
+    close(fd);
+    return NULL;
+  }
+  
+  if (compr && axio_compr(riop, compr) < 0)
+    node_msg("connect_to: axio_compr failed");
+
+  User.state = STATE_CONNECTED;
+  update_user();
+  return riop;
+}
+
+int do_connect(int argc, char **argv)
+{
+  int i, k;
+  ax25io *riop;
+  struct ax_routes *ax;
+  struct flex_dst *flx;
+  struct flex_gt *flgt;
+  int c, compress, family = AF_UNSPEC, stay, escape;
+  char *nodoconn = NULL;  
+  fd_set fdset;
+  char *connstr = NULL;
+  axio_puts("",NodeIo);
+ 
+  stay = ReConnectTo;
+  if (!strcasecmp(argv[argc - 1], "s")) {
+    stay = 1;
+    argv[--argc] = NULL;
+  } else if (!strcasecmp(argv[argc - 1], "d")) {
+    stay = 0;
+    argv[--argc] = NULL;
+  }
+  compress = 0;
+  c = argv[0][0];
+#ifdef HAVE_ZLIB_H
+  if (*argv[0] == 'z') {
+    compress = 1;
+    c = argv[0][1];
+  }
+#endif
+
+  if (argc < 2) {
+    if (User.ul_type == AF_NETROM) {
+      axio_printf(NodeIo,"%s} ", NodeId);
+    }
+    if (c == 't')
+      axio_printf(NodeIo,"Usage: telnet <host> [<port>] [d|s]");
+    else
+      axio_printf(NodeIo,"Usage: connect [<port>] <call> [via <call1> ...] [d|s]");
+    if (User.ul_type == AF_NETROM) {
+      node_msg("");
+    }
+    return 0;
+  }
+  if (c == 't')
+    family = AF_INET;
+  else if (argc > 2) {
+    // #ifdef HAVE_ROSE		
+    if (strspn(argv[2], "0123456789") == strlen(argv[2]))
+      family = AF_ROSE;
+    else		
+      // #endif
+      family = AF_AX25;
+  }
+  else if (argc == 2) { /* Determine destination */
+    /* call buffer increased by VE3TOK */
+    static char call[10];
+    strncpy(call, strupr(argv[1]), 10);
+
+    /*    if (find_node(argv[1], NULL)!=NULL) { 
+	  family = AF_NETROM;
+	  }
+	  else */
+
+    if ((flx=find_dest(argv[1], NULL))!=NULL) {  /* Check FlexNet */
+      k=1;
+      flgt=find_gateway(flx->addr, NULL);
+      argv[k++]=ax25_config_get_name(flgt->dev);
+      argv[k++]=call;
+      while((k-3)<AX25_MAX_DIGIS&&flgt->digis[k-3][0]!='\0') argv[k]=flgt->digis[(k++)-3];
+      argv[k++]=flgt->call;
+      argv[k]=NULL;
+      argc=k;
+      family = AF_FLEXNET;
+    }
+    else if (find_node(argv[1], NULL)!=NULL) {
+      family = AF_NETROM;
+    }	
+
+    else if ((ax=find_route(argv[1], NULL))!=NULL) {  /* Check AX25 Links */
+      k=1;
+
+      switch(*ax->conn_type)  { 
+      case CONN_TYPE_DIRECT:
+	{
+	  argv[k++]=ax->dev;
+	  argv[k++]=ax->dest_call;
+	  break;  
+	} 
+      case CONN_TYPE_DIGI:
+	{
+	  argv[k++]=ax->dev;
+	  argv[k++]=ax->dest_call; 
+	  while((k-3)<AX25_MAX_DIGIS&&ax->digis[k-3][0]!='\0') argv[k]=ax->digis[(k++)-3];
+	  break;
+	}
+      case CONN_TYPE_NODE:
+	{  
+	  argv[k++]=ax->dev;
+	  argv[k++]=ax->digis[0];
+	  nodoconn=ax->dest_call;
+	  break;
+	}
+      }
+      argv[k]=NULL;
+      argc=k;
+      family = AF_AX25;
+    } 
+    /* else if ((flx=find_dest(argv[1], NULL))!=NULL) {   Check FlexNet 
+       k=1;
+       flgt=find_gateway(flx->addr, NULL);      
+       argv[k++]=ax25_config_get_name(flgt->dev);
+       argv[k++]=call;
+       while((k-3)<AX25_MAX_DIGIS&&flgt->digis[k-3][0]!='\0') argv[k]=flgt->digis[(k++)-3];
+       argv[k++]=flgt->call;
+       argv[k]=NULL;
+       argc=k;
+       family = AF_FLEXNET; 
+       else if (find_node(argv[1], NULL)!=NULL) { 
+       family = AF_NETROM;
+       } */
+	
+    else if ((ax=find_mheard(argv[1]))!=NULL) { /* Check Mheard database */
+      k=1;
+      /*	K2MF supplied code	*/
+      /*	This code *actually* reads mheard.dat and fixes
+       *	the digi path the way it should be.  -N1URO 	*/
+      argv[k++] = ax->dev;
+      argv[k++] = ax->dest_call;
+
+      /* First count the number of digipeaters in the path
+       * from the destination */
+      i = k - 3;
+
+      while(i < AX25_MAX_DIGIS) {
+	if(ax->digis[i][0] == '\0')
+	  break;
+
+	i++;
+      }
+      /* Then construct the reverse digipeater path back to
+       * the destination */
+      while(i && ax->digis[i - 1][0] != '\0')
+	argv[k++] = ax->digis[--i];
+      /*   end K2MF code   */                
+      argv[k]=NULL; 
+      argc=k;
+      family = AF_AX25;
+    } else {  /* Give up */
+      if (User.ul_type == AF_NETROM) {
+	axio_printf(NodeIo,"%s} ", NodeId);
+      }
+      axio_printf(NodeIo,"Remote not in Desti, NetRom, or MHeard tables. Retry your entry.");
+      family = AF_UNSPEC;
+      //      free_flex_dst(flx);
+      //      free_ax_routes(ax);
+      if (User.ul_type == AF_NETROM) {
+	node_msg("");
+      }
+      return 0;
+    }
+  }
+
+  if (family == AF_INET && argc > 3) connstr = argv[3];
+  escape = (check_perms(PERM_NOESC, 0L) == 0) ? -1 : EscChar;
+  riop = connect_to(++argv, family, escape, compress);
+  if (riop == NULL) {
+    if (fcntl(STDIN_FILENO, F_SETFL, 0) == -1)
+      node_perror("do_connect: fcntl - stdin", errno);
+    return 0;
+  }
+  if (family == AF_INET)
+    axio_tnmode(riop, 1);
+  if (connstr) {
+    axio_printf(riop, "%s\n", connstr);
+    axio_flush(riop);
+  } 
+
+  /*
+   * If eol conventions are compatible, switch to binary mode,
+   * else switch to special gateway mode.
+   */
+  if (axio_cmpeol(riop, NodeIo) == 0) {
+    axio_eolmode(riop, EOLMODE_BINARY);
+    axio_eolmode(NodeIo, EOLMODE_BINARY);
+  } else {
+    axio_eolmode(riop, EOLMODE_GW);
+    axio_eolmode(NodeIo, EOLMODE_GW);
+  }
+  if (nodoconn != NULL) axio_printf(riop, "C %s\n",nodoconn); 
+  
+  while (1) {
+    FD_ZERO(&fdset);
+    FD_SET(riop->ifd, &fdset);
+    FD_SET(STDIN_FILENO, &fdset);
+    if (select(32, &fdset, 0, 0, 0) == -1) {
+      node_perror("do_connect: select", errno);
+      break;
+    }
+    if (FD_ISSET(riop->ifd, &fdset)) {
+      alarm(ConnTimeout);
+      while((c = axio_getc(riop)) != -1)
+	axio_putc(c, NodeIo);
+      if (errno != EAGAIN) {
+	if (errno && errno != ENOTCONN)
+	  axio_printf(NodeIo,"%s", strerror(errno));
+	break;
+      }
+    }
+    if (FD_ISSET(STDIN_FILENO, &fdset)) {
+      alarm(ConnTimeout);
+      while((c = axio_getc(NodeIo)) != -1) {
+	if (escape != -1 && c == escape) break;
+	axio_putc(c, riop);
+      }
+      if (escape != -1 && c == escape) {
+	axio_eolmode(NodeIo, EOLMODE_TEXT);
+	axio_getline(NodeIo);
+	break;
+      }
+      if (errno != EAGAIN) {
+	stay = 0;
+	break;
+      }
+    }
+    axio_flush(riop);
+    axio_flush(NodeIo);
+  }
+  axio_end(riop);
+  node_log(LOGLVL_GW, "Disconnected from %s", User.dl_name);
+#ifdef HAVEMOTD 
+  /*  if (User.ul_type != AF_NETROM) {  */
+  /*  if (stay) { */
+  axio_eolmode(NodeIo, EOLMODE_TEXT);
+  if (fcntl(STDIN_FILENO, F_SETFL, 0) == -1)
+    node_perror("do_connect: fcntl - stdin", errno);
+  if (User.ul_type == AF_INET) {
+    if (check_perms(PERM_ANSI, 0L) != -1) {
+      axio_printf(NodeIo,"\e[01;31m");
+    }
+    axio_printf(NodeIo,"\nReturning you to the shell... ");
+  } else
+    if (User.ul_type == AF_AX25) {
+      if (check_perms(PERM_ANSI, 0L) != -1) {
+	axio_printf(NodeIo,"\e[01;31m");
+      }
+      axio_printf(NodeIo,"\r*** reconnected to %s", FlexId);
+      if (check_perms(PERM_ANSI, 0L) != -1) {
+	axio_printf(NodeIo,"\e[0;m");
+      }
+    }
+      if (User.ul_type == AF_ROSE) {
+      if (check_perms(PERM_ANSI, 0L) != -1) {
+        axio_printf(NodeIo,"\e[01;31m");
+      }
+      axio_printf(NodeIo,"\r*** reconnected to %s", RoseId);
+      if (check_perms(PERM_ANSI, 0L) != -1) {
+        axio_printf(NodeIo,"\e[0;m");
+      }
+    }
+  if (User.ul_type == AF_INET) {
+    if (check_perms(PERM_ANSI, 0L) != -1) {
+      axio_printf(NodeIo, "\e[0m");
+    }
+  } 
+  /*     }	*/
+  /*  } */
+  if ((User.ul_type == AF_NETROM) && (!stay)) {
+    node_logout("No reconnect");
+  } 
+  if ((User.ul_type == AF_NETROM) && (stay)) {
+    axio_printf(NodeIo,"%s} ", NodeId);
+    if (check_perms(PERM_ANSI, 0L) != -1) {
+      axio_printf(NodeIo,"\e[01;31mWelcome back.\n\e[0;m");
+    }
+    if (check_perms(PERM_ANSI, 0L) == -1) {
+      axio_printf(NodeIo,"Welcome back.\n");	
+    }	
+  }
+#else 
+  node_logout("No reconnect"); 
+#endif 
+  //      free_flex_dst(flx);
+  //      free_ax_routes(ax);
+  return 0;
+}
+int do_finger(int argc, char **argv)
+{
+  ax25io *riop;
+  int i, compress;
+  char *name, *addr[3], *cp;
+  compress = 0; 
+  
+  /*  if (User.ul_type == AF_NETROM) {
+      axio_printf(NodeIo,"%s} ", NodeId);
+      }  */
+  axio_puts("",NodeIo);
+  if (argc < 2) {
+    if (User.ul_type == AF_NETROM) {
+      axio_printf(NodeIo,"%s} ", NodeId);
+    }
+    axio_printf(NodeIo,"Usage: finger user@<hostname or ip address>.");
+    if (User.ul_type == AF_NETROM) {
+      node_msg("");
+    }
+    return 0;
+  } else if ((cp = strchr(argv[1], '@')) != NULL) {
+    *cp = 0;
+    name = argv[1];
+    addr[0] = ++cp;
+  } else {
+    name = argv[1];
+    addr[0] = "localhost"; 
+    if (User.ul_type == AF_NETROM) {
+      axio_printf(NodeIo,"%s} ", NodeId);
+    }
+    axio_printf(NodeIo,"Usage: finger user@<hostname or ip address>.");
+    if (User.ul_type == AF_NETROM) {
+      node_msg("");
+    }
+    return 0;
+  }
+  addr[1] = "finger";
+  addr[2] = NULL;
+  riop = connect_to(addr, AF_INET, 0, compress);
+  /* If you uncommented 'Trying' state on, uncomment this also. */
+  /*  escape = (check_perms(PERM_NOESC, 0L) == 0) ? -1 : EscChar; */
+  if (riop != NULL) {
+    if (fcntl(riop->ifd, F_SETFL, 0) == -1)
+      node_perror("do_finger: fcntl - fd", errno);
+    axio_printf(NodeIo,"[%s]\n", addr[0]);
+    axio_printf(riop, "%s\n", name);
+    axio_flush(riop);
+    while((i = axio_getc(riop)) != -1)
+      axio_putc(i, NodeIo);
+    axio_end(riop);
+    if (User.ul_type == AF_NETROM) {
+      axio_printf(NodeIo,"%s} ", NodeId);
+    }
+    if (check_perms(PERM_ANSI, 0L) != -1) {
+      axio_printf(NodeIo,"\e[01;31m");
+    }
+    axio_printf(NodeIo,"Finger complete.");
+    if (check_perms(PERM_ANSI, 0L) != -1) {
+      axio_printf(NodeIo, "\e[0;m");
+    }
+    if (User.ul_type == AF_NETROM) {
+      node_msg("");
+    }
+  }
+  axio_eolmode(NodeIo, EOLMODE_TEXT);
+  if (fcntl(STDIN_FILENO, F_SETFL, 0) == -1)
+    node_perror("do_finger: fcntl - stdin", errno);
+  return 0;
+}
+
+/*
+ * Returns difference of tv1 and tv2 in milliseconds.
+ */
+static long calc_rtt(struct timeval tv1, struct timeval tv2)
+{
+  struct timeval tv;
+
+  tv.tv_usec = tv1.tv_usec - tv2.tv_usec;
+  tv.tv_sec = tv1.tv_sec - tv2.tv_sec;
+  if (tv.tv_usec < 0) {
+    tv.tv_sec -= 1L;
+    tv.tv_usec += 1000000L;
+  }
+  return ((tv.tv_sec * 1000L) + (tv.tv_usec / 1000L));
+}
+
+/*
+ * Checksum routine for Internet Protocol family headers (C Version)
+ */
+static unsigned short in_cksum(unsigned char *addr, int len)
+{
+  register int nleft = len;
+  register unsigned char *w = addr;
+  register unsigned int sum = 0;
+  unsigned short answer = 0;
+
+  /*
+   * Our algorithm is simple, using a 32 bit accumulator (sum), we add
+   * sequential 16 bit words to it, and at the end, fold back all the
+   * carry bits from the top 16 bits into the lower 16 bits.
+   */
+  while (nleft > 1)  {
+    sum += (*(w + 1) << 8) + *(w);
+    w     += 2;
+    nleft -= 2;
+  }
+
+  /* mop up an odd byte, if necessary */
+  if (nleft == 1) {
+    sum += *w;
+  }
+
+  /* add back carry outs from top 16 bits to low 16 bits */
+  sum = (sum >> 16) + (sum & 0xffff);     /* add hi 16 to low 16 */
+  sum += (sum >> 16);                     /* add carry */
+  answer = ~sum;                          /* truncate to 16 bits */
+  return answer;
+}
+
+int do_ping(int argc, char **argv)
+{
+  static int sequence = 0;
+  unsigned char buf[256];
+  struct hostent *hp;
+  struct sockaddr_in to, from;
+  struct protoent *prot;
+  struct icmphdr *icp;
+  struct timeval tv1, tv2;
+  struct iphdr *ip;
+  fd_set fdset;
+  int fd, i, id, len = sizeof(struct icmphdr);
+  int salen = sizeof(struct sockaddr);
+
+  /*  if (User.ul_type == AF_NETROM) {
+      axio_printf(NodeIo,"%s} ", NodeId);
+      } */
+  axio_puts("",NodeIo);
+  if (argc < 2) {
+    if (User.ul_type == AF_NETROM) {
+      axio_printf(NodeIo,"%s} ", NodeId);
+    }
+    axio_printf(NodeIo,"Usage: ping <host> [<size>]");
+    if (User.ul_type == AF_NETROM) {
+      node_msg("");
+    }
+    return 0;
+  }
+  if (argc > 2) {
+    len = atoi(argv[2]) + sizeof(struct icmphdr);
+    if (len > 256) {
+      if (User.ul_type == AF_NETROM) {
+	axio_printf(NodeIo,"%s} ", NodeId);
+      }
+      axio_printf(NodeIo,"Maximum size is %d", 256 - sizeof(struct icmphdr));
+      if (User.ul_type == AF_NETROM) {
+	node_msg("");
+      }
+      return 0;
+    }
+  }
+  if ((hp = gethostbyname(argv[1])) == NULL) {
+    if (User.ul_type == AF_NETROM) {
+      axio_printf(NodeIo,"%s} ", NodeId);
+    }
+    axio_printf(NodeIo,"Unknown host %s", argv[1]);
+    if (User.ul_type == AF_NETROM) {
+      node_msg("");
+    }
+    return 0;
+  }
+  memset(&to, 0, sizeof(to));
+  to.sin_family = AF_INET;
+  to.sin_addr.s_addr = ((struct in_addr *)(hp->h_addr))->s_addr;
+  if ((prot = getprotobyname("icmp")) == NULL) {
+    if (User.ul_type == AF_NETROM) {
+      axio_printf(NodeIo,"%s} ", NodeId);
+    }
+    axio_printf(NodeIo,"Unknown protocol icmp");
+    if (User.ul_type == AF_NETROM) {
+      node_msg("");
+    }
+    return 0;
+  }
+  if ((fd = socket(AF_INET, SOCK_RAW, prot->p_proto)) == -1) {
+    node_perror("do_ping: socket", errno);
+    return 0;
+  }
+  if (check_perms(PERM_ANSI, 0L) != -1) {
+    axio_printf(NodeIo,"\e[01;35mICMP Echo request sent to: \e[0m");
+  }
+  if (check_perms(PERM_ANSI, 0L) == -1) {
+    axio_printf(NodeIo, "ICMP Echo request sent to: ");
+  }
+  node_msg("%s", inet_ntoa(to.sin_addr));
+  axio_flush(NodeIo);
+  strcpy(User.dl_name, inet_ntoa(to.sin_addr));
+  User.dl_type = AF_INET;
+  User.state = STATE_PINGING;
+  update_user();
+  /*
+   * Fill the data portion (if any) with some garbage.
+   */
+  for (i = sizeof(struct icmphdr); i < len; i++)
+    buf[i] = (i - sizeof(struct icmphdr)) & 0xff;
+  /*
+   * Fill in the icmp header.
+   */
+  id = getpid() & 0xffff;
+  icp = (struct icmphdr *)buf;
+  icp->type = ICMP_ECHO;
+  icp->code = 0;
+  icp->checksum = 0;
+  icp->un.echo.id = id;
+  icp->un.echo.sequence = sequence++;
+  /*
+   * Calculate checksum.
+   */
+  icp->checksum = in_cksum(buf, len);
+  /*
+   * Take the time and send the packet.
+   */
+  gettimeofday(&tv1, NULL);
+  if (sendto(fd, buf, len, 0, (struct sockaddr *)&to, salen) != len) {
+    node_perror("do_ping: sendto", errno);
+    close(fd);
+    return 0;
+  }
+  /*
+   * Now wait for it to come back (or user to abort).
+   */
+  if (fcntl(STDIN_FILENO, F_SETFL, O_NONBLOCK) == -1) {
+    node_perror("do_ping: fcntl - stdin", errno);
+    close(fd);
+    return 0;
+  }
+  while (1) {
+    FD_ZERO(&fdset);
+    FD_SET(fd, &fdset);
+    FD_SET(STDIN_FILENO, &fdset);
+    if (select(fd + 1, &fdset, 0, 0, 0) == -1) {
+      node_perror("do_ping: select", errno);
+      break;
+    }
+    if (FD_ISSET(fd, &fdset)) {
+      if ((len = recvfrom(fd, buf, 256, 0, (struct sockaddr *)&from, &salen)) == -1) {
+	node_perror("do_ping: recvfrom", errno);
+	break;
+      }
+      gettimeofday(&tv2, NULL);
+      ip = (struct iphdr *)buf;
+      /* Is it long enough? */
+      if (len >= (ip->ihl << 2) + sizeof(struct icmphdr)) {
+	len -= ip->ihl << 2;
+	icp = (struct icmphdr *)(buf + (ip->ihl << 2));
+	/* Is it ours? */
+	if (icp->type == ICMP_ECHOREPLY && icp->un.echo.id == id && icp->un.echo.sequence == sequence - 1) {
+	  if (check_perms(PERM_ANSI, 0L) != -1) {
+	    axio_printf(NodeIo,"\e[01;35mICMP Echo reply received from: \e[0m");
+	  }
+	  if (check_perms(PERM_ANSI, 0L) == -1) {
+	    axio_printf(NodeIo, "ICMP Echo reply received from: ");
+	  }
+          node_msg("%s", inet_ntoa(to.sin_addr));
+	  if (User.ul_type == AF_NETROM) {
+	    axio_printf(NodeIo,"%s} ", NodeId);
+	  }
+	  if (check_perms(PERM_ANSI, 0L) != -1) {
+	    axio_printf(NodeIo, "\e[01;31m");
+	  }
+	  /*	  if (User.ul_type == AF_NETROM) {
+		  axio_printf(NodeIo,"%s} ", NodeId);
+		  }  */
+	  axio_printf(NodeIo, "Ping completed in: %ldms (ttl=%d)", calc_rtt(tv2, tv1), ip->ttl);
+	  if (User.ul_type == AF_NETROM) {
+	    node_msg("");
+	  }  
+	  if (check_perms(PERM_ANSI, 0L) != -1) {
+	    axio_printf(NodeIo, "\e[0;m");
+	  }
+	  break;
+	}
+      }
+    }
+    if (FD_ISSET(STDIN_FILENO, &fdset)) {
+      if (axio_getline(NodeIo) != NULL) {
+        if (User.ul_type ==  AF_NETROM){
+	  axio_printf(NodeIo,"%s} ", NodeId);
+	}
+	if (User.ul_type == AF_INET) {
+	  if (check_perms(PERM_ANSI, 0L) != -1) {
+	    axio_printf(NodeIo, "\e[05;38m");
+	  }
+	}
+	axio_printf(NodeIo,"Aborted");
+	if (User.ul_type == AF_INET) {
+	  if (check_perms(PERM_ANSI, 0L) != -1) {
+	    axio_printf(NodeIo, "\e[0;m");
+	  }
+	}
+	if (User.ul_type == AF_NETROM) {
+	  node_msg("");
+	}
+	break;
+      } else if (errno != EAGAIN) {
+	break;
+      }
+    }
+  }
+  if (fcntl(STDIN_FILENO, F_SETFL, 0) == -1)
+    node_perror("do_ping: fcntl - stdin", errno);
+  close(fd);
+  return 0;
+}
+
diff --git a/ipc.c b/ipc.c
new file mode 100644
index 0000000..c171c34
--- /dev/null
+++ b/ipc.c
@@ -0,0 +1,193 @@
+/* oringinal by Heikki Hannikainen, modified by Brian Rogers */
+
+#include <sys/types.h>
+#include <sys/ipc.h>
+#include <sys/msg.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <signal.h>
+#include <string.h>
+#include <errno.h>
+#include <stdio.h>
+
+#include <netax25/ax25.h>
+#include <netrose/rose.h>
+#include <netax25/axlib.h>
+#include <netax25/axconfig.h>
+#include <netax25/nrconfig.h>
+#include <netax25/rsconfig.h>
+#include <netax25/procutils.h>
+
+#include "node.h"
+
+#define FIRST_KEY (3694	- 1)		/* Where to start looking for a key */
+#define LAST_KEY (FIRST_KEY + 200) 	/* How far to search */
+#define M_LEN 1024			/* Largest message transferred */
+
+struct nmsgbuf {
+  long mtype;		/* message type, must be > 0 */
+  char mtext[M_LEN];	/* message data */
+};
+
+static int ipc_id = -1;
+
+static void usr2_handler(int sig)
+{
+  struct nmsgbuf buf;
+	
+  if (msgrcv(ipc_id, (struct msgbuf *)&buf, M_LEN, 0, IPC_NOWAIT|MSG_NOERROR) != -1) {
+    node_msg("%s", buf.mtext);
+    if (User.ul_type != AF_NETROM) {
+      node_prompt();
+    }
+    if (User.ul_type == AF_NETROM) {
+      node_msg("");
+    }
+    axio_flush(NodeIo);
+  } else
+    node_log(LOGLVL_ERROR, "usr2_handler: Caught SIGUSR2, but couldn't receive a message");
+
+  signal(SIGUSR2, usr2_handler); /* Restore handler */
+}
+
+int ipc_send(key_t key, long mtype, char *mtext)
+{
+  struct nmsgbuf buf;
+  int id;
+	
+  if ((id = msgget(key, S_IRWXU)) == -1) {
+    node_perror("ipc_send: Could not get transmit channel", errno);
+    if (User.ul_type == AF_NETROM) {
+      node_msg("");
+    }
+    return -1;
+  }
+	
+  buf.mtype = mtype;
+  strncpy(buf.mtext, mtext, M_LEN);
+	
+  if (msgsnd(id, (struct msgbuf *)&buf, M_LEN, 0) == -1) {
+    node_perror("ipc_send: Could not send message", errno);
+    if (User.ul_type == AF_NETROM) {
+      node_msg("");
+    }
+    return -1;
+  }
+  if (User.ul_type == AF_NETROM) {
+    node_msg("");
+  }
+  return 0;
+}
+
+int ipc_open(void)
+{
+  key_t key = FIRST_KEY;
+	
+  do {
+    key++;
+    ipc_id = msgget(key, S_IRWXU | IPC_CREAT | IPC_EXCL);
+  } while ((ipc_id == -1) && (key != LAST_KEY));
+
+  if (ipc_id == -1)
+    node_perror("ipc_open: Could not get an IPC channel", errno);
+
+#if 0
+  node_msg("debug: ipc_id=%d key=%d", ipc_id, key);
+#endif
+
+  User.ipc_key = key;
+
+  if (key != -1)
+    signal(SIGUSR2, usr2_handler);
+  else
+    signal(SIGUSR2, SIG_IGN);
+
+  return 0;
+}
+
+int ipc_close(void)
+{
+  struct msqid_ds buf;
+	
+  if (ipc_id != -1)	/* Remove the IPC channel */
+    if (msgctl(ipc_id, IPC_RMID, &buf) == -1) {
+      node_log(LOGLVL_ERROR, "ipc_close: Could not remove IPC channel: %s", strerror(errno)); 
+      return -1;
+    } else {
+      node_log(LOGLVL_ERROR, "ipc_close: Removing IPC channel for %s", User.call);
+    }
+  return 0;
+}
+
+int do_msg(int argc, char **argv)
+{
+  FILE *f;
+  struct user u;
+  char call[10];
+  char mtext[M_LEN];
+  int i, hits = 0, sent = 0;
+
+  if (argc < 3) {
+    node_msg("Usage: msg <call> <your text msg>");
+    if (User.ul_type == AF_NETROM) {
+      node_msg("");
+    }
+    return 0;
+  }
+
+  if ((f = fopen(DATA_NODE_LOGIN_FILE, "r")) == NULL) {
+    node_perror(DATA_NODE_LOGIN_FILE, errno);
+    return 0;
+  }
+  sprintf(mtext, "\n*** Msg from %s:\n\a", User.call);
+  for (i = 2; i < argc; i++) {
+    strncat(mtext, argv[i], M_LEN - strlen(mtext));
+    strncat(mtext, " ", M_LEN - strlen(mtext));
+  }
+  strncat(mtext, "\n*** End of msg.", M_LEN - strlen(mtext));
+  mtext[M_LEN - 1] = 0;
+	
+  strncpy(call, argv[1], 9);
+  call[9] = 0;
+
+  while (fread(&u, sizeof(u), 1, f) == 1) {
+    if (u.pid == -1 || (kill(u.pid, 0) == -1 && errno == ESRCH))
+      continue;
+    if (!strcasecmp(u.call, call)) {
+      hits++;
+      if (u.ipc_key != -1 && u.state == STATE_IDLE) {
+	ipc_send(u.ipc_key, 1, mtext);
+	kill(u.pid, SIGUSR2);
+	sent++;
+      }
+    }
+  }
+  fclose(f);
+  if (hits == 0) {
+    if (User.ul_type == AF_NETROM) {
+      axio_printf(NodeIo, "%s} ", NodeId);
+    }
+    axio_printf(NodeIo, "%s is not on the node now.\a", call);
+    if (User.ul_type == AF_NETROM) {
+      node_msg("");
+    }
+  } else if (sent == 0) {
+    if (User.ul_type == AF_NETROM) {
+      axio_printf(NodeIo, "%s} ", NodeId);
+    }
+    axio_printf(NodeIo, "%s is busy and not accepting msgs now.\a", call);
+    if (User.ul_type == AF_NETROM) {
+      node_msg("");
+    }
+  } else if (sent != 0) {
+    if (User.ul_type == AF_NETROM) {
+      axio_printf(NodeIo, "%s} ", NodeId);
+    }
+    axio_printf(NodeIo, "Msg sent to %s.\a", call);
+  } 
+  if (User.ul_type == AF_NETROM) {
+    node_msg("");
+  }
+  axio_flush(NodeIo);
+  return 0;
+}
diff --git a/man/axdigi.8.gz b/man/axdigi.8.gz
new file mode 100644
index 0000000..a058441
Binary files /dev/null and b/man/axdigi.8.gz differ
diff --git a/man/flexd.conf.5.gz b/man/flexd.conf.5.gz
new file mode 100644
index 0000000..efa7cc8
Binary files /dev/null and b/man/flexd.conf.5.gz differ
diff --git a/man/nodeusers.1.gz b/man/nodeusers.1.gz
new file mode 100644
index 0000000..f5e2430
Binary files /dev/null and b/man/nodeusers.1.gz differ
diff --git a/man/uronode.8.gz b/man/uronode.8.gz
new file mode 100644
index 0000000..7d2e410
Binary files /dev/null and b/man/uronode.8.gz differ
diff --git a/man/uronode.conf.5.gz b/man/uronode.conf.5.gz
new file mode 100644
index 0000000..5ab80b0
Binary files /dev/null and b/man/uronode.conf.5.gz differ
diff --git a/man/uronode.perms.5.gz b/man/uronode.perms.5.gz
new file mode 100644
index 0000000..9e88876
Binary files /dev/null and b/man/uronode.perms.5.gz differ
diff --git a/mheard.c b/mheard.c
new file mode 100644
index 0000000..9c2ed9a
--- /dev/null
+++ b/mheard.c
@@ -0,0 +1,151 @@
+/* Routine rewritten mainly by Barry K2MF (Mr. MFNOS) and Brian N1URO */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <time.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <netax25/ax25.h>
+#include <netrose/rose.h>
+
+#include <netax25/axlib.h>
+#include <netax25/axconfig.h>
+#include <netax25/mheard.h>
+
+#include "config.h"   /* Bob VE3TOK 30Nov2014 */
+#include "procinfo.h"
+#include "node.h"
+
+struct mheard_list {
+  struct mheard_struct data;
+  struct mheard_list *next;
+};
+
+int do_mheard (int argc,char **argv) {
+  FILE *fp;
+  struct mheard_struct mh;
+  struct mheard_list *list = NULL, *new, *tmp, *p;
+  char *s, *t, *u;
+  int mhcount = 0;
+
+  axio_puts("",NodeIo);
+
+  if(User.ul_type == AF_NETROM)
+    axio_printf(NodeIo,"%s} ",NodeId);
+
+  if(argc > 1) {
+    if(ax25_config_get_dev(argv[1]) == NULL
+       || (check_perms(PERM_HIDDEN, 0) == -1
+	   && is_hidden(argv[1]))) {
+      axio_printf(NodeIo,"Invalid port: %s",argv[1]);
+
+      if(User.ul_type == AF_NETROM)
+	node_msg("");
+		
+      return 0;
+    }
+  }
+  if((fp = fopen(DATA_MHEARD_FILE,"r")) == NULL) {
+    node_perror(DATA_MHEARD_FILE,errno);
+    return 0;
+  }
+  while(mhcount < 20 && fread(&mh,sizeof(struct mheard_struct),1,fp)
+	== 1) {
+    if(argc > 1) {
+      if(strcmp(argv[1],mh.portname))
+	continue;
+    }
+    if(check_perms(PERM_HIDDEN,0) == -1 && is_hidden(mh.portname))
+      continue;
+
+    if((new = calloc(1,sizeof(struct mheard_list))) == NULL) {
+      node_perror("do_mheard: calloc",errno);
+      break;
+    }
+    new->data = mh;
+
+    if(list == NULL || mh.last_heard > list->data.last_heard) {
+      tmp = list;
+      list = new;
+    } else {
+      for(p = list; p->next != NULL; p = p->next) {
+	if(mh.last_heard > p->next->data.last_heard)
+	  break;
+      }
+      tmp = p->next;
+      p->next = new;
+    }
+    new->next = tmp;
+    mhcount++;
+  }
+  fclose(fp);
+
+  if(check_perms(PERM_ANSI,0L) != -1)
+    axio_printf(NodeIo,"\e[01;33m");
+
+  node_msg("MHeard list:");
+
+  if(check_perms(PERM_ANSI,0L) != -1)
+    axio_printf(NodeIo,"\e[0;m");
+
+  axio_printf(NodeIo,"Callsign  Device Packets  Date & Time     Frame Type(s)\n");
+  axio_printf(NodeIo,"--------- ------ -------- --------------- -------------");
+
+  while(list != NULL) {
+    s = ctime(&list->data.last_heard);
+    s[19] = 0;
+    s += 4;
+    t = ax25_ntoa(&list->data.from_call);
+
+    if((u = strstr(t,"-0")) != NULL)
+      *u = '\0';
+
+    axio_printf(NodeIo,"\n%-9s %-6s %-8d %s",t,list->data.portname,list->data.count,s);
+
+    if(list->data.mode & MHEARD_MODE_ARP)
+      axio_printf(NodeIo," ARP");
+
+    if(list->data.mode & MHEARD_MODE_FLEXNET)
+      axio_printf(NodeIo," FlexNet");
+
+    if(list->data.mode & MHEARD_MODE_IP_DG)
+      axio_printf(NodeIo," IP-DG");
+
+    if(list->data.mode & MHEARD_MODE_IP_VC)
+      axio_printf(NodeIo," IP-VC");
+
+    if(list->data.mode & MHEARD_MODE_NETROM)
+      axio_printf(NodeIo," NetRom");
+
+    if(list->data.mode & MHEARD_MODE_ROSE)
+      axio_printf(NodeIo," Rose");
+
+    if(list->data.mode & MHEARD_MODE_SEGMENT)
+      axio_printf(NodeIo," Segment");
+
+    if(list->data.mode & MHEARD_MODE_TEXNET)
+      axio_printf(NodeIo," TexNet");
+
+    if(list->data.mode & MHEARD_MODE_TEXT)
+      axio_printf(NodeIo," Text");
+
+    if(list->data.mode & MHEARD_MODE_PSATFT)
+      axio_printf(NodeIo," PacsatFT");
+
+    if(list->data.mode & MHEARD_MODE_PSATPB)
+      axio_printf(NodeIo," PacsatPB");
+
+    if(list->data.mode & MHEARD_MODE_UNKNOWN)
+      axio_printf(NodeIo," Unknown");
+
+    tmp = list;
+    list = list->next;
+    free(tmp);
+
+  }
+  if(User.ul_type == AF_NETROM)
+    node_msg("");
+  return 0;
+}
diff --git a/node.c b/node.c
new file mode 100644
index 0000000..f1ebafc
--- /dev/null
+++ b/node.c
@@ -0,0 +1,419 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <signal.h>
+#include <time.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <netax25/ax25.h>
+#include <netrose/rose.h>
+#include <netax25/axlib.h>
+#include <netax25/axconfig.h>
+#include <netax25/nrconfig.h>
+#include <netax25/rsconfig.h>
+#include <netax25/procutils.h>
+
+#include "node.h"
+
+ax25io *NodeIo  = NULL;
+
+int aliascmd = 0;
+
+/*
+ * Do some validity checking for callsign pointed to by `s'.
+ */
+static int check_call(const char *s)
+{
+  int len = 0;
+  int nums = 0;
+  int ssid = 0;
+  char *p[1];
+
+  if (s == NULL)
+    return -1;
+  while (*s && *s != '-') {
+    if (!isalnum(*s))
+      return -1;
+    if (isdigit(*s))
+      nums++;
+    len++;
+    s++;
+  }
+  if (*s == '-') {
+    if (!isdigit(*++s))
+      return -1;
+    ssid = strtol(s, p, 10);
+    if (**p)
+      return -1;
+  }
+  if (len < 4 || len > 6 || !nums || nums > 2 || ssid < 0 || ssid > 15)
+    return -1;
+  return 0;
+}
+
+static void alarm_handler(int sig)
+{
+  axio_eolmode(NodeIo, EOLMODE_TEXT);
+  axio_puts("\n",NodeIo);
+  if (check_perms(PERM_ANSI, 0L) != -1) {
+    axio_printf(NodeIo,"\e[05;31m");
+  }
+  if (User.ul_type == AF_NETROM) {
+    node_msg("%s} Inactivity timeout! Closing circuit... ", NodeId);
+  }
+  if ((User.ul_type == AF_AX25) || (User.ul_type == AF_ROSE)) {
+    node_msg("Inactivity timeout! Disconnecting you... ");
+  }
+  if (User.ul_type ==  AF_INET) {
+    node_msg("Inactivity timeout! Disconnecting you...");
+  }
+  if (User.ul_type == AF_INET) {
+    if (check_perms(PERM_ANSI, 0L) != -1) {
+      axio_printf(NodeIo,"\e[0;m");
+    }
+  }
+  node_logout("User timed out"); 
+}
+
+static void term_handler(int sig)
+{
+  axio_eolmode(NodeIo, EOLMODE_TEXT);
+  if (User.ul_type == AF_NETROM) {
+    node_msg("%s} Termination received!", NodeId);
+  } else {
+    node_msg("%s - System going down! Disconnecting...", FlexId);
+  }
+  node_logout("SIGTERM");
+}
+
+static void quit_handler(int sig)
+{
+  axio_eolmode(NodeIo, EOLMODE_TEXT);
+  node_logout("User terminated at remote");
+}
+
+int main(int argc, char *argv[])
+{
+  union {
+    struct full_sockaddr_ax25 sax;
+#ifdef HAVE_ROSE		
+    struct sockaddr_rose      srose;
+#endif
+    struct sockaddr_in        sin;
+  } saddr;
+  int i, slen = sizeof(saddr);
+#ifdef HAVEMOTD
+  char *p, buf[256], *pw;
+#else
+  char *p, *pw;
+#endif
+  int paclen;
+#ifdef HAVEMOTD
+  FILE *fp;
+#endif
+  int invalid_cmds = 0;
+  int no_password = 2;
+  int first_time = 1; 
+ 	
+  signal(SIGALRM, alarm_handler);
+  signal(SIGTERM, term_handler);
+  signal(SIGPIPE, quit_handler);
+  signal(SIGQUIT, quit_handler);
+
+#ifdef HAVE_AX25
+  if (ax25_config_load_ports() == 0) {
+    node_log(LOGLVL_ERROR, "No AX.25 port data configured");
+    return 1;
+  }
+#endif	
+
+#ifdef HAVE_NETROM
+  nr_config_load_ports();
+#endif	
+#ifdef HAVE_ROSE			
+  rs_config_load_ports();
+#endif	
+  if (getpeername(STDOUT_FILENO, (struct sockaddr *)&saddr, &slen) == -1) {
+    if (errno != ENOTSOCK) {
+      node_log(LOGLVL_ERROR, "getpeername: %s", strerror(errno));
+      return 1;
+    }
+    User.ul_type = AF_UNSPEC;
+  } else
+    User.ul_type = saddr.sax.fsa_ax25.sax25_family;
+  switch (User.ul_type) {
+  case AF_FLEXNET:
+  case AF_AX25:
+    strcpy(User.call, ax25_ntoa(&saddr.sax.fsa_ax25.sax25_call));
+    if (getsockname(STDOUT_FILENO, (struct sockaddr *)&saddr.sax, &slen) == -1) {
+      node_log(LOGLVL_ERROR, "getsockname: %s", strerror(errno));
+      return 1;
+    }
+    strcpy(User.ul_name, ax25_config_get_port(&saddr.sax.fsa_digipeater[0]));
+    paclen = ax25_config_get_paclen(User.ul_name);
+    p = AX25_EOL;
+    break;
+  case AF_NETROM:
+    strcpy(User.call, ax25_ntoa(&saddr.sax.fsa_ax25.sax25_call));
+    strcpy(User.ul_name, ax25_ntoa(&saddr.sax.fsa_digipeater[0]));
+    if (getsockname(STDOUT_FILENO, (struct sockaddr *)&saddr.sax, &slen) == -1) {
+      node_log(LOGLVL_ERROR, "getsockname: %s", strerror(errno));
+      return 1;
+    }
+    strcpy(User.ul_port, nr_config_get_port(&saddr.sax.fsa_ax25.sax25_call));
+    paclen = nr_config_get_paclen(User.ul_port);
+    p = NETROM_EOL;
+    break;
+#ifdef HAVE_ROSE				
+  case AF_ROSE:
+    strcpy(User.call, ax25_ntoa(&saddr.srose.srose_call));
+    strcpy(User.ul_name, rose_ntoa(&saddr.srose.srose_addr));
+    paclen = rs_config_get_paclen(NULL);
+    p = ROSE_EOL;
+    break;
+#endif		
+  case AF_INET:
+  case AF_INET6:
+    strcpy(User.ul_name, inet_ntoa(saddr.sin.sin_addr));
+    paclen = 1024;
+    p = INET_EOL;
+    break;
+  case AF_UNSPEC:
+    strcpy(User.ul_name, "local");
+    if ((p = get_call(getuid())) == NULL) {
+      node_log(LOGLVL_ERROR, "No uid->callsign association found", -1);
+      printf("Launching: telnet localhost 3694 ...\n");
+      printf("if this fails please RTFM to see how to properly configure it.\n  - 73 de N1URO\a\n"); 
+      node_log(LOGLVL_ERROR, "Tool ran me from the console so I'm forcing", -1);
+      node_log(LOGLVL_ERROR, "a telnet session to port 3694/tcp on them.", -1);
+      /*			axio_flush(NodeIo); */
+      if(NodeIo!=NULL)
+	axio_flush(NodeIo);
+	if (system("telnet 127.0.0.1 3694") < 0 ) {                        /* VE3TOK - 18Nov2014, return value */
+           syslog(LOG_DEBUG, "Can't \"execute telnet 127.0.0.1 3694\"");
+           return 1;
+        }
+	node_log(LOGLVL_ERROR,"Closing console telnet session.", -1);
+      return -1;
+    }
+    strcpy(User.call, p);
+    paclen = 1024;
+    p = UNSPEC_EOL;
+    break;
+  default:
+    node_log(LOGLVL_ERROR, "Unsupported address family %d", User.ul_type);
+    return 1;
+  }
+  NodeIo = axio_init(STDIN_FILENO, STDOUT_FILENO, paclen, p);
+  if (NodeIo == NULL) {
+    node_log(LOGLVL_ERROR, "Error initializing I/O");
+    return 1;
+  }
+#ifdef HAVE_ZLIB_H
+  if (argc > 1 && strcmp(argv[1], "-c") == 0) {
+    axio_compr(NodeIo, 1);
+  }
+#endif
+  if (User.ul_type == AF_INET) {
+    axio_tnmode(NodeIo, 1);
+    axio_tn_do_linemode(NodeIo);
+  }
+  init_nodecmds();
+  if (read_config() == -1) {
+    axio_end(NodeIo);
+    return 1;
+  }
+  for(i=1;i<argc;i++) {
+    if (strcmp(argv[i],"--delay")==0) {
+      axio_flush(NodeIo);
+      p = axio_getline(NodeIo);
+    }
+  }
+  User.state = STATE_LOGIN;
+  login_user();
+  if (User.call[0] == 0) {
+    axio_printf(NodeIo,"(%s:uronode) login: ", HostName);
+    axio_flush(NodeIo);
+    alarm(60L);			/* 1 min timeout */
+    if ((p = axio_getline(NodeIo)) == NULL)
+      node_logout("User disconnected");
+    alarm(0L);
+    strncpy(User.call, p, 9);
+    User.call[9] = 0;
+    strlwr(User.call);
+  }
+  if ((p = strstr(User.call, "-0")) != NULL)
+    *p = 0;
+  if (check_call(User.call) == -1) {
+    node_msg("%s - Invalid callsign", FlexId);
+    node_log(LOGLVL_LOGIN, "Invalid callsign %s @ %s", User.call, User.ul_name);
+    node_logout("Invalid callsign");
+  }
+  if ((pw = read_perms(&User, saddr.sin.sin_addr.s_addr)) == NULL) {
+    node_msg("Sorry, I'm not allowed to talk to you.");
+    node_log(LOGLVL_LOGIN, "Login denied for %s @ %s", User.call, User.ul_name);
+    node_logout("Login denied");
+  } else if (strcmp(pw, "*") != 0) {
+    node_msg("*** Password required! If you don't have a password please email\r\n%s for a password you wish to use.", Email);
+    axio_printf(NodeIo,"\rPassword: ");
+    if (User.ul_type == AF_INET) {
+      axio_tn_will_echo(NodeIo);
+      axio_eolmode(NodeIo, EOLMODE_BINARY);
+    }
+    axio_flush(NodeIo);
+    p = axio_getline(NodeIo);
+    if (User.ul_type == AF_INET) {
+      axio_tn_wont_echo(NodeIo);
+      axio_eolmode(NodeIo, EOLMODE_TEXT);
+      /*			axio_puts("\n",NodeIo); */
+    }
+    if (p == NULL || strcmp(p, pw) != 0) {
+      axio_printf(NodeIo, "\n");
+      if (User.ul_type == AF_NETROM) {
+	node_msg("%s} Invalid or incorrect password...", NodeId);
+      } else {
+	node_msg("%s Invalid or incorrect password...", FlexId);
+      }
+      node_log(LOGLVL_LOGIN, "Login failed for %s @ %s", User.call, User.ul_name);
+      node_logout("Login failed");
+    }
+    no_password = 0;
+  };
+  free(pw);
+  examine_user();
+  ipc_open();
+  node_log(LOGLVL_LOGIN, "%s @ %s logged in", User.call, User.ul_name);
+#ifdef HAVEMOTD
+  if (User.ul_type == AF_NETROM) {
+    /*		axio_printf(NodeIo, "%s} Welcome.\n", NodeId);  */
+  } else 
+    if (User.ul_type == AF_INET) {
+      if (check_perms(PERM_ANSI, 0L) != -1) { 
+	node_msg("\n\e[01;34m[\e[01;37m%s\e[01;34m]\e[0m\nWelcome %s to the %s packet shell.", VERSION, User.call, HostName);
+      } else if (check_perms(PERM_ANSI, 0L) == -1) {
+	node_msg("\n[%s]\nWelcome %s to the %s packet shell.", VERSION, User.call, HostName);
+      }
+      if ((fp = fopen(HAVEMOTD, "r")) != NULL) {
+	while (fgets(buf,256, fp) != NULL) axio_puts(buf,NodeIo);
+	axio_printf (NodeIo, "\n");
+	axio_flush(NodeIo);
+      }
+    } else if (User.ul_type == AF_AX25) { 
+      if (check_perms(PERM_ANSI, 0L) != -1) {
+	node_msg("\e[01;34m[\e[01;37m%s\e[01;34m]\e[0m - Welcome to %s", VERSION, FlexId);
+      } else
+	node_msg("%s - Welcome to %s", VERSION, FlexId); 
+      if ((fp = fopen(HAVEMOTD, "r")) != NULL) {
+	while (fgets(buf, 256, fp) != NULL) axio_puts(buf,NodeIo);
+	axio_puts ("\n",NodeIo);
+	axio_flush(NodeIo);
+      } 
+    } else if (User.ul_type == AF_ROSE) {
+	node_msg("%s - Welcome to %s", VERSION, RoseId);
+        if ((fp = fopen(HAVEMOTD, "r")) != NULL) {
+        while (fgets(buf, 256, fp) != NULL) axio_puts(buf,NodeIo);
+        axio_puts ("\n",NodeIo);
+        axio_flush(NodeIo);
+      }      
+    }
+  lastlog();
+#endif
+  axio_flush(NodeIo);
+  while (1) { if (User.ul_type != AF_NETROM) {
+      axio_flush(NodeIo);
+      if (check_perms(PERM_ANSI, 0L) != -1) {
+	axio_printf(NodeIo,"\e[01;34");
+      }
+      if (no_password == 2) 	{ 
+	node_prompt();
+      }
+      if (no_password == 1) 	{
+	node_prompt();
+	no_password = 2;
+      }
+      if (no_password == 0) 
+	{
+	  if (first_time == 1) 
+	    {
+	      first_time = 0;
+	      if (User.ul_type != AF_NETROM) {
+		/* node_prompt("3"); */
+		if ((User.ul_type == AF_AX25) || (User.ul_type == AF_ROSE)) {
+		  node_prompt();
+		}
+	      }
+	    }
+	  else if ((User.ul_type != AF_NETROM) && (User.ul_type != AF_ROSE)) {
+	    node_prompt();
+	  } else if ((User.ul_type == AF_NETROM) || (User.ul_type == AF_ROSE)) {
+	    axio_printf(NodeIo,"\n");
+	  }
+	}
+    }
+    if (check_perms(PERM_ANSI, 0L) != -1) {
+      /* Not needed from what I see so far.        */
+      if (User.ul_type == AF_AX25) {
+	axio_printf(NodeIo,"\e[0m"); 
+      }
+    }
+    axio_flush(NodeIo); 
+    User.state = STATE_IDLE;
+    time(&User.cmdtime);
+    update_user();
+    alarm(IdleTimeout);
+    errno = 0;
+    if ((p = axio_getline(NodeIo)) == NULL) {
+      if (errno == EINTR)
+	continue;
+      node_logout("User disconnected");
+    };
+    alarm(IdleTimeout);
+    errno = 0;
+    time(&User.cmdtime);
+    update_user();
+    aliascmd = 0;
+    switch (cmdparse(Nodecmds, p))
+      {
+      case -1: 
+	if (++invalid_cmds < 3) {
+	  /* 			node_msg("%s Unknown command. Type ? for a list", NodeId); */
+	  if (User.ul_type == AF_NETROM) {
+	    node_msg("What?\007"); 
+	  } else if (User.ul_type == AF_ROSE) {
+	    axio_printf(NodeIo,"Que?\007");
+	  } else if (User.ul_type == AF_INET) {
+	    axio_printf(NodeIo, "Huh?\007");
+	  } else {
+	    axio_printf(NodeIo,"Eh?\007");
+	  }
+	  node_log(LOGLVL_ERROR,"%s Tool tried bogus command", NodeId);
+	}
+	else 	{
+	  if (User.ul_type == AF_NETROM) {
+	    node_msg("%s Too many invalid commands. Disconnecting...", NodeId);
+	    node_logout("Too many invalid commands");
+	  } else {
+	    node_msg("Too many invalid commands, disconnecting you...");
+	    node_logout("Too many invalid commands");
+	  }
+	}
+	break;
+      case 0: 
+	invalid_cmds = 0;
+	/*			axio_puts ("\n",NodeIo); */
+	break;
+      case 1:
+	invalid_cmds = 0;
+	break;
+      case 2: 
+	invalid_cmds = 0;
+	break;
+      }
+  }
+  node_logout("Out of main loop !?!?!?");
+}
diff --git a/node.h b/node.h
new file mode 100644
index 0000000..20a0f87
--- /dev/null
+++ b/node.h
@@ -0,0 +1,172 @@
+#define VERSION                "URONode v2.3.1"
+#define COMPILING	       "February 14, 2015"
+
+#define STATE_IDLE	0
+#define STATE_TRYING	1
+#define STATE_CONNECTED	2
+#define STATE_PINGING	3
+#define STATE_EXTCMD	4
+#define STATE_LOGIN	5
+#define STATE_QUIT	6
+
+#define LOGLVL_NONE	0
+#define LOGLVL_ERROR	1
+#define LOGLVL_LOGIN	2
+#define LOGLVL_GW	3
+
+#define PERM_LOGIN		1	/* Permit login			*/
+#define PERM_AX25		2	/* AX.25 gatewaying		*/
+#define PERM_NETROM		4	/* NETROM gatewaying		*/
+#define PERM_TELNET_LOCAL	8	/* Telnet to "local" hosts	*/
+#define PERM_TELNET_AMPR	16	/* Telnet to 44.xx.xx.xx hosts	*/
+#define PERM_TELNET_INET	32	/* Telnet to other hosts	*/
+#define PERM_ANSI		64	/* Ansi Color graphics		*/ 
+#define PERM_ROSE		128	/* ROSE gatewaying		*/
+#define PERM_NOESC		256	/* No escape character		*/
+#define PERM_HIDDEN		512	/* Use hidden ports - to be removed */
+
+#define PERM_TELNET (PERM_TELNET_LOCAL & PERM_TELNET_AMPR & PERM_TELNET_INET)
+
+/* Fake id for Flexnet */
+#define AF_FLEXNET 128
+
+#include <sys/types.h>
+#include <sys/ipc.h>	/* for key_t */
+#include <errno.h>
+
+#include <netax25/ax25io.h>
+
+#include "config.h"
+
+struct user
+{
+        pid_t           pid;
+        key_t           ipc_key;
+        time_t          logintime;
+        time_t          cmdtime;
+        unsigned char   state;
+        char            call[10];
+        unsigned short  ul_type;
+        unsigned short  dl_type;
+        char            ul_name[32];
+        char            dl_name[32];
+        char            ul_port[32];
+        char            dl_port[32];
+
+        char            unused[92];
+};
+
+extern struct user User;
+
+extern ax25io *NodeIo;
+
+extern long IdleTimeout;
+extern long ConnTimeout;
+extern int ReConnectTo;
+extern int LogLevel;
+extern int EscChar;
+extern int aliascmd;
+
+extern char *Email;
+extern char *HostName;
+extern char *NodeId;
+extern char *FlexId;
+extern char *RoseId;
+extern char *NrPort;
+extern char *Prompt;
+extern char *PassPrompt;
+
+#define	CMD_INTERNAL	1
+#define	CMD_ALIAS	2
+#define	CMD_EXTERNAL	3
+
+struct cmd {
+	char	*name;
+	int	len;
+	int	type;
+	int	(*function) (int argc, char **argv);
+	char	*command;
+	int	flags;
+	int	uid;
+	int	gid;
+	char	*path;
+
+	struct cmd *next;
+};
+
+extern struct cmd *Nodecmds;
+
+#define min(a,b)	((a) < (b) ? (a) : (b))
+#define max(a,b)	((a) > (b) ? (a) : (b))
+
+/* in cmdparse.c */
+void free_cmdlist(struct cmd *list);
+extern void insert_cmd(struct cmd **list, struct cmd *new);
+extern int add_internal_cmd(struct cmd **list, char *name, int len, int (*function) (int argc, char **argv));
+/* extern char *expand_string(char *str, int argc, char **argv); */
+extern int parse_args(char **argv, char *cmd);
+extern int cmdparse(struct cmd *cmdp, char *cmdline);
+
+/* in util.c */
+extern void node_msg(const char *fmt, ...);
+extern void node_perror(char *str, int err);
+extern char *print_node(const char *alias, const char *call);
+extern void node_log(int, const char *, ...);
+
+/* in user.c */
+extern void login_user(void);
+extern void logout_user(void);
+extern void update_user(void);
+extern int user_list(int argc, char **argv);
+extern int user_count(void);
+extern int system_user_count(void);
+
+/* in config.c */
+extern int is_hidden(const char *port);
+extern int check_perms(int what, unsigned long peer);
+extern char *read_perms(struct user *up, unsigned long peer);
+extern int read_config(void);
+extern int get_escape(char *s);
+
+/* in command.c */
+void init_nodecmds(void);
+extern void node_logout(char *reason);
+extern int nuser_list(int argc, char **argv);
+extern int do_bye(int argc, char **argv);
+extern int do_escape(int argc, char **argv);
+extern int do_help(int argc, char **argv);
+extern int do_host(int argc, char **argv);
+extern int do_ports(int argc, char **argv);
+extern int do_sessions(int argc, char **argv);
+extern int do_routes(int argc, char **argv);
+extern int do_nodes(int argc, char **argv);
+extern int do_status(int argc, char **argv);
+extern int do_version(int argc, char **argv);
+extern int do_last(int argc, char **last);
+
+/* in gateway.c */
+extern int do_connect(int argc, char **argv);
+extern int do_finger(int argc, char **argv);
+extern int do_ping(int argc, char **argv);
+
+/* in router.c */
+extern int do_links(int argc, char **argv);
+extern int do_dest(int argc, char **argv);
+
+/* in ipc.c */
+extern int ipc_open(void);
+extern int ipc_close(void);
+extern int do_msg(int argc, char **argv);
+
+/* in extcmd.c */
+extern int extcmd(struct cmd *cmdp, char **argv);
+
+/* in system.c */
+extern int do_system(int argc, char **argv);
+extern int examine_user(void);
+extern void newmail(void);
+extern void mailcheck(void);
+extern void lastlog(void);
+
+/* in mheard.c */
+extern int do_mheard(int argc, char **argv);
diff --git a/nodeusers.c b/nodeusers.c
new file mode 100644
index 0000000..1190a20
--- /dev/null
+++ b/nodeusers.c
@@ -0,0 +1,82 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <time.h>
+#include <sys/file.h>
+#include <sys/socket.h>
+#include <signal.h>
+#include <syslog.h>
+#include <netax25/ax25.h>
+#include <netrose/rose.h>
+#include <netax25/axlib.h>
+#include <netax25/procutils.h>
+
+#include "node.h"
+#include "config.h"
+
+char *NodeId		= "Nodeusers:";
+int LogLevel		= LOGLVL_NONE;
+ax25io *NodeIo		= NULL;
+static void pipe_handler(int sig)
+{
+  syslog(LOG_ERR, "received SIGPIPE");
+  axio_end(NodeIo);
+  exit(1);
+}
+
+int main(int argc, char **argv)
+{
+  int n, len = 1024;
+  char *cp = UNSPEC_EOL;
+  int inet = 0;
+  int logging = 0;
+
+  while ((n = getopt(argc, argv, "ail")) != -1) {
+    switch (n) {
+    case 'a':
+      cp = AX25_EOL;
+      len = 128;
+      break;
+    case 'i':
+      cp = INET_EOL;
+      inet = 1;
+      break;
+    case 'l':
+      logging = 1;
+      break;
+
+    default:
+      fprintf(stderr, "usage: nodeusers [-a] [-i] [-l]\r\n");
+      return 1;
+    }
+  }
+  if (logging)
+    openlog("nodeusers", LOG_PID, LOG_DAEMON);
+  signal(SIGPIPE, pipe_handler);
+  NodeIo = axio_init(STDIN_FILENO, STDOUT_FILENO, len, cp);
+  if (NodeIo == NULL) {
+    fprintf(stderr, "nodeusers: axio_init failes\r\n");
+    return 1;
+  }
+  if (inet && axio_getline(NodeIo) == NULL) {
+    if (logging)
+      syslog(LOG_ERR, "axio_getline: %m");
+    axio_printf(NodeIo,"\n");
+    axio_end(NodeIo);
+    return 1;
+  }
+  n = user_count();
+  axio_printf(NodeIo,"\n%s (%s), %d user%s.\n",
+	      VERSION, COMPILING, n, n == 1 ? "" : "s");
+  user_list(0, NULL);
+  if (n > 0)
+    axio_printf(NodeIo,"\n");
+  if (axio_flush(NodeIo) == -1 && logging)
+    syslog(LOG_ERR, "axio_flush: %m");
+  axio_end(NodeIo);
+  usleep(500000L);
+  closelog();
+  return 0;
+}
diff --git a/procinfo.c b/procinfo.c
new file mode 100644
index 0000000..7673cbb
--- /dev/null
+++ b/procinfo.c
@@ -0,0 +1,358 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+
+#include <netax25/ax25.h>
+#include <netrose/rose.h>
+#include <netax25/axlib.h>
+#include <netax25/axconfig.h>
+#include <netax25/mheard.h>
+
+#include "procinfo.h"
+
+#include "node.h"
+
+
+/*
+ * Version of atoi() that returns zero if s == NULL.
+ */
+int safe_atoi(const char *s)
+{
+  return (s == NULL) ? 0 : atoi(s);
+}
+
+/*
+ * Version of strncpy() that returns NULL if either src or dest is NULL
+ * and also makes sure destination string is always terminated.
+ */
+char *safe_strncpy(char *dest, char *src, int n)
+{
+  if (dest == NULL || src == NULL) return NULL;
+  dest[n] = 0;
+  return strncpy(dest, src, n);
+}
+
+struct proc_dev *read_proc_dev(void)
+{
+  FILE *fp;
+  char buffer[256];
+  struct proc_dev *p;
+  struct proc_dev *list = NULL;
+  int i = 0;
+  
+  errno = 0;
+  if ((fp = fopen(PROC_DEV_FILE, "r")) == NULL) return NULL;
+  while (fgets(buffer, 256, fp) != NULL) {
+    if (i++<2) continue;
+    if ((p = calloc(1, sizeof(struct proc_dev))) == NULL) break;
+
+    safe_strncpy(p->interface, strtok(buffer, ":\n\r"), 6);
+    while (*p->interface==' ') strcpy(p->interface, p->interface+1);
+    p->rx_bytes = safe_atoi(strtok(NULL, " \t\n\r"));
+    p->rx_packets = safe_atoi(strtok(NULL, " \t\n\r"));
+    p->rx_errs = safe_atoi(strtok(NULL, " \t\n\r"));
+    p->rx_drop = safe_atoi(strtok(NULL, " \t\n\r"));
+    p->rx_fifo = safe_atoi(strtok(NULL, " \t\n\r"));
+    p->rx_frame = safe_atoi(strtok(NULL, " \t\n\r"));
+    p->rx_compressed = safe_atoi(strtok(NULL, " \t\n\r"));
+    p->rx_multicast = safe_atoi(strtok(NULL, " \t\n\r"));
+    p->tx_bytes = safe_atoi(strtok(NULL, " \t\n\r"));
+    p->tx_packets = safe_atoi(strtok(NULL, " \t\n\r"));
+    p->tx_errs = safe_atoi(strtok(NULL, " \t\n\r"));
+    p->tx_drop = safe_atoi(strtok(NULL, " \t\n\r"));
+    p->tx_fifo = safe_atoi(strtok(NULL, " \t\n\r"));
+    p->tx_colls = safe_atoi(strtok(NULL, " \t\n\r"));
+    p->tx_carrier = safe_atoi(strtok(NULL, " \t\n\r"));
+    p->tx_compressed = safe_atoi(strtok(NULL, " \t\n\r"));
+    p->next = list;
+    list = p;
+  }
+  fclose(fp);
+  return list;
+}
+
+void free_proc_dev(struct proc_dev *ap)
+{
+  struct proc_dev *p;
+  
+  while (ap != NULL) {
+    p = ap->next;
+    free(ap);
+    ap = p;
+  }
+}
+
+struct flex_gt *read_flex_gt(void)
+{
+  FILE *fp;
+  char buffer[256], *cp;
+  struct flex_gt *p=NULL, *list = NULL, *new_el;
+  int i = 0, k;
+  
+  errno = 0;
+  if ((fp = fopen(FLEX_GT_FILE, "r")) == NULL) return NULL;
+  while (fgets(buffer, 256, fp) != NULL) {
+    if (i++<1) continue;
+    if ((new_el = calloc(1, sizeof(struct flex_gt))) == NULL) break;
+
+    new_el->addr = safe_atoi(strtok(buffer, " \t\n\r"));
+    safe_strncpy(new_el->call, strtok(NULL, " \t\n\r"), 9);
+    safe_strncpy(new_el->dev, strtok(NULL, " \t\n\r"), 4);
+    
+    k=0;
+    while((cp=strtok(NULL, " \t\n\r"))!=NULL&&k<AX25_MAX_DIGIS) safe_strncpy(new_el->digis[k++],cp,9);
+    while(k<AX25_MAX_DIGIS) strcpy(new_el->digis[k++],"\0");
+
+    if(list==NULL) {
+      list=new_el;
+      p=list;
+    } else {
+      p->next = new_el;
+      p=p->next;
+    }
+  }
+  fclose(fp);
+  return list;
+}
+
+void free_flex_gt(struct flex_gt *fp)
+{
+  struct flex_gt *p;
+  
+  while (fp != NULL) {
+    p = fp->next;
+    free(fp);
+    fp = p;
+  }
+}
+
+struct flex_dst *read_flex_dst(void)
+{
+  FILE *fp;
+  char buffer[256];
+  struct flex_dst *p=NULL, *list = NULL, *new_el;
+  int i = 0;
+  
+  errno = 0;
+  if ((fp = fopen(FLEX_DST_FILE, "r")) == NULL) return NULL;
+  while (fgets(buffer, 256, fp) != NULL) {
+    if (i++<1) continue;
+    if ((new_el = calloc(1, sizeof(struct flex_dst))) == NULL) break;
+
+    safe_strncpy(new_el->dest_call, strtok(buffer, " \t\n\r"), 9);
+    new_el->ssida = safe_atoi(strtok(NULL, " -\t\n\r"));
+    new_el->sside = safe_atoi(strtok(NULL, " -\t\n\r"));
+    new_el->rtt = safe_atoi(strtok(NULL, " \t\n\r"));
+    new_el->addr = safe_atoi(strtok(NULL, " \t\n\r"));
+
+    if(list==NULL) {
+      list=new_el;
+      p=list;
+    } else {
+      p->next = new_el;
+      p=p->next;
+    }
+  }
+  fclose(fp);
+  return list;
+}
+
+void free_flex_dst(struct flex_dst *fp)
+{
+  struct flex_dst *p;
+  
+  while (fp != NULL) {
+    p = fp->next;
+    free(fp);
+    fp = p;
+  }
+}
+
+struct ax_routes *read_ax_routes(void)
+{
+  FILE *fp;
+  char buffer[256], *cp, *cmd;
+  struct ax_routes *p=NULL, *list = NULL, *new_el;
+  int i = 0, k;
+  
+  errno = 0;
+  if ((fp = fopen(AX_ROUTES_FILE, "r")) == NULL) return NULL;
+  while (fgets(buffer, 256, fp) != NULL) {
+    if (i++<1) continue;
+
+    if(*buffer=='#' || *buffer==' ' ) continue; /* commented line */
+    cp=strchr(buffer, '#'); /* ignore comments */
+    if (cp) *cp='\0';
+
+    cmd=strtok(buffer, " \t\n\r");
+    if(cmd==NULL) continue; /* empty line */
+
+    if (strcasecmp(cmd,"route")==0) { /* add route */
+      if ((new_el = calloc(1, sizeof(struct ax_routes))) == NULL) break;
+      safe_strncpy(new_el->dest_call, strupr(strtok(NULL, " \t\n\r")), 9);
+      safe_strncpy(new_el->alias, strupr(strtok(NULL, " \t\n\r")), 9);
+      safe_strncpy(new_el->dev, strtok(NULL, " \t\n\r"), 13);
+      safe_strncpy(new_el->conn_type, strupr(strtok(NULL, " \t\n\r")), 1);
+      safe_strncpy(new_el->description, strtok(NULL, "'\t\n\r"), 50);
+      if (new_el->description==NULL) strcpy(new_el->description," ");
+      
+      switch(*new_el->conn_type) {
+      case CONN_TYPE_DIRECT: 
+	{ 
+	  break;
+	}
+      case CONN_TYPE_NODE:
+	{
+	  safe_strncpy(new_el->digis[0], strupr(strtok(NULL, " \t\n\r")), 9);
+      
+	  break;
+	}
+      case CONN_TYPE_DIGI:
+	{
+	  k=0;      
+	  while((cp=strtok(NULL, " \t\n\r"))!=NULL&&k<AX25_MAX_DIGIS) 
+	    safe_strncpy(new_el->digis[k++],strupr(cp),9);
+	  while(k<AX25_MAX_DIGIS) strcpy(new_el->digis[k++],"\0");
+	  break;
+	}
+      default: 
+	{
+	  return NULL;
+	  break;
+	}
+      }
+
+      
+      if(list==NULL) {
+	list=new_el;
+	p=list;
+      } else {
+	p->next = new_el;
+	p=p->next;
+      }
+    }
+  }
+  fclose(fp);
+  return list;
+}
+
+void free_ax_routes(struct ax_routes *ap)
+{
+  struct ax_routes *p;
+  
+  while (ap != NULL) {
+    p = ap->next;
+    free(ap);
+    ap = p;
+  }
+}
+
+struct ax_routes *find_route(char *dest_call, struct ax_routes *list)
+{
+  static struct ax_routes a;
+  struct ax_routes *axrt=NULL, *p;
+  char *cp, call[10];
+
+  safe_strncpy(call,dest_call,9);
+
+  if ((cp = strchr(call, '-')) != NULL && *(cp + 1) == '0') *cp = 0;
+  axrt=list?list:read_ax_routes();
+  for (p=axrt;p!=NULL;p=p->next) {
+    if (!strcasecmp(call, p->dest_call)) {
+      a = *p;
+      a.next = NULL;
+      p = &a;
+      break;
+    }
+    if (!strcasecmp(call, p->alias)) {
+      a = *p;
+      a.next = NULL;
+      p = &a;
+      break;
+    }
+ 
+  }
+  if (list==NULL) free_ax_routes(axrt);
+  return p;
+}
+
+struct flex_dst *find_dest(char *dest_call, struct flex_dst *list)
+{
+  static struct flex_dst f;
+  struct flex_dst *fdst=NULL, *p;
+  char *cp, call[10];
+  int ssid;
+
+  safe_strncpy(call, dest_call, 9);
+  cp=strchr(call,'-'); 
+  if (cp==NULL) ssid=0;
+  else {
+    ssid=safe_atoi(cp+1);
+    *cp='\0';
+  }
+
+  fdst=list?list:read_flex_dst();
+  for (p=fdst;p!=NULL;p=p->next) {
+    if (!strcasecmp(call, p->dest_call) && (ssid>=p->ssida && ssid<=p->sside)) {
+      f = *p;
+      f.next = NULL;
+      p = &f;
+      break;
+    }
+  }
+  if (list==NULL) free_flex_dst(fdst);
+  return p;
+}
+
+struct flex_gt *find_gateway(int addr, struct flex_gt *list)
+{
+  static struct flex_gt f;
+  struct flex_gt *flgt=NULL, *p;
+
+  flgt=list?list:read_flex_gt();
+  for (p=flgt;p!=NULL;p=p->next) {
+    if (addr==p->addr) {
+      f = *p;
+      f.next = NULL;
+      p = &f;
+      break;
+    }
+  }
+  if (list==NULL) free_flex_gt(flgt);
+  return p;
+}
+
+struct ax_routes *find_mheard(char *dest_call)
+{
+  FILE *fp;
+  static struct ax_routes a;
+  struct mheard_struct mh;
+  char call[12];
+  char *cp;
+  int k;
+
+  if ((fp = fopen(DATA_MHEARD_FILE, "r")) == NULL) {
+    return NULL;
+  }
+  
+  safe_strncpy(call,dest_call,9);
+  cp=strchr(call, '-');
+  if (cp==NULL) strcat(call,"-0");
+
+  while (fread(&mh, sizeof(struct mheard_struct), 1, fp) == 1) {
+    if (strcasecmp(call, ax25_ntoa(&mh.from_call))==0) {
+      fclose(fp);
+      safe_strncpy(a.dest_call, ax25_ntoa(&mh.from_call), 9);
+      safe_strncpy(a.dev, mh.portname, 13);
+      for(k=0;k<AX25_MAX_DIGIS;k++) {
+	if (k<=mh.ndigis) safe_strncpy(a.digis[k],ax25_ntoa(&mh.digis[k]),9);
+	else strcpy(a.digis[k],"\0");
+      }
+      return &a;
+    }
+  }
+  fclose(fp);
+
+  return NULL;
+}
diff --git a/procinfo.h b/procinfo.h
new file mode 100644
index 0000000..366a7bd
--- /dev/null
+++ b/procinfo.h
@@ -0,0 +1,99 @@
+#ifndef _PROCINFO_H
+#define _PROCINFO_H
+
+#define PROC_NR_FILE  "/proc/net/nr"
+#define PROC_DEV_FILE "/proc/net/dev"
+
+/* VE3TOK 30Nov2014 - A number of defines moved to config.h  */
+
+#define CONN_TYPE_DIRECT 'D'
+#define CONN_TYPE_NODE 'N'
+#define CONN_TYPE_DIGI 'V'
+
+struct proc_dev {
+  char          interface[6];
+  int           rx_bytes;
+  int           rx_packets;
+  int           rx_errs;
+  int           rx_drop;
+  int           rx_fifo;
+  int           rx_frame;
+  int           rx_compressed;
+  int           rx_multicast;
+  int           tx_bytes;
+  int           tx_packets;
+  int           tx_errs;
+  int           tx_drop;
+  int           tx_fifo;  
+  int           tx_colls;  
+  int           tx_carrier;  
+  int           tx_compressed;
+
+  struct proc_dev  *next;
+};
+
+
+/*
+ * /var/ax25/flex/gateways: (example)
+ * addr  callsign  dev  dest  digipeaters
+ * 00001 PI4TUE    ax1   935
+ */
+
+struct flex_gt {
+  int                     addr;
+  char                    call[10];
+  char                    dev[14];
+  char                    digis[AX25_MAX_DIGIS][10];
+  
+  struct flex_gt          *next;
+};
+
+/*
+ * /usr/local/var/ax25/flex/destinations: (example)
+ * callsign  ssid    rtt  gateway
+ * 9A0XZG    0-15   2575    00001
+ * DB0AAA    0-0      63    00001
+ */
+
+struct flex_dst {
+  char                    dest_call[10];
+  unsigned short          ssida;
+  unsigned short          sside;
+  unsigned long           rtt;
+  int                     addr;
+  
+  struct flex_dst         *next;
+};
+
+struct ax_routes {
+  char                    dest_call[10];
+  char 			  alias[10]; 
+  char                    dev[14];  
+  char			  conn_type[1];  
+  char 			  description[50];
+  char                    digis[AX25_MAX_DIGIS][10];
+
+  struct ax_routes        *next;
+};
+
+extern int safe_atoi(const char *s);
+extern char *safe_strncpy(char *dest, char *src, int n);
+
+extern struct proc_dev *read_proc_dev(void);
+extern void free_proc_dev(struct proc_dev *ap);
+
+extern struct flex_gt *read_flex_gt(void);
+extern void free_flex_gt(struct flex_gt *fp);
+
+extern struct flex_dst *read_flex_dst(void);
+extern void free_flex_dst(struct flex_dst *fp);
+
+extern struct ax_routes *read_ax_routes(void);
+extern void free_ax_routes(struct ax_routes *ap);
+
+extern struct ax_routes *find_route(char *dest_call, struct ax_routes *list);
+extern struct flex_dst *find_dest(char *dest_call, struct flex_dst *list);
+extern struct flex_gt *find_gateway(int addr, struct flex_gt *list);
+extern struct ax_routes *find_mheard(char *dest_call);
+
+#endif  /* _PROCINFO_H */
diff --git a/router.c b/router.c
new file mode 100644
index 0000000..e68f54c
--- /dev/null
+++ b/router.c
@@ -0,0 +1,261 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <signal.h>
+
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <netax25/ax25.h>
+#include <netrose/rose.h>
+
+#include <netax25/axlib.h>
+#include <netax25/axconfig.h>
+#include "procinfo.h"
+
+#include "node.h"
+
+
+int do_links(int argc, char **argv)
+{
+  struct ax_routes *axrt, *p;
+  char digipath[AX25_MAX_DIGIS*10];
+  char tipoconn[9];  
+  int i=0;
+
+  axio_puts("",NodeIo);
+  if (User.ul_type == AF_NETROM) {
+    axio_printf(NodeIo,"%s} ", NodeId);
+  }
+  if ((axrt=read_ax_routes()) == NULL) {
+    if (errno) node_perror("do_links: read_ax_routes", errno);
+    else axio_printf(NodeIo,"No known links");
+    if (User.ul_type == AF_NETROM) {
+      node_msg("");
+    }
+    return 0;
+  }
+
+  /* "links" */
+  if (check_perms(PERM_ANSI, 0L) != -1) {
+    axio_printf(NodeIo, "\e[01;33m");
+  }
+  if (argc == 1) {
+    node_msg("AX25 Links:");
+    if (check_perms(PERM_ANSI, 0L) != -1) {
+      axio_printf(NodeIo, "\e[0;m");
+    }
+    axio_printf(NodeIo,"Call      Alias     Description\n");
+    axio_printf(NodeIo,"--------- --------- -----------");                        
+    for(p=axrt;p!=NULL;p=p->next) 
+      axio_printf(NodeIo,"\n%-9s %-9s %s", p->dest_call, p->alias, p->description);
+    free_ax_routes(axrt);
+    if (User.ul_type == AF_NETROM) {
+      node_msg("");
+    }
+    return 0;
+  }
+
+  
+  /* "links d" */
+  if ((*argv[1]=='d') && (strlen(argv[1])==1)) {
+    node_msg("AX25 Direct Links:");
+    if (check_perms(PERM_ANSI, 0L) != -1) {
+      axio_printf(NodeIo, "\e[0;m");
+    }
+    axio_printf(NodeIo,"Call      Alias     Interf  Description\n");
+    axio_printf(NodeIo,"--------- --------- ------- -----------");
+    for(p=axrt;p!=NULL;p=p->next) 
+      {  if (*p->conn_type==CONN_TYPE_DIRECT)  axio_printf(NodeIo,"\n%-9s %-9s %-7s %s", p->dest_call, p->alias, p->dev, p->description); }
+    free_ax_routes(axrt);
+    if (User.ul_type == AF_NETROM) {
+      node_msg("");
+    }
+    return 0;
+  }
+  
+  
+  /* "links n" */
+  if ((*argv[1]=='n') && (strlen(argv[1])==1)) {
+    node_msg("AX25 Links via other nodes:");
+    if (check_perms(PERM_ANSI, 0L) != -1) {
+      axio_printf(NodeIo, "\e[0;m");
+    }
+    axio_printf(NodeIo,"Call      Alias     Interf  Routing   Description\n");
+    axio_printf(NodeIo,"--------- --------- ------- --------- -----------");
+    for(p=axrt;p!=NULL;p=p->next) 
+      { if (*p->conn_type==CONN_TYPE_NODE) axio_printf(NodeIo,"\n%-9s %-9s %-7s %-9s %s", p->dest_call, p->alias, p->dev, p->digis[0], p->description); }
+    free_ax_routes(axrt);
+    if (User.ul_type == AF_NETROM) {
+      node_msg("");
+    }
+    return 0;
+  }
+  
+  
+  
+  /* "links v" */
+  if ((*argv[1]=='v') && (strlen(argv[1])==1)) {
+    node_msg("AX25 Links via digipeaters:");
+    if (check_perms(PERM_ANSI, 0L) != -1) {
+      axio_printf(NodeIo, "\e[0;m");
+    }
+    axio_printf(NodeIo,"Call      Alias     Interf  Digipeaters\n");
+    axio_printf(NodeIo,"--------- --------- ------- -----------");
+    for(p=axrt;p!=NULL;p=p->next) {
+      *digipath='\0';
+      for(i=0;i<AX25_MAX_DIGIS;i++) {
+	if (p->digis[i]==NULL) break;
+	if (i!=0) strcat(digipath," ");
+	strcat(digipath, p->digis[i]);
+      }
+      if (*p->conn_type==CONN_TYPE_DIGI) axio_printf(NodeIo,"\n%-9s %-9s %-7s %s", p->dest_call, p->alias,  p->dev, digipath);
+    }
+    free_ax_routes(axrt);
+    if (User.ul_type == AF_NETROM) {
+      node_msg("");
+    }
+    return 0;
+  }
+
+  /* "links <call>" */
+  p=find_route(argv[1], axrt);
+  if(p!=NULL) {
+    node_msg("AX25 Link to %s:", p->dest_call);
+    if (check_perms(PERM_ANSI, 0L) != -1) {
+      axio_printf(NodeIo, "\e[0;m");
+    }
+    axio_printf(NodeIo,"Call      Alias     Interf  Type     Description\n");
+    axio_printf(NodeIo,"--------- --------- ------- -------- -----------");
+    switch(*p->conn_type) {
+    case CONN_TYPE_DIRECT:
+      { strcpy(tipoconn,"Direct"); break; }
+    case CONN_TYPE_NODE:
+      { strcpy(tipoconn,"Via Node"); break; }
+    case CONN_TYPE_DIGI:
+      { strcpy(tipoconn,"Via Digi"); break; }
+    }
+    axio_printf(NodeIo,"\n%-9s %-9s %-7s %-10s %s", p->dest_call, p->alias, p->dev, tipoconn, p->description);
+    if (User.ul_type == AF_NETROM) {
+      node_msg("");
+    }
+  } else {
+    axio_printf(NodeIo,"No such link");
+    if (User.ul_type == AF_NETROM) {
+      node_msg("");
+    }
+  }
+
+  free_ax_routes(axrt);
+  return 0;
+}
+
+/* ssid buffer increased by 1 by VE3TOK */
+int do_dest(int argc, char **argv)
+{
+  struct flex_dst *fdst, *p;
+  struct flex_gt *flgt, *q;
+  char ssid[6];
+  int i=0;
+
+  axio_puts("",NodeIo);
+  if (User.ul_type == AF_NETROM) {
+    axio_printf(NodeIo,"%s} ", NodeId);
+  }
+  if ((fdst=read_flex_dst()) == NULL) {
+    axio_printf(NodeIo,"No known destinations");
+    if (User.ul_type == AF_NETROM) {
+      node_msg("");
+    }
+    return 0;
+  }
+
+  /* "dest" */
+  if (argc == 1) {
+    if (check_perms(PERM_ANSI, 0L) != -1) {
+      axio_printf(NodeIo,"\e[01;33m");
+    }
+    if (User.ul_type != AF_AX25) {
+      axio_printf(NodeIo,"FlexNet Destinations:\n");
+    }
+    if (check_perms(PERM_ANSI, 0L) != -1) {
+      axio_printf(NodeIo, "\e[0;m");
+    }
+    for (p=fdst;p!=NULL;p=p->next) {
+      sprintf(ssid, "%d-%d", p->ssida, p->sside);
+      axio_printf(NodeIo,"%-7s %-5s %4ld%s",p->dest_call,ssid,p->rtt,(++i % 4) ? "  " : "\n");
+    }
+    if ((i % 4) != 0) axio_printf(NodeIo,""); 
+    free_flex_dst(fdst);
+    if (User.ul_type == AF_NETROM) {
+      node_msg("");
+    }
+    return 0;
+  }
+  if ((flgt=read_flex_gt()) == NULL) {
+    node_perror("do_dest: read_flex_gt", errno);
+    if (User.ul_type == AF_NETROM) {
+      node_msg("");
+    }
+    return 0;
+  }
+  /* "dest *" */
+  if (*argv[1]=='*') {
+    if (check_perms(PERM_ANSI, 0L) != -1) {
+      axio_printf(NodeIo,"\e[01;33m");
+    }
+    node_msg("FlexNet Destinations:");
+    if (check_perms(PERM_ANSI, 0L) != -1) {
+      axio_printf(NodeIo, "\e[0;m");
+    }
+    axio_printf(NodeIo,"Dest     SSID    RTT Gateway\n");
+    axio_printf(NodeIo,"-------- ----- ----- --------");
+    for(p=fdst;p!=NULL;p=p->next) {
+      sprintf(ssid, "%d-%d", p->ssida, p->sside);
+      q=find_gateway(p->addr,flgt);
+      axio_printf(NodeIo,"\n%-8s %-5s %5ld %-8s", p->dest_call, ssid, 
+		  p->rtt, q!=NULL?q->call:"?");
+    }
+    free_flex_dst(fdst);
+    free_flex_gt(flgt);
+    if (User.ul_type == AF_NETROM) {
+      node_msg("");
+    }
+    return 0;
+  }
+  /* "dest <call>" */
+  p=find_dest(argv[1], fdst);
+  if(p!=NULL) {
+    if (check_perms(PERM_ANSI, 0L) != -1) {
+      axio_printf(NodeIo,"\e[01;33m");
+    }
+    node_msg("FlexNet Destination %s:", p->dest_call);
+    if (check_perms(PERM_ANSI, 0L) != -1) {
+      axio_printf(NodeIo, "\e[0;m");
+    }
+    axio_printf(NodeIo,"Dest     SSID    RTT Gateway\n");
+    axio_printf(NodeIo,"-------- ----- ----- -------");
+    sprintf(ssid, "%d-%d", p->ssida, p->sside);
+    q=find_gateway(p->addr,flgt);
+    axio_printf(NodeIo,"\n%-8s %-5s %5ld %-8s", p->dest_call, ssid, p->rtt, q!=NULL?q->call:"?");
+    if (User.ul_type == AF_NETROM) {
+      node_msg("");
+    }
+  } else {
+    axio_printf(NodeIo,"No such destination");
+    if (User.ul_type == AF_NETROM) {
+      node_msg("");
+    }
+  }
+
+  free_flex_dst(fdst);
+  free_flex_gt(flgt);
+
+  return 0;
+}
+
+
diff --git a/sysinfo.c b/sysinfo.c
new file mode 100644
index 0000000..564164c
--- /dev/null
+++ b/sysinfo.c
@@ -0,0 +1,243 @@
+/*
+ * This code is slightly modified from the procps package.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <utmp.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <signal.h>
+
+#include "node.h"
+#include "sysinfo.h"
+
+char *xmalloc(size_t);
+char *fixup_null_alloc(size_t);
+int read_utmp(char *);
+int list_entries(int);
+int who(void);
+
+#define UPTIME_FILE  "/proc/uptime"
+#define LOADAVG_FILE "/proc/loadavg"
+#define MEMINFO_FILE "/proc/meminfo"
+
+#define STRUCT_UTMP struct utmp
+static STRUCT_UTMP *utmp_contents;
+
+#ifndef UTMP_FILE
+#define UTMP_FILE "/var/run/utmp"
+#endif
+
+#ifndef EMAILLEN
+#define EMAILLEN 64
+#endif
+
+#ifndef MAXHOSTNAMELEN
+#define MAXHOSTNAMELEN 64
+#endif
+
+#ifndef S_IWGRP
+#define S_IWGRP 020
+#endif
+
+static char buf[300];
+
+/* This macro opens FILE only if necessary and seeks to 0 so that successive
+   calls to the functions are more efficient.  It also reads the current
+   contents of the file into the global buf.
+*/
+#define FILE_TO_BUF(FILE) {					\
+    static int n, fd = -1;					\
+    if (fd == -1 && (fd = open(FILE, O_RDONLY)) == -1) {	\
+      close(fd);						\
+      return 0;							\
+    }								\
+    lseek(fd, 0L, SEEK_SET);					\
+    if ((n = read(fd, buf, sizeof buf - 1)) < 0) {		\
+      close(fd);						\
+      fd = -1;							\
+      return 0;							\
+    }								\
+    buf[n] = '\0';						\
+  }
+
+#define SET_IF_DESIRED(x,y)  if (x) *(x) = (y)	/* evals 'x' twice */
+
+int uptime(double *uptime_secs, double *idle_secs) {
+  double up=0, idle=0;
+    
+  FILE_TO_BUF(UPTIME_FILE)
+    if (sscanf(buf, "%lf %lf", &up, &idle) < 2) {
+      printf("Bad data in %s\n", UPTIME_FILE );
+      return 0;
+    }
+  SET_IF_DESIRED(uptime_secs, up);
+  SET_IF_DESIRED(idle_secs, idle);
+  return up;	/* assume never be zero seconds in practice */
+}
+
+int loadavg(double *av1, double *av5, double *av15) {
+  double avg_1=0, avg_5=0, avg_15=0;
+    
+  FILE_TO_BUF(LOADAVG_FILE)
+    if (sscanf(buf, "%lf %lf %lf", &avg_1, &avg_5, &avg_15) < 3) {
+      printf("Bad data in %s\n", LOADAVG_FILE );
+      return 0;
+    }
+  SET_IF_DESIRED(av1,  avg_1);
+  SET_IF_DESIRED(av5,  avg_5);
+  SET_IF_DESIRED(av15, avg_15);
+  return 1;
+}
+
+/* The following /proc/meminfo parsing routine assumes the following format:
+   [ <label> ... ]				# header lines
+   [ <label> ] <num> [ <num> ... ]		# table rows
+   [ repeats of above line ]
+   
+   Any lines with fewer <num>s than <label>s get trailing <num>s set to zero.
+   The return value is a NULL terminated unsigned** which is the table of
+   numbers without labels.  Convenient enumeration constants for the major and
+   minor dimensions are available in the header file.  Note that this version
+   requires that labels do not contain digits.  It is readily extensible to
+   labels which do not *begin* with digits, though.
+*/
+
+#define MAX_ROW 27	/* these are a little liberal for flexibility */
+#define MAX_COL 2
+
+unsigned** meminfo(void) {
+  static unsigned *row[MAX_ROW + 1];		/* row pointers */
+  static unsigned num[MAX_ROW * MAX_COL];	/* number storage */
+  char *p;
+  int i, j, k, l;
+    
+  FILE_TO_BUF(MEMINFO_FILE)
+    if (!row[0])				/* init ptrs 1st time through */
+      for (i=0; i < MAX_ROW; i++)		/* std column major order: */
+	row[i] = num + MAX_COL*i;		/* A[i][j] = A + COLS*i + j */
+  p = buf;
+  for (i=0; i < MAX_ROW; i++)			/* zero unassigned fields */
+    for (j=0; j < MAX_COL; j++)
+      row[i][j] = 0;
+  for (i=0; i < MAX_ROW && *p; i++) {		/* loop over rows */
+    while(*p && !isdigit(*p)) p++;		/* skip chars until a digit */
+    for (j=0; j < MAX_COL && *p; j++) {	/* scanf column-by-column */
+      l = sscanf(p, "%u%n", row[i] + j, &k);
+      p += k;				/* step over used buffer */
+      if (*p == '\n' || l < 1)		/* end of line/buffer */
+	break;
+    }
+  }
+  /*    row[i+1] = NULL;	terminate the row list, currently unnecessary */
+  return row;					/* NULL return ==> error */
+} 
+
+int system_user_count(void)
+{
+  int users;
+
+  users=who();
+  return users;
+}
+
+int who(void)
+{
+  int users;
+
+  users=read_utmp(UTMP_FILE);
+  return list_entries(users);
+}
+
+int read_utmp (filename)
+     char *filename;
+{
+  FILE *utmp;
+  struct stat file_stats;
+  int n_read;
+  size_t size;
+
+  utmp = fopen (filename, "r");
+  if (utmp == NULL) return 0;
+
+  fstat (fileno (utmp), &file_stats);
+  size = file_stats.st_size;
+  if (size > 0)
+    utmp_contents = (STRUCT_UTMP *) xmalloc (size);
+  else
+    {
+      fclose (utmp);
+      return 0;
+    }
+
+  /* Use < instead of != in case the utmp just grew.  */
+  n_read = fread (utmp_contents, 1, size, utmp);
+  if (ferror (utmp) || fclose (utmp) == EOF || n_read < size) return 0;
+
+  return size / sizeof (STRUCT_UTMP);
+}
+int list_entries (n)
+     int n;
+{
+  register STRUCT_UTMP *this = utmp_contents;
+  register int entries = 0;
+
+  while (n--)
+    {
+      if (this->ut_name[0]
+#ifdef USER_PROCESS
+          && this->ut_type == USER_PROCESS
+#endif
+	  )
+        {
+          char trimmed_name[sizeof (this->ut_name) + 1];
+          int i;
+
+          strncpy (trimmed_name, this->ut_name, sizeof (this->ut_name));
+          trimmed_name[sizeof (this->ut_name)] = ' ';
+          for (i = 0; i <= sizeof (this->ut_name); i++)
+            {
+              if (trimmed_name[i] == ' ')
+                break;
+            }
+          trimmed_name[i] = '\0';
+
+          /* tprintf("%s ", trimmed_name); */
+          entries++;
+        }
+      this++;
+    }
+  return entries;
+}
+
+char *fixup_null_alloc (n)
+     size_t n;
+{
+  char *p;
+
+  p = 0;
+  if (n == 0)
+    p = malloc ((size_t) 1);
+  if (p == 0) return NULL;
+  return p;
+}
+
+/* Allocate N bytes of memory dynamically, with error checking.  */
+
+char *xmalloc (n)
+     size_t n;
+{
+  char *p;
+
+  p = malloc (n);
+  if (p == 0)
+    p = fixup_null_alloc (n);
+  return p;
+}
diff --git a/sysinfo.h b/sysinfo.h
new file mode 100644
index 0000000..5d2e32f
--- /dev/null
+++ b/sysinfo.h
@@ -0,0 +1,26 @@
+#ifndef SYSINFO_H
+#define SYSINFO_H
+
+int        loadavg(double *av1, double *av5, double *av15);
+int        uptime (double *uptime_secs, double *idle_secs);
+
+unsigned** meminfo(void);
+
+enum meminfo_row { meminfo_main = 0, meminfo_free, meminfo_buffers, 
+		meminfo_cached, meminfo_scached, meminfo_active,
+		meminfo_inactive, meminfo_htotal, meminfo_hfree,
+		meminfo_ltotal, meminfo_lfree, meminfo_stotal, 
+		meminfo_sfree, meminfo_dirty, meminfo_writeback,
+		meminfo_anonpages, meminfo_mapped, meminfo_slab,
+		meminfo_sreclaim, meminfo_sunreclaim, meminfo_pagetables,
+		meminfo_nfs_unstab, meminfo_bounce, meminfo_climit,
+		meminfo_cas, meminfo_vmtotal, meminfo_vmused, 
+		meminfo_vmchunk 
+};
+
+enum meminfo_col { meminfo_total = 0
+}; 
+
+unsigned read_total_main(void);
+
+#endif /* SYSINFO_H */
diff --git a/system.c b/system.c
new file mode 100644
index 0000000..e7805fb
--- /dev/null
+++ b/system.c
@@ -0,0 +1,632 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <errno.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/file.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/param.h>
+
+#include <fcntl.h>
+#include <ctype.h>
+#include <signal.h>
+
+#include <paths.h>
+#include <pwd.h>
+#include <utmp.h>
+#include <time.h>
+
+#include <termios.h>
+#include <unistd.h>
+
+#include <netax25/ax25.h>
+#include <netrose/rose.h>
+#include <netax25/axlib.h>
+#include <netax25/axconfig.h>
+
+#include "node.h"
+#include "procinfo.h"
+#include "config.h"  /* VE3TOK - Dec20, 2014 */
+
+#define USER_NOBODY "nobody"
+
+#define NUMPTY 176
+#define SYSTEM_TIMEOUT 7200
+#define LAST_DATA_SIZE 120
+
+int shell=0;
+char *envp[16], *argp[16], mbox[40];
+char other_id[20];
+int in_queue=0;
+int pid=-1;
+char ptyname[80], Password[256];
+int ptyfd;
+
+/*---------------------------------------------------------------------------*/
+
+int cusgets(char *buf, int buflen, ax25io *iop)
+{
+  int c, len = 0;
+
+  while (len < (buflen - 1)) {
+    c = axio_getc(iop);
+    if (c == -1) {
+      if (len > 0) {
+        buf[len] = 0;
+        return (len);
+      } else return -1;
+    }
+    /* NULL also interpreted as EOL */
+    if (c == '\n' || c == '\r' || c == 0) {
+      buf[len++] = c;
+      buf[len] = 0;
+      return (len);
+    }
+    buf[len++] = c;
+  }
+  buf[buflen - 1] = 0;
+  return (buflen-1);
+}
+
+/*---------------------------------------------------------------------------*/
+
+int find_pty(char *ptyname)
+{
+  char master[80];
+  int fd;
+  int num;
+  static int lastnum = -1;
+
+  for(num = lastnum + 1; ; num++) {
+    if (num >= NUMPTY) num = 0;
+    sprintf(master, "/dev/pty%c%x", 'p' + (num >> 4), num & 0xf); 
+/*      sprintf(master, "/dev/pts/%x", num & 0xf); */
+    if ((fd = open(master, O_RDWR | O_NONBLOCK, 0600)) >= 0) {
+      sprintf(ptyname, "/dev/tty%c%x", 'p' + (num >> 4), num & 0xf);
+/*     sprintf(ptyname, "/dev/pts/%x", num & 0xf); */
+      lastnum = num;
+      return fd;
+    }
+    if (num == lastnum) break;
+  }
+
+  return -1;
+}
+
+/*---------------------------------------------------------------------------*/
+
+void login_close(void)
+{
+  struct utmp utmpbuf, *ut;
+  FILE *fp;
+
+  if (ptyfd > 0) {
+    chown(ptyname, 0, 0);
+    chmod(ptyname, 0666);
+    ioctl(ptyfd, TCFLSH, 2);
+    close(ptyfd);
+  }
+  if (pid>0) {
+    kill(pid, SIGHUP);
+    pid=0;
+  }
+
+  memset(&utmpbuf, 0, sizeof(utmpbuf));
+  setutent();
+  utmpbuf.ut_type=LOGIN_PROCESS;
+  strcpy(utmpbuf.ut_line, ptyname+5);
+  strcpy(utmpbuf.ut_id, ptyname+strlen(ptyname)-2);
+  ut=getutid(&utmpbuf);
+  ut->ut_type=DEAD_PROCESS;
+  memset(ut->ut_host,0,UT_HOSTSIZE);
+  memset(ut->ut_user,0,UT_NAMESIZE);
+  time(&ut->ut_time); 
+/*  ut->ut_xtime = (unsigned int)time(NULL); */
+  pututline(ut);
+  endutent();
+  if ((fp = fopen(_PATH_WTMP, "r+")) != NULL) {
+    fseek(fp, 0L, SEEK_END);
+    fwrite(ut, sizeof(utmpbuf), 1, fp);
+    fclose(fp);
+  }
+  if (User.ul_type == AF_NETROM) {
+    axio_printf(NodeIo,"%s} Welcome back.\n", NodeId);
+  } else {
+    axio_printf(NodeIo,"Welcome back.");
+  }
+}
+
+/*---------------------------------------------------------------------------*/
+
+int login_open(struct passwd *pw, char *command)
+{
+  if ((ptyfd=find_pty(ptyname)) < 0) {
+    syslog(LOG_ERR, "Error opening pseudo terminal for %s", pw->pw_name);
+    return -1;
+  }
+
+  syslog(LOG_INFO, "Opened pseudo terminal (%s) for %s", ptyname, pw->pw_name);
+
+  pid=fork();
+  
+  if (pid==-1) { 
+    syslog(LOG_ERR, "Cannot fork for %s", pw->pw_name);
+    return -1;
+  }
+
+  if (pid==0) { /* child */
+    struct termios termios;
+    struct utmp utmpbuf;
+    int i;
+
+    for(i=0;i<FD_SETSIZE;i++) close(i);
+    setsid();
+    open(ptyname, O_RDWR, 0666);
+    dup(0);
+    dup(0);
+    chmod(ptyname, 0622);
+    ioctl(0, TIOCSCTTY, 0);
+    
+    memset(&termios, 0 , sizeof(termios));
+    termios.c_iflag = ICRNL | IXOFF;
+    termios.c_oflag = OPOST | ONLCR | TAB3;
+    termios.c_cflag = CS8 | CREAD | CLOCAL;
+    termios.c_lflag = ISIG | ICANON;
+
+    termios.c_cc[VINTR] = 127;
+    termios.c_cc[VQUIT] = 28;
+    termios.c_cc[VERASE] = 8;
+    termios.c_cc[VKILL] = 24;
+    termios.c_cc[VEOF] = 4;
+
+    cfsetispeed(&termios, B38400);
+    cfsetospeed(&termios, B38400);
+    tcsetattr(0, TCSANOW, &termios);
+
+    memset(&utmpbuf, 0, sizeof(utmpbuf));
+    utmpbuf.ut_type=USER_PROCESS;                          /* Type of login */
+    utmpbuf.ut_pid=getpid();                               /* Pid of login process */
+    strcpy(utmpbuf.ut_line, ptyname+5);                    /* Devicename of tty */
+    strcpy(utmpbuf.ut_id, ptyname+strlen(ptyname)-2);      /* Inittab id */
+    strcpy(utmpbuf.ut_user, pw->pw_name);                  /* Username */
+    strcpy(utmpbuf.ut_host, "local:uronode");
+    utmpbuf.ut_addr=0x7f000000;
+    time(&utmpbuf.ut_time);                                /* Time entry was made */
+/*    utmpbuf.ut_xtime = (unsigned int)time(NULL); */
+
+    setutent();
+    pututline(&utmpbuf);
+    endutent();
+
+    setgid(pw->pw_gid);
+    setuid(pw->pw_uid);
+
+    execve(command, argp, envp);
+    exit(1);
+  }
+
+  if (pid!=0) {
+    int k, cnt;
+    fd_set fds_read, fds_err;
+    struct timeval tv;
+    char buf[1500];
+
+    while(1) {
+      FD_ZERO(&fds_read);
+      FD_ZERO(&fds_err);
+      FD_SET(STDIN_FILENO, &fds_read);
+      /* FD_SET(User.fd, &fds_err); */
+      FD_SET(ptyfd, &fds_read);
+      /* FD_SET(ptyfd, &fds_err); */
+
+      if (User.ul_type==AF_INET) {
+	tv.tv_usec=25; 
+	tv.tv_sec=0;
+      } else {
+	tv.tv_usec=750; 
+	tv.tv_sec=0;
+      }
+
+      if (in_queue>0) k=select(ptyfd+1, &fds_read, NULL, &fds_err, &tv);
+      else k=select(ptyfd+1, &fds_read, NULL, &fds_err, NULL);
+					  
+      if (k == -1) {
+	if (errno!=EINTR) {
+	  syslog(LOG_DEBUG,"I/O select");
+	  break;
+	}
+      }
+
+      if (k == 0) {
+	if (in_queue>0) {
+	  axio_flush(NodeIo);
+	  in_queue=0;
+	}
+      }
+
+      /*      if (FD_ISSET(User.fd, &fds_err)) {    
+	      syslog(LOG_DEBUG,"I/O end: error channel, user");
+	      break;
+	      }
+      
+	      if (FD_ISSET(ptyfd, &fds_err)) {
+	      syslog(LOG_DEBUG,"I/O end: error channel, application");
+	      break;
+	      } */
+
+      if (FD_ISSET(STDIN_FILENO, &fds_read)) {
+        alarm(SYSTEM_TIMEOUT);
+	cnt=cusgets(buf, sizeof(buf), NodeIo);
+	if (cnt < 0)
+	  {   
+	    syslog(LOG_DEBUG,"I/O end: stdio channel, user");
+	    break;
+	  } else {
+	  write(ptyfd, buf, cnt);
+	}   
+      }
+      
+      if (FD_ISSET(ptyfd, &fds_read)) {
+        alarm(SYSTEM_TIMEOUT);
+	cnt = read(ptyfd, buf, sizeof(buf));
+	if (cnt < 0) {
+	  syslog(LOG_DEBUG,"I/O end: stdio channel, application");
+	  break;
+	}
+	for(k = 0 ; k < cnt ; k++) {
+	  if (buf[k]=='\n' && (User.ul_type==AF_AX25 || User.ul_type==AF_FLEXNET || User.ul_type==AF_NETROM)) continue;
+	  axio_putc(buf[k], NodeIo);
+	}
+	in_queue+=cnt;
+      }
+    }
+
+    login_close();
+  }
+
+  return 0;
+}
+
+/*---------------------------------------------------------------------------*/
+
+int check_passwd(void)
+{
+  char buffer[400]="",
+    tmp[100]="";
+  int  pass[5],
+    level,i;
+  long timet;
+
+  char answer[81]="";
+  char buf[2048];
+
+  level=strlen(Password);
+  timet=time(NULL);
+  srandom((int) timet);
+  for(i=0;i<5;i++) pass[i]=(int) (level * (random()/(RAND_MAX+1.0)));
+	
+  sprintf(buffer,"%10.10ld%s",timet,Password);
+  axio_printf(NodeIo,"%s %d %d %d %d %d [%010.10ld]\n",
+	      PassPrompt,pass[0]+1,pass[1]+1,pass[2]+1,pass[3]+1,pass[4]+1,timet);
+	
+  sprintf(answer,"%c%c%c%c%c",Password[pass[0]],Password[pass[1]],Password[pass[2]],Password[pass[3]],Password[pass[4]]);
+
+  axio_flush(NodeIo);
+  axio_gets(buf, sizeof(buf), NodeIo);
+  
+
+  if(strlen(buf)==32) i=strcmp(buf,tmp);
+  else	i=strcmp(buf,answer);
+
+  if(i)	{
+    axio_printf(NodeIo,"Password incorrect!");
+    return 0;
+  }
+  if (User.ul_type == AF_NETROM) {
+    axio_printf(NodeIo,"%s} ", NodeId);
+  }
+  axio_printf(NodeIo,"URONode Shell engaged - use EXTREME caution! \n\n");
+  return 1;
+} 
+
+/*---------------------------------------------------------------------------*/
+
+int do_system(int argc, char **argv)
+{
+  int i;
+  struct passwd *pw=NULL;
+  argp[0]=argv[0];
+  for(i=1;i<(argc);i++) argp[i]=argv[i];
+  argp[argc]=NULL;
+
+  axio_puts("",NodeIo);
+  if (other_id!=NULL && strcmp(other_id, USER_NOBODY)!=0) pw=getpwnam(other_id);
+
+  if (pw==NULL) {
+    if (User.ul_type == AF_NETROM) {
+      axio_printf(NodeIo,"%s} ", NodeId);
+    } 
+    node_msg("Permission denied\n");
+    syslog(LOG_INFO, "system: %s attempted command %s", User.call, argv[0]);
+    axio_puts("",NodeIo);
+    return 1;
+  }
+  if (strncmp(argv[0],"sysop",strlen(argv[0]))==0) 
+    {
+      if (shell==1) {
+	User.state = STATE_EXTCMD;
+	User.dl_type = AF_UNSPEC;
+	strcpy(User.dl_name, "sysop");
+	strupr(User.dl_name);
+	update_user();
+	if (check_passwd()==0) return 0; 
+	login_open(pw, "/bin/bash");
+	axio_puts("",NodeIo);
+	return 0;
+      } else {
+	if (User.ul_type == AF_NETROM) {
+	  axio_printf(NodeIo,"%s} ", NodeId);
+	}
+	node_msg("permission denied");
+	axio_puts("",NodeIo);
+	return 1;
+      };
+    }
+  if (User.ul_type == AF_NETROM) {
+    axio_printf(NodeIo,"%s} ", NodeId);
+  }
+  node_msg("unknown command");
+
+  return 0;
+}
+
+int examine_user(void)
+{
+  FILE *users;
+  char call[10], buf[1024], *cp, *ep;
+  char flags[40];
+
+  strcpy(other_id, USER_NOBODY);
+
+  if ((users=fopen(CONF_USERS_FILE, "r"))==NULL) {
+    node_msg("system: cannot open authority file: %s", CONF_USERS_FILE);
+    syslog(LOG_ERR, "system: cannot open authority file: %s", CONF_USERS_FILE);
+    axio_puts("",NodeIo);
+    return 1;
+  }
+
+  strcpy(call, User.call);
+  cp=strchr(call, '-');
+  if (cp) *cp='\0';
+
+  while(fgets(buf, 1024, users)) {
+    ep=strchr(buf, '#');
+    if (ep) *ep='\0';
+    if (*buf==0) continue;
+    cp=strtok(buf, ":\t\n\r");
+    if (cp==NULL) continue;
+    if (strcasecmp(cp, call)==0) {
+      cp=strtok(NULL, ":\t\n\r");
+      if (cp==NULL) continue;
+      strcpy(Password, cp);
+      cp=strtok(NULL, ":\t\n\r");
+      if (cp==NULL) continue;
+      strcpy(other_id, cp);
+      cp=strtok(NULL, ":\t\n\r");
+      if (cp==NULL) continue;
+      strcpy(flags, cp);
+    }
+  }
+
+  if (strcmp(other_id, USER_NOBODY)==0) return 0;
+  
+  cp=strtok(flags, " ,;-/\t\n\r");
+  if (cp==NULL) return 0;
+  do {
+    if (strcmp(cp, "shell")==0) {
+      shell=1;
+      add_internal_cmd(&Nodecmds, "SYSop",	1, do_system);
+    }
+    cp=strtok(NULL, " ,;-/\t\n\r");
+  } while(cp!=NULL);
+
+  return 0;
+}
+
+struct nodelastlog {
+  char ll_user[8];
+  long ll_time;
+  char ll_line[LAST_DATA_SIZE];
+  char ll_host[LAST_DATA_SIZE];
+  int  ll_count;
+};
+
+struct ipheardlastlog {
+  char ii_host[LAST_DATA_SIZE];
+};
+
+void lastlog(void)
+{
+  struct nodelastlog ll;
+  int last;
+  int count=0;
+  int hit=0;
+  int UserId=0;
+  char tty[LAST_DATA_SIZE];
+  char hostname[LAST_DATA_SIZE];
+  char usercall[10];
+  char *cp;
+  int escape;
+  strcpy(usercall, User.call);  
+  cp=strchr(usercall, '-');
+  if (cp) *cp='\0';
+  strcpy(tty, "");
+  switch (User.ul_type) {
+  case AF_FLEXNET: strcpy(hostname, "FlexNet");
+    break;
+  case AF_AX25: strcpy(hostname, "[");
+    strcat(hostname, "AX25");
+    strcat(hostname, "] ");
+    strcat(hostname, User.call);
+    if (strlen(User.ul_name)>0) {
+      strcat(hostname, " via ");
+      strcat(hostname, User.ul_name);
+    }
+    break;
+  case AF_NETROM: strcpy(hostname, "<");
+    strcat(hostname, User.ul_port);
+    strcat(hostname, "> ");
+    strcat(hostname, User.call);
+    if (strlen(User.ul_name)>0) {
+      strcat(hostname, "@");
+      strcat(hostname, User.ul_name);
+    }
+    break;
+#ifdef HAVE_ROSE
+  case AF_ROSE:   strcpy(hostname, User.call);
+    if (strlen(User.ul_name)>0) {
+      strcat(hostname, " at ");
+      strcat(hostname, User.ul_name);
+    }
+    break;
+#endif    
+  case AF_INET:   strcpy(hostname, User.ul_name);
+    break;
+  case AF_UNSPEC: strcpy(hostname, User.call);
+    strcat(hostname, " on local");
+    break;
+  default:        strcpy(hostname, "");
+    break;
+  }
+
+  if ((last = open(DATA_NODE_LAST_FILE, O_RDWR, 0)) >= 0) { 
+    lseek(last, (off_t)UserId * sizeof(ll), L_SET);
+    while (read(last, (char *)&ll, sizeof(ll)) == sizeof(ll) && ll.ll_time != 0) {
+      if (strcmp(ll.ll_user,usercall)==0) {
+	escape = (check_perms(PERM_NOESC, 0L) == 0) ? -1 : EscChar;
+#ifdef HAVEMOTD
+	/*
+	  if (User.ul_type != AF_NETROM) {
+	  axio_printf(NodeIo," Escape is: %s%c\n", escape < 32 ? "CTRL-" : "", escape < 32 ? (escape + 'A' - 1) : escape);
+	  axio_printf(NodeIo,"Last login: %.*s ",24-5,(char *)ctime(&ll.ll_time));
+	  if (*ll.ll_host != '\0') axio_printf(NodeIo,"\n      From: %.*s\n",(int)sizeof(ll.ll_host), ll.ll_host);
+	  else                     axio_printf(NodeIo," on %.*s\n",(int)sizeof(ll.ll_line), ll.ll_line); 
+	  }
+	*/
+#endif
+        count=ll.ll_count;
+        hit++;
+        break;
+      } else UserId++;
+    }
+    lseek(last, (off_t)UserId * sizeof(ll), L_SET); 
+  }
+  memset((char *)&ll, 0, sizeof(ll)); 
+  if ((hit==0) && (User.ul_type != AF_NETROM)) {
+    axio_printf(NodeIo,"Welcome, new user! Please use the Info and ? commands.\n\n");
+    count=0;
+  }
+  ll.ll_count=count+1;
+  (void)time(&ll.ll_time);
+  strncpy(ll.ll_line, tty, sizeof(ll.ll_line));
+  strncpy(ll.ll_user, usercall, sizeof(ll.ll_user));
+  if (hostname) strncpy(ll.ll_host, hostname, sizeof(ll.ll_host));
+  write(last, (char *)&ll, sizeof(ll));
+  close(last);
+}
+
+int do_last(int argc, char **argv)
+{
+  int last;
+  struct nodelastlog ll;
+  int Entries=0;
+  char call[10], *cp;
+
+  if ((last = open(DATA_NODE_LAST_FILE, O_RDONLY, 0)) <= 0) {
+    node_perror(DATA_NODE_LAST_FILE, errno);
+    return -1;
+  }
+
+  if (argc < 2) {
+    if (User.ul_type == AF_NETROM) {
+      axio_printf(NodeIo,"%s} ", NodeId);
+    }
+    axio_printf(NodeIo,"Usage: Who <callsign or *>");
+    close(last);
+    if (User.ul_type == AF_NETROM) {
+      node_msg("");
+    }
+    return 0;
+  }
+
+  if (strcmp(argv[1],"*")==0) {
+    cp=NULL;
+    if (User.ul_type == AF_NETROM) {
+      axio_printf(NodeIo,"%s} ", NodeId);
+    }
+    if (check_perms(PERM_ANSI, 0L) != -1) {
+      axio_printf(NodeIo, "\e[01;37m");
+    }
+    axio_printf(NodeIo,"Logins for ALL:\n", call);
+    if (check_perms(PERM_ANSI, 0L) != -1) {
+      axio_printf(NodeIo, "\e[0m");
+    }
+  } else {
+    if (!ax25_aton_entry(argv[1], call)) {
+      strcpy(call,strupr(argv[1]));
+      cp=strchr(call,'-');
+      if (cp) *cp='\0';
+      cp=call;
+      if (User.ul_type == AF_NETROM) {
+	axio_printf(NodeIo,"%s} ", NodeId);
+      }
+      if (check_perms(PERM_ANSI, 0L) != -1) {
+        axio_printf(NodeIo, "\e[01;37m");
+      }
+      axio_printf(NodeIo,"Last online information for %s:\n", call);
+      if (check_perms(PERM_ANSI, 0L) != -1) {
+        axio_printf(NodeIo, "\e[0m");
+      }
+    } else {
+      if (User.ul_type == AF_NETROM) {
+	axio_printf(NodeIo,"%s} ", NodeId);
+      }
+      axio_printf(NodeIo,"Usage: Who <callsign or *>\n");
+      if (User.ul_type == AF_NETROM) {
+      	node_msg("");
+      }
+      close(last);
+      return -1;
+    }
+  }
+  
+  lseek(last, (off_t)Entries * sizeof(ll), L_SET);
+  /*  while (Entries < 20 && (read(last, (char *)&ll, sizeof(ll)) == sizeof(ll) && ll.ll_time != 0)) {  */
+  while (read(last, (char *)&ll, sizeof(ll)) == sizeof(ll) && ll.ll_time !=0) {
+    if (cp && strcasecmp(cp,ll.ll_user)!=0) continue;
+    if (Entries==0) {
+      axio_printf(NodeIo,"User       Last Online          Count  From\n");
+      axio_printf(NodeIo,"------     -------------------- -----  -----------------------------");
+    }
+    axio_printf(NodeIo,"\n%-10s ", ll.ll_user); 
+    axio_printf(NodeIo,"%.*s  ",24-5,(char *)ctime(&ll.ll_time));
+    axio_printf(NodeIo,"%-5d ",ll.ll_count);
+    if (*ll.ll_host != '\0') axio_printf(NodeIo," %.*s",(int)sizeof(ll.ll_host), ll.ll_host);
+    else axio_printf(NodeIo," on %.*s",(int)sizeof(ll.ll_line), ll.ll_line);
+    Entries++;
+  }
+  lseek(last, (off_t)Entries * sizeof(ll), L_SET);
+  
+  close(last);
+  if (!cp && Entries==0) axio_printf(NodeIo,"No users in the lastlog database.");
+  if (cp && Entries==0) axio_printf(NodeIo,"%s Never logged in.", call);
+
+  if (User.ul_type == AF_NETROM) {
+    node_msg("");
+  }
+  return 0;
+}
diff --git a/user.c b/user.c
new file mode 100644
index 0000000..2b1fb44
--- /dev/null
+++ b/user.c
@@ -0,0 +1,289 @@
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <time.h>
+#include <sys/utsname.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/file.h>
+#include <sys/socket.h>
+#include <signal.h>
+#include <netax25/procutils.h>
+#include <netax25/axlib.h>
+
+#include "node.h"
+#include "sysinfo.h"
+
+struct user User	= {0};
+static long CallerPos	= -1L;
+
+void login_user(void)
+{
+  FILE *f;
+  struct user u;
+  long pos = 0L;
+  long free = -1L;
+  struct stat statbuf;
+
+  if (stat(DATA_NODE_LOGIN_FILE, &statbuf) == -1) {
+    node_perror(DATA_NODE_LOGIN_FILE, errno);
+    return;
+  }
+  if (statbuf.st_size % sizeof(struct user) != 0) {
+    node_msg("%s: Incorrect size", DATA_NODE_LOGIN_FILE);
+    node_log(LOGLVL_ERROR, "%s: Incorrect size", DATA_NODE_LOGIN_FILE);
+    return;
+  }
+  time(&User.logintime);
+  User.cmdtime = User.logintime;
+  User.pid     = getpid();
+  if ((f = fopen(DATA_NODE_LOGIN_FILE, "r+")) == NULL) {
+    node_perror(DATA_NODE_LOGIN_FILE, errno);
+    return;
+  }
+  if (flock(fileno(f), LOCK_EX) == -1) {
+    node_perror("login_user: flock", errno);
+    fclose(f);
+    return;
+  }
+  while (fread(&u, sizeof(u), 1, f) == 1) {
+    if (u.pid == -1 || (kill(u.pid, 0) == -1 && errno == ESRCH)) {
+      free = pos;
+      break;
+    }
+    pos += sizeof(u);
+  }
+  if (free != -1L && fseek(f, free, 0L) == -1) {
+    node_perror("login_user: fseek", errno);
+    fclose(f);
+    return;
+  }
+  fflush(f);
+  CallerPos = ftell(f);	
+  fwrite(&User, sizeof(User), 1, f);
+  fflush(f);
+  flock(fileno(f), LOCK_UN);
+  fclose(f);
+}
+
+void logout_user(void)
+{
+  FILE *f;
+
+  if (CallerPos == -1L)
+    return;
+  if ((f = fopen(DATA_NODE_LOGIN_FILE, "r+")) == NULL) {
+    node_perror(DATA_NODE_LOGIN_FILE, errno);
+    return;
+  }
+  if (fseek(f, CallerPos, 0) == -1) {
+    node_perror("logout_user: fseek", errno);
+    fclose(f);
+    return;
+  }
+  User.pid = -1;
+  fwrite(&User, sizeof(User), 1, f);
+  fclose(f);
+}
+
+void update_user(void)
+{
+  FILE *f;
+
+  if (CallerPos == -1L)
+    return;
+  if ((f = fopen(DATA_NODE_LOGIN_FILE, "r+")) == NULL) {
+    node_perror(DATA_NODE_LOGIN_FILE, errno);
+    return;
+  }
+  if (fseek(f, CallerPos, 0) == -1) {
+    node_perror("update_user: fseek", errno);
+    fclose(f);
+    return;
+  }
+  fwrite(&User, sizeof(User), 1, f);
+  fclose(f);
+}
+
+int user_count(void)
+{
+  FILE *f;
+  struct user u;
+  int cnt = 0;
+
+  if ((f = fopen(DATA_NODE_LOGIN_FILE, "r")) == NULL) {
+    node_perror(DATA_NODE_LOGIN_FILE, errno);
+    return 0;
+  }
+  while (fread(&u, sizeof(u), 1, f) == 1)
+    if (u.pid != -1 && (kill(u.pid, 0) != -1 || errno != ESRCH))
+      cnt++;
+  fclose(f);
+  return cnt;
+}
+
+int user_list(int argc, char **argv)
+{
+  FILE *f;
+  struct user u;
+  struct tm *tp;
+  struct proc_nr_nodes *np;
+  char buf[80];
+  long l;
+  axio_puts("",NodeIo);
+  if ((f = fopen(DATA_NODE_LOGIN_FILE, "r")) == NULL) {
+    node_perror(DATA_NODE_LOGIN_FILE, errno);
+    return 0;
+  }
+  if (User.ul_type == AF_NETROM) {
+    axio_printf(NodeIo, "%s} %s", NodeId, VERSION);
+  }
+  if (User.ul_type == AF_INET)  {
+    axio_printf(NodeIo, "\e[01;35m"); 
+  } else {
+    axio_printf(NodeIo, "Current users:");
+  }
+  if (user_count() == 0) {
+    axio_printf(NodeIo, " No users online.\n");
+  }
+  if (User.ul_type == AF_INET) {
+    axio_printf(NodeIo,"\e[0;m");
+  } 
+  if (user_count() != 0) /* axio_printf(NodeIo,"") */ ;
+  while (fread(&u, sizeof(u), 1, f) == 1) {
+    if (u.pid == -1 || (kill(u.pid, 0) == -1 && errno == ESRCH))
+      continue;
+    switch (u.ul_type) {
+    case AF_FLEXNET:
+      sprintf(buf, "\nFlexNet (%.9s)",
+	      u.call);
+      break;
+    case AF_AX25:
+      sprintf(buf, "\nUplink (%.9s on interface %.10s)",
+	      u.call, u.ul_name);
+      break;
+    case AF_NETROM:
+      if ((np = find_node(u.ul_name, NULL)) != NULL) {
+	sprintf(buf, "\nCircuit (%.9s %.18s)",
+		u.call,
+		print_node(np->alias, np->call));
+      } else {
+	sprintf(buf, "\nCircuit (%.9s %.18s)",
+		u.call, u.ul_name);
+      }
+      break;
+#ifdef HAVE_ROSE			
+    case AF_ROSE:
+      sprintf(buf, "\nROSE (%.9s %.18s)",
+	      u.call, u.ul_name);
+      break;
+#endif			
+    case AF_INET:
+      sprintf(buf, "\nTelnet (%.9s @ %.16s)",
+	      u.call, u.ul_name);
+      break;
+    case AF_UNSPEC:
+      sprintf(buf, "\nHost (%.9s on local)",
+	      u.call);
+      break;
+    default:
+      sprintf(buf, "\n?????? (%.9s %.18s)",
+	      u.call, u.ul_name);
+      break;
+    }
+    axio_printf(NodeIo,"%-37.37s ", buf);
+    switch (u.state) {
+    case STATE_QUIT:
+      logout_user();
+      break;
+    case STATE_LOGIN:
+      axio_puts("  -> Logging in",NodeIo);
+      break;
+    case STATE_IDLE:
+      time(&l);
+      l -= u.cmdtime;
+      tp = gmtime(&l);
+      axio_printf(NodeIo,"  -> Idle (%d:%02d:%02d:%02d)",
+		  tp->tm_yday, tp->tm_hour,
+		  tp->tm_min, tp->tm_sec);
+      break;
+    case STATE_TRYING:
+      switch (u.dl_type) {
+      case AF_FLEXNET:
+	axio_printf(NodeIo,"  -> Trying (%s)",
+		    u.dl_name);
+	break;
+      case AF_AX25:
+	axio_printf(NodeIo,"  -> Trying (%s on interface %s)",
+		    u.dl_name, u.dl_port);
+	break;
+      case AF_NETROM:
+	axio_printf(NodeIo,"  -> Trying (%s)",
+		    u.dl_name);
+	break;
+#ifdef HAVE_ROSE							
+      case AF_ROSE:
+	axio_printf(NodeIo,"  -> Trying (%s)",
+		    u.dl_name);
+	break;
+#endif				
+      case AF_INET:
+	axio_printf(NodeIo,"  -> Trying (%s:%s)",
+		    u.dl_name, u.dl_port);
+	break;
+      default:
+	axio_puts("  -> ???",NodeIo);
+	break;
+      }
+      break;
+    case STATE_CONNECTED:
+      switch (u.dl_type) {
+      case AF_FLEXNET:
+	axio_printf(NodeIo,"<--> FlexNet (%s)",
+		    u.dl_name);
+	break;
+      case AF_AX25:
+	axio_printf(NodeIo,"<--> Downlink (%s on interface %s)",
+		    u.dl_name, u.dl_port);
+	break;
+      case AF_NETROM:
+	axio_printf(NodeIo,"<--> Circuit (%s)",
+		    u.dl_name);
+	break;
+#ifdef HAVE_ROSE							
+      case AF_ROSE:
+	axio_printf(NodeIo,"<--> ROSE (%s)",
+		    u.dl_name);
+	break;
+#endif				
+      case AF_INET:
+	axio_printf(NodeIo,"<--> Telnet (%s:%s)",
+		    u.dl_name, u.dl_port);
+	break;
+      default:
+	axio_printf(NodeIo,"<--> ???");
+	break;
+      }
+      break;
+    case STATE_PINGING:
+      axio_printf(NodeIo,"<--> Pinging (%s)", u.dl_name);
+      break;
+    case STATE_EXTCMD:
+      axio_printf(NodeIo,"<--> Extcmd  (%s)", u.dl_name);
+      break;
+    default:
+      axio_puts("  -> ??????",NodeIo);
+      break;
+    }
+    axio_puts("",NodeIo);
+  }
+  if (User.ul_type == AF_NETROM) {
+    node_msg("");
+  }
+  fclose(f);
+  return 0;
+}
+
diff --git a/util.c b/util.c
new file mode 100644
index 0000000..a7e8e37
--- /dev/null
+++ b/util.c
@@ -0,0 +1,115 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <syslog.h>
+#include <string.h>
+#include <time.h>
+#include <sys/file.h>
+
+#include <sys/socket.h>
+#include <netax25/ax25.h>
+#include <netrose/rose.h>
+#include <netax25/axlib.h>
+
+#include "node.h"
+#include "sysinfo.h"
+#include "procinfo.h"
+
+static char buf[256];
+char *HostName;
+char *Prompt;
+
+void node_msg(const char *fmt, ...)
+{
+  va_list args;
+	
+  va_start(args, fmt);
+  vsprintf(buf, fmt, args);
+  va_end(args);
+  axio_printf(NodeIo,"%s\n", buf);
+}
+/*
+  void node_prompt(const char *fmt, ...)
+  {
+  va_list args;
+  va_start(args, fmt);
+  vsprintf(buf, fmt, args);
+  va_end(args);
+  if (User.ul_type == AF_NETROM) {
+  axio_printf(NodeIo,"%s} ", NodeId);
+  }
+  if ((User.ul_type == AF_INET) && (check_perms(PERM_ANSI, 0L) != -1)) {
+  axio_printf(NodeIo,"\n\e[01;31m%s\e[0m@\e[01;34m%s\e[0m:/uronode$ ",User.call, HostName);
+  } 
+  if ((User.ul_type == AF_INET) && (check_perms(PERM_ANSI, 0L) == -1)) {
+  axio_printf(NodeIo,"\n%s@%s:/uronode$ ", User.call, HostName);
+  }
+  if (User.ul_type == AF_AX25) {
+  axio_printf(NodeIo,"%s",Prompt);
+  }
+  }
+*/
+void node_perror(char *str, int err)
+{
+  int oldmode;
+
+  oldmode = axio_eolmode(NodeIo, EOLMODE_TEXT);
+  buf[0] = 0;
+  if (str)
+    strcpy(buf, str);
+  if (str && err != -1)
+    strcat(buf, ": ");
+  if (err != -1)
+    strcat(buf, strerror(err));
+  axio_printf(NodeIo,"\nERROR; %s\n", buf);
+  axio_eolmode(NodeIo, oldmode);
+  axio_flush(NodeIo);
+  node_log(LOGLVL_ERROR, buf);
+}
+
+char *print_node(const char *alias, const char *call)
+{
+  static char node[17];
+
+  sprintf(node, "%s%s%s",
+	  !strcmp(alias, "*") ? "" : alias,
+	  !strcmp(call, "*") ? "" : ":", call);
+  
+  return node;
+}
+
+void node_log(int loglevel, const char *fmt, ...)
+{
+  static int opened = 0;
+  va_list args;
+  int pri;
+
+  if (LogLevel < loglevel)
+    return;
+  if (!opened) {
+    openlog("uronode", LOG_PID, LOG_LOCAL7);
+    opened = 1;
+  }
+  switch (loglevel) {
+  case LOGLVL_ERROR:
+    pri = LOG_ERR;
+    break;
+  case LOGLVL_LOGIN:
+    pri = LOG_NOTICE;
+    break;
+  case LOGLVL_GW:
+    pri = LOG_INFO;
+    break;
+  default:
+    pri = LOG_INFO;
+    break;
+  }
+  va_start(args, fmt);
+  vsnprintf(buf, sizeof(buf), fmt, args);
+  buf[sizeof(buf) - 1] = 0;
+  va_end(args);	
+  syslog(pri, "%s", buf);
+
+}
+

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



More information about the pkg-hamradio-commits mailing list